diff --git a/packages/cli-v3/src/build/extensions.ts b/packages/cli-v3/src/build/extensions.ts index 750be7dc6..e114a592c 100644 --- a/packages/cli-v3/src/build/extensions.ts +++ b/packages/cli-v3/src/build/extensions.ts @@ -126,37 +126,37 @@ function applyLayerToManifest(layer: BuildLayer, manifest: BuildManifest): Build let $manifest = { ...manifest }; if (layer.commands) { - manifest.build.commands ??= []; - manifest.build.commands = manifest.build.commands.concat(layer.commands); + $manifest.build.commands ??= []; + $manifest.build.commands = $manifest.build.commands.concat(layer.commands); } if (layer.build?.env) { - manifest.build.env ??= {}; - Object.assign(manifest.build.env, layer.build.env); + $manifest.build.env ??= {}; + Object.assign($manifest.build.env, layer.build.env); } if (layer.deploy?.env) { - manifest.deploy.env ??= {}; - manifest.deploy.sync ??= {}; - manifest.deploy.sync.env ??= {}; + $manifest.deploy.env ??= {}; + $manifest.deploy.sync ??= {}; + $manifest.deploy.sync.env ??= {}; for (const [key, value] of Object.entries(layer.deploy.env)) { if (!value) { continue; } - if (layer.deploy.override || manifest.deploy.env[key] === undefined) { - const existingValue = manifest.deploy.env[key]; + if (layer.deploy.override || $manifest.deploy.env[key] === undefined) { + const existingValue = $manifest.deploy.env[key]; if (existingValue !== value) { - manifest.deploy.sync.env[key] = value; + $manifest.deploy.sync.env[key] = value; } } } } if (layer.dependencies) { - const externals = manifest.externals ?? []; + const externals = $manifest.externals ?? []; for (const [name, version] of Object.entries(layer.dependencies)) { externals.push({ name, version }); @@ -165,6 +165,21 @@ function applyLayerToManifest(layer: BuildLayer, manifest: BuildManifest): Build $manifest.externals = externals; } + if (layer.image) { + $manifest.image ??= {}; + $manifest.image.instructions ??= []; + $manifest.image.pkgs ??= []; + + if (layer.image.instructions) { + $manifest.image.instructions = $manifest.image.instructions.concat(layer.image.instructions); + } + + if (layer.image.pkgs) { + $manifest.image.pkgs = $manifest.image.pkgs.concat(layer.image.pkgs); + $manifest.image.pkgs = Array.from(new Set($manifest.image.pkgs)); + } + } + return $manifest; } diff --git a/packages/cli-v3/src/commands/deploy.ts b/packages/cli-v3/src/commands/deploy.ts index 4e3f27b7c..256f753b0 100644 --- a/packages/cli-v3/src/commands/deploy.ts +++ b/packages/cli-v3/src/commands/deploy.ts @@ -378,6 +378,7 @@ async function _deployCommand(dir: string, options: DeployCommandOptions) { apiKey: projectClient.client.accessToken!, authAccessToken: authorization.auth.accessToken, compilationPath: destination.path, + buildEnvVars: buildManifest.build.env, }); logger.debug("Build result", buildResult); @@ -564,6 +565,7 @@ async function writeContainerfile(outputPath: string, buildManifest: BuildManife runtime: buildManifest.runtime, entrypoint: buildManifest.runControllerEntryPoint, build: buildManifest.build, + image: buildManifest.image, indexScript: buildManifest.indexControllerEntryPoint, }); diff --git a/packages/cli-v3/src/deploy/buildImage.ts b/packages/cli-v3/src/deploy/buildImage.ts index 6109fbce2..508750ca9 100644 --- a/packages/cli-v3/src/deploy/buildImage.ts +++ b/packages/cli-v3/src/deploy/buildImage.ts @@ -34,6 +34,7 @@ export interface BuildImageOptions { extraCACerts?: string; apiUrl: string; apiKey: string; + buildEnvVars?: Record; // Optional deployment spinner deploymentSpinner?: any; // Replace 'any' with the actual type if known @@ -62,6 +63,7 @@ export async function buildImage(options: BuildImageOptions) { extraCACerts, apiUrl, apiKey, + buildEnvVars, } = options; if (selfHosted) { @@ -81,6 +83,7 @@ export async function buildImage(options: BuildImageOptions) { extraCACerts: extraCACerts, apiUrl, apiKey, + buildEnvVars, }); } @@ -109,6 +112,7 @@ export async function buildImage(options: BuildImageOptions) { extraCACerts, apiUrl, apiKey, + buildEnvVars, }); } @@ -131,6 +135,7 @@ export interface DepotBuildImageOptions { loadImage?: boolean; noCache?: boolean; extraCACerts?: string; + buildEnvVars?: Record; } type BuildImageSuccess = { @@ -156,6 +161,10 @@ async function depotBuildImage(options: DepotBuildImageOptions): Promise value) + .flatMap(([key, value]) => ["--build-arg", `${key}=${value}`]); + const args = [ "build", "-f", @@ -179,6 +188,7 @@ async function depotBuildImage(options: DepotBuildImageOptions): Promise; } async function selfHostedBuildImage( @@ -273,7 +284,11 @@ async function selfHostedBuildImage( ): Promise { const imageRef = `${options.registryHost ? `${options.registryHost}/` : ""}${options.imageTag}`; - const buildArgs = [ + const buildArgs = Object.entries(options.buildEnvVars || {}) + .filter(([key, value]) => value) + .flatMap(([key, value]) => ["--build-arg", `${key}=${value}`]); + + const args = [ "build", "-f", "Containerfile", @@ -294,6 +309,7 @@ async function selfHostedBuildImage( `TRIGGER_API_URL=${options.apiUrl}`, "--build-arg", `TRIGGER_SECRET_KEY=${options.apiKey}`, + ...(buildArgs || []), ...(options.extraCACerts ? ["--build-arg", `NODE_EXTRA_CA_CERTS=${options.extraCACerts}`] : []), "--progress", "plain", @@ -302,7 +318,7 @@ async function selfHostedBuildImage( ".", // The build context ].filter(Boolean) as string[]; - logger.debug(`docker ${buildArgs.join(" ")}`, { + logger.debug(`docker ${args.join(" ")}`, { cwd: options.cwd, }); @@ -310,7 +326,7 @@ async function selfHostedBuildImage( let digest: string | undefined; // Build the image - const buildProcess = x("docker", buildArgs, { + const buildProcess = x("docker", args, { nodeOptions: { cwd: options.cwd }, }); @@ -408,10 +424,13 @@ function extractImageDigest(outputs: string[]) { export type GenerateContainerfileOptions = { runtime: BuildRuntime; build: BuildManifest["build"]; + image: BuildManifest["image"]; indexScript: string; entrypoint: string; }; +const DEFAULT_PACKAGES = ["busybox", "ca-certificates", "dumb-init", "git", "openssl"]; + export async function generateContainerfile(options: GenerateContainerfileOptions) { switch (options.runtime) { case "node": { @@ -434,9 +453,18 @@ async function generateBunContainerfile(options: GenerateContainerfileOptions) { const postInstallCommands = (options.build.commands || []).map((cmd) => `RUN ${cmd}`).join("\n"); + const baseInstructions = (options.image?.instructions || []).join("\n"); + const packages = Array.from(new Set(DEFAULT_PACKAGES.concat(options.image?.pkgs || []))).join( + " " + ); + return ` FROM imbios/bun-node:22-debian AS base -RUN apt-get update && apt-get --fix-broken install -y && apt-get install -y --no-install-recommends busybox ca-certificates dumb-init git openssl && apt-get clean && rm -rf /var/lib/apt/lists/* + +${baseInstructions} + +ENV DEBIAN_FRONTEND=noninteractive +RUN apt-get update && apt-get --fix-broken install -y && apt-get install -y --no-install-recommends ${packages} && apt-get clean && rm -rf /var/lib/apt/lists/* FROM base AS build @@ -530,10 +558,18 @@ async function generateNodeContainerfile(options: GenerateContainerfileOptions) const postInstallCommands = (options.build.commands || []).map((cmd) => `RUN ${cmd}`).join("\n"); + const baseInstructions = (options.image?.instructions || []).join("\n"); + const packages = Array.from(new Set(DEFAULT_PACKAGES.concat(options.image?.pkgs || []))).join( + " " + ); + return ` FROM node:21-bookworm-slim@sha256:99afef5df7400a8d118e0504576d32ca700de5034c4f9271d2ff7c91cc12d170 AS base + +${baseInstructions} + ENV DEBIAN_FRONTEND=noninteractive -RUN apt-get update && apt-get --fix-broken install -y && apt-get install -y --no-install-recommends busybox ca-certificates dumb-init git openssl && apt-get clean && rm -rf /var/lib/apt/lists/* +RUN apt-get update && apt-get --fix-broken install -y && apt-get install -y --no-install-recommends ${packages} && apt-get clean && rm -rf /var/lib/apt/lists/* FROM base AS build diff --git a/packages/core/src/v3/build/extensions.ts b/packages/core/src/v3/build/extensions.ts index 6f1b223a2..e6d63c7ed 100644 --- a/packages/core/src/v3/build/extensions.ts +++ b/packages/core/src/v3/build/extensions.ts @@ -56,6 +56,10 @@ export interface BuildLayer { id: string; commands?: string[]; files?: Record; + image?: { + pkgs?: string[]; + instructions?: string[]; + }; build?: { env?: Record; }; diff --git a/packages/core/src/v3/extensions/audioWaveform.ts b/packages/core/src/v3/extensions/audioWaveform.ts new file mode 100644 index 000000000..591111e6b --- /dev/null +++ b/packages/core/src/v3/extensions/audioWaveform.ts @@ -0,0 +1,59 @@ +import { BuildContext, BuildExtension } from "../build/extensions.js"; +import { BuildManifest } from "../schemas/build.js"; + +export type AudioWaveformOptions = { + version?: string; + checksum?: string; +}; + +const AUDIOWAVEFORM_VERSION = "1.10.1"; +const AUDIOWAVEFORM_CHECKSUM = + "sha256:00b41ea4d6e7a5b4affcfe4ac99951ec89da81a8cba40af19e9b98c3a8f9b4b8"; + +export function audioWaveform(options: AudioWaveformOptions = {}): BuildExtension { + return new AudioWaveformExtension(); +} + +class AudioWaveformExtension implements BuildExtension { + public readonly name = "AudioWaveformExtension"; + + constructor(private options: AudioWaveformOptions = {}) {} + + async onBuildComplete(context: BuildContext, manifest: BuildManifest) { + if (context.target === "dev") { + return; + } + + const opts = this.options.version + ? { + version: this.options.version, + checksum: this.options.checksum, + } + : { + version: AUDIOWAVEFORM_VERSION, + checksum: AUDIOWAVEFORM_CHECKSUM, + }; + + context.logger.debug("Adding audiowaveform to the build", { + ...opts, + }); + + const instructions = [ + `ADD ${ + opts.checksum ? `--checksum=${opts.checksum}` : "" + } https://github.com/bbc/audiowaveform/releases/download/${opts.version}/audiowaveform_${ + opts.version + }-1-12_amd64.deb .`, + `RUN dpkg -i audiowaveform_${opts.version}-1-12_amd64.deb || true`, + `RUN rm audiowaveform*.deb`, + ]; + + context.addLayer({ + id: "audiowaveform", + image: { + pkgs: ["sox"], + instructions, + }, + }); + } +} diff --git a/packages/core/src/v3/extensions/index.ts b/packages/core/src/v3/extensions/index.ts index 570aa844a..a6d0203d3 100644 --- a/packages/core/src/v3/extensions/index.ts +++ b/packages/core/src/v3/extensions/index.ts @@ -3,3 +3,4 @@ export * from "./additionalFiles.js"; export * from "./additionalPackages.js"; export * from "./prisma.js"; export * from "./syncEnvVars.js"; +export * from "./audioWaveform.js"; diff --git a/packages/core/src/v3/extensions/prisma.ts b/packages/core/src/v3/extensions/prisma.ts index 0846f9a95..d362b20d4 100644 --- a/packages/core/src/v3/extensions/prisma.ts +++ b/packages/core/src/v3/extensions/prisma.ts @@ -1,19 +1,24 @@ import assert from "node:assert"; import { existsSync } from "node:fs"; -import { cp } from "node:fs/promises"; -import { join, resolve } from "node:path"; +import { cp, readdir } from "node:fs/promises"; +import { dirname, join, resolve } from "node:path"; import { BuildContext, BuildExtension } from "../build/extensions.js"; -import { BuildManifest, BuildTarget } from "../schemas/build.js"; import { binaryForRuntime } from "../build/runtime.js"; +import { BuildManifest, BuildTarget } from "../schemas/build.js"; export type PrismaExtensionOptions = { schema: string; migrate?: boolean; version?: string; + directUrlEnvVarName?: string; }; const BINARY_TARGET = "linux-arm64-openssl-3.0.x"; +export function prismaExtension(options: PrismaExtensionOptions): PrismaExtension { + return new PrismaExtension(options); +} + export class PrismaExtension implements BuildExtension { moduleExternals: string[]; @@ -76,51 +81,109 @@ export class PrismaExtension implements BuildExtension { context.logger.debug(`PrismaExtension is generating the Prisma client for version ${version}`); - // Now we need to add a layer that: - // Copies the prisma schema to the build outputPath - // Adds the `prisma` CLI dependency to the dependencies - // Adds the `prisma generate` command, which generates the Prisma client - const schemaDestinationPath = join(manifest.outputPath, "prisma", "schema.prisma"); - // Copy the prisma schema to the build output path - context.logger.debug( - `Copying the prisma schema from ${this._resolvedSchemaPath} to ${schemaDestinationPath}` - ); + const usingSchemaFolder = dirname(this._resolvedSchemaPath).endsWith("schema"); - await cp(this._resolvedSchemaPath, schemaDestinationPath); + const commands: string[] = []; - const commands = [ - `${binaryForRuntime( - manifest.runtime - )} node_modules/prisma/build/index.js generate --schema=./prisma/schema.prisma`, - ]; + let prismaDir: string | undefined; + + if (usingSchemaFolder) { + const schemaDir = dirname(this._resolvedSchemaPath); + + prismaDir = dirname(schemaDir); + + context.logger.debug(`Using the schema folder: ${schemaDir}`); + + // Find all the files in schemaDir that end with .prisma (excluding the schema.prisma file) + const prismaFiles = await readdir(schemaDir).then((files) => + files.filter((file) => file.endsWith(".prisma")) + ); + + context.logger.debug(`Found prisma files in the schema folder`, { + prismaFiles, + }); + + const schemaDestinationPath = join(manifest.outputPath, "prisma", "schema"); + + const allPrismaFiles = [...prismaFiles]; + + for (const file of allPrismaFiles) { + const destination = join(schemaDestinationPath, file); + const source = join(schemaDir, file); + + context.logger.debug(`Copying the prisma schema from ${source} to ${destination}`); + + await cp(source, destination); + } + + commands.push( + `${binaryForRuntime(manifest.runtime)} node_modules/prisma/build/index.js generate` // Don't add the --schema flag or this will fail + ); + } else { + prismaDir = dirname(this._resolvedSchemaPath); + // Now we need to add a layer that: + // Copies the prisma schema to the build outputPath + // Adds the `prisma` CLI dependency to the dependencies + // Adds the `prisma generate` command, which generates the Prisma client + const schemaDestinationPath = join(manifest.outputPath, "prisma", "schema.prisma"); + // Copy the prisma schema to the build output path + context.logger.debug( + `Copying the prisma schema from ${this._resolvedSchemaPath} to ${schemaDestinationPath}` + ); + + await cp(this._resolvedSchemaPath, schemaDestinationPath); + + commands.push( + `${binaryForRuntime( + manifest.runtime + )} node_modules/prisma/build/index.js generate --schema=./prisma/schema.prisma` + ); + } + + const env: Record = {}; if (this.options.migrate) { + // Copy the migrations directory to the build output path + const migrationsDir = join(prismaDir, "migrations"); + const migrationsDestinationPath = join(manifest.outputPath, "prisma", "migrations"); + + context.logger.debug( + `Copying the prisma migrations from ${migrationsDir} to ${migrationsDestinationPath}` + ); + + await cp(migrationsDir, migrationsDestinationPath, { recursive: true }); + commands.push( `${binaryForRuntime(manifest.runtime)} node_modules/prisma/build/index.js migrate deploy` ); + + env.DATABASE_URL = manifest.deploy.env?.DATABASE_URL; + + if (this.options.directUrlEnvVarName) { + env[this.options.directUrlEnvVarName] = + manifest.deploy.env?.[this.options.directUrlEnvVarName]; + } else { + env.DIRECT_URL = manifest.deploy.env?.DIRECT_URL; + } } + context.logger.debug(`Adding the prisma layer with the following commands`, { + commands, + env, + dependencies: { + prisma: version, + }, + }); + context.addLayer({ id: "prisma", commands, dependencies: { prisma: version, }, - build: this.options.migrate - ? { - env: { - DATABASE_URL: manifest.deploy.env?.DATABASE_URL, - DATABASE_DIRECT_URL: - manifest.deploy.env?.DATABASE_DIRECT_URL ?? - manifest.deploy.env?.DIRECT_URL ?? - manifest.deploy.env?.DATABASE_URL, - DIRECT_URL: - manifest.deploy.env?.DATABASE_DIRECT_URL ?? - manifest.deploy.env?.DIRECT_URL ?? - manifest.deploy.env?.DATABASE_URL, - }, - } - : {}, + build: { + env, + }, }); } } diff --git a/packages/core/src/v3/schemas/build.ts b/packages/core/src/v3/schemas/build.ts index fd3ca6f2a..19f745489 100644 --- a/packages/core/src/v3/schemas/build.ts +++ b/packages/core/src/v3/schemas/build.ts @@ -52,6 +52,12 @@ export const BuildManifest = z.object({ }) .optional(), }), + image: z + .object({ + pkgs: z.array(z.string()).optional(), + instructions: z.array(z.string()).optional(), + }) + .optional(), otelImportHook: z .object({ include: z.array(z.string()).optional(), diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ae6fefcea..3d9209b58 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1354,6 +1354,9 @@ importers: '@opentelemetry/api': specifier: 1.4.1 version: 1.4.1 + '@prisma/client': + specifier: 5.18.0 + version: 5.18.0(prisma@5.18.0) '@react-email/components': specifier: ^0.0.17 version: 0.0.17(@types/react@18.3.1)(react@18.2.0) @@ -1475,6 +1478,9 @@ importers: esbuild: specifier: ^0.19.11 version: 0.19.11 + prisma: + specifier: 5.18.0 + version: 5.18.0 trigger.dev: specifier: workspace:* version: link:../../packages/cli-v3 @@ -7878,6 +7884,19 @@ packages: resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==} dev: false + /@prisma/client@5.18.0(prisma@5.18.0): + resolution: {integrity: sha512-BWivkLh+af1kqC89zCJYkHsRcyWsM8/JHpsDMM76DjP3ZdEquJhXa4IeX+HkWPnwJ5FanxEJFZZDTWiDs/Kvyw==} + engines: {node: '>=16.13'} + requiresBuild: true + peerDependencies: + prisma: '*' + peerDependenciesMeta: + prisma: + optional: true + dependencies: + prisma: 5.18.0 + dev: false + /@prisma/client@5.4.1(prisma@5.4.1): resolution: {integrity: sha512-xyD0DJ3gRNfLbPsC+YfMBBuLJtZKQfy1OD2qU/PZg+HKrr7SO+09174LMeTlWP0YF2wca9LxtVd4HnAiB5ketQ==} engines: {node: '>=16.13'} @@ -7892,14 +7911,41 @@ packages: prisma: 5.4.1 dev: false + /@prisma/debug@5.18.0: + resolution: {integrity: sha512-f+ZvpTLidSo3LMJxQPVgAxdAjzv5OpzAo/eF8qZqbwvgi2F5cTOI9XCpdRzJYA0iGfajjwjOKKrVq64vkxEfUw==} + + /@prisma/engines-version@5.18.0-25.4c784e32044a8a016d99474bd02a3b6123742169: + resolution: {integrity: sha512-a/+LpJj8vYU3nmtkg+N3X51ddbt35yYrRe8wqHTJtYQt7l1f8kjIBcCs6sHJvodW/EK5XGvboOiwm47fmNrbgg==} + /@prisma/engines-version@5.4.1-1.2f302df92bd8945e20ad4595a73def5b96afa54f: resolution: {integrity: sha512-+nUQM/y8C+1GG5Ioeqcu6itFslCfxvQSAUVSMC9XM2G2Fcq0F4Afnp6m0pXF6X6iUBWen7jZBPmM9Qlq4Nr3/A==} dev: false + /@prisma/engines@5.18.0: + resolution: {integrity: sha512-ofmpGLeJ2q2P0wa/XaEgTnX/IsLnvSp/gZts0zjgLNdBhfuj2lowOOPmDcfKljLQUXMvAek3lw5T01kHmCG8rg==} + requiresBuild: true + dependencies: + '@prisma/debug': 5.18.0 + '@prisma/engines-version': 5.18.0-25.4c784e32044a8a016d99474bd02a3b6123742169 + '@prisma/fetch-engine': 5.18.0 + '@prisma/get-platform': 5.18.0 + /@prisma/engines@5.4.1: resolution: {integrity: sha512-vJTdY4la/5V3N7SFvWRmSMUh4mIQnyb/MNoDjzVbh9iLmEC+uEykj/1GPviVsorvfz7DbYSQC4RiwmlEpTEvGA==} requiresBuild: true + /@prisma/fetch-engine@5.18.0: + resolution: {integrity: sha512-I/3u0x2n31rGaAuBRx2YK4eB7R/1zCuayo2DGwSpGyrJWsZesrV7QVw7ND0/Suxeo/vLkJ5OwuBqHoCxvTHpOg==} + dependencies: + '@prisma/debug': 5.18.0 + '@prisma/engines-version': 5.18.0-25.4c784e32044a8a016d99474bd02a3b6123742169 + '@prisma/get-platform': 5.18.0 + + /@prisma/get-platform@5.18.0: + resolution: {integrity: sha512-Tk+m7+uhqcKDgnMnFN0lRiH7Ewea0OEsZZs9pqXa7i3+7svS3FSCqDBCaM9x5fmhhkufiG0BtunJVDka+46DlA==} + dependencies: + '@prisma/debug': 5.18.0 + /@prisma/instrumentation@5.11.0: resolution: {integrity: sha512-ou4nvDpNEY6+t3Dn9juOTz6tK33D0Y4XXkEZ2uPd8KH6Mqmc+4LYOOm470DP7noj7dyJjuGiM+wpPk//HKrcDg==} dependencies: @@ -23543,6 +23589,14 @@ packages: react: 18.2.0 dev: false + /prisma@5.18.0: + resolution: {integrity: sha512-+TrSIxZsh64OPOmaSgVPH7ALL9dfU0jceYaMJXsNrTkFHO7/3RANi5K2ZiPB1De9+KDxCWn7jvRq8y8pvk+o9g==} + engines: {node: '>=16.13'} + hasBin: true + requiresBuild: true + dependencies: + '@prisma/engines': 5.18.0 + /prisma@5.4.1: resolution: {integrity: sha512-op9PmU8Bcw5dNAas82wBYTG0yHnpq9/O3bhxbDBrNzwZTwBqsVCxxYRLf6wHNh9HVaDGhgjjHlu1+BcW8qdnBg==} engines: {node: '>=16.13'} diff --git a/references/v3-catalog/package.json b/references/v3-catalog/package.json index 8e923bd85..1a516cf6b 100644 --- a/references/v3-catalog/package.json +++ b/references/v3-catalog/package.json @@ -13,9 +13,10 @@ "build:client": "tsup-node ./src/clientUsage.ts --format esm,cjs", "client": "ts-node -r dotenv/config -r tsconfig-paths/register ./src/clientUsage.ts", "triggerWithLargePayload": "ts-node -r dotenv/config -r tsconfig-paths/register ./src/triggerWithLargePayload.ts", - "postinstall": "echo 'package.json postinstall'" + "postinstall": "prisma generate --no-hints" }, "dependencies": { + "@prisma/client": "5.18.0", "@ffmpeg-installer/ffmpeg": "^1.1.0", "@ffprobe-installer/ffprobe": "^2.1.2", "@infisical/sdk": "^2.1.9", @@ -66,6 +67,7 @@ "trigger.dev": "workspace:*", "ts-node": "^10.9.2", "tsconfig-paths": "^4.2.0", - "typescript": "^5.5.4" + "typescript": "^5.5.4", + "prisma": "5.18.0" } } \ No newline at end of file diff --git a/references/v3-catalog/prisma/migrations/20240821142001_add_initial_schema/migration.sql b/references/v3-catalog/prisma/migrations/20240821142001_add_initial_schema/migration.sql new file mode 100644 index 000000000..af34bdc63 --- /dev/null +++ b/references/v3-catalog/prisma/migrations/20240821142001_add_initial_schema/migration.sql @@ -0,0 +1,20 @@ +-- CreateTable +CREATE TABLE "Post" ( + "id" SERIAL NOT NULL, + "title" TEXT NOT NULL, + "content" TEXT NOT NULL, + "authorId" INTEGER NOT NULL, + + CONSTRAINT "Post_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "User" ( + "id" SERIAL NOT NULL, + "name" TEXT NOT NULL, + + CONSTRAINT "User_pkey" PRIMARY KEY ("id") +); + +-- AddForeignKey +ALTER TABLE "Post" ADD CONSTRAINT "Post_authorId_fkey" FOREIGN KEY ("authorId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; diff --git a/references/v3-catalog/prisma/migrations/migration_lock.toml b/references/v3-catalog/prisma/migrations/migration_lock.toml new file mode 100644 index 000000000..fbffa92c2 --- /dev/null +++ b/references/v3-catalog/prisma/migrations/migration_lock.toml @@ -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" \ No newline at end of file diff --git a/references/v3-catalog/prisma/schema.prisma b/references/v3-catalog/prisma/schema.prisma deleted file mode 100644 index 0789f5d39..000000000 --- a/references/v3-catalog/prisma/schema.prisma +++ /dev/null @@ -1,14 +0,0 @@ -datasource db { - provider = "postgresql" - url = env("DATABASE_URL") - directUrl = env("DIRECT_URL") -} - -generator client { - provider = "prisma-client-js" -} - -model User { - id String @id @default(cuid()) - email String @unique -} diff --git a/references/v3-catalog/prisma/schema/post.prisma b/references/v3-catalog/prisma/schema/post.prisma new file mode 100644 index 000000000..0daf663ad --- /dev/null +++ b/references/v3-catalog/prisma/schema/post.prisma @@ -0,0 +1,8 @@ +// post.prisma +model Post { + id Int @id @default(autoincrement()) + title String + content String + authorId Int + author User @relation(fields: [authorId], references: [id]) +} diff --git a/references/v3-catalog/prisma/schema/schema.prisma b/references/v3-catalog/prisma/schema/schema.prisma new file mode 100644 index 000000000..f933d5370 --- /dev/null +++ b/references/v3-catalog/prisma/schema/schema.prisma @@ -0,0 +1,16 @@ +// This is your Prisma schema file, +// learn more about it in the docs: https://pris.ly/d/prisma-schema + +// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions? +// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init + +generator client { + provider = "prisma-client-js" + previewFeatures = ["prismaSchemaFolder"] +} + +datasource db { + provider = "postgresql" + url = env("DATABASE_URL") + directUrl = env("DATABASE_URL_UNPOOLED") +} diff --git a/references/v3-catalog/prisma/schema/user.prisma b/references/v3-catalog/prisma/schema/user.prisma new file mode 100644 index 000000000..5327f3982 --- /dev/null +++ b/references/v3-catalog/prisma/schema/user.prisma @@ -0,0 +1,6 @@ +// user.prisma +model User { + id Int @id @default(autoincrement()) + name String + posts Post[] +} diff --git a/references/v3-catalog/src/db.ts b/references/v3-catalog/src/db.ts new file mode 100644 index 000000000..901f3a0d9 --- /dev/null +++ b/references/v3-catalog/src/db.ts @@ -0,0 +1,3 @@ +import { PrismaClient } from "@prisma/client"; + +export const prisma = new PrismaClient(); diff --git a/references/v3-catalog/src/trigger/prismaTasks.ts b/references/v3-catalog/src/trigger/prismaTasks.ts new file mode 100644 index 000000000..a80dda290 --- /dev/null +++ b/references/v3-catalog/src/trigger/prismaTasks.ts @@ -0,0 +1,17 @@ +import { prisma } from "@/db.js"; +import { task } from "@trigger.dev/sdk/v3"; + +export const prismaTask = task({ + id: "prisma-task", + run: async () => { + const users = await prisma.user.findMany(); + + await prisma.user.create({ + data: { + name: "Alice", + }, + }); + + return users; + }, +}); diff --git a/references/v3-catalog/trigger.config.ts b/references/v3-catalog/trigger.config.ts index d58f01a7c..ad3d01e16 100644 --- a/references/v3-catalog/trigger.config.ts +++ b/references/v3-catalog/trigger.config.ts @@ -1,6 +1,10 @@ import { OpenAIInstrumentation } from "@traceloop/instrumentation-openai"; import { defineConfig, ResolveEnvironmentVariablesFunction } from "@trigger.dev/sdk/v3"; -import { emitDecoratorMetadata } from "@trigger.dev/sdk/v3/extensions"; +import { + emitDecoratorMetadata, + audioWaveform, + prismaExtension, +} from "@trigger.dev/sdk/v3/extensions"; import { InfisicalClient } from "@infisical/sdk"; export const resolveEnvVars: ResolveEnvironmentVariablesFunction = async (ctx) => { @@ -55,7 +59,15 @@ export default defineConfig({ console.log(`Task ${ctx.task.id} failed ${ctx.run.id}`); }, build: { - extensions: [emitDecoratorMetadata()], + extensions: [ + emitDecoratorMetadata(), + audioWaveform(), + prismaExtension({ + schema: "prisma/schema/schema.prisma", + migrate: true, + directUrlEnvVarName: "DATABASE_URL_UNPOOLED", + }), + ], external: ["@ffmpeg-installer/ffmpeg", "re2"], }, });