Add v1 migrations

This commit is contained in:
Owen
2026-08-17 16:50:51 -04:00
parent 92916cd9db
commit 7d10b63dc5
2 changed files with 729 additions and 0 deletions
+365
View File
@@ -20,6 +20,371 @@ export default async function migration() {
await db.execute(sql`
`);
await db.execute(sql`
CREATE TABLE "aiBudgetBreachEvents" (
"id" serial PRIMARY KEY NOT NULL,
"orgId" varchar NOT NULL,
"budgetId" integer NOT NULL,
"enforcement" varchar NOT NULL,
"unit" varchar NOT NULL,
"period" varchar NOT NULL,
"amount" real NOT NULL,
"usageAmount" real NOT NULL,
"blocked" boolean NOT NULL,
"requestUserId" varchar,
"createdAt" bigint NOT NULL
);
`);
await db.execute(sql`
CREATE TABLE "aiBudgets" (
"budgetId" serial PRIMARY KEY NOT NULL,
"orgId" varchar NOT NULL,
"providerId" integer,
"modelId" integer,
"resourceId" integer,
"siteResourceId" integer,
"roleId" integer,
"virtualApiKeyId" varchar,
"amount" real NOT NULL,
"unit" varchar NOT NULL,
"period" varchar DEFAULT 'monthly' NOT NULL,
"enforcement" varchar DEFAULT 'hard' NOT NULL,
"enabled" boolean DEFAULT true NOT NULL,
"createdAt" bigint NOT NULL,
"updatedAt" bigint NOT NULL,
CONSTRAINT "ai_budget_provider_uniq" UNIQUE("providerId","unit","period"),
CONSTRAINT "ai_budget_model_uniq" UNIQUE("modelId","unit","period"),
CONSTRAINT "ai_budget_resource_uniq" UNIQUE("resourceId","unit","period"),
CONSTRAINT "ai_budget_site_resource_uniq" UNIQUE("siteResourceId","unit","period"),
CONSTRAINT "ai_budget_role_uniq" UNIQUE("roleId","unit","period"),
CONSTRAINT "ai_budget_virtual_api_key_uniq" UNIQUE("virtualApiKeyId","unit","period")
);
`);
await db.execute(sql`
CREATE TABLE "aiModels" (
"modelId" serial PRIMARY KEY NOT NULL,
"providerId" integer NOT NULL,
"modelKey" varchar NOT NULL,
"name" varchar NOT NULL,
"listType" varchar DEFAULT 'allow' NOT NULL,
"enabled" boolean DEFAULT true NOT NULL,
"createdAt" bigint NOT NULL,
"updatedAt" bigint NOT NULL,
CONSTRAINT "ai_model_provider_key_uniq" UNIQUE("providerId","modelKey")
);
`);
await db.execute(sql`
CREATE TABLE "aiProviders" (
"providerId" serial PRIMARY KEY NOT NULL,
"orgId" varchar NOT NULL,
"name" varchar NOT NULL,
"niceId" varchar NOT NULL,
"type" varchar NOT NULL,
"upstreamUrl" text,
"apiKey" text,
"apiKeyLastChars" varchar,
"authType" varchar NOT NULL,
"routingMode" varchar DEFAULT 'url' NOT NULL,
"capabilities" text DEFAULT '[]' NOT NULL,
"headers" text,
"skipTlsVerification" boolean DEFAULT false NOT NULL,
"enabled" boolean DEFAULT true NOT NULL,
"createdAt" bigint NOT NULL,
"updatedAt" bigint NOT NULL
);
`);
await db.execute(sql`
CREATE TABLE "aiSessionLog" (
"id" serial PRIMARY KEY NOT NULL,
"sessionId" varchar NOT NULL,
"orgId" varchar,
"providerId" integer,
"capability" varchar NOT NULL,
"resourceId" integer,
"siteResourceId" integer,
"userId" varchar,
"virtualApiKeyId" varchar,
"requestedModel" varchar,
"isStream" boolean DEFAULT false NOT NULL,
"requestBody" text,
"responseBody" text,
"normalizedRequest" text,
"normalizedResponse" text,
"truncated" boolean DEFAULT false NOT NULL,
"statusCode" integer,
"createdAt" bigint NOT NULL
);
`);
await db.execute(sql`
CREATE TABLE "aiUsageRecords" (
"id" serial PRIMARY KEY NOT NULL,
"orgId" varchar NOT NULL,
"providerId" integer,
"resourceId" integer,
"siteResourceId" integer,
"userId" varchar,
"virtualApiKeyId" varchar,
"sessionId" varchar,
"requestedModel" varchar NOT NULL,
"promptTokens" integer DEFAULT 0 NOT NULL,
"cacheReadTokens" integer DEFAULT 0 NOT NULL,
"cacheWriteTokens" integer DEFAULT 0 NOT NULL,
"completionTokens" integer DEFAULT 0 NOT NULL,
"reasoningTokens" integer DEFAULT 0 NOT NULL,
"totalTokens" integer DEFAULT 0 NOT NULL,
"costUsd" real,
"estimated" boolean DEFAULT false NOT NULL,
"createdAt" bigint NOT NULL
);
`);
await db.execute(sql`
CREATE TABLE "resourceAiModels" (
"resourceId" integer NOT NULL,
"modelId" integer NOT NULL,
"listType" varchar DEFAULT 'allow' NOT NULL,
CONSTRAINT "resourceAiModels_resourceId_modelId_pk" PRIMARY KEY("resourceId","modelId")
);
`);
await db.execute(sql`
CREATE TABLE "resourceAiProviders" (
"resourceId" integer NOT NULL,
"providerId" integer NOT NULL,
"accessMode" varchar DEFAULT 'inherit' NOT NULL,
"enabled" boolean DEFAULT true NOT NULL,
CONSTRAINT "resourceAiProviders_resourceId_providerId_pk" PRIMARY KEY("resourceId","providerId")
);
`);
await db.execute(sql`
CREATE TABLE "siteResourceAiModels" (
"siteResourceId" integer NOT NULL,
"modelId" integer NOT NULL,
"listType" varchar DEFAULT 'allow' NOT NULL,
CONSTRAINT "siteResourceAiModels_siteResourceId_modelId_pk" PRIMARY KEY("siteResourceId","modelId")
);
`);
await db.execute(sql`
CREATE TABLE "siteResourceAiProviders" (
"siteResourceId" integer NOT NULL,
"providerId" integer NOT NULL,
"accessMode" varchar DEFAULT 'inherit' NOT NULL,
"enabled" boolean DEFAULT true NOT NULL,
CONSTRAINT "siteResourceAiProviders_siteResourceId_providerId_pk" PRIMARY KEY("siteResourceId","providerId")
);
`);
await db.execute(sql`
CREATE TABLE "virtualApiKeyResources" (
"virtualApiKeyId" varchar NOT NULL,
"resourceId" integer NOT NULL,
CONSTRAINT "virtualApiKeyResources_virtualApiKeyId_resourceId_pk" PRIMARY KEY("virtualApiKeyId","resourceId")
);
`);
await db.execute(sql`
CREATE TABLE "virtualApiKeys" (
"virtualApiKeyId" varchar PRIMARY KEY NOT NULL,
"orgId" varchar NOT NULL,
"kind" varchar NOT NULL,
"userId" varchar,
"name" varchar,
"description" varchar,
"token" varchar NOT NULL,
"lastChars" varchar NOT NULL,
"allResources" boolean DEFAULT false NOT NULL,
"expiresAt" bigint,
"lastUsedAt" bigint,
"createdAt" bigint NOT NULL,
"createdByUserId" varchar
);
`);
await db.execute(
sql`ALTER TABLE "clients" RENAME COLUMN "subnet" TO "exitNodeSubnet";`
);
await db.execute(
sql`ALTER TABLE "roles" ALTER COLUMN "sshSudoMode" SET DEFAULT 'full';`
);
await db.execute(
sql`ALTER TABLE "targets" ALTER COLUMN "resourceId" DROP NOT NULL;`
);
await db.execute(
sql`ALTER TABLE "subscriptions" ADD COLUMN "override" boolean DEFAULT false;`
);
await db.execute(
sql`ALTER TABLE "orgs" ADD COLUMN "settingsLogRetentionDaysAISessions" integer DEFAULT 7 NOT NULL;`
);
await db.execute(
sql`ALTER TABLE "siteResources" ADD COLUMN "requiresExitNodeConnection" boolean DEFAULT false NOT NULL;`
);
await db.execute(
sql`ALTER TABLE "sites" ADD COLUMN "exitNodeSubnet" text;`
);
await db.execute(
sql`ALTER TABLE "targets" ADD COLUMN "providerId" integer;`
);
await db.execute(
sql`ALTER TABLE "aiBudgetBreachEvents" ADD CONSTRAINT "aiBudgetBreachEvents_orgId_orgs_orgId_fk" FOREIGN KEY ("orgId") REFERENCES "public"."orgs"("orgId") ON DELETE cascade ON UPDATE no action;`
);
await db.execute(
sql`ALTER TABLE "aiBudgetBreachEvents" ADD CONSTRAINT "aiBudgetBreachEvents_budgetId_aiBudgets_budgetId_fk" FOREIGN KEY ("budgetId") REFERENCES "public"."aiBudgets"("budgetId") ON DELETE cascade ON UPDATE no action;`
);
await db.execute(
sql`ALTER TABLE "aiBudgetBreachEvents" ADD CONSTRAINT "aiBudgetBreachEvents_requestUserId_user_id_fk" FOREIGN KEY ("requestUserId") REFERENCES "public"."user"("id") ON DELETE set null ON UPDATE no action;`
);
await db.execute(
sql`ALTER TABLE "aiBudgets" ADD CONSTRAINT "aiBudgets_orgId_orgs_orgId_fk" FOREIGN KEY ("orgId") REFERENCES "public"."orgs"("orgId") ON DELETE cascade ON UPDATE no action;`
);
await db.execute(
sql`ALTER TABLE "aiBudgets" ADD CONSTRAINT "aiBudgets_providerId_aiProviders_providerId_fk" FOREIGN KEY ("providerId") REFERENCES "public"."aiProviders"("providerId") ON DELETE cascade ON UPDATE no action;`
);
await db.execute(
sql`ALTER TABLE "aiBudgets" ADD CONSTRAINT "aiBudgets_modelId_aiModels_modelId_fk" FOREIGN KEY ("modelId") REFERENCES "public"."aiModels"("modelId") ON DELETE cascade ON UPDATE no action;`
);
await db.execute(
sql`ALTER TABLE "aiBudgets" ADD CONSTRAINT "aiBudgets_resourceId_resources_resourceId_fk" FOREIGN KEY ("resourceId") REFERENCES "public"."resources"("resourceId") ON DELETE cascade ON UPDATE no action;`
);
await db.execute(
sql`ALTER TABLE "aiBudgets" ADD CONSTRAINT "aiBudgets_siteResourceId_siteResources_siteResourceId_fk" FOREIGN KEY ("siteResourceId") REFERENCES "public"."siteResources"("siteResourceId") ON DELETE cascade ON UPDATE no action;`
);
await db.execute(
sql`ALTER TABLE "aiBudgets" ADD CONSTRAINT "aiBudgets_roleId_roles_roleId_fk" FOREIGN KEY ("roleId") REFERENCES "public"."roles"("roleId") ON DELETE cascade ON UPDATE no action;`
);
await db.execute(
sql`ALTER TABLE "aiBudgets" ADD CONSTRAINT "aiBudgets_virtualApiKeyId_virtualApiKeys_virtualApiKeyId_fk" FOREIGN KEY ("virtualApiKeyId") REFERENCES "public"."virtualApiKeys"("virtualApiKeyId") ON DELETE cascade ON UPDATE no action;`
);
await db.execute(
sql`ALTER TABLE "aiModels" ADD CONSTRAINT "aiModels_providerId_aiProviders_providerId_fk" FOREIGN KEY ("providerId") REFERENCES "public"."aiProviders"("providerId") ON DELETE cascade ON UPDATE no action;`
);
await db.execute(
sql`ALTER TABLE "aiProviders" ADD CONSTRAINT "aiProviders_orgId_orgs_orgId_fk" FOREIGN KEY ("orgId") REFERENCES "public"."orgs"("orgId") ON DELETE cascade ON UPDATE no action;`
);
await db.execute(
sql`ALTER TABLE "aiSessionLog" ADD CONSTRAINT "aiSessionLog_orgId_orgs_orgId_fk" FOREIGN KEY ("orgId") REFERENCES "public"."orgs"("orgId") ON DELETE cascade ON UPDATE no action;`
);
await db.execute(
sql`ALTER TABLE "aiSessionLog" ADD CONSTRAINT "aiSessionLog_providerId_aiProviders_providerId_fk" FOREIGN KEY ("providerId") REFERENCES "public"."aiProviders"("providerId") ON DELETE set null ON UPDATE no action;`
);
await db.execute(
sql`ALTER TABLE "aiSessionLog" ADD CONSTRAINT "aiSessionLog_resourceId_resources_resourceId_fk" FOREIGN KEY ("resourceId") REFERENCES "public"."resources"("resourceId") ON DELETE set null ON UPDATE no action;`
);
await db.execute(
sql`ALTER TABLE "aiSessionLog" ADD CONSTRAINT "aiSessionLog_siteResourceId_siteResources_siteResourceId_fk" FOREIGN KEY ("siteResourceId") REFERENCES "public"."siteResources"("siteResourceId") ON DELETE set null ON UPDATE no action;`
);
await db.execute(
sql`ALTER TABLE "aiSessionLog" ADD CONSTRAINT "aiSessionLog_userId_user_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user"("id") ON DELETE set null ON UPDATE no action;`
);
await db.execute(
sql`ALTER TABLE "aiSessionLog" ADD CONSTRAINT "aiSessionLog_virtualApiKeyId_virtualApiKeys_virtualApiKeyId_fk" FOREIGN KEY ("virtualApiKeyId") REFERENCES "public"."virtualApiKeys"("virtualApiKeyId") ON DELETE set null ON UPDATE no action;`
);
await db.execute(
sql`ALTER TABLE "aiUsageRecords" ADD CONSTRAINT "aiUsageRecords_orgId_orgs_orgId_fk" FOREIGN KEY ("orgId") REFERENCES "public"."orgs"("orgId") ON DELETE cascade ON UPDATE no action;`
);
await db.execute(
sql`ALTER TABLE "aiUsageRecords" ADD CONSTRAINT "aiUsageRecords_providerId_aiProviders_providerId_fk" FOREIGN KEY ("providerId") REFERENCES "public"."aiProviders"("providerId") ON DELETE set null ON UPDATE no action;`
);
await db.execute(
sql`ALTER TABLE "aiUsageRecords" ADD CONSTRAINT "aiUsageRecords_resourceId_resources_resourceId_fk" FOREIGN KEY ("resourceId") REFERENCES "public"."resources"("resourceId") ON DELETE set null ON UPDATE no action;`
);
await db.execute(
sql`ALTER TABLE "aiUsageRecords" ADD CONSTRAINT "aiUsageRecords_siteResourceId_siteResources_siteResourceId_fk" FOREIGN KEY ("siteResourceId") REFERENCES "public"."siteResources"("siteResourceId") ON DELETE set null ON UPDATE no action;`
);
await db.execute(
sql`ALTER TABLE "aiUsageRecords" ADD CONSTRAINT "aiUsageRecords_userId_user_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user"("id") ON DELETE set null ON UPDATE no action;`
);
await db.execute(
sql`ALTER TABLE "aiUsageRecords" ADD CONSTRAINT "aiUsageRecords_virtualApiKeyId_virtualApiKeys_virtualApiKeyId_fk" FOREIGN KEY ("virtualApiKeyId") REFERENCES "public"."virtualApiKeys"("virtualApiKeyId") ON DELETE set null ON UPDATE no action;`
);
await db.execute(
sql`ALTER TABLE "resourceAiModels" ADD CONSTRAINT "resourceAiModels_resourceId_resources_resourceId_fk" FOREIGN KEY ("resourceId") REFERENCES "public"."resources"("resourceId") ON DELETE cascade ON UPDATE no action;`
);
await db.execute(
sql`ALTER TABLE "resourceAiModels" ADD CONSTRAINT "resourceAiModels_modelId_aiModels_modelId_fk" FOREIGN KEY ("modelId") REFERENCES "public"."aiModels"("modelId") ON DELETE cascade ON UPDATE no action;`
);
await db.execute(
sql`ALTER TABLE "resourceAiProviders" ADD CONSTRAINT "resourceAiProviders_resourceId_resources_resourceId_fk" FOREIGN KEY ("resourceId") REFERENCES "public"."resources"("resourceId") ON DELETE cascade ON UPDATE no action;`
);
await db.execute(
sql`ALTER TABLE "resourceAiProviders" ADD CONSTRAINT "resourceAiProviders_providerId_aiProviders_providerId_fk" FOREIGN KEY ("providerId") REFERENCES "public"."aiProviders"("providerId") ON DELETE cascade ON UPDATE no action;`
);
await db.execute(
sql`ALTER TABLE "siteResourceAiModels" ADD CONSTRAINT "siteResourceAiModels_siteResourceId_siteResources_siteResourceId_fk" FOREIGN KEY ("siteResourceId") REFERENCES "public"."siteResources"("siteResourceId") ON DELETE cascade ON UPDATE no action;`
);
await db.execute(
sql`ALTER TABLE "siteResourceAiModels" ADD CONSTRAINT "siteResourceAiModels_modelId_aiModels_modelId_fk" FOREIGN KEY ("modelId") REFERENCES "public"."aiModels"("modelId") ON DELETE cascade ON UPDATE no action;`
);
await db.execute(
sql`ALTER TABLE "siteResourceAiProviders" ADD CONSTRAINT "siteResourceAiProviders_siteResourceId_siteResources_siteResourceId_fk" FOREIGN KEY ("siteResourceId") REFERENCES "public"."siteResources"("siteResourceId") ON DELETE cascade ON UPDATE no action;`
);
await db.execute(
sql`ALTER TABLE "siteResourceAiProviders" ADD CONSTRAINT "siteResourceAiProviders_providerId_aiProviders_providerId_fk" FOREIGN KEY ("providerId") REFERENCES "public"."aiProviders"("providerId") ON DELETE cascade ON UPDATE no action;`
);
await db.execute(
sql`ALTER TABLE "virtualApiKeyResources" ADD CONSTRAINT "virtualApiKeyResources_virtualApiKeyId_virtualApiKeys_virtualApiKeyId_fk" FOREIGN KEY ("virtualApiKeyId") REFERENCES "public"."virtualApiKeys"("virtualApiKeyId") ON DELETE cascade ON UPDATE no action;`
);
await db.execute(
sql`ALTER TABLE "virtualApiKeyResources" ADD CONSTRAINT "virtualApiKeyResources_resourceId_resources_resourceId_fk" FOREIGN KEY ("resourceId") REFERENCES "public"."resources"("resourceId") ON DELETE cascade ON UPDATE no action;`
);
await db.execute(
sql`ALTER TABLE "virtualApiKeys" ADD CONSTRAINT "virtualApiKeys_orgId_orgs_orgId_fk" FOREIGN KEY ("orgId") REFERENCES "public"."orgs"("orgId") ON DELETE cascade ON UPDATE no action;`
);
await db.execute(
sql`ALTER TABLE "virtualApiKeys" ADD CONSTRAINT "virtualApiKeys_userId_user_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action;`
);
await db.execute(
sql`ALTER TABLE "virtualApiKeys" ADD CONSTRAINT "virtualApiKeys_createdByUserId_user_id_fk" FOREIGN KEY ("createdByUserId") REFERENCES "public"."user"("id") ON DELETE set null ON UPDATE no action;`
);
await db.execute(
sql`CREATE INDEX "idx_ai_budget_breach_events_budget_created" ON "aiBudgetBreachEvents" USING btree ("budgetId","createdAt");`
);
await db.execute(
sql`CREATE INDEX "idx_aiProviders_orgId_niceId" ON "aiProviders" USING btree ("orgId","niceId");`
);
await db.execute(
sql`CREATE INDEX "idx_ai_session_log_org_created" ON "aiSessionLog" USING btree ("orgId","createdAt");`
);
await db.execute(
sql`CREATE INDEX "idx_ai_session_log_org_provider_created" ON "aiSessionLog" USING btree ("orgId","providerId","createdAt");`
);
await db.execute(
sql`CREATE INDEX "idx_ai_session_log_org_resource_created" ON "aiSessionLog" USING btree ("orgId","resourceId","createdAt");`
);
await db.execute(
sql`CREATE INDEX "idx_ai_session_log_org_site_resource_created" ON "aiSessionLog" USING btree ("orgId","siteResourceId","createdAt");`
);
await db.execute(
sql`CREATE INDEX "idx_ai_session_log_org_user_created" ON "aiSessionLog" USING btree ("orgId","userId","createdAt");`
);
await db.execute(
sql`CREATE INDEX "idx_ai_session_log_org_virtual_api_key_created" ON "aiSessionLog" USING btree ("orgId","virtualApiKeyId","createdAt");`
);
await db.execute(
sql`CREATE INDEX "idx_ai_session_log_session" ON "aiSessionLog" USING btree ("sessionId");`
);
await db.execute(
sql`CREATE INDEX "idx_ai_usage_records_org_provider_created" ON "aiUsageRecords" USING btree ("orgId","providerId","createdAt");`
);
await db.execute(
sql`CREATE INDEX "idx_ai_usage_records_org_resource_created" ON "aiUsageRecords" USING btree ("orgId","resourceId","createdAt");`
);
await db.execute(
sql`CREATE INDEX "idx_ai_usage_records_org_site_resource_created" ON "aiUsageRecords" USING btree ("orgId","siteResourceId","createdAt");`
);
await db.execute(
sql`CREATE INDEX "idx_ai_usage_records_org_user_created" ON "aiUsageRecords" USING btree ("orgId","userId","createdAt");`
);
await db.execute(
sql`CREATE INDEX "idx_ai_usage_records_org_virtual_api_key_created" ON "aiUsageRecords" USING btree ("orgId","virtualApiKeyId","createdAt");`
);
await db.execute(
sql`CREATE INDEX "idx_ai_usage_records_session" ON "aiUsageRecords" USING btree ("sessionId");`
);
await db.execute(
sql`CREATE UNIQUE INDEX "virtual_api_key_user_identity_uniq" ON "virtualApiKeys" USING btree ("orgId","userId") WHERE "virtualApiKeys"."kind" = 'user';`
);
await db.execute(
sql`ALTER TABLE "targets" ADD CONSTRAINT "targets_providerId_aiProviders_providerId_fk" FOREIGN KEY ("providerId") REFERENCES "public"."aiProviders"("providerId") ON DELETE cascade ON UPDATE no action;`
);
await db.execute(
sql`CREATE INDEX "idx_targets_providerid_siteid" ON "targets" USING btree ("providerId","siteId");`
);
for (const actionId of actionsToGrant) {
await db.execute(sql`
INSERT INTO "roleActions" ("roleId", "actionId", "orgId")
+364
View File
@@ -20,10 +20,374 @@ export default async function migration() {
db.pragma("foreign_keys = OFF");
db.transaction(() => {
db.prepare(
`ALTER TABLE 'sites' RENAME COLUMN "subnet" TO "exitNodeSubnet";`
).run();
db.prepare(
`
CREATE TABLE 'aiBudgetBreachEvents' (
'id' integer PRIMARY KEY AUTOINCREMENT NOT NULL,
'orgId' text NOT NULL,
'budgetId' integer NOT NULL,
'enforcement' text NOT NULL,
'unit' text NOT NULL,
'period' text NOT NULL,
'amount' real NOT NULL,
'usageAmount' real NOT NULL,
'blocked' integer NOT NULL,
'requestUserId' text,
'createdAt' integer NOT NULL,
FOREIGN KEY ('orgId') REFERENCES 'orgs'('orgId') ON UPDATE no action ON DELETE cascade,
FOREIGN KEY ('budgetId') REFERENCES 'aiBudgets'('budgetId') ON UPDATE no action ON DELETE cascade,
FOREIGN KEY ('requestUserId') REFERENCES 'user'('id') ON UPDATE no action ON DELETE set null
);
`
).run();
db.prepare(
`
CREATE INDEX 'idx_ai_budget_breach_events_budget_created' ON 'aiBudgetBreachEvents' ('budgetId','createdAt');
`
).run();
db.prepare(
`
CREATE TABLE 'aiBudgets' (
'budgetId' integer PRIMARY KEY AUTOINCREMENT NOT NULL,
'orgId' text NOT NULL,
'providerId' integer,
'modelId' integer,
'resourceId' integer,
'siteResourceId' integer,
'roleId' integer,
'virtualApiKeyId' text,
'amount' real NOT NULL,
'unit' text NOT NULL,
'period' text DEFAULT 'monthly' NOT NULL,
'enforcement' text DEFAULT 'hard' NOT NULL,
'enabled' integer DEFAULT true NOT NULL,
'createdAt' integer NOT NULL,
'updatedAt' integer NOT NULL,
FOREIGN KEY ('orgId') REFERENCES 'orgs'('orgId') ON UPDATE no action ON DELETE cascade,
FOREIGN KEY ('providerId') REFERENCES 'aiProviders'('providerId') ON UPDATE no action ON DELETE cascade,
FOREIGN KEY ('modelId') REFERENCES 'aiModels'('modelId') ON UPDATE no action ON DELETE cascade,
FOREIGN KEY ('resourceId') REFERENCES 'resources'('resourceId') ON UPDATE no action ON DELETE cascade,
FOREIGN KEY ('siteResourceId') REFERENCES 'siteResources'('siteResourceId') ON UPDATE no action ON DELETE cascade,
FOREIGN KEY ('roleId') REFERENCES 'roles'('roleId') ON UPDATE no action ON DELETE cascade,
FOREIGN KEY ('virtualApiKeyId') REFERENCES 'virtualApiKeys'('virtualApiKeyId') ON UPDATE no action ON DELETE cascade
);
`
).run();
db.prepare(
`CREATE UNIQUE INDEX 'ai_budget_provider_uniq' ON 'aiBudgets' ('providerId','unit','period');`
).run();
db.prepare(
`CREATE UNIQUE INDEX 'ai_budget_model_uniq' ON 'aiBudgets' ('modelId','unit','period');`
).run();
db.prepare(
`CREATE UNIQUE INDEX 'ai_budget_resource_uniq' ON 'aiBudgets' ('resourceId','unit','period');`
).run();
db.prepare(
`CREATE UNIQUE INDEX 'ai_budget_site_resource_uniq' ON 'aiBudgets' ('siteResourceId','unit','period');`
).run();
db.prepare(
`CREATE UNIQUE INDEX 'ai_budget_role_uniq' ON 'aiBudgets' ('roleId','unit','period');`
).run();
db.prepare(
`CREATE UNIQUE INDEX 'ai_budget_virtual_api_key_uniq' ON 'aiBudgets' ('virtualApiKeyId','unit','period');`
).run();
db.prepare(
`
CREATE TABLE 'aiModels' (
'modelId' integer PRIMARY KEY AUTOINCREMENT NOT NULL,
'providerId' integer NOT NULL,
'modelKey' text NOT NULL,
'name' text NOT NULL,
'listType' text DEFAULT 'allow' NOT NULL,
'enabled' integer DEFAULT true NOT NULL,
'createdAt' integer NOT NULL,
'updatedAt' integer NOT NULL,
FOREIGN KEY ('providerId') REFERENCES 'aiProviders'('providerId') ON UPDATE no action ON DELETE cascade
);
`
).run();
db.prepare(
`
CREATE UNIQUE INDEX 'ai_model_provider_key_uniq' ON 'aiModels' ('providerId','modelKey');
`
).run();
db.prepare(
`
CREATE TABLE 'aiProviders' (
'providerId' integer PRIMARY KEY AUTOINCREMENT NOT NULL,
'orgId' text NOT NULL,
'name' text NOT NULL,
'niceId' text NOT NULL,
'type' text NOT NULL,
'upstreamUrl' text,
'apiKey' text,
'apiKeyLastChars' text,
'authType' text NOT NULL,
'routingMode' text DEFAULT 'url' NOT NULL,
'capabilities' text DEFAULT '[]' NOT NULL,
'headers' text,
'skipTlsVerification' integer DEFAULT false NOT NULL,
'enabled' integer DEFAULT true NOT NULL,
'createdAt' integer NOT NULL,
'updatedAt' integer NOT NULL,
FOREIGN KEY ('orgId') REFERENCES 'orgs'('orgId') ON UPDATE no action ON DELETE cascade
);
`
).run();
db.prepare(
`
CREATE INDEX 'idx_aiProviders_orgId_niceId' ON 'aiProviders' ('orgId','niceId');
`
).run();
db.prepare(
`
CREATE TABLE 'aiSessionLog' (
'id' integer PRIMARY KEY AUTOINCREMENT NOT NULL,
'sessionId' text NOT NULL,
'orgId' text,
'providerId' integer,
'capability' text NOT NULL,
'resourceId' integer,
'siteResourceId' integer,
'userId' text,
'virtualApiKeyId' text,
'requestedModel' text,
'isStream' integer DEFAULT false NOT NULL,
'requestBody' text,
'responseBody' text,
'normalizedRequest' text,
'normalizedResponse' text,
'truncated' integer DEFAULT false NOT NULL,
'statusCode' integer,
'createdAt' integer NOT NULL,
FOREIGN KEY ('orgId') REFERENCES 'orgs'('orgId') ON UPDATE no action ON DELETE cascade,
FOREIGN KEY ('providerId') REFERENCES 'aiProviders'('providerId') ON UPDATE no action ON DELETE set null,
FOREIGN KEY ('resourceId') REFERENCES 'resources'('resourceId') ON UPDATE no action ON DELETE set null,
FOREIGN KEY ('siteResourceId') REFERENCES 'siteResources'('siteResourceId') ON UPDATE no action ON DELETE set null,
FOREIGN KEY ('userId') REFERENCES 'user'('id') ON UPDATE no action ON DELETE set null,
FOREIGN KEY ('virtualApiKeyId') REFERENCES 'virtualApiKeys'('virtualApiKeyId') ON UPDATE no action ON DELETE set null
);
`
).run();
db.prepare(
`CREATE INDEX 'idx_ai_session_log_org_created' ON 'aiSessionLog' ('orgId','createdAt');`
).run();
db.prepare(
`CREATE INDEX 'idx_ai_session_log_org_provider_created' ON 'aiSessionLog' ('orgId','providerId','createdAt');`
).run();
db.prepare(
`CREATE INDEX 'idx_ai_session_log_org_resource_created' ON 'aiSessionLog' ('orgId','resourceId','createdAt');`
).run();
db.prepare(
`CREATE INDEX 'idx_ai_session_log_org_site_resource_created' ON 'aiSessionLog' ('orgId','siteResourceId','createdAt');`
).run();
db.prepare(
`CREATE INDEX 'idx_ai_session_log_org_user_created' ON 'aiSessionLog' ('orgId','userId','createdAt');`
).run();
db.prepare(
`CREATE INDEX 'idx_ai_session_log_org_virtual_api_key_created' ON 'aiSessionLog' ('orgId','virtualApiKeyId','createdAt');`
).run();
db.prepare(
`CREATE INDEX 'idx_ai_session_log_session' ON 'aiSessionLog' ('sessionId');`
).run();
db.prepare(
`
CREATE TABLE 'aiUsageRecords' (
'id' integer PRIMARY KEY AUTOINCREMENT NOT NULL,
'orgId' text NOT NULL,
'providerId' integer,
'resourceId' integer,
'siteResourceId' integer,
'userId' text,
'virtualApiKeyId' text,
'sessionId' text,
'requestedModel' text NOT NULL,
'promptTokens' integer DEFAULT 0 NOT NULL,
'cacheReadTokens' integer DEFAULT 0 NOT NULL,
'cacheWriteTokens' integer DEFAULT 0 NOT NULL,
'completionTokens' integer DEFAULT 0 NOT NULL,
'reasoningTokens' integer DEFAULT 0 NOT NULL,
'totalTokens' integer DEFAULT 0 NOT NULL,
'costUsd' real,
'estimated' integer DEFAULT false NOT NULL,
'createdAt' integer NOT NULL,
FOREIGN KEY ('orgId') REFERENCES 'orgs'('orgId') ON UPDATE no action ON DELETE cascade,
FOREIGN KEY ('providerId') REFERENCES 'aiProviders'('providerId') ON UPDATE no action ON DELETE set null,
FOREIGN KEY ('resourceId') REFERENCES 'resources'('resourceId') ON UPDATE no action ON DELETE set null,
FOREIGN KEY ('siteResourceId') REFERENCES 'siteResources'('siteResourceId') ON UPDATE no action ON DELETE set null,
FOREIGN KEY ('userId') REFERENCES 'user'('id') ON UPDATE no action ON DELETE set null,
FOREIGN KEY ('virtualApiKeyId') REFERENCES 'virtualApiKeys'('virtualApiKeyId') ON UPDATE no action ON DELETE set null
);
`
).run();
db.prepare(
`CREATE INDEX 'idx_ai_usage_records_org_provider_created' ON 'aiUsageRecords' ('orgId','providerId','createdAt');`
).run();
db.prepare(
`CREATE INDEX 'idx_ai_usage_records_org_resource_created' ON 'aiUsageRecords' ('orgId','resourceId','createdAt');`
).run();
db.prepare(
`CREATE INDEX 'idx_ai_usage_records_org_site_resource_created' ON 'aiUsageRecords' ('orgId','siteResourceId','createdAt');`
).run();
db.prepare(
`CREATE INDEX 'idx_ai_usage_records_org_user_created' ON 'aiUsageRecords' ('orgId','userId','createdAt');`
).run();
db.prepare(
`CREATE INDEX 'idx_ai_usage_records_org_virtual_api_key_created' ON 'aiUsageRecords' ('orgId','virtualApiKeyId','createdAt');`
).run();
db.prepare(
`CREATE INDEX 'idx_ai_usage_records_session' ON 'aiUsageRecords' ('sessionId');`
).run();
db.prepare(
`
CREATE TABLE 'resourceAiModels' (
'resourceId' integer NOT NULL,
'modelId' integer NOT NULL,
'listType' text DEFAULT 'allow' NOT NULL,
PRIMARY KEY('resourceId', 'modelId'),
FOREIGN KEY ('resourceId') REFERENCES 'resources'('resourceId') ON UPDATE no action ON DELETE cascade,
FOREIGN KEY ('modelId') REFERENCES 'aiModels'('modelId') ON UPDATE no action ON DELETE cascade
);
`
).run();
db.prepare(
`
CREATE TABLE 'resourceAiProviders' (
'resourceId' integer NOT NULL,
'providerId' integer NOT NULL,
'accessMode' text DEFAULT 'inherit' NOT NULL,
'enabled' integer DEFAULT true NOT NULL,
PRIMARY KEY('resourceId', 'providerId'),
FOREIGN KEY ('resourceId') REFERENCES 'resources'('resourceId') ON UPDATE no action ON DELETE cascade,
FOREIGN KEY ('providerId') REFERENCES 'aiProviders'('providerId') ON UPDATE no action ON DELETE cascade
);
`
).run();
db.prepare(
`
CREATE TABLE 'siteResourceAiModels' (
'siteResourceId' integer NOT NULL,
'modelId' integer NOT NULL,
'listType' text DEFAULT 'allow' NOT NULL,
PRIMARY KEY('siteResourceId', 'modelId'),
FOREIGN KEY ('siteResourceId') REFERENCES 'siteResources'('siteResourceId') ON UPDATE no action ON DELETE cascade,
FOREIGN KEY ('modelId') REFERENCES 'aiModels'('modelId') ON UPDATE no action ON DELETE cascade
);
`
).run();
db.prepare(
`
CREATE TABLE 'siteResourceAiProviders' (
'siteResourceId' integer NOT NULL,
'providerId' integer NOT NULL,
'accessMode' text DEFAULT 'inherit' NOT NULL,
'enabled' integer DEFAULT true NOT NULL,
PRIMARY KEY('siteResourceId', 'providerId'),
FOREIGN KEY ('siteResourceId') REFERENCES 'siteResources'('siteResourceId') ON UPDATE no action ON DELETE cascade,
FOREIGN KEY ('providerId') REFERENCES 'aiProviders'('providerId') ON UPDATE no action ON DELETE cascade
);
`
).run();
db.prepare(
`
CREATE TABLE 'virtualApiKeyResources' (
'virtualApiKeyId' text NOT NULL,
'resourceId' integer NOT NULL,
PRIMARY KEY('virtualApiKeyId', 'resourceId'),
FOREIGN KEY ('virtualApiKeyId') REFERENCES 'virtualApiKeys'('virtualApiKeyId') ON UPDATE no action ON DELETE cascade,
FOREIGN KEY ('resourceId') REFERENCES 'resources'('resourceId') ON UPDATE no action ON DELETE cascade
);
`
).run();
db.prepare(
`
CREATE TABLE 'virtualApiKeys' (
'virtualApiKeyId' text PRIMARY KEY NOT NULL,
'orgId' text NOT NULL,
'kind' text NOT NULL,
'userId' text,
'name' text,
'description' text,
'token' text NOT NULL,
'lastChars' text NOT NULL,
'allResources' integer DEFAULT false NOT NULL,
'expiresAt' integer,
'lastUsedAt' integer,
'createdAt' integer NOT NULL,
'createdByUserId' text,
FOREIGN KEY ('orgId') REFERENCES 'orgs'('orgId') ON UPDATE no action ON DELETE cascade,
FOREIGN KEY ('userId') REFERENCES 'user'('id') ON UPDATE no action ON DELETE cascade,
FOREIGN KEY ('createdByUserId') REFERENCES 'user'('id') ON UPDATE no action ON DELETE set null
);
`
).run();
db.prepare(
`
CREATE UNIQUE INDEX 'virtual_api_key_user_identity_uniq' ON 'virtualApiKeys' ('orgId','userId') WHERE "virtualApiKeys"."kind" = 'user';
`
).run();
db.prepare(
`ALTER TABLE 'roles' ADD COLUMN 'sshSudoModeNew' text DEFAULT 'full';`
).run();
db.prepare(
`UPDATE 'roles' SET "sshSudoModeNew" = "sshSudoMode";`
).run();
db.prepare(`ALTER TABLE 'roles' DROP COLUMN "sshSudoMode";`).run();
db.prepare(
`ALTER TABLE 'roles' RENAME COLUMN "sshSudoModeNew" TO "sshSudoMode";`
).run();
db.prepare(
`
CREATE TABLE '__new_targets' (
'targetId' integer PRIMARY KEY AUTOINCREMENT NOT NULL,
'resourceId' integer,
'providerId' integer,
'siteId' integer NOT NULL,
'ip' text NOT NULL,
'method' text,
'port' integer NOT NULL,
'internalPort' integer,
'enabled' integer DEFAULT true NOT NULL,
'path' text,
'pathMatchType' text,
'rewritePath' text,
'rewritePathType' text,
'priority' integer DEFAULT 100 NOT NULL,
'mode' text DEFAULT 'http' NOT NULL,
'authToken' text,
FOREIGN KEY ('resourceId') REFERENCES 'resources'('resourceId') ON UPDATE no action ON DELETE cascade,
FOREIGN KEY ('providerId') REFERENCES 'aiProviders'('providerId') ON UPDATE no action ON DELETE cascade,
FOREIGN KEY ('siteId') REFERENCES 'sites'('siteId') ON UPDATE no action ON DELETE cascade
);
`
).run();
db.prepare(
`INSERT INTO '__new_targets'("targetId", "resourceId", "providerId", "siteId", "ip", "method", "port", "internalPort", "enabled", "path", "pathMatchType", "rewritePath", "rewritePathType", "priority", "mode", "authToken") SELECT "targetId", "resourceId", "providerId", "siteId", "ip", "method", "port", "internalPort", "enabled", "path", "pathMatchType", "rewritePath", "rewritePathType", "priority", "mode", "authToken" FROM 'targets';`
).run();
db.prepare(`DROP TABLE 'targets';`).run();
db.prepare(
`ALTER TABLE '__new_targets' RENAME TO 'targets';`
).run();
db.prepare(
`ALTER TABLE 'subscriptions' ADD 'override' integer DEFAULT false;`
).run();
db.prepare(
`ALTER TABLE 'clients' ADD 'exitNodeSubnet' text;`
).run();
db.prepare(
`ALTER TABLE 'orgs' ADD 'settingsLogRetentionDaysAISessions' integer DEFAULT 7 NOT NULL;`
).run();
db.prepare(
`ALTER TABLE 'siteResources' ADD 'requiresExitNodeConnection' integer DEFAULT false NOT NULL;`
).run();
const insertRoleAction = db.prepare(`
INSERT INTO 'roleActions' ("roleId", "actionId", "orgId")