Extension api and db (#16)

Co-authored-by: cte <cestreich@gmail.com>
This commit is contained in:
John Richmond 2025-05-17 16:47:51 -07:00 committed by GitHub
parent 4a0697c09f
commit 82b0e45668
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 290 additions and 0 deletions

View file

@ -0,0 +1,36 @@
'use server';
import { auth } from '@clerk/nextjs/server';
import { db } from '@/db';
import { organizationSettings } from '@/db/schema';
import { eq } from 'drizzle-orm';
import { type OrganizationSettings } from '@/schemas';
/**
* Get organization settings for the current organization
*/
export async function getOrganizationSettings(): Promise<
OrganizationSettings | undefined
> {
const { userId, orgId } = await auth();
if (!userId) {
throw new Error('Unauthorized');
}
if (!orgId) {
throw new Error('Organization not found');
}
const settings = await db
.select()
.from(organizationSettings)
.where(eq(organizationSettings.organizationId, orgId))
.limit(1);
if (settings.length === 0) {
return;
}
return settings[0];
}

View file

@ -0,0 +1,39 @@
import { auth } from '@clerk/nextjs/server';
import { NextResponse } from 'next/server';
import { getOrganizationSettings } from '@/actions/organizationSettings';
import { ORGANIZATION_ALLOW_ALL, type OrganizationSettings } from '@/schemas';
export async function GET() {
try {
const { userId, orgId } = await auth();
if (!userId) {
return NextResponse.json(
{ error: 'Unauthorized request' },
{ status: 401 },
);
}
if (!orgId) {
return NextResponse.json(
{ error: 'Organization not found' },
{ status: 404 },
);
}
const settings: OrganizationSettings =
(await getOrganizationSettings()) || {
defaultSettings: {},
allowList: ORGANIZATION_ALLOW_ALL,
version: 0,
};
return NextResponse.json(settings);
} catch (error) {
console.error('Error fetching organization settings:', error);
return NextResponse.json(
{ error: 'Failed to fetch organization settings' },
{ status: 500 },
);
}
}

View file

@ -0,0 +1,8 @@
CREATE TABLE "organization_settings" (
"organization_id" text PRIMARY KEY NOT NULL,
"version" integer NOT NULL DEFAULT 1,
"default_settings" jsonb NOT NULL DEFAULT '{}',
"allow_list" jsonb NOT NULL DEFAULT '{"allowAll": true, "providers": {}}'::jsonb,
"created_at" timestamp NOT NULL DEFAULT now(),
"updated_at" timestamp NOT NULL DEFAULT now()
);

View file

@ -0,0 +1,135 @@
{
"id": "a7b8c9d0-e1f2-3456-7890-a1b2c3d4e5f6",
"prevId": "6600a193-62ff-4475-9533-eb1dafc7339e",
"version": "7",
"dialect": "postgresql",
"tables": {
"public.audit_logs": {
"name": "audit_logs",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": true
},
"organization_id": {
"name": "organization_id",
"type": "text",
"primaryKey": false,
"notNull": true
},
"target_type": {
"name": "target_type",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"target_id": {
"name": "target_id",
"type": "text",
"primaryKey": false,
"notNull": true
},
"new_value": {
"name": "new_value",
"type": "jsonb",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.organization_settings": {
"name": "organization_settings",
"schema": "",
"columns": {
"organization_id": {
"name": "organization_id",
"type": "text",
"primaryKey": true,
"notNull": true
},
"version": {
"name": "version",
"type": "integer",
"primaryKey": false,
"notNull": true,
"default": "1"
},
"default_settings": {
"name": "default_settings",
"type": "jsonb",
"primaryKey": false,
"notNull": true,
"default": "'{}'::jsonb"
},
"allow_list": {
"name": "allow_list",
"type": "jsonb",
"primaryKey": false,
"notNull": true,
"default": "{\"allowAll\": true, \"providers\": {}}"
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
}
},
"enums": {},
"schemas": {},
"sequences": {},
"roles": {},
"policies": {},
"views": {},
"_meta": {
"columns": {},
"schemas": {},
"tables": {}
}
}

View file

@ -8,6 +8,13 @@
"when": 1747347845063,
"tag": "0000_daffy_psylocke",
"breakpoints": true
},
{
"idx": 1,
"version": "7",
"when": 1747347900000,
"tag": "0001_add_organization_settings",
"breakpoints": true
}
]
}

View file

@ -1,3 +1,8 @@
import {
ORGANIZATION_ALLOW_ALL,
OrganizationDefaultSettings,
type OrganizationAllowList,
} from '@/schemas';
import {
pgTable,
text,
@ -29,3 +34,21 @@ export enum AuditLogTargetType {
export type AuditLog = typeof auditLogs.$inferSelect & {
targetType: AuditLogTargetType;
};
export const organizationSettings = pgTable('organization_settings', {
// Organization ID (from Clerk)
organizationId: text('organization_id').notNull().primaryKey(),
// Version number, incremented on updates
version: integer('version').notNull().default(1),
defaultSettings: jsonb('default_settings')
.notNull()
.$type<OrganizationDefaultSettings>()
.default({}),
allowList: jsonb('allow_list')
.notNull()
.$type<OrganizationAllowList>()
.default(ORGANIZATION_ALLOW_ALL),
createdAt: timestamp('created_at').notNull().defaultNow(),
updatedAt: timestamp('updated_at').notNull().defaultNow(),
});

View file

@ -2,6 +2,48 @@
* TimePeriod
*/
import { z } from 'zod';
export const timePeriods = [7, 30, 90] as const;
export type TimePeriod = (typeof timePeriods)[number];
export const organizationAllowListSchema = z.object({
allowAll: z.boolean(),
providers: z.record(
z.object({
allowAll: z.boolean(),
models: z.array(z.string()).optional(),
}),
),
});
// From Roo-Code-Internal
export type OrganizationAllowList = z.infer<typeof organizationAllowListSchema>;
export const ORGANIZATION_ALLOW_ALL: OrganizationAllowList = {
allowAll: true,
providers: {},
} as const;
export const organizationDefaultSettingsSchema = z.object({
enableCheckpoints: z.boolean().optional(),
maxOpenTabsContext: z.number().optional(),
maxWorkspaceFiles: z.number().optional(),
showRooIgnoredFiles: z.boolean().optional(),
maxReadFileLine: z.number().optional(),
fuzzyMatchThreshold: z.number().optional(),
});
export type OrganizationDefaultSettings = z.infer<
typeof organizationDefaultSettingsSchema
>;
export const organizationSettingsSchema = z.object({
version: z.number(),
defaultSettings: organizationDefaultSettingsSchema,
allowList: organizationAllowListSchema,
});
export type OrganizationSettings = z.infer<typeof organizationSettingsSchema>;