Add basic provisioning room v1 and update keys

This commit is contained in:
Owen
2026-03-29 16:28:51 -07:00
parent 77cef554be
commit fcf92d4e2c
19 changed files with 219 additions and 71 deletions

View File

@@ -391,7 +391,8 @@ export const siteProvisioningKeys = pgTable("siteProvisioningKeys", {
lastUsed: varchar("lastUsed", { length: 255 }),
maxBatchSize: integer("maxBatchSize"), // null = no limit
numUsed: integer("numUsed").notNull().default(0),
validUntil: varchar("validUntil", { length: 255 })
validUntil: varchar("validUntil", { length: 255 }),
approveNewSites: boolean("approveNewSites").notNull().default(true)
});
export const siteProvisioningKeyOrg = pgTable(

View File

@@ -101,7 +101,7 @@ export const sites = pgTable("sites", {
lastHolePunch: bigint("lastHolePunch", { mode: "number" }),
listenPort: integer("listenPort"),
dockerSocketEnabled: boolean("dockerSocketEnabled").notNull().default(true),
status: varchar("status").$type<"pending" | "accepted">()
status: varchar("status").$type<"pending" | "approved">()
});
export const resources = pgTable("resources", {

View File

@@ -375,7 +375,10 @@ export const siteProvisioningKeys = sqliteTable("siteProvisioningKeys", {
lastUsed: text("lastUsed"),
maxBatchSize: integer("maxBatchSize"), // null = no limit
numUsed: integer("numUsed").notNull().default(0),
validUntil: text("validUntil")
validUntil: text("validUntil"),
approveNewSites: integer("approveNewSites", { mode: "boolean" })
.notNull()
.default(true)
});
export const siteProvisioningKeyOrg = sqliteTable(

View File

@@ -111,7 +111,7 @@ export const sites = sqliteTable("sites", {
dockerSocketEnabled: integer("dockerSocketEnabled", { mode: "boolean" })
.notNull()
.default(true),
status: text("status").$type<"pending" | "accepted">()
status: text("status").$type<"pending" | "approved">()
});
export const resources = sqliteTable("resources", {

View File

@@ -38,7 +38,8 @@ const bodySchema = z
z.null(),
z.coerce.number().int().positive().max(1_000_000)
]),
validUntil: z.string().max(255).optional()
validUntil: z.string().max(255).optional(),
approveNewSites: z.boolean().optional().default(true)
})
.superRefine((data, ctx) => {
const v = data.validUntil;
@@ -82,7 +83,7 @@ export async function createSiteProvisioningKey(
}
const { orgId } = parsedParams.data;
const { name, maxBatchSize } = parsedBody.data;
const { name, maxBatchSize, approveNewSites } = parsedBody.data;
const vuRaw = parsedBody.data.validUntil;
const validUntil =
vuRaw == null || vuRaw.trim() === ""
@@ -106,7 +107,8 @@ export async function createSiteProvisioningKey(
lastUsed: null,
maxBatchSize,
numUsed: 0,
validUntil
validUntil,
approveNewSites
});
await trx.insert(siteProvisioningKeyOrg).values({
@@ -127,7 +129,8 @@ export async function createSiteProvisioningKey(
lastUsed: null,
maxBatchSize,
numUsed: 0,
validUntil
validUntil,
approveNewSites
},
success: true,
error: false,

View File

@@ -57,7 +57,8 @@ function querySiteProvisioningKeys(orgId: string) {
lastUsed: siteProvisioningKeys.lastUsed,
maxBatchSize: siteProvisioningKeys.maxBatchSize,
numUsed: siteProvisioningKeys.numUsed,
validUntil: siteProvisioningKeys.validUntil
validUntil: siteProvisioningKeys.validUntil,
approveNewSites: siteProvisioningKeys.approveNewSites
})
.from(siteProvisioningKeyOrg)
.innerJoin(

View File

@@ -39,16 +39,18 @@ const bodySchema = z
z.coerce.number().int().positive().max(1_000_000)
])
.optional(),
validUntil: z.string().max(255).optional()
validUntil: z.string().max(255).optional(),
approveNewSites: z.boolean().optional()
})
.superRefine((data, ctx) => {
if (
data.maxBatchSize === undefined &&
data.validUntil === undefined
data.validUntil === undefined &&
data.approveNewSites === undefined
) {
ctx.addIssue({
code: "custom",
message: "Provide maxBatchSize and/or validUntil",
message: "Provide maxBatchSize and/or validUntil and/or approveNewSites",
path: ["maxBatchSize"]
});
}
@@ -129,6 +131,7 @@ export async function updateSiteProvisioningKey(
const setValues: {
maxBatchSize?: number | null;
validUntil?: string | null;
approveNewSites?: boolean;
} = {};
if (body.maxBatchSize !== undefined) {
setValues.maxBatchSize = body.maxBatchSize;
@@ -139,6 +142,9 @@ export async function updateSiteProvisioningKey(
? null
: new Date(Date.parse(body.validUntil)).toISOString();
}
if (body.approveNewSites !== undefined) {
setValues.approveNewSites = body.approveNewSites;
}
await db
.update(siteProvisioningKeys)
@@ -160,7 +166,8 @@ export async function updateSiteProvisioningKey(
lastUsed: siteProvisioningKeys.lastUsed,
maxBatchSize: siteProvisioningKeys.maxBatchSize,
numUsed: siteProvisioningKeys.numUsed,
validUntil: siteProvisioningKeys.validUntil
validUntil: siteProvisioningKeys.validUntil,
approveNewSites: siteProvisioningKeys.approveNewSites
})
.from(siteProvisioningKeys)
.where(

View File

@@ -82,7 +82,8 @@ export async function registerNewt(
orgId: siteProvisioningKeyOrg.orgId,
maxBatchSize: siteProvisioningKeys.maxBatchSize,
numUsed: siteProvisioningKeys.numUsed,
validUntil: siteProvisioningKeys.validUntil
validUntil: siteProvisioningKeys.validUntil,
approveNewSites: siteProvisioningKeys.approveNewSites,
})
.from(siteProvisioningKeys)
.innerJoin(
@@ -197,7 +198,7 @@ export async function registerNewt(
niceId,
type: "newt",
dockerSocketEnabled: true,
status: "pending"
status: keyRecord.approveNewSites ? "approved" : "pending",
})
.returning();

View File

@@ -299,7 +299,7 @@ export async function createSite(
address: updatedAddress || null,
type,
dockerSocketEnabled: true,
status: "accepted"
status: "approved"
})
.returning();
} else if (type == "wireguard") {
@@ -357,7 +357,7 @@ export async function createSite(
subnet,
type,
pubKey: pubKey || null,
status: "accepted"
status: "approved"
})
.returning();
} else if (type == "local") {
@@ -373,7 +373,7 @@ export async function createSite(
dockerSocketEnabled: false,
online: true,
subnet: "0.0.0.0/32",
status: "accepted"
status: "approved"
})
.returning();
} else {

View File

@@ -137,12 +137,12 @@ const listSitesSchema = z.object({
description: "Filter by online status"
}),
status: z
.enum(["pending", "accepted"])
.enum(["pending", "approved"])
.optional()
.catch(undefined)
.openapi({
type: "string",
enum: ["pending", "accepted"],
enum: ["pending", "approved"],
description: "Filter by site status"
})
});

View File

@@ -20,7 +20,7 @@ const updateSiteBodySchema = z
name: z.string().min(1).max(255).optional(),
niceId: z.string().min(1).max(255).optional(),
dockerSocketEnabled: z.boolean().optional(),
status: z.enum(["pending", "accepted"]).optional(),
status: z.enum(["pending", "approved"]).optional(),
// remoteSubnets: z.string().optional()
// subdomain: z
// .string()

View File

@@ -8,6 +8,7 @@ export type SiteProvisioningKeyListItem = {
maxBatchSize: number | null;
numUsed: number;
validUntil: string | null;
approveNewSites: boolean;
};
export type ListSiteProvisioningKeysResponse = {
@@ -26,6 +27,7 @@ export type CreateSiteProvisioningKeyResponse = {
maxBatchSize: number | null;
numUsed: number;
validUntil: string | null;
approveNewSites: boolean;
};
export type UpdateSiteProvisioningKeyResponse = {
@@ -38,4 +40,5 @@ export type UpdateSiteProvisioningKeyResponse = {
maxBatchSize: number | null;
numUsed: number;
validUntil: string | null;
approveNewSites: boolean;
};