feat(db): mesh data model — meshes, members, invites, audit log

- pgSchema "mesh" with 4 tables isolating the peer mesh domain
- Enums: visibility, transport, tier, role
- audit_log is metadata-only (E2E encryption enforced at broker/client)
- Cascade on mesh delete, soft-delete via archivedAt/revokedAt

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Alejandro Gutiérrez
2026-04-04 21:19:32 +01:00
commit d3163a5bff
1384 changed files with 314925 additions and 0 deletions

View File

@@ -0,0 +1 @@
export * from "./providers/env";

View File

@@ -0,0 +1,13 @@
import * as z from "zod";
import { env } from "../env";
export const getObjectUrlSchema = z.object({
path: z.string(),
bucket: z
.string()
.optional()
.default(env.S3_BUCKET ?? ""),
});
export type GetObjectUrlInput = z.input<typeof getObjectUrlSchema>;

View File

@@ -0,0 +1 @@
export * from "./s3/env";

View File

@@ -0,0 +1 @@
export * from "./s3";

View File

@@ -0,0 +1,27 @@
import { S3Client } from "@aws-sdk/client-s3";
import { env } from "../../env";
let s3Client: S3Client | null = null;
export const getClient = () => {
if (s3Client) {
return s3Client;
}
if (!env.S3_ACCESS_KEY_ID || !env.S3_SECRET_ACCESS_KEY) {
throw new Error("S3_ACCESS_KEY_ID and S3_SECRET_ACCESS_KEY are required when using S3 storage");
}
s3Client = new S3Client({
forcePathStyle: true,
region: env.S3_REGION,
endpoint: env.S3_ENDPOINT,
credentials: {
accessKeyId: env.S3_ACCESS_KEY_ID,
secretAccessKey: env.S3_SECRET_ACCESS_KEY,
},
});
return s3Client;
};

View File

@@ -0,0 +1,22 @@
import { defineEnv } from "envin";
import * as z from "zod";
import { envConfig } from "@turbostarter/shared/constants";
import type { Preset } from "envin/types";
export const preset = {
id: "s3",
server: {
S3_BUCKET: z.string().optional(),
S3_REGION: z.string().optional().default("us-east-1"),
S3_ENDPOINT: z.string().optional(),
S3_ACCESS_KEY_ID: z.string().optional(),
S3_SECRET_ACCESS_KEY: z.string().optional(),
},
} as const satisfies Preset;
export const env = defineEnv({
...envConfig,
...preset,
});

View File

@@ -0,0 +1,94 @@
import {
DeleteObjectCommand,
GetObjectCommand,
PutObjectCommand,
} from "@aws-sdk/client-s3";
import { getSignedUrl as getSignedUrlCommand } from "@aws-sdk/s3-request-presigner";
import { getObjectUrlSchema } from "../../lib/schema";
import { getClient } from "./client";
import type { GetObjectUrlInput } from "../../lib/schema";
import type { StorageProviderStrategy } from "../types";
// Helper to apply schema defaults (bucket from env)
const withDefaults = (input: GetObjectUrlInput) => getObjectUrlSchema.parse(input);
export const { getUploadUrl, getSignedUrl, getPublicUrl, getDeleteUrl } = {
getUploadUrl: async (input: GetObjectUrlInput) => {
const { path, bucket } = withDefaults(input);
const client = getClient();
const url = await getSignedUrlCommand(
client,
new PutObjectCommand({
Bucket: bucket,
Key: path,
}),
{
expiresIn: 60,
},
);
return { url };
},
getSignedUrl: async (input: GetObjectUrlInput) => {
const { path, bucket } = withDefaults(input);
const client = getClient();
const url = await getSignedUrlCommand(
client,
new GetObjectCommand({
Bucket: bucket,
Key: path,
}),
{
expiresIn: 3600,
},
);
return { url };
},
getPublicUrl: async (input: GetObjectUrlInput) => {
const { path, bucket } = withDefaults(input);
const client = getClient();
const endpoint = await client.config.endpoint?.();
const forcePathStyle = client.config.forcePathStyle;
if (endpoint?.hostname.includes("supabase.co")) {
return {
url: `${endpoint.protocol}//${endpoint.hostname}/storage/v1/object/public/${bucket}/${path}`,
};
}
// Use path-style URL for MinIO and other S3-compatible storage (forcePathStyle: true)
if (forcePathStyle) {
const port = endpoint?.port ? `:${endpoint.port}` : "";
return {
url: `${endpoint?.protocol}//${endpoint?.hostname}${port}/${bucket}/${path}`,
};
}
return {
url: `${endpoint?.protocol}//${bucket}.${endpoint?.hostname}/${path}`,
};
},
getDeleteUrl: async (input: GetObjectUrlInput) => {
const { path, bucket } = withDefaults(input);
const client = getClient();
const url = await getSignedUrlCommand(
client,
new DeleteObjectCommand({
Bucket: bucket,
Key: path,
}),
{
expiresIn: 60,
},
);
return { url };
},
} satisfies StorageProviderStrategy;

View File

@@ -0,0 +1,8 @@
import type { GetObjectUrlInput } from "../lib/schema";
export interface StorageProviderStrategy {
getUploadUrl: (data: GetObjectUrlInput) => Promise<{ url: string }>;
getSignedUrl: (data: GetObjectUrlInput) => Promise<{ url: string }>;
getPublicUrl: (data: GetObjectUrlInput) => Promise<{ url: string }>;
getDeleteUrl: (data: GetObjectUrlInput) => Promise<{ url: string }>;
}

View File

@@ -0,0 +1,8 @@
export {
getUploadUrl,
getDeleteUrl,
getPublicUrl,
getSignedUrl,
} from "./providers";
export * from "./lib/schema";