mirror of
https://github.com/fosrl/pangolin.git
synced 2026-08-18 10:12:55 +02:00
Add v1 migrations
This commit is contained in:
@@ -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")
|
||||
|
||||
@@ -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")
|
||||
|
||||
Reference in New Issue
Block a user