From 4ae738ce41852e0bc5cc230e86bc47a8fa805f25 Mon Sep 17 00:00:00 2001 From: Nicolas Meienberger Date: Thu, 23 Oct 2025 19:25:12 +0200 Subject: [PATCH] refactor: use schema constants --- .../api-client/@tanstack/react-query.gen.ts | 110 ++++++ apps/client/app/api-client/client.gen.ts | 2 +- apps/client/app/api-client/sdk.gen.ts | 60 ++++ apps/client/app/api-client/types.gen.ts | 149 ++++++++- apps/server/drizzle/0007_watery_sersi.sql | 1 + apps/server/drizzle/meta/0007_snapshot.json | 313 ++++++++++++++++++ apps/server/drizzle/meta/_journal.json | 7 + apps/server/package.json | 3 +- apps/server/src/db/schema.ts | 2 +- .../modules/repositories/repositories.dto.ts | 15 +- .../repositories/repositories.service.ts | 10 +- apps/server/src/modules/volumes/volume.dto.ts | 12 +- bun.lock | 11 +- packages/schemas/src/restic.ts | 1 - 14 files changed, 661 insertions(+), 35 deletions(-) create mode 100644 apps/server/drizzle/0007_watery_sersi.sql create mode 100644 apps/server/drizzle/meta/0007_snapshot.json diff --git a/apps/client/app/api-client/@tanstack/react-query.gen.ts b/apps/client/app/api-client/@tanstack/react-query.gen.ts index 35e8bf0..4dc4c91 100644 --- a/apps/client/app/api-client/@tanstack/react-query.gen.ts +++ b/apps/client/app/api-client/@tanstack/react-query.gen.ts @@ -18,6 +18,10 @@ import { unmountVolume, healthCheckVolume, listFiles, + listRepositories, + createRepository, + deleteRepository, + getRepository, } from "../sdk.gen"; import { queryOptions, type UseMutationOptions, type DefaultError } from "@tanstack/react-query"; import type { @@ -47,6 +51,12 @@ import type { HealthCheckVolumeData, HealthCheckVolumeResponse, ListFilesData, + ListRepositoriesData, + CreateRepositoryData, + CreateRepositoryResponse, + DeleteRepositoryData, + DeleteRepositoryResponse, + GetRepositoryData, } from "../types.gen"; import { client as _heyApiClient } from "../client.gen"; @@ -561,3 +571,103 @@ export const listFilesOptions = (options: Options) => { queryKey: listFilesQueryKey(options), }); }; + +export const listRepositoriesQueryKey = (options?: Options) => + createQueryKey("listRepositories", options); + +/** + * List all repositories + */ +export const listRepositoriesOptions = (options?: Options) => { + return queryOptions({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await listRepositories({ + ...options, + ...queryKey[0], + signal, + throwOnError: true, + }); + return data; + }, + queryKey: listRepositoriesQueryKey(options), + }); +}; + +export const createRepositoryQueryKey = (options?: Options) => + createQueryKey("createRepository", options); + +/** + * Create a new restic repository + */ +export const createRepositoryOptions = (options?: Options) => { + return queryOptions({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await createRepository({ + ...options, + ...queryKey[0], + signal, + throwOnError: true, + }); + return data; + }, + queryKey: createRepositoryQueryKey(options), + }); +}; + +/** + * Create a new restic repository + */ +export const createRepositoryMutation = ( + options?: Partial>, +): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (localOptions) => { + const { data } = await createRepository({ + ...options, + ...localOptions, + throwOnError: true, + }); + return data; + }, + }; + return mutationOptions; +}; + +/** + * Delete a repository + */ +export const deleteRepositoryMutation = ( + options?: Partial>, +): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (localOptions) => { + const { data } = await deleteRepository({ + ...options, + ...localOptions, + throwOnError: true, + }); + return data; + }, + }; + return mutationOptions; +}; + +export const getRepositoryQueryKey = (options: Options) => createQueryKey("getRepository", options); + +/** + * Get a single repository by name + */ +export const getRepositoryOptions = (options: Options) => { + return queryOptions({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await getRepository({ + ...options, + ...queryKey[0], + signal, + throwOnError: true, + }); + return data; + }, + queryKey: getRepositoryQueryKey(options), + }); +}; diff --git a/apps/client/app/api-client/client.gen.ts b/apps/client/app/api-client/client.gen.ts index c467a6f..d30d8c1 100644 --- a/apps/client/app/api-client/client.gen.ts +++ b/apps/client/app/api-client/client.gen.ts @@ -17,6 +17,6 @@ export type CreateClientConfig = export const client = createClient( createConfig({ - baseUrl: "http://localhost:4096", + baseUrl: "http://192.168.2.42:4096", }), ); diff --git a/apps/client/app/api-client/sdk.gen.ts b/apps/client/app/api-client/sdk.gen.ts index 7a08e9b..81bb3af 100644 --- a/apps/client/app/api-client/sdk.gen.ts +++ b/apps/client/app/api-client/sdk.gen.ts @@ -44,6 +44,14 @@ import type { ListFilesData, ListFilesResponses, ListFilesErrors, + ListRepositoriesData, + ListRepositoriesResponses, + CreateRepositoryData, + CreateRepositoryResponses, + DeleteRepositoryData, + DeleteRepositoryResponses, + GetRepositoryData, + GetRepositoryResponses, } from "./types.gen"; import { client as _heyApiClient } from "./client.gen"; @@ -261,3 +269,55 @@ export const listFiles = (options: Options ...options, }); }; + +/** + * List all repositories + */ +export const listRepositories = ( + options?: Options, +) => { + return (options?.client ?? _heyApiClient).get({ + url: "/api/v1/repositories", + ...options, + }); +}; + +/** + * Create a new restic repository + */ +export const createRepository = ( + options?: Options, +) => { + return (options?.client ?? _heyApiClient).post({ + url: "/api/v1/repositories", + ...options, + headers: { + "Content-Type": "application/json", + ...options?.headers, + }, + }); +}; + +/** + * Delete a repository + */ +export const deleteRepository = ( + options: Options, +) => { + return (options.client ?? _heyApiClient).delete({ + url: "/api/v1/repositories/{name}", + ...options, + }); +}; + +/** + * Get a single repository by name + */ +export const getRepository = ( + options: Options, +) => { + return (options.client ?? _heyApiClient).get({ + url: "/api/v1/repositories/{name}", + ...options, + }); +}; diff --git a/apps/client/app/api-client/types.gen.ts b/apps/client/app/api-client/types.gen.ts index 25dea17..7313aa1 100644 --- a/apps/client/app/api-client/types.gen.ts +++ b/apps/client/app/api-client/types.gen.ts @@ -178,7 +178,7 @@ export type ListVolumesResponses = { lastHealthCheck: number; name: string; path: string; - status: "error" | "mounted" | "unknown" | "unmounted"; + status: "error" | "mounted" | "unmounted"; type: "directory" | "nfs" | "smb" | "webdav"; updatedAt: number; }>; @@ -374,7 +374,7 @@ export type GetVolumeResponses = { lastHealthCheck: number; name: string; path: string; - status: "error" | "mounted" | "unknown" | "unmounted"; + status: "error" | "mounted" | "unmounted"; type: "directory" | "nfs" | "smb" | "webdav"; updatedAt: number; }; @@ -474,7 +474,7 @@ export type UpdateVolumeResponses = { lastHealthCheck: number; name: string; path: string; - status: "error" | "mounted" | "unknown" | "unmounted"; + status: "error" | "mounted" | "unmounted"; type: "directory" | "nfs" | "smb" | "webdav"; updatedAt: number; }; @@ -639,6 +639,145 @@ export type ListFilesResponses = { export type ListFilesResponse = ListFilesResponses[keyof ListFilesResponses]; -export type ClientOptions = { - baseUrl: "http://localhost:4096" | (string & {}); +export type ListRepositoriesData = { + body?: never; + path?: never; + query?: never; + url: "/api/v1/repositories"; +}; + +export type ListRepositoriesResponses = { + /** + * List of repositories + */ + 200: { + repositories: Array<{ + compressionMode: "auto" | "better" | "fastest" | "max" | "off" | null; + config: + | { + accessKeyId: string; + backend: "s3"; + bucket: string; + endpoint: string; + secretAccessKey: string; + } + | { + backend: "local"; + path: string; + }; + createdAt: number; + id: string; + lastChecked: number | null; + lastError: string | null; + name: string; + status: "error" | "healthy" | "unknown" | null; + type: "local" | "s3"; + updatedAt: number; + }>; + }; +}; + +export type ListRepositoriesResponse = ListRepositoriesResponses[keyof ListRepositoriesResponses]; + +export type CreateRepositoryData = { + body?: { + config: + | { + accessKeyId: string; + backend: "s3"; + bucket: string; + endpoint: string; + secretAccessKey: string; + } + | { + backend: "local"; + path: string; + }; + name: string; + compressionMode?: "auto" | "better" | "fastest" | "max" | "off"; + }; + path?: never; + query?: never; + url: "/api/v1/repositories"; +}; + +export type CreateRepositoryResponses = { + /** + * Repository created successfully + */ + 201: { + message: string; + repository: { + id: string; + name: string; + }; + }; +}; + +export type CreateRepositoryResponse = CreateRepositoryResponses[keyof CreateRepositoryResponses]; + +export type DeleteRepositoryData = { + body?: never; + path: { + name: string; + }; + query?: never; + url: "/api/v1/repositories/{name}"; +}; + +export type DeleteRepositoryResponses = { + /** + * Repository deleted successfully + */ + 200: { + message: string; + }; +}; + +export type DeleteRepositoryResponse = DeleteRepositoryResponses[keyof DeleteRepositoryResponses]; + +export type GetRepositoryData = { + body?: never; + path: { + name: string; + }; + query?: never; + url: "/api/v1/repositories/{name}"; +}; + +export type GetRepositoryResponses = { + /** + * Repository details + */ + 200: { + repository: { + compressionMode: "auto" | "better" | "fastest" | "max" | "off" | null; + config: + | { + accessKeyId: string; + backend: "s3"; + bucket: string; + endpoint: string; + secretAccessKey: string; + } + | { + backend: "local"; + path: string; + }; + createdAt: number; + id: string; + lastChecked: number | null; + lastError: string | null; + name: string; + status: "error" | "healthy" | "unknown" | null; + type: "local" | "s3"; + updatedAt: number; + }; + }; +}; + +export type GetRepositoryResponse = GetRepositoryResponses[keyof GetRepositoryResponses]; + +export type ClientOptions = { + baseUrl: "http://192.168.2.42:4096" | (string & {}); }; diff --git a/apps/server/drizzle/0007_watery_sersi.sql b/apps/server/drizzle/0007_watery_sersi.sql new file mode 100644 index 0000000..60744e5 --- /dev/null +++ b/apps/server/drizzle/0007_watery_sersi.sql @@ -0,0 +1 @@ +ALTER TABLE `repositories_table` RENAME COLUMN "backend" TO "type"; \ No newline at end of file diff --git a/apps/server/drizzle/meta/0007_snapshot.json b/apps/server/drizzle/meta/0007_snapshot.json new file mode 100644 index 0000000..ae52d4f --- /dev/null +++ b/apps/server/drizzle/meta/0007_snapshot.json @@ -0,0 +1,313 @@ +{ + "version": "6", + "dialect": "sqlite", + "id": "866b1d3b-454b-4cf7-9835-a0f60d048b6e", + "prevId": "16f360b6-fb61-44f3-a7f7-2bae78ebf7ca", + "tables": { + "repositories_table": { + "name": "repositories_table", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "config": { + "name": "config", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "compression_mode": { + "name": "compression_mode", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "'auto'" + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "'unknown'" + }, + "last_checked": { + "name": "last_checked", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "last_error": { + "name": "last_error", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(unixepoch())" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(unixepoch())" + } + }, + "indexes": { + "repositories_table_name_unique": { + "name": "repositories_table_name_unique", + "columns": [ + "name" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "sessions_table": { + "name": "sessions_table", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(unixepoch())" + } + }, + "indexes": {}, + "foreignKeys": { + "sessions_table_user_id_users_table_id_fk": { + "name": "sessions_table_user_id_users_table_id_fk", + "tableFrom": "sessions_table", + "tableTo": "users_table", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "users_table": { + "name": "users_table", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "password_hash": { + "name": "password_hash", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(unixepoch())" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(unixepoch())" + } + }, + "indexes": { + "users_table_username_unique": { + "name": "users_table_username_unique", + "columns": [ + "username" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "volumes_table": { + "name": "volumes_table", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'unmounted'" + }, + "last_error": { + "name": "last_error", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "last_health_check": { + "name": "last_health_check", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(unixepoch())" + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(unixepoch())" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(unixepoch())" + }, + "config": { + "name": "config", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "auto_remount": { + "name": "auto_remount", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + } + }, + "indexes": { + "volumes_table_name_unique": { + "name": "volumes_table_name_unique", + "columns": [ + "name" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + } + }, + "views": {}, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": { + "\"repositories_table\".\"backend\"": "\"repositories_table\".\"type\"" + } + }, + "internal": { + "indexes": {} + } +} \ No newline at end of file diff --git a/apps/server/drizzle/meta/_journal.json b/apps/server/drizzle/meta/_journal.json index 8838894..02f6133 100644 --- a/apps/server/drizzle/meta/_journal.json +++ b/apps/server/drizzle/meta/_journal.json @@ -50,6 +50,13 @@ "when": 1760734377440, "tag": "0006_secret_micromacro", "breakpoints": true + }, + { + "idx": 7, + "version": "6", + "when": 1761224911352, + "tag": "0007_watery_sersi", + "breakpoints": true } ] } \ No newline at end of file diff --git a/apps/server/package.json b/apps/server/package.json index 603630c..3fcf665 100644 --- a/apps/server/package.json +++ b/apps/server/package.json @@ -9,11 +9,10 @@ "studio": "drizzle-kit studio" }, "dependencies": { - "@hono/arktype-validator": "^2.0.1", "@hono/standard-validator": "^0.1.5", "@ironmount/schemas": "workspace:*", "@scalar/hono-api-reference": "^0.9.13", - "arktype": "^2.1.20", + "arktype": "^2.1.23", "dockerode": "^4.0.8", "dotenv": "^17.2.1", "drizzle-orm": "^0.44.6", diff --git a/apps/server/src/db/schema.ts b/apps/server/src/db/schema.ts index 1950acb..efa7e8a 100644 --- a/apps/server/src/db/schema.ts +++ b/apps/server/src/db/schema.ts @@ -47,7 +47,7 @@ export type Session = typeof sessionsTable.$inferSelect; export const repositoriesTable = sqliteTable("repositories_table", { id: text().primaryKey(), name: text().notNull().unique(), - backend: text().$type().notNull(), + type: text().$type().notNull(), config: text("config", { mode: "json" }).$type().notNull(), compressionMode: text("compression_mode").$type().default("auto"), status: text().$type().default("unknown"), diff --git a/apps/server/src/modules/repositories/repositories.dto.ts b/apps/server/src/modules/repositories/repositories.dto.ts index 4a5bba3..a443a46 100644 --- a/apps/server/src/modules/repositories/repositories.dto.ts +++ b/apps/server/src/modules/repositories/repositories.dto.ts @@ -1,14 +1,19 @@ -import { repositoryConfigSchema } from "@ironmount/schemas/restic"; +import { + COMPRESSION_MODES, + REPOSITORY_BACKENDS, + REPOSITORY_STATUS, + repositoryConfigSchema, +} from "@ironmount/schemas/restic"; import { type } from "arktype"; import { describeRoute, resolver } from "hono-openapi"; const repositorySchema = type({ id: "string", name: "string", - backend: type.enumerated("local", "sftp", "s3"), + type: type.valueOf(REPOSITORY_BACKENDS), config: repositoryConfigSchema, - compressionMode: type.enumerated("off", "auto", "fastest", "better", "max").or("null"), - status: type.enumerated("healthy", "error", "unknown").or("null"), + compressionMode: type.valueOf(COMPRESSION_MODES).or("null"), + status: type.valueOf(REPOSITORY_STATUS).or("null"), lastChecked: "number | null", lastError: "string | null", createdAt: "number", @@ -46,8 +51,8 @@ export const listRepositoriesDto = describeRoute({ */ export const createRepositoryBody = type({ name: "string", + compressionMode: type.valueOf(COMPRESSION_MODES).optional(), config: repositoryConfigSchema, - "compressionMode?": type.enumerated("off", "auto", "fastest", "better", "max"), }); export type CreateRepositoryBody = typeof createRepositoryBody.infer; diff --git a/apps/server/src/modules/repositories/repositories.service.ts b/apps/server/src/modules/repositories/repositories.service.ts index c8cc642..313dfa1 100644 --- a/apps/server/src/modules/repositories/repositories.service.ts +++ b/apps/server/src/modules/repositories/repositories.service.ts @@ -1,5 +1,5 @@ import crypto from "node:crypto"; -import type { CompressionMode, RepositoryConfig } from "@ironmount/schemas"; +import type { CompressionMode, RepositoryConfig } from "@ironmount/schemas/restic"; import { eq } from "drizzle-orm"; import { ConflictError, InternalServerError, NotFoundError } from "http-errors-enhanced"; import slugify from "slugify"; @@ -15,14 +15,16 @@ const listRepositories = async () => { }; const encryptConfig = async (config: RepositoryConfig): Promise => { - const encryptedConfig = { ...config }; + const encryptedConfig: Record = { ...config }; + switch (config.backend) { case "s3": encryptedConfig.accessKeyId = await cryptoUtils.encrypt(config.accessKeyId); encryptedConfig.secretAccessKey = await cryptoUtils.encrypt(config.secretAccessKey); break; } - return encryptedConfig; + + return encryptedConfig as RepositoryConfig; }; const createRepository = async (name: string, config: RepositoryConfig, compressionMode?: CompressionMode) => { @@ -45,7 +47,7 @@ const createRepository = async (name: string, config: RepositoryConfig, compress .values({ id, name: slug, - backend: config.backend, + type: config.backend, config: encryptedConfig, compressionMode: compressionMode ?? "auto", status: "unknown", diff --git a/apps/server/src/modules/volumes/volume.dto.ts b/apps/server/src/modules/volumes/volume.dto.ts index d3c4ae5..f07f699 100644 --- a/apps/server/src/modules/volumes/volume.dto.ts +++ b/apps/server/src/modules/volumes/volume.dto.ts @@ -1,12 +1,12 @@ -import { volumeConfigSchema } from "@ironmount/schemas"; +import { BACKEND_STATUS, BACKEND_TYPES, volumeConfigSchema } from "@ironmount/schemas"; import { type } from "arktype"; import { describeRoute, resolver } from "hono-openapi"; const volumeSchema = type({ name: "string", path: "string", - type: type.enumerated("nfs", "smb", "directory", "webdav"), - status: type.enumerated("mounted", "unmounted", "error", "unknown"), + type: type.valueOf(BACKEND_TYPES), + status: type.valueOf(BACKEND_STATUS), lastError: "string | null", createdAt: "number", updatedAt: "number", @@ -199,7 +199,7 @@ export const testConnectionDto = describeRoute({ */ export const mountVolumeResponse = type({ error: "string?", - status: type.enumerated("mounted", "unmounted", "error"), + status: type.valueOf(BACKEND_STATUS), }); export const mountVolumeDto = describeRoute({ @@ -226,7 +226,7 @@ export const mountVolumeDto = describeRoute({ */ export const unmountVolumeResponse = type({ error: "string?", - status: type.enumerated("mounted", "unmounted", "error"), + status: type.valueOf(BACKEND_STATUS), }); export const unmountVolumeDto = describeRoute({ @@ -250,7 +250,7 @@ export const unmountVolumeDto = describeRoute({ export const healthCheckResponse = type({ error: "string?", - status: type.enumerated("mounted", "unmounted", "error"), + status: type.valueOf(BACKEND_STATUS), }); export const healthCheckDto = describeRoute({ diff --git a/bun.lock b/bun.lock index 832dc41..16e647d 100644 --- a/bun.lock +++ b/bun.lock @@ -63,11 +63,10 @@ "apps/server": { "name": "@ironmount/server", "dependencies": { - "@hono/arktype-validator": "^2.0.1", "@hono/standard-validator": "^0.1.5", "@ironmount/schemas": "workspace:*", "@scalar/hono-api-reference": "^0.9.13", - "arktype": "^2.1.20", + "arktype": "^2.1.23", "dockerode": "^4.0.8", "dotenv": "^17.2.1", "drizzle-orm": "^0.44.6", @@ -239,8 +238,6 @@ "@hey-api/openapi-ts": ["@hey-api/openapi-ts@0.80.18", "", { "dependencies": { "@hey-api/json-schema-ref-parser": "1.0.6", "ansi-colors": "4.1.3", "c12": "2.0.1", "color-support": "1.1.3", "commander": "13.0.0", "handlebars": "4.7.8", "js-yaml": "4.1.0", "open": "10.1.2", "semver": "7.7.2" }, "peerDependencies": { "typescript": "^5.5.3" }, "bin": { "openapi-ts": "bin/index.cjs" } }, "sha512-YCcRdw+OmD/WgBk5ZNaSblEb94PfqBKp4gDvfEYtEdRVS76etdgVOD0CPz72Tus+6zeSzGDVlWE8GOfcib0C6g=="], - "@hono/arktype-validator": ["@hono/arktype-validator@2.0.1", "", { "peerDependencies": { "arktype": "^2.0.0-dev.14", "hono": "*" } }, "sha512-Z4PQFtzgbGneBap+TTViRIBAoUWbwEwg8PaKNqALAP6z9N2ksJI81PfcsSQNUzwtrn8LipkMvBb8/D9Pei2GJw=="], - "@hono/standard-validator": ["@hono/standard-validator@0.1.5", "", { "peerDependencies": { "@standard-schema/spec": "1.0.0", "hono": ">=3.9.0" } }, "sha512-EIyZPPwkyLn6XKwFj5NBEWHXhXbgmnVh2ceIFo5GO7gKI9WmzTjPDKnppQB0KrqKeAkq3kpoW4SIbu5X1dgx3w=="], "@hookform/resolvers": ["@hookform/resolvers@5.2.2", "", { "dependencies": { "@standard-schema/utils": "^0.3.0" }, "peerDependencies": { "react-hook-form": "^7.55.0" } }, "sha512-A/IxlMLShx3KjV/HeTcTfaMxdwy690+L/ZADoeaTltLx+CVuzkeVIPuybK3jrRfw7YZnmdKsVVHAlEPIAEUNlA=="], @@ -1299,8 +1296,6 @@ "@grpc/grpc-js/@grpc/proto-loader": ["@grpc/proto-loader@0.8.0", "", { "dependencies": { "lodash.camelcase": "^4.3.0", "long": "^5.0.0", "protobufjs": "^7.5.3", "yargs": "^17.7.2" }, "bin": { "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" } }, "sha512-rc1hOQtjIWGxcxpb9aHAfLpIctjEnsDehj0DAiVfBlmT84uvR0uUtN2hEi/ecvWVjXUGf5qPF4qEgiLOx1YIMQ=="], - "@ironmount/server/arktype": ["arktype@2.1.22", "", { "dependencies": { "@ark/schema": "0.49.0", "@ark/util": "0.49.0" } }, "sha512-xdzl6WcAhrdahvRRnXaNwsipCgHuNoLobRqhiP8RjnfL9Gp947abGlo68GAIyLtxbD+MLzNyH2YR4kEqioMmYQ=="], - "@isaacs/cliui/string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="], "@isaacs/cliui/strip-ansi": ["strip-ansi@7.1.2", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA=="], @@ -1433,10 +1428,6 @@ "@esbuild-kit/core-utils/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.18.20", "", { "os": "win32", "cpu": "x64" }, "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ=="], - "@ironmount/server/arktype/@ark/schema": ["@ark/schema@0.49.0", "", { "dependencies": { "@ark/util": "0.49.0" } }, "sha512-GphZBLpW72iS0v4YkeUtV3YIno35Gimd7+ezbPO9GwEi9kzdUrPVjvf6aXSBAfHikaFc/9pqZOpv3pOXnC71tw=="], - - "@ironmount/server/arktype/@ark/util": ["@ark/util@0.49.0", "", {}, "sha512-/BtnX7oCjNkxi2vi6y1399b+9xd1jnCrDYhZ61f0a+3X8x8DxlK52VgEEzyuC2UQMPACIfYrmHkhD3lGt2GaMA=="], - "@isaacs/cliui/string-width/emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="], "@isaacs/cliui/strip-ansi/ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="], diff --git a/packages/schemas/src/restic.ts b/packages/schemas/src/restic.ts index a3be96f..2b5ba7a 100644 --- a/packages/schemas/src/restic.ts +++ b/packages/schemas/src/restic.ts @@ -2,7 +2,6 @@ import { type } from "arktype"; export const REPOSITORY_BACKENDS = { local: "local", - sftp: "sftp", s3: "s3", } as const;