aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFuwn <[email protected]>2026-02-03 05:18:44 -0800
committerFuwn <[email protected]>2026-02-03 19:34:35 -0800
commit3b50e39267af9971c32c1ef1bdbf8db46afd7bbd (patch)
tree5ab4d3790851613be0f96f0c855137ba77580cc7
parentchore(root): Add Supabase schema migration (diff)
downloadarchived-imemio-3b50e39267af9971c32c1ef1bdbf8db46afd7bbd.tar.xz
archived-imemio-3b50e39267af9971c32c1ef1bdbf8db46afd7bbd.zip
feat(sdk): Implement Supabase storage adapters
-rw-r--r--packages/sdk/package.json3
-rw-r--r--packages/sdk/src/in-memory-project-store.ts13
-rw-r--r--packages/sdk/src/index.ts6
-rw-r--r--packages/sdk/src/supabase-client.ts7
-rw-r--r--packages/sdk/src/supabase-project-store.ts291
-rw-r--r--packages/sdk/src/supabase-store.ts167
-rw-r--r--pnpm-lock.yaml98
7 files changed, 577 insertions, 8 deletions
diff --git a/packages/sdk/package.json b/packages/sdk/package.json
index 432c4e4..bfa4ada 100644
--- a/packages/sdk/package.json
+++ b/packages/sdk/package.json
@@ -24,5 +24,8 @@
"@types/node": "^22.13.3",
"typescript": "^5.7.3",
"vitest": "^3.0.5"
+ },
+ "dependencies": {
+ "@supabase/supabase-js": "^2.94.0"
}
}
diff --git a/packages/sdk/src/in-memory-project-store.ts b/packages/sdk/src/in-memory-project-store.ts
index 09c2a3a..6208327 100644
--- a/packages/sdk/src/in-memory-project-store.ts
+++ b/packages/sdk/src/in-memory-project-store.ts
@@ -113,7 +113,6 @@ export class InMemoryProjectStore implements ProjectStore {
createdAt: now,
updatedAt: now,
};
-
const updatedProject: Project = {
...project,
folders: [...project.folders, folder],
@@ -136,15 +135,14 @@ export class InMemoryProjectStore implements ProjectStore {
return failure(projectNotFoundError(projectId));
}
- const folderIndex = project.folders.findIndex(
+ const existingFolder = project.folders.find(
(folder) => folder.id === folderId,
);
- if (folderIndex === -1) {
+ if (!existingFolder) {
return failure(folderNotFoundError(folderId));
}
- const existingFolder = project.folders[folderIndex];
const updatedFolder: Folder = {
...existingFolder,
name: input.name ?? existingFolder.name,
@@ -154,10 +152,9 @@ export class InMemoryProjectStore implements ProjectStore {
: existingFolder.description,
updatedAt: new Date(),
};
-
- const updatedFolders = [...project.folders];
- updatedFolders[folderIndex] = updatedFolder;
-
+ const updatedFolders = project.folders.map((folder) =>
+ folder.id === folderId ? updatedFolder : folder,
+ );
const updatedProject: Project = {
...project,
folders: updatedFolders,
diff --git a/packages/sdk/src/index.ts b/packages/sdk/src/index.ts
index 71ed7eb..b61164e 100644
--- a/packages/sdk/src/index.ts
+++ b/packages/sdk/src/index.ts
@@ -30,3 +30,9 @@ export type {
export { success, failure } from "./result.js";
export { InMemoryStore } from "./in-memory-store.js";
export { InMemoryProjectStore } from "./in-memory-project-store.js";
+export {
+ createSupabaseClient,
+ type SupabaseClient,
+} from "./supabase-client.js";
+export { SupabaseStore } from "./supabase-store.js";
+export { SupabaseProjectStore } from "./supabase-project-store.js";
diff --git a/packages/sdk/src/supabase-client.ts b/packages/sdk/src/supabase-client.ts
new file mode 100644
index 0000000..33f96b3
--- /dev/null
+++ b/packages/sdk/src/supabase-client.ts
@@ -0,0 +1,7 @@
+import { createClient, type SupabaseClient } from "@supabase/supabase-js";
+
+export type { SupabaseClient };
+
+export function createSupabaseClient(url: string, key: string): SupabaseClient {
+ return createClient(url, key);
+}
diff --git a/packages/sdk/src/supabase-project-store.ts b/packages/sdk/src/supabase-project-store.ts
new file mode 100644
index 0000000..3116eaf
--- /dev/null
+++ b/packages/sdk/src/supabase-project-store.ts
@@ -0,0 +1,291 @@
+import type { SupabaseClient } from "@supabase/supabase-js";
+import type {
+ FolderCreateInput,
+ FolderNotFoundError,
+ FolderUpdateInput,
+ ProjectCreateInput,
+ ProjectNotFoundError,
+ ProjectStore,
+ ProjectUpdateInput,
+} from "./project-store.js";
+import { failure, type Result, success } from "./result.js";
+import type { Folder, Project } from "./types.js";
+
+type ProjectRow = {
+ id: string;
+ user_id: string;
+ name: string;
+ description: string | null;
+ is_global: boolean;
+ created_at: string;
+ updated_at: string;
+};
+
+type FolderRow = {
+ id: string;
+ project_id: string;
+ name: string;
+ description: string | null;
+ created_at: string;
+ updated_at: string;
+};
+
+function projectNotFoundError(projectId: string): ProjectNotFoundError {
+ return { type: "PROJECT_NOT_FOUND", projectId };
+}
+
+function folderNotFoundError(folderId: string): FolderNotFoundError {
+ return { type: "FOLDER_NOT_FOUND", folderId };
+}
+
+function rowToProject(row: ProjectRow, folders: Folder[]): Project {
+ return {
+ id: row.id,
+ name: row.name,
+ description: row.description,
+ isGlobal: row.is_global,
+ folders,
+ createdAt: new Date(row.created_at),
+ updatedAt: new Date(row.updated_at),
+ };
+}
+
+function rowToFolder(row: FolderRow): Folder {
+ return {
+ id: row.id,
+ name: row.name,
+ description: row.description,
+ projectId: row.project_id,
+ createdAt: new Date(row.created_at),
+ updatedAt: new Date(row.updated_at),
+ };
+}
+
+export class SupabaseProjectStore implements ProjectStore {
+ private client: SupabaseClient;
+ private userId: string;
+
+ constructor(client: SupabaseClient, userId: string) {
+ this.client = client;
+ this.userId = userId;
+ }
+
+ private async fetchFoldersForProject(projectId: string): Promise<Folder[]> {
+ const { data, error } = await this.client
+ .from("folders")
+ .select()
+ .eq("project_id", projectId);
+
+ if (error) {
+ throw new Error(`Failed to fetch folders: ${error.message}`);
+ }
+
+ return (data as FolderRow[]).map(rowToFolder);
+ }
+
+ async create(input: ProjectCreateInput): Promise<Result<Project, never>> {
+ const { data, error } = await this.client
+ .from("projects")
+ .insert({
+ user_id: this.userId,
+ name: input.name,
+ description: input.description ?? null,
+ is_global: input.isGlobal ?? false,
+ })
+ .select()
+ .single();
+
+ if (error) {
+ throw new Error(`Failed to create project: ${error.message}`);
+ }
+
+ return success(rowToProject(data as ProjectRow, []));
+ }
+
+ async get(id: string): Promise<Result<Project, ProjectNotFoundError>> {
+ const { data, error } = await this.client
+ .from("projects")
+ .select()
+ .eq("id", id)
+ .eq("user_id", this.userId)
+ .single();
+
+ if (error || !data) {
+ return failure(projectNotFoundError(id));
+ }
+
+ const folders = await this.fetchFoldersForProject(id);
+
+ return success(rowToProject(data as ProjectRow, folders));
+ }
+
+ async update(
+ id: string,
+ input: ProjectUpdateInput,
+ ): Promise<Result<Project, ProjectNotFoundError>> {
+ const updates: Record<string, unknown> = {};
+
+ if (input.name !== undefined) {
+ updates.name = input.name;
+ }
+
+ if (input.description !== undefined) {
+ updates.description = input.description;
+ }
+
+ if (input.isGlobal !== undefined) {
+ updates.is_global = input.isGlobal;
+ }
+
+ const { data, error } = await this.client
+ .from("projects")
+ .update(updates)
+ .eq("id", id)
+ .eq("user_id", this.userId)
+ .select()
+ .single();
+
+ if (error || !data) {
+ return failure(projectNotFoundError(id));
+ }
+
+ const folders = await this.fetchFoldersForProject(id);
+
+ return success(rowToProject(data as ProjectRow, folders));
+ }
+
+ async delete(id: string): Promise<Result<void, ProjectNotFoundError>> {
+ const { error, count } = await this.client
+ .from("projects")
+ .delete({ count: "exact" })
+ .eq("id", id)
+ .eq("user_id", this.userId);
+
+ if (error || count === 0) {
+ return failure(projectNotFoundError(id));
+ }
+
+ return success(undefined);
+ }
+
+ async list(): Promise<Result<Project[], never>> {
+ const { data: projectRows, error } = await this.client
+ .from("projects")
+ .select()
+ .eq("user_id", this.userId);
+
+ if (error) {
+ throw new Error(`Failed to list projects: ${error.message}`);
+ }
+
+ const projects: Project[] = [];
+
+ for (const row of projectRows as ProjectRow[]) {
+ const folders = await this.fetchFoldersForProject(row.id);
+
+ projects.push(rowToProject(row, folders));
+ }
+
+ return success(projects);
+ }
+
+ async addFolder(
+ projectId: string,
+ input: FolderCreateInput,
+ ): Promise<Result<Folder, ProjectNotFoundError>> {
+ const projectResult = await this.get(projectId);
+
+ if (!projectResult.success) {
+ return failure(projectNotFoundError(projectId));
+ }
+
+ const { data, error } = await this.client
+ .from("folders")
+ .insert({
+ project_id: projectId,
+ name: input.name,
+ description: input.description ?? null,
+ })
+ .select()
+ .single();
+
+ if (error) {
+ throw new Error(`Failed to create folder: ${error.message}`);
+ }
+
+ return success(rowToFolder(data as FolderRow));
+ }
+
+ async updateFolder(
+ projectId: string,
+ folderId: string,
+ input: FolderUpdateInput,
+ ): Promise<Result<Folder, ProjectNotFoundError | FolderNotFoundError>> {
+ const projectResult = await this.get(projectId);
+
+ if (!projectResult.success) {
+ return failure(projectNotFoundError(projectId));
+ }
+
+ const updates: Record<string, unknown> = {};
+
+ if (input.name !== undefined) {
+ updates.name = input.name;
+ }
+
+ if (input.description !== undefined) {
+ updates.description = input.description;
+ }
+
+ const { data, error } = await this.client
+ .from("folders")
+ .update(updates)
+ .eq("id", folderId)
+ .eq("project_id", projectId)
+ .select()
+ .single();
+
+ if (error || !data) {
+ return failure(folderNotFoundError(folderId));
+ }
+
+ return success(rowToFolder(data as FolderRow));
+ }
+
+ async removeFolder(
+ projectId: string,
+ folderId: string,
+ ): Promise<Result<void, ProjectNotFoundError | FolderNotFoundError>> {
+ const projectResult = await this.get(projectId);
+
+ if (!projectResult.success) {
+ return failure(projectNotFoundError(projectId));
+ }
+
+ const { error, count } = await this.client
+ .from("folders")
+ .delete({ count: "exact" })
+ .eq("id", folderId)
+ .eq("project_id", projectId);
+
+ if (error || count === 0) {
+ return failure(folderNotFoundError(folderId));
+ }
+
+ return success(undefined);
+ }
+
+ async listFolders(
+ projectId: string,
+ ): Promise<Result<Folder[], ProjectNotFoundError>> {
+ const projectResult = await this.get(projectId);
+
+ if (!projectResult.success) {
+ return failure(projectNotFoundError(projectId));
+ }
+
+ const folders = await this.fetchFoldersForProject(projectId);
+
+ return success(folders);
+ }
+}
diff --git a/packages/sdk/src/supabase-store.ts b/packages/sdk/src/supabase-store.ts
new file mode 100644
index 0000000..acb9364
--- /dev/null
+++ b/packages/sdk/src/supabase-store.ts
@@ -0,0 +1,167 @@
+import type { SupabaseClient } from "@supabase/supabase-js";
+import type { MemoryNotFoundError, MemoryStore } from "./memory-store.js";
+import { failure, type Result, success } from "./result.js";
+import type {
+ Memory,
+ MemoryCreateInput,
+ MemoryFilter,
+ MemoryUpdateInput,
+ Tag,
+} from "./types.js";
+
+type MemoryRow = {
+ id: string;
+ user_id: string;
+ project_id: string;
+ folder_id: string | null;
+ content: string;
+ tags: Tag[];
+ metadata: Record<string, unknown>;
+ embedding: unknown;
+ created_at: string;
+ updated_at: string;
+};
+
+function memoryNotFoundError(memoryId: string): MemoryNotFoundError {
+ return { type: "MEMORY_NOT_FOUND", memoryId };
+}
+
+function rowToMemory(row: MemoryRow): Memory {
+ return {
+ id: row.id,
+ content: row.content,
+ projectId: row.project_id,
+ folderId: row.folder_id,
+ tags: row.tags ?? [],
+ metadata: row.metadata ?? {},
+ createdAt: new Date(row.created_at),
+ updatedAt: new Date(row.updated_at),
+ };
+}
+
+export class SupabaseStore implements MemoryStore {
+ private client: SupabaseClient;
+ private userId: string;
+
+ constructor(client: SupabaseClient, userId: string) {
+ this.client = client;
+ this.userId = userId;
+ }
+
+ async create(input: MemoryCreateInput): Promise<Memory> {
+ const { data, error } = await this.client
+ .from("memories")
+ .insert({
+ user_id: this.userId,
+ project_id: input.projectId,
+ folder_id: input.folderId ?? null,
+ content: input.content,
+ tags: input.tags ?? [],
+ metadata: input.metadata ?? {},
+ })
+ .select()
+ .single();
+
+ if (error) {
+ throw new Error(`Failed to create memory: ${error.message}`);
+ }
+
+ return rowToMemory(data as MemoryRow);
+ }
+
+ async read(id: string): Promise<Result<Memory, MemoryNotFoundError>> {
+ const { data, error } = await this.client
+ .from("memories")
+ .select()
+ .eq("id", id)
+ .eq("user_id", this.userId)
+ .single();
+
+ if (error || !data) {
+ return failure(memoryNotFoundError(id));
+ }
+
+ return success(rowToMemory(data as MemoryRow));
+ }
+
+ async update(
+ id: string,
+ input: MemoryUpdateInput,
+ ): Promise<Result<Memory, MemoryNotFoundError>> {
+ const updates: Record<string, unknown> = {};
+
+ if (input.content !== undefined) {
+ updates.content = input.content;
+ }
+
+ if (input.folderId !== undefined) {
+ updates.folder_id = input.folderId;
+ }
+
+ if (input.tags !== undefined) {
+ updates.tags = input.tags;
+ }
+
+ if (input.metadata !== undefined) {
+ updates.metadata = input.metadata;
+ }
+
+ const { data, error } = await this.client
+ .from("memories")
+ .update(updates)
+ .eq("id", id)
+ .eq("user_id", this.userId)
+ .select()
+ .single();
+
+ if (error || !data) {
+ return failure(memoryNotFoundError(id));
+ }
+
+ return success(rowToMemory(data as MemoryRow));
+ }
+
+ async delete(id: string): Promise<Result<void, MemoryNotFoundError>> {
+ const { error, count } = await this.client
+ .from("memories")
+ .delete({ count: "exact" })
+ .eq("id", id)
+ .eq("user_id", this.userId);
+
+ if (error || count === 0) {
+ return failure(memoryNotFoundError(id));
+ }
+
+ return success(undefined);
+ }
+
+ async list(filter?: MemoryFilter): Promise<Memory[]> {
+ let query = this.client
+ .from("memories")
+ .select()
+ .eq("user_id", this.userId);
+
+ if (filter?.projectId) {
+ query = query.eq("project_id", filter.projectId);
+ }
+
+ if (filter?.folderId) {
+ query = query.eq("folder_id", filter.folderId);
+ }
+
+ if (filter?.tags && filter.tags.length > 0) {
+ query = query.contains(
+ "tags",
+ filter.tags.map((id) => ({ id })),
+ );
+ }
+
+ const { data, error } = await query;
+
+ if (error) {
+ throw new Error(`Failed to list memories: ${error.message}`);
+ }
+
+ return (data as MemoryRow[]).map(rowToMemory);
+ }
+}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index f176633..f0d6a79 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -35,6 +35,10 @@ importers:
version: 5.9.3
packages/sdk:
+ dependencies:
+ '@supabase/supabase-js':
+ specifier: ^2.94.0
+ version: 2.94.0
devDependencies:
'@types/node':
specifier: ^22.13.3
@@ -829,6 +833,30 @@ packages:
cpu: [x64]
os: [win32]
+ '@supabase/[email protected]':
+ resolution: {integrity: sha512-FPFx8DzEreSoLo2HVfwNY0p/uNQ9rONQp3VKw68UP8wg1YwXK5g+TM4d4U7LTGW4HqwG0rjUdQ1it7QPw09r2w==}
+ engines: {node: '>=20.0.0'}
+
+ '@supabase/[email protected]':
+ resolution: {integrity: sha512-DAbIptT7e7hAvYHp4FhRH+LxxvKQ38QGxjaFHLoDoeQBqDaAbP/iu74dLOn6PIAnSRAqUkN2bKGs3awzNzBgKA==}
+ engines: {node: '>=20.0.0'}
+
+ '@supabase/[email protected]':
+ resolution: {integrity: sha512-3YKoDJu8VxvlJdCe2U2edzSQ9uArR0OLM3A4eAsS4QnIqzs+HuY5ZnubeoWnn/zRNeTENMLSXXZHAeMBPkyXew==}
+ engines: {node: '>=20.0.0'}
+
+ '@supabase/[email protected]':
+ resolution: {integrity: sha512-TTPVttf4yMZTd0Jo65rIn4eyTAlI7XlwgB6OVEnne4Sz4VOddXPavEw4xRISOKJZ1n8ULLRz03hilMtqnj9gNg==}
+ engines: {node: '>=20.0.0'}
+
+ '@supabase/[email protected]':
+ resolution: {integrity: sha512-wLdfqKqSfdDgGbLqgsT8ssEELBaHJm1xwiymq3cvVgxcbjRR6ECtUGtA1kj0JvX/F9DiARbrk/zkIsQ+OaUVBg==}
+ engines: {node: '>=20.0.0'}
+
+ '@supabase/[email protected]':
+ resolution: {integrity: sha512-KcqoA3ITW++CwoyCFxwV10npzR6wMfjKbMz87Q1PSuLw26SmHFQjjbBLvuZpzOrPoQ67on5W55irFsK8e0BhWg==}
+ engines: {node: '>=20.0.0'}
+
resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==}
@@ -989,6 +1017,9 @@ packages:
resolution: {integrity: sha512-ebO/Yl+EAvVe8DnMfi+iaAyIqYdK0q/q0y0rw82INWEKJOBe6b/P3YWE8NW7oOlF/nXFNrHwhARrN/hdgDkraA==}
+ '@types/[email protected]':
+ resolution: {integrity: sha512-oN9ive//QSBkf19rfDv45M7eZPi0eEXylht2OLEXicu5b4KoQ1OzXIw+xDSGWxSxe1JmepRR/ZH283vsu518/Q==}
+
resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==}
peerDependencies:
@@ -997,6 +1028,9 @@ packages:
resolution: {integrity: sha512-WPigyYuGhgZ/cTPRXB2EwUw+XvsRA3GqHlsP4qteqrnnjDrApbS7MxcGr/hke5iUoeB7E/gQtrs9I37zAJ0Vjw==}
+ '@types/[email protected]':
+ resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==}
+
'@vitest/[email protected]':
resolution: {integrity: sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==}
@@ -1274,6 +1308,10 @@ packages:
resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==}
engines: {node: '>= 0.8'}
+ resolution: {integrity: sha512-1dhVQZXhcHje7798IVM+xoo/1ZdVfzOMIc8/rgVSijRK38EDqOJoGula9N/8ZI5RD8QTxNQtK/Gozpr+qUqRRA==}
+ engines: {node: '>=20.0.0'}
+
resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==}
engines: {node: '>=0.10.0'}
@@ -1836,6 +1874,18 @@ packages:
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
+ resolution: {integrity: sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==}
+ engines: {node: '>=10.0.0'}
+ peerDependencies:
+ bufferutil: ^4.0.1
+ utf-8-validate: '>=5.0.2'
+ peerDependenciesMeta:
+ bufferutil:
+ optional: true
+ utf-8-validate:
+ optional: true
+
resolution: {integrity: sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA==}
peerDependencies:
@@ -2287,6 +2337,44 @@ snapshots:
'@rollup/[email protected]':
optional: true
+ '@supabase/[email protected]':
+ dependencies:
+ tslib: 2.8.1
+
+ '@supabase/[email protected]':
+ dependencies:
+ tslib: 2.8.1
+
+ '@supabase/[email protected]':
+ dependencies:
+ tslib: 2.8.1
+
+ '@supabase/[email protected]':
+ dependencies:
+ '@types/phoenix': 1.6.7
+ '@types/ws': 8.18.1
+ tslib: 2.8.1
+ ws: 8.19.0
+ transitivePeerDependencies:
+ - bufferutil
+ - utf-8-validate
+
+ '@supabase/[email protected]':
+ dependencies:
+ iceberg-js: 0.8.1
+ tslib: 2.8.1
+
+ '@supabase/[email protected]':
+ dependencies:
+ '@supabase/auth-js': 2.94.0
+ '@supabase/functions-js': 2.94.0
+ '@supabase/postgrest-js': 2.94.0
+ '@supabase/realtime-js': 2.94.0
+ '@supabase/storage-js': 2.94.0
+ transitivePeerDependencies:
+ - bufferutil
+ - utf-8-validate
+
dependencies:
tslib: 2.8.1
@@ -2410,6 +2498,8 @@ snapshots:
dependencies:
undici-types: 6.21.0
+ '@types/[email protected]': {}
+
dependencies:
'@types/react': 19.2.10
@@ -2418,6 +2508,10 @@ snapshots:
dependencies:
csstype: 3.2.3
+ '@types/[email protected]':
+ dependencies:
+ '@types/node': 22.19.8
+
'@vitest/[email protected]':
dependencies:
'@types/chai': 5.2.3
@@ -2761,6 +2855,8 @@ snapshots:
statuses: 2.0.2
toidentifier: 1.0.1
+
dependencies:
safer-buffer: 2.1.2
@@ -3279,6 +3375,8 @@ snapshots:
+
dependencies:
zod: 3.25.76