mirror of https://github.com/buster-so/buster.git
Merge pull request #475 from buster-so/nate/hot-fix-server-build
Server build update
This commit is contained in:
commit
252a892cae
|
@ -1,37 +0,0 @@
|
||||||
# Custom Base Image - Published base with tools + dependencies
|
|
||||||
# ================================================================
|
|
||||||
# This image contains:
|
|
||||||
# - Node 22 + npm
|
|
||||||
# - pnpm + bun
|
|
||||||
# - All workspace dependencies pre-installed
|
|
||||||
#
|
|
||||||
# Build and publish this multi-platform image:
|
|
||||||
# docker buildx build --platform linux/amd64,linux/arm64 \
|
|
||||||
# -f apps/server/Dockerfile.custom-base \
|
|
||||||
# -t ghcr.io/buster-so/server-base:latest \
|
|
||||||
# --push .
|
|
||||||
|
|
||||||
FROM node:22-alpine
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
# Install tools: pnpm + bun
|
|
||||||
RUN echo "=== Installing build tools: $(date) ===" && \
|
|
||||||
apk add --no-cache curl bash git && \
|
|
||||||
npm install -g pnpm@9.15.0 turbo && \
|
|
||||||
curl -fsSL https://bun.sh/install | bash && \
|
|
||||||
echo "=== Tools installed: $(date) ==="
|
|
||||||
|
|
||||||
ENV PATH="/root/.bun/bin:$PATH"
|
|
||||||
|
|
||||||
# Copy package configuration files
|
|
||||||
COPY package.json pnpm-lock.yaml* turbo.json* pnpm-workspace.yaml* ./
|
|
||||||
COPY packages/ ./packages/
|
|
||||||
COPY apps/server/package.json ./apps/server/
|
|
||||||
|
|
||||||
# Install ALL dependencies (this is the heavy lifting)
|
|
||||||
RUN echo "=== Installing all dependencies: $(date) ===" && \
|
|
||||||
time pnpm install --ignore-scripts && \
|
|
||||||
echo "=== Dependencies installed: $(date) ===" && \
|
|
||||||
echo "Base image ready with $(du -sh node_modules | cut -f1) of dependencies"
|
|
||||||
|
|
||||||
# This base image is now ready to be published and reused!
|
|
|
@ -1,51 +0,0 @@
|
||||||
# Buster Server Docker Workflow
|
|
||||||
Two-step build process for maximum efficiency
|
|
||||||
|
|
||||||
## 🔐 GitHub Container Registry Setup
|
|
||||||
|
|
||||||
First, authenticate with GitHub Container Registry:
|
|
||||||
|
|
||||||
- The password to login must be a github access token (made with token classic) with write and write package permissions
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker login ghcr.io
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🏗️ Step 1: Build & Publish Base Image (Do this occasionally)
|
|
||||||
|
|
||||||
The base image contains all heavy dependencies and build tools.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Build the base image with all dependencies
|
|
||||||
docker build -f apps/server/Dockerfile.custom-base -t ghcr.io/buster-so/server-base:latest .
|
|
||||||
|
|
||||||
# Publish to GitHub Container Registry
|
|
||||||
docker push ghcr.io/buster-so/server-base:latest
|
|
||||||
```
|
|
||||||
|
|
||||||
**When to rebuild the base:**
|
|
||||||
- Major dependency updates
|
|
||||||
- New packages added to workspace
|
|
||||||
- Tool version updates (pnpm, bun)
|
|
||||||
- Weekly/monthly maintenance
|
|
||||||
|
|
||||||
## ⚡ Step 2: Ultra-Fast App Builds (CI/CD)
|
|
||||||
|
|
||||||
Use the published base for lightning-fast builds:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Pull the latest base (in CI/CD)
|
|
||||||
docker pull ghcr.io/buster-so/buster-server-base:latest
|
|
||||||
|
|
||||||
# Build your app (super fast!)
|
|
||||||
docker build -f apps/server/Dockerfile.ultra-fast -t buster-server:latest .
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
### Update Base Image (periodically):
|
|
||||||
```bash
|
|
||||||
# Rebuild and push new base
|
|
||||||
docker buildx build --platform linux/amd64,linux/arm64 \
|
|
||||||
-f apps/server/Dockerfile.custom-base \
|
|
||||||
-t ghcr.io/buster-so/server-base:latest \
|
|
||||||
--push .
|
|
|
@ -7,11 +7,10 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"prebuild": "bun run scripts/validate-env.js",
|
"prebuild": "bun run scripts/validate-env.js && pnpm run typecheck",
|
||||||
"build": "bun build src/index.ts --outdir ./dist --target bun --external pino-pretty",
|
"build": "tsup",
|
||||||
"dev": "bun --max-old-space-size=512 run --hot src/index.ts",
|
"dev": "tsup --watch",
|
||||||
"lint": "biome check",
|
"lint": "biome check",
|
||||||
"prod": "pnpm run build:vercel && pnpm run start:vercel",
|
|
||||||
"start": "bun dist/index.js",
|
"start": "bun dist/index.js",
|
||||||
"test": "vitest run",
|
"test": "vitest run",
|
||||||
"test:coverage": "vitest --coverage",
|
"test:coverage": "vitest --coverage",
|
||||||
|
@ -31,13 +30,10 @@
|
||||||
"@trigger.dev/sdk": "catalog:",
|
"@trigger.dev/sdk": "catalog:",
|
||||||
"drizzle-orm": "catalog:",
|
"drizzle-orm": "catalog:",
|
||||||
"hono": "catalog:",
|
"hono": "catalog:",
|
||||||
"hono-pino": "^0.8.0",
|
"hono-pino": "^0.9.1",
|
||||||
"pino": "^9.7.0",
|
"pino": "^9.7.0",
|
||||||
"pino-pretty": "^13.0.0",
|
"pino-pretty": "^13.0.0",
|
||||||
|
"tsup": "catalog:",
|
||||||
"zod": "catalog:"
|
"zod": "catalog:"
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@vercel/node": "^5.3.3",
|
|
||||||
"tsup": "^8.5.0"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,15 +16,10 @@ import type {
|
||||||
ChatMessageResponseMessage,
|
ChatMessageResponseMessage,
|
||||||
ChatWithMessages,
|
ChatWithMessages,
|
||||||
} from '@buster/server-shared/chats';
|
} from '@buster/server-shared/chats';
|
||||||
import {
|
import { ChatError, ChatErrorCode } from '@buster/server-shared/chats';
|
||||||
ChatError,
|
|
||||||
ChatErrorCode,
|
|
||||||
ReasoningMessageSchema,
|
|
||||||
ResponseMessageSchema,
|
|
||||||
} from '@buster/server-shared/chats';
|
|
||||||
import { PostProcessingMessageSchema } from '@buster/server-shared/message';
|
import { PostProcessingMessageSchema } from '@buster/server-shared/message';
|
||||||
import { and, eq, gte, isNull } from 'drizzle-orm';
|
import { and, eq, gte, isNull } from 'drizzle-orm';
|
||||||
import type { z } from 'zod/v4';
|
import type { z } from 'zod';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validates a nullable JSONB field against a Zod schema
|
* Validates a nullable JSONB field against a Zod schema
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
import { randomUUID } from 'node:crypto';
|
import { randomUUID } from 'node:crypto';
|
||||||
import { db, organizations, users, usersToOrganizations } from '@buster/database';
|
import { db, organizations, users, usersToOrganizations } from '@buster/database';
|
||||||
import type { Organization, User } from '@buster/database';
|
import type { User } from '@buster/database';
|
||||||
|
import type { UserOrganizationRole } from '@buster/server-shared/user';
|
||||||
|
import type { InferInsertModel, InferSelectModel } from 'drizzle-orm';
|
||||||
|
|
||||||
|
type Organization = InferSelectModel<typeof organizations>;
|
||||||
import { and, eq, isNull } from 'drizzle-orm';
|
import { and, eq, isNull } from 'drizzle-orm';
|
||||||
|
|
||||||
export async function createTestUserInDb(userData: Partial<User> = {}): Promise<User> {
|
export async function createTestUserInDb(userData: Partial<User> = {}): Promise<User> {
|
||||||
|
@ -48,26 +52,28 @@ export async function createTestOrganizationInDb(
|
||||||
const id = randomUUID();
|
const id = randomUUID();
|
||||||
// Use a unique domain for each organization to avoid conflicts with the trigger
|
// Use a unique domain for each organization to avoid conflicts with the trigger
|
||||||
const uniqueDomain = `test-${id.substring(0, 8)}.com`;
|
const uniqueDomain = `test-${id.substring(0, 8)}.com`;
|
||||||
const org = {
|
const org: Organization = {
|
||||||
id,
|
id,
|
||||||
name: `Test Organization ${id}`,
|
name: `Test Organization ${id}`,
|
||||||
domains: orgData.domains !== undefined ? orgData.domains : [uniqueDomain],
|
domains: orgData.domains !== undefined ? orgData.domains : [uniqueDomain],
|
||||||
restrictNewUserInvitations: false,
|
restrictNewUserInvitations: false,
|
||||||
defaultRole: 'restricted_querier',
|
defaultRole: 'restricted_querier' as const,
|
||||||
createdAt: new Date().toISOString(),
|
createdAt: new Date().toISOString(),
|
||||||
updatedAt: new Date().toISOString(),
|
updatedAt: new Date().toISOString(),
|
||||||
deletedAt: null,
|
deletedAt: null,
|
||||||
|
domain: null,
|
||||||
|
paymentRequired: true,
|
||||||
...orgData,
|
...orgData,
|
||||||
};
|
};
|
||||||
|
|
||||||
await db.insert(organizations).values(org);
|
await db.insert(organizations).values(org);
|
||||||
return org as Organization;
|
return org;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function createTestOrgMemberInDb(
|
export async function createTestOrgMemberInDb(
|
||||||
userId: string,
|
userId: string,
|
||||||
organizationId: string,
|
organizationId: string,
|
||||||
role = 'querier'
|
role: UserOrganizationRole = 'querier'
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
// First check if there's already a membership
|
// First check if there's already a membership
|
||||||
const existing = await db
|
const existing = await db
|
||||||
|
@ -80,7 +86,7 @@ export async function createTestOrgMemberInDb(
|
||||||
await db.delete(usersToOrganizations).where(eq(usersToOrganizations.userId, userId));
|
await db.delete(usersToOrganizations).where(eq(usersToOrganizations.userId, userId));
|
||||||
}
|
}
|
||||||
|
|
||||||
const member = {
|
const member: InferInsertModel<typeof usersToOrganizations> = {
|
||||||
userId,
|
userId,
|
||||||
organizationId,
|
organizationId,
|
||||||
role,
|
role,
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
import type { Organization, User } from '@buster/database';
|
import type { User, organizations } from '@buster/database';
|
||||||
|
import type { InferSelectModel } from 'drizzle-orm';
|
||||||
|
|
||||||
|
type Organization = InferSelectModel<typeof organizations>;
|
||||||
|
|
||||||
export function createTestUser(overrides?: Partial<User>): User {
|
export function createTestUser(overrides?: Partial<User>): User {
|
||||||
const id = `test-user-${Math.random().toString(36).substring(7)}`;
|
const id = `test-user-${Math.random().toString(36).substring(7)}`;
|
||||||
|
|
|
@ -111,8 +111,8 @@ async function updateOrganizationSettings(
|
||||||
restrictNewUserInvitations: updateData.restrictNewUserInvitations,
|
restrictNewUserInvitations: updateData.restrictNewUserInvitations,
|
||||||
}),
|
}),
|
||||||
...(updateData.defaultRole !== undefined &&
|
...(updateData.defaultRole !== undefined &&
|
||||||
updateData.defaultRole !== 'none' && {
|
updateData.defaultRole && {
|
||||||
defaultRole: updateData.defaultRole as Exclude<OrganizationRole, 'none'>,
|
defaultRole: updateData.defaultRole,
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -130,10 +130,10 @@ export class SlackHandler {
|
||||||
* Handle OAuth callback from Slack
|
* Handle OAuth callback from Slack
|
||||||
*/
|
*/
|
||||||
async handleOAuthCallback(c: Context): Promise<Response> {
|
async handleOAuthCallback(c: Context): Promise<Response> {
|
||||||
try {
|
// Get base URL from environment
|
||||||
// Get base URL from environment
|
const baseUrl = process.env.BUSTER_URL || '';
|
||||||
const baseUrl = process.env.BUSTER_URL || '';
|
|
||||||
|
|
||||||
|
try {
|
||||||
// Get service instance (lazy initialization)
|
// Get service instance (lazy initialization)
|
||||||
const slackOAuthService = this.getSlackOAuthService();
|
const slackOAuthService = this.getSlackOAuthService();
|
||||||
|
|
||||||
|
|
|
@ -10,8 +10,8 @@ const SlackEnvSchema = z.object({
|
||||||
SERVER_URL: z.string().url(),
|
SERVER_URL: z.string().url(),
|
||||||
SLACK_INTEGRATION_ENABLED: z
|
SLACK_INTEGRATION_ENABLED: z
|
||||||
.string()
|
.string()
|
||||||
.transform((val) => val === 'true')
|
.default('false')
|
||||||
.default('false'),
|
.transform((val) => val === 'true'),
|
||||||
});
|
});
|
||||||
|
|
||||||
// OAuth metadata schema
|
// OAuth metadata schema
|
||||||
|
|
|
@ -32,7 +32,13 @@ app.onError((err, c) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err instanceof z.ZodError) {
|
if (err instanceof z.ZodError) {
|
||||||
return c.text(err.errors.map((e) => e.message).join(', '), 400);
|
return c.json(
|
||||||
|
{
|
||||||
|
error: 'Validation Error',
|
||||||
|
message: err.issues.map((issue) => issue.message).join(', '),
|
||||||
|
},
|
||||||
|
400
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.json(
|
return c.json(
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
import { defineConfig } from 'tsup';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
entry: ['src/index.ts'],
|
||||||
|
format: ['esm'],
|
||||||
|
target: 'node22', // Bun is compatible with recent Node.js versions
|
||||||
|
platform: 'node',
|
||||||
|
outDir: 'dist',
|
||||||
|
clean: true,
|
||||||
|
dts: false, // Disable for now due to TypeScript file list errors
|
||||||
|
sourcemap: true,
|
||||||
|
minify: false, // Don't minify for bun runtime
|
||||||
|
splitting: false,
|
||||||
|
shims: false, // Bun doesn't need shims
|
||||||
|
external: [
|
||||||
|
// Mark all workspace packages as external to avoid bundling them
|
||||||
|
'@buster/access-controls',
|
||||||
|
'@buster/database',
|
||||||
|
'@buster/server-shared',
|
||||||
|
'@buster/slack',
|
||||||
|
'@buster/test-utils',
|
||||||
|
'@buster/typescript-config',
|
||||||
|
'@buster/vitest-config',
|
||||||
|
],
|
||||||
|
noExternal: [
|
||||||
|
// Bundle these specific packages if needed
|
||||||
|
],
|
||||||
|
esbuildOptions(options) {
|
||||||
|
// Additional esbuild options for bun compatibility
|
||||||
|
options.keepNames = true; // Preserve function names for better debugging
|
||||||
|
},
|
||||||
|
onSuccess: async () => {
|
||||||
|
console.log('Build completed successfully!');
|
||||||
|
},
|
||||||
|
});
|
|
@ -27,13 +27,13 @@
|
||||||
"@buster/typescript-config": "workspace:*",
|
"@buster/typescript-config": "workspace:*",
|
||||||
"@buster/vitest-config": "workspace:*",
|
"@buster/vitest-config": "workspace:*",
|
||||||
"@mastra/core": "catalog:",
|
"@mastra/core": "catalog:",
|
||||||
"@trigger.dev/sdk": "4.0.0-v4-beta.22",
|
"@trigger.dev/sdk": "catalog:",
|
||||||
"ai": "catalog:",
|
"ai": "catalog:",
|
||||||
"braintrust": "^0.0.206",
|
"braintrust": "catalog:",
|
||||||
"vitest": "catalog:",
|
"vitest": "catalog:",
|
||||||
"zod": "catalog:"
|
"zod": "catalog:"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@trigger.dev/build": "4.0.0-v4-beta.22"
|
"@trigger.dev/build": "catalog:"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,7 @@
|
||||||
"@mastra/core": "catalog:",
|
"@mastra/core": "catalog:",
|
||||||
"@mastra/loggers": "^0.10.3",
|
"@mastra/loggers": "^0.10.3",
|
||||||
"ai": "catalog:",
|
"ai": "catalog:",
|
||||||
"braintrust": "^0.0.206",
|
"braintrust": "catalog:",
|
||||||
"drizzle-orm": "catalog:",
|
"drizzle-orm": "catalog:",
|
||||||
"glob": "^11.0.3",
|
"glob": "^11.0.3",
|
||||||
"minimatch": "^10.0.3",
|
"minimatch": "^10.0.3",
|
||||||
|
|
|
@ -66,7 +66,7 @@
|
||||||
"@buster/vitest-config": "workspace:*",
|
"@buster/vitest-config": "workspace:*",
|
||||||
"@buster/typescript-config": "workspace:*",
|
"@buster/typescript-config": "workspace:*",
|
||||||
"@buster/database": "workspace:*",
|
"@buster/database": "workspace:*",
|
||||||
"zod": "catalog:"
|
"zod": "^3.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"vitest": "catalog:"
|
"vitest": "catalog:"
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { z } from 'zod/v4';
|
import { z } from 'zod';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Error codes for chat operations
|
* Error codes for chat operations
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { z } from 'zod/v4';
|
import { z } from 'zod';
|
||||||
import { PostProcessingMessageSchema } from '../message';
|
import { PostProcessingMessageSchema } from '../message';
|
||||||
|
|
||||||
// Message role for chat messages
|
// Message role for chat messages
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { z } from 'zod/v4';
|
import { z } from 'zod';
|
||||||
import { ChatMessageSchema } from './chat-message.types';
|
import { ChatMessageSchema } from './chat-message.types';
|
||||||
|
|
||||||
const AssetType = z.enum(['metric_file', 'dashboard_file']);
|
const AssetType = z.enum(['metric_file', 'dashboard_file']);
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { z } from 'zod/v4';
|
import { z } from 'zod';
|
||||||
|
|
||||||
export const CurrencySchema = z.object({
|
export const CurrencySchema = z.object({
|
||||||
code: z.string(),
|
code: z.string(),
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { z } from 'zod/v4';
|
import { z } from 'zod';
|
||||||
|
|
||||||
export const AssumptionClassificationSchema = z.enum([
|
export const AssumptionClassificationSchema = z.enum([
|
||||||
'fieldMapping',
|
'fieldMapping',
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { z } from 'zod/v4';
|
import { z } from 'zod';
|
||||||
import { getDefaults } from '../defaultHelpers';
|
import { getDefaults } from '../defaultHelpers';
|
||||||
|
|
||||||
// Goal line is a line that is drawn on the chart to represent a goal.
|
// Goal line is a line that is drawn on the chart to represent a goal.
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { z } from 'zod/v4';
|
import { z } from 'zod';
|
||||||
|
|
||||||
export const BarAndLineAxisSchema = z
|
export const BarAndLineAxisSchema = z
|
||||||
.object({
|
.object({
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { z } from 'zod/v4';
|
import { z } from 'zod';
|
||||||
import { BarAndLineAxisSchema } from './axisInterfaces';
|
import { BarAndLineAxisSchema } from './axisInterfaces';
|
||||||
import { BarSortBySchema } from './etcInterfaces';
|
import { BarSortBySchema } from './etcInterfaces';
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { z } from 'zod/v4';
|
import { z } from 'zod';
|
||||||
import { getDefaults } from '../defaultHelpers';
|
import { getDefaults } from '../defaultHelpers';
|
||||||
import { GoalLineSchema, TrendlineSchema } from './annotationInterfaces';
|
import { GoalLineSchema, TrendlineSchema } from './annotationInterfaces';
|
||||||
import { BarChartPropsSchema } from './barChartProps';
|
import { BarChartPropsSchema } from './barChartProps';
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { z } from 'zod/v4';
|
import { z } from 'zod';
|
||||||
import { getDefaults } from '../defaultHelpers';
|
import { getDefaults } from '../defaultHelpers';
|
||||||
|
|
||||||
export const LineColumnSettingsSchema = z.object({
|
export const LineColumnSettingsSchema = z.object({
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { z } from 'zod/v4';
|
import { z } from 'zod';
|
||||||
import { getDefaults } from '../defaultHelpers';
|
import { getDefaults } from '../defaultHelpers';
|
||||||
|
|
||||||
export const ColumnLabelFormatSchema = z.object({
|
export const ColumnLabelFormatSchema = z.object({
|
||||||
|
@ -14,10 +14,8 @@ export const ColumnLabelFormatSchema = z.object({
|
||||||
.optional(
|
.optional(
|
||||||
z
|
z
|
||||||
.number()
|
.number()
|
||||||
.check(
|
.min(0, 'Minimum fraction digits must be at least 0')
|
||||||
z.gte(0, 'Minimum fraction digits must be at least 0'),
|
.max(20, 'Minimum fraction digits must be at most 20')
|
||||||
z.lte(20, 'Minimum fraction digits must be at most 20')
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
.default(0),
|
.default(0),
|
||||||
// OPTIONAL: default is 2. This is essentially used to set a maximum number of decimal places. This will only apply if the format is set to 'number'.
|
// OPTIONAL: default is 2. This is essentially used to set a maximum number of decimal places. This will only apply if the format is set to 'number'.
|
||||||
|
@ -25,10 +23,8 @@ export const ColumnLabelFormatSchema = z.object({
|
||||||
.optional(
|
.optional(
|
||||||
z
|
z
|
||||||
.number()
|
.number()
|
||||||
.check(
|
.min(0, 'Maximum fraction digits must be at least 0')
|
||||||
z.gte(0, 'Maximum fraction digits must be at least 0'),
|
.max(20, 'Maximum fraction digits must be at most 20')
|
||||||
z.lte(20, 'Maximum fraction digits must be at most 20')
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
.default(2),
|
.default(2),
|
||||||
// OPTIONAL: default is 1. This will only apply if the format is set to 'number', 'currency', or 'percent'.
|
// OPTIONAL: default is 1. This will only apply if the format is set to 'number', 'currency', or 'percent'.
|
||||||
|
@ -36,10 +32,8 @@ export const ColumnLabelFormatSchema = z.object({
|
||||||
.optional(
|
.optional(
|
||||||
z
|
z
|
||||||
.number()
|
.number()
|
||||||
.check(
|
.min(0.001, 'Multiplier must be at least 0.001')
|
||||||
z.gte(0.001, 'Multiplier must be at least 0.001'),
|
.max(1000000, 'Multiplier must be at most 1,000,000')
|
||||||
z.lte(1000000, 'Multiplier must be at most 1,000,000')
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
.default(1),
|
.default(1),
|
||||||
// OPTIONAL: default is ''. This sets a prefix to go in front of each value found within the column. This will only apply if the format is set to 'number' or 'percent'.
|
// OPTIONAL: default is ''. This sets a prefix to go in front of each value found within the column. This will only apply if the format is set to 'number' or 'percent'.
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { z } from 'zod/v4';
|
import { z } from 'zod';
|
||||||
import { ComboChartAxisSchema } from './axisInterfaces';
|
import { ComboChartAxisSchema } from './axisInterfaces';
|
||||||
|
|
||||||
export const ComboChartPropsSchema = z.object({
|
export const ComboChartPropsSchema = z.object({
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { z } from 'zod/v4';
|
import { z } from 'zod';
|
||||||
|
|
||||||
export const ChartTypeSchema = z
|
export const ChartTypeSchema = z
|
||||||
.enum(['line', 'bar', 'scatter', 'pie', 'metric', 'table', 'combo'])
|
.enum(['line', 'bar', 'scatter', 'pie', 'metric', 'table', 'combo'])
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { z } from 'zod/v4';
|
import { z } from 'zod';
|
||||||
|
|
||||||
// OPTIONAL: default is no sorting (none). The first item in the array will be the primary sort. The second item will be the secondary sort. This will only apply if the X axis type is not a date.
|
// OPTIONAL: default is no sorting (none). The first item in the array will be the primary sort. The second item will be the secondary sort. This will only apply if the X axis type is not a date.
|
||||||
export const BarSortBySchema = z.array(z.enum(['asc', 'desc', 'none'])).default([]);
|
export const BarSortBySchema = z.array(z.enum(['asc', 'desc', 'none'])).default([]);
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { z } from 'zod/v4';
|
import { z } from 'zod';
|
||||||
|
|
||||||
export const LineChartPropsSchema = z.object({
|
export const LineChartPropsSchema = z.object({
|
||||||
// OPTIONAL: default is null. This will only apply if the columnVisualization is set to 'line'. If this is set to stack it will stack the lines on top of each other. The UI has this labeled as "Show as %"
|
// OPTIONAL: default is null. This will only apply if the columnVisualization is set to 'line'. If this is set to stack it will stack the lines on top of each other. The UI has this labeled as "Show as %"
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { z } from 'zod/v4';
|
import { z } from 'zod';
|
||||||
|
|
||||||
export const DerivedMetricTitleSchema = z.object({
|
export const DerivedMetricTitleSchema = z.object({
|
||||||
// which column to use.
|
// which column to use.
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { z } from 'zod/v4';
|
import { z } from 'zod';
|
||||||
import { PieChartAxisSchema } from './axisInterfaces';
|
import { PieChartAxisSchema } from './axisInterfaces';
|
||||||
import { PieSortBySchema } from './etcInterfaces';
|
import { PieSortBySchema } from './etcInterfaces';
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { z } from 'zod/v4';
|
import { z } from 'zod';
|
||||||
import { ScatterAxisSchema } from './axisInterfaces';
|
import { ScatterAxisSchema } from './axisInterfaces';
|
||||||
|
|
||||||
export const ScatterChartPropsSchema = z.object({
|
export const ScatterChartPropsSchema = z.object({
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { z } from 'zod/v4';
|
import { z } from 'zod';
|
||||||
|
|
||||||
export const TableChartPropsSchema = z.object({
|
export const TableChartPropsSchema = z.object({
|
||||||
tableColumnOrder: z.nullable(z.array(z.string())).default(null),
|
tableColumnOrder: z.nullable(z.array(z.string())).default(null),
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { z } from 'zod/v4';
|
import { z } from 'zod';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configuration options for the Y-axis of a chart.
|
* Configuration options for the Y-axis of a chart.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { describe, expect, it } from 'vitest';
|
import { describe, expect, it } from 'vitest';
|
||||||
import { z } from 'zod/v4';
|
import { z } from 'zod';
|
||||||
import { getDefaults, getDefaultsPartial } from './defaultHelpers';
|
import { getDefaults, getDefaultsPartial } from './defaultHelpers';
|
||||||
|
|
||||||
describe('getDefaults', () => {
|
describe('getDefaults', () => {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import type { z } from 'zod/v4';
|
import type { z } from 'zod';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extracts all default values from a Zod schema.
|
* Extracts all default values from a Zod schema.
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { z } from 'zod/v4';
|
import { z } from 'zod';
|
||||||
|
|
||||||
export const ColumnMetaDataSchema = z.object({
|
export const ColumnMetaDataSchema = z.object({
|
||||||
name: z.string(),
|
name: z.string(),
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { z } from 'zod/v4';
|
import { z } from 'zod';
|
||||||
import { ShareConfigSchema, VerificationStatusSchema } from '../share';
|
import { ShareConfigSchema, VerificationStatusSchema } from '../share';
|
||||||
import { ChartConfigPropsSchema } from './charts';
|
import { ChartConfigPropsSchema } from './charts';
|
||||||
import { DEFAULT_CHART_CONFIG } from './charts/chartConfigProps';
|
import { DEFAULT_CHART_CONFIG } from './charts/chartConfigProps';
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { z } from 'zod/v4';
|
import { z } from 'zod';
|
||||||
import { VerificationStatusSchema } from '../share';
|
import { VerificationStatusSchema } from '../share';
|
||||||
|
|
||||||
export const MetricListItemSchema = z.object({
|
export const MetricListItemSchema = z.object({
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { z } from 'zod/v4';
|
import { z } from 'zod';
|
||||||
import { ShareRoleSchema, VerificationStatusSchema } from '../share';
|
import { ShareRoleSchema, VerificationStatusSchema } from '../share';
|
||||||
import { ChartConfigPropsSchema } from './charts';
|
import { ChartConfigPropsSchema } from './charts';
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { z } from 'zod/v4';
|
import { z } from 'zod';
|
||||||
import { DataMetadataSchema, DataResultSchema } from './metadata.type';
|
import { DataMetadataSchema, DataResultSchema } from './metadata.type';
|
||||||
import { MetricSchema } from './metric.types';
|
import { MetricSchema } from './metric.types';
|
||||||
import { MetricListItemSchema } from './metrics-list.types';
|
import { MetricListItemSchema } from './metrics-list.types';
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { z } from 'zod/v4';
|
import { z } from 'zod';
|
||||||
import { OrganizationRoleSchema } from './roles.types';
|
import { OrganizationRoleSchema } from './roles.types';
|
||||||
|
|
||||||
export const OrganizationSchema = z.object({
|
export const OrganizationSchema = z.object({
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import type { userOrganizationRoleEnum } from '@buster/database'; //we import as type to avoid postgres dependency in the frontend ☹️
|
import type { userOrganizationRoleEnum } from '@buster/database'; //we import as type to avoid postgres dependency in the frontend ☹️
|
||||||
import { z } from 'zod/v4';
|
import { z } from 'zod';
|
||||||
|
|
||||||
type OrganizationRoleBase = (typeof userOrganizationRoleEnum.enumValues)[number];
|
type OrganizationRoleBase = (typeof userOrganizationRoleEnum.enumValues)[number];
|
||||||
|
|
||||||
|
@ -14,6 +14,8 @@ export const OrganizationRoleEnum: Record<OrganizationRoleBase, OrganizationRole
|
||||||
restricted_querier: 'restricted_querier',
|
restricted_querier: 'restricted_querier',
|
||||||
});
|
});
|
||||||
|
|
||||||
export const OrganizationRoleSchema = z.enum(Object.values(OrganizationRoleEnum));
|
export const OrganizationRoleSchema = z.enum(
|
||||||
|
Object.values(OrganizationRoleEnum) as [OrganizationRoleBase, ...OrganizationRoleBase[]]
|
||||||
|
);
|
||||||
|
|
||||||
export type OrganizationRole = z.infer<typeof OrganizationRoleSchema>;
|
export type OrganizationRole = z.infer<typeof OrganizationRoleSchema>;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { z } from 'zod/v4';
|
import { z } from 'zod';
|
||||||
import { OrganizationRoleSchema } from './roles.types';
|
import { OrganizationRoleSchema } from './roles.types';
|
||||||
|
|
||||||
export const LineageUserItemTypeSchema = z.enum(['user', 'datasets', 'permissionGroups']);
|
export const LineageUserItemTypeSchema = z.enum(['user', 'datasets', 'permissionGroups']);
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { z } from 'zod/v4';
|
import { z } from 'zod';
|
||||||
import { OrganizationRoleSchema } from '../organization';
|
import { OrganizationRoleSchema } from '../organization';
|
||||||
|
|
||||||
export const UpdateInviteLinkRequestSchema = z.object({
|
export const UpdateInviteLinkRequestSchema = z.object({
|
||||||
|
@ -43,7 +43,7 @@ export const UpdateWorkspaceSettingsRequestSchema = z.object({
|
||||||
restrict_new_user_invitations: z.boolean().optional(),
|
restrict_new_user_invitations: z.boolean().optional(),
|
||||||
default_role: OrganizationRoleSchema.optional(),
|
default_role: OrganizationRoleSchema.optional(),
|
||||||
// this can either be a uuid or "all"
|
// this can either be a uuid or "all"
|
||||||
default_datasets_ids: z.array(z.union([z.uuid(), z.literal('all')])).optional(),
|
default_datasets_ids: z.array(z.union([z.string(), z.literal('all')])).optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export type UpdateWorkspaceSettingsRequest = z.infer<typeof UpdateWorkspaceSettingsRequestSchema>;
|
export type UpdateWorkspaceSettingsRequest = z.infer<typeof UpdateWorkspaceSettingsRequestSchema>;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { z } from 'zod/v4';
|
import { z } from 'zod';
|
||||||
import { OrganizationRoleSchema } from '../organization';
|
import { OrganizationRoleSchema } from '../organization';
|
||||||
|
|
||||||
export const GetInviteLinkResponseSchema = z.object({
|
export const GetInviteLinkResponseSchema = z.object({
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { z } from 'zod/v4';
|
import { z } from 'zod';
|
||||||
|
|
||||||
export const ShareRoleSchema = z.enum([
|
export const ShareRoleSchema = z.enum([
|
||||||
'owner', //owner of the asset
|
'owner', //owner of the asset
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { z } from 'zod/v4';
|
import { z } from 'zod';
|
||||||
|
|
||||||
export const VerificationStatusSchema = z.enum([
|
export const VerificationStatusSchema = z.enum([
|
||||||
'notRequested',
|
'notRequested',
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { z } from 'zod/v4';
|
import { z } from 'zod';
|
||||||
|
|
||||||
// POST /api/v2/slack/auth/init
|
// POST /api/v2/slack/auth/init
|
||||||
export const InitiateOAuthSchema = z
|
export const InitiateOAuthSchema = z
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { z } from 'zod/v4';
|
import { z } from 'zod';
|
||||||
|
|
||||||
export const CreateTeamRequestSchema = z.object({
|
export const CreateTeamRequestSchema = z.object({
|
||||||
name: z.string(),
|
name: z.string(),
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { z } from 'zod/v4';
|
import { z } from 'zod';
|
||||||
import { TeamSchema } from './teams.types';
|
import { TeamSchema } from './teams.types';
|
||||||
|
|
||||||
export const TeamListResponseSchema = z.array(TeamSchema);
|
export const TeamListResponseSchema = z.array(TeamSchema);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import type { teamRoleEnum } from '@buster/database'; //we import as type to avoid postgres dependency in the frontend ☹️
|
import type { teamRoleEnum } from '@buster/database'; //we import as type to avoid postgres dependency in the frontend ☹️
|
||||||
import { z } from 'zod/v4';
|
import { z } from 'zod';
|
||||||
import { SharingSettingSchema } from '../user/sharing-setting.types';
|
import { SharingSettingSchema } from '../user/sharing-setting.types';
|
||||||
|
|
||||||
type TeamRoleBase = (typeof teamRoleEnum.enumValues)[number] | 'none';
|
type TeamRoleBase = (typeof teamRoleEnum.enumValues)[number] | 'none';
|
||||||
|
@ -8,7 +8,9 @@ const TeamRoleEnums: Record<TeamRoleBase, TeamRoleBase> = Object.freeze({
|
||||||
manager: 'manager',
|
manager: 'manager',
|
||||||
member: 'member',
|
member: 'member',
|
||||||
});
|
});
|
||||||
export const TeamRoleSchema = z.enum(Object.values(TeamRoleEnums));
|
export const TeamRoleSchema = z.enum(
|
||||||
|
Object.values(TeamRoleEnums) as [TeamRoleBase, ...TeamRoleBase[]]
|
||||||
|
);
|
||||||
|
|
||||||
export type TeamRole = z.infer<typeof TeamRoleSchema>;
|
export type TeamRole = z.infer<typeof TeamRoleSchema>;
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { z } from 'zod/v4';
|
import { z } from 'zod';
|
||||||
import { ShareAssetTypeSchema } from '../share';
|
import { ShareAssetTypeSchema } from '../share';
|
||||||
|
|
||||||
export const UserFavoriteSchema = z.object({
|
export const UserFavoriteSchema = z.object({
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { z } from 'zod/v4';
|
import { z } from 'zod';
|
||||||
import { OrganizationRoleSchema } from '../organization/roles.types';
|
import { OrganizationRoleSchema } from '../organization/roles.types';
|
||||||
import { ShareAssetTypeSchema } from '../share';
|
import { ShareAssetTypeSchema } from '../share';
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { z } from 'zod/v4';
|
import { z } from 'zod';
|
||||||
import { OrganizationSchema } from '../organization/organization.types';
|
import { OrganizationSchema } from '../organization/organization.types';
|
||||||
import { OrganizationRoleSchema } from '../organization/roles.types';
|
import { OrganizationRoleSchema } from '../organization/roles.types';
|
||||||
import { TeamSchema } from '../teams/teams.types';
|
import { TeamSchema } from '../teams/teams.types';
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
import type { userOrganizationRoleEnum } from '@buster/database'; //we import as type to avoid postgres dependency in the frontend ☹️
|
import type { userOrganizationRoleEnum } from '@buster/database'; //we import as type to avoid postgres dependency in the frontend ☹️
|
||||||
import { z } from 'zod/v4';
|
import { z } from 'zod';
|
||||||
|
|
||||||
type UserOrganizationRoleBase = (typeof userOrganizationRoleEnum.enumValues)[number] | 'none';
|
type UserOrganizationRoleBase = (typeof userOrganizationRoleEnum.enumValues)[number];
|
||||||
|
|
||||||
const UserOrganizationRoleEnums: Record<UserOrganizationRoleBase, UserOrganizationRoleBase> =
|
const UserOrganizationRoleEnums: Record<UserOrganizationRoleBase, UserOrganizationRoleBase> =
|
||||||
Object.freeze({
|
Object.freeze({
|
||||||
none: 'none',
|
|
||||||
viewer: 'viewer',
|
viewer: 'viewer',
|
||||||
workspace_admin: 'workspace_admin',
|
workspace_admin: 'workspace_admin',
|
||||||
data_admin: 'data_admin',
|
data_admin: 'data_admin',
|
||||||
|
@ -13,6 +12,11 @@ const UserOrganizationRoleEnums: Record<UserOrganizationRoleBase, UserOrganizati
|
||||||
restricted_querier: 'restricted_querier',
|
restricted_querier: 'restricted_querier',
|
||||||
});
|
});
|
||||||
|
|
||||||
export const UserOrganizationRoleSchema = z.enum(Object.values(UserOrganizationRoleEnums));
|
export const UserOrganizationRoleSchema = z.enum(
|
||||||
|
Object.values(UserOrganizationRoleEnums) as [
|
||||||
|
UserOrganizationRoleBase,
|
||||||
|
...UserOrganizationRoleBase[],
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
export type UserOrganizationRole = z.infer<typeof UserOrganizationRoleSchema>;
|
export type UserOrganizationRole = z.infer<typeof UserOrganizationRoleSchema>;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import type { sharingSettingEnum } from '@buster/database'; //we import as type to avoid postgres dependency in the frontend ☹️
|
import type { sharingSettingEnum } from '@buster/database'; //we import as type to avoid postgres dependency in the frontend ☹️
|
||||||
import { z } from 'zod/v4';
|
import { z } from 'zod';
|
||||||
|
|
||||||
type SharingSettingBase = (typeof sharingSettingEnum.enumValues)[number] | 'none';
|
type SharingSettingBase = (typeof sharingSettingEnum.enumValues)[number] | 'none';
|
||||||
|
|
||||||
|
@ -9,6 +9,9 @@ const SharingSettingEnums: Record<SharingSettingBase, SharingSettingBase> = Obje
|
||||||
team: 'team',
|
team: 'team',
|
||||||
organization: 'organization',
|
organization: 'organization',
|
||||||
});
|
});
|
||||||
export const SharingSettingSchema = z.enum(Object.values(SharingSettingEnums));
|
|
||||||
|
const test = Object.values(SharingSettingEnums) as [SharingSettingBase, ...SharingSettingBase[]];
|
||||||
|
|
||||||
|
export const SharingSettingSchema = z.enum(test);
|
||||||
|
|
||||||
export type SharingSetting = z.infer<typeof SharingSettingSchema>;
|
export type SharingSetting = z.infer<typeof SharingSettingSchema>;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { z } from 'zod/v4';
|
import { z } from 'zod';
|
||||||
import type { UserFavorite } from './favorites.types';
|
import type { UserFavorite } from './favorites.types';
|
||||||
import type { UserOrganizationRole } from './roles.types';
|
import type { UserOrganizationRole } from './roles.types';
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,6 @@
|
||||||
"@buster/typescript-config": "workspace:*",
|
"@buster/typescript-config": "workspace:*",
|
||||||
"@buster/vitest-config": "workspace:*",
|
"@buster/vitest-config": "workspace:*",
|
||||||
"ai": "catalog:",
|
"ai": "catalog:",
|
||||||
"zod": "catalog:"
|
"zod": "^3.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,21 +2,22 @@
|
||||||
"$schema": "https://json.schemastore.org/tsconfig",
|
"$schema": "https://json.schemastore.org/tsconfig",
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"allowImportingTsExtensions": false,
|
"allowImportingTsExtensions": false,
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
"composite": true,
|
"composite": true,
|
||||||
"declaration": true,
|
"declaration": true,
|
||||||
"declarationMap": true,
|
"declarationMap": true,
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
"allowSyntheticDefaultImports": true,
|
|
||||||
"incremental": true,
|
"incremental": true,
|
||||||
"inlineSources": false,
|
"inlineSources": false,
|
||||||
"isolatedModules": true,
|
"isolatedModules": true,
|
||||||
|
"lib": ["ESNext"],
|
||||||
"module": "ESNext",
|
"module": "ESNext",
|
||||||
"moduleResolution": "bundler",
|
"moduleResolution": "bundler",
|
||||||
"noEmit": false,
|
"noEmit": false,
|
||||||
"preserveWatchOutput": true,
|
"preserveWatchOutput": true,
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"target": "ES2022",
|
"strict": true,
|
||||||
"lib": ["ESNext"]
|
"target": "ES2022"
|
||||||
},
|
},
|
||||||
"exclude": ["node_modules"],
|
"exclude": ["node_modules"],
|
||||||
"extends": "./type-checking.json"
|
"extends": "./type-checking.json"
|
||||||
|
|
931
pnpm-lock.yaml
931
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
|
@ -10,17 +10,19 @@ packages:
|
||||||
- "apps/api"
|
- "apps/api"
|
||||||
|
|
||||||
catalog:
|
catalog:
|
||||||
|
"@mastra/core": "^0.10.8"
|
||||||
"@supabase/supabase-js": "^2.50.0"
|
"@supabase/supabase-js": "^2.50.0"
|
||||||
"@trigger.dev/build": "^4.0.0-v4-beta.22"
|
"@trigger.dev/build": "^4.0.0-v4-beta.22"
|
||||||
"@trigger.dev/sdk": "^4.0.0-v4-beta.22"
|
"@trigger.dev/sdk": "^4.0.0-v4-beta.22"
|
||||||
ai: "^4.0.0"
|
ai: "^4.0.0"
|
||||||
axios: "^1.10.0"
|
axios: "^1.10.0"
|
||||||
"vite-tsconfig-paths": "^5.1.4"
|
"braintrust": "^0.0.209"
|
||||||
drizzle-orm: "^0.44.2"
|
drizzle-orm: "^0.44.2"
|
||||||
hono: "^4.8.0"
|
hono: "^4.8.0"
|
||||||
"@mastra/core": "^0.10.8"
|
|
||||||
pg: "^8.16.2"
|
pg: "^8.16.2"
|
||||||
|
tsup: "^8.5.0"
|
||||||
uuid: "^11.0.0"
|
uuid: "^11.0.0"
|
||||||
vitest: "3.2.4"
|
|
||||||
vite: "6.3.5"
|
vite: "6.3.5"
|
||||||
zod: "^3.0.0"
|
"vite-tsconfig-paths": "^5.1.4"
|
||||||
|
vitest: "3.2.4"
|
||||||
|
zod: "^3.25.0"
|
||||||
|
|
Loading…
Reference in New Issue