diff --git a/infrastructure/evault-core/package.json b/infrastructure/evault-core/package.json index acdc7f38d..b4d470a6f 100644 --- a/infrastructure/evault-core/package.json +++ b/infrastructure/evault-core/package.json @@ -24,6 +24,7 @@ "vitest": "^3.0.9" }, "dependencies": { + "@fastify/formbody": "^8.0.2", "@fastify/swagger": "^8.14.0", "@fastify/swagger-ui": "^3.0.0", "@testcontainers/neo4j": "^10.24.2", diff --git a/infrastructure/evault-core/src/db/schema.ts b/infrastructure/evault-core/src/db/schema.ts index 995da720e..e50c6d38a 100644 --- a/infrastructure/evault-core/src/db/schema.ts +++ b/infrastructure/evault-core/src/db/schema.ts @@ -1,84 +1,85 @@ import { JSONSchema7 } from "json-schema"; export type SchemaType = { - schema: JSONSchema7; - deserialize: (value: any) => any; + schema: JSONSchema7; + deserialize: (value: any) => any; }; export const SchemaTypes: Record = { - date: { - schema: { - type: "string", - format: "date-time", + date: { + schema: { + type: "string", + format: "date-time", + }, + deserialize: (value: string) => new Date(value), }, - deserialize: (value: string) => new Date(value), - }, - number: { - schema: { - type: "number", + number: { + schema: { + type: "number", + }, + + deserialize: (value: number) => value, }, - deserialize: (value: number) => value, - }, - string: { - schema: { - type: "string", + string: { + schema: { + type: "string", + }, + deserialize: (value: string) => value, }, - deserialize: (value: string) => value, - }, - boolean: { - schema: { - type: "boolean", + boolean: { + schema: { + type: "boolean", + }, + deserialize: (value: boolean) => value, }, - deserialize: (value: boolean) => value, - }, - array: { - schema: { - type: "array", + array: { + schema: { + type: "array", + }, + deserialize: (value: any[]) => value, }, - deserialize: (value: any[]) => value, - }, - object: { - schema: { - type: "object", + object: { + schema: { + type: "object", + }, + deserialize: (value: Record) => value, }, - deserialize: (value: Record) => value, - }, }; export function getSchemaType(value: any): SchemaType { - if (value instanceof Date) return SchemaTypes.date; - if (Array.isArray(value)) return SchemaTypes.array; - if (typeof value === "object" && value !== null) return SchemaTypes.object; - if (typeof value === "number") return SchemaTypes.number; - if (typeof value === "boolean") return SchemaTypes.boolean; - return SchemaTypes.string; + if (value instanceof Date) return SchemaTypes.date; + if (Array.isArray(value)) return SchemaTypes.array; + if (typeof value === "object" && value !== null) return SchemaTypes.object; + if (typeof value === "number") return SchemaTypes.number; + if (typeof value === "boolean") return SchemaTypes.boolean; + return SchemaTypes.string; } export function serializeValue(value: any): { value: any; type: string } { - const type = getSchemaType(value); - let serializedValue = value; + const type = getSchemaType(value); + let serializedValue = value; - if (type === SchemaTypes.date) { - serializedValue = value.toISOString(); - } else if (type === SchemaTypes.object) { - serializedValue = JSON.stringify(value); - } + if (type === SchemaTypes.date) { + serializedValue = value.toISOString(); + } else if (type === SchemaTypes.object) { + serializedValue = JSON.stringify(value); + } - return { - value: serializedValue, - type: - Object.keys(SchemaTypes).find((key) => SchemaTypes[key] === type) || - "string", - }; + return { + value: serializedValue, + type: + Object.keys(SchemaTypes).find((key) => SchemaTypes[key] === type) || + "string", + }; } export function deserializeValue(value: any, type: string): any { - const schemaType = SchemaTypes[type]; - if (!schemaType) return value; + const schemaType = SchemaTypes[type]; + if (!schemaType) return value; - if (type === "object") { - return JSON.parse(value); - } + if (type === "object") { + return JSON.parse(value); + } - return schemaType.deserialize(value); + return schemaType.deserialize(value); } diff --git a/infrastructure/evault-core/src/evault.ts b/infrastructure/evault-core/src/evault.ts index 402f0d1bc..e820c0e1a 100644 --- a/infrastructure/evault-core/src/evault.ts +++ b/infrastructure/evault-core/src/evault.ts @@ -57,30 +57,17 @@ class EVault { password: process.env.ENCRYPTION_PASSWORD, }); - const yoga = createYoga({ - schema: this.graphqlServer.getSchema(), - graphiql: true, - }); - // change + const yoga = this.graphqlServer.init(); this.server.route({ - url: "/graphql", + // Bind to the Yoga's endpoint to avoid rendering on any path + url: yoga.graphqlEndpoint, method: ["GET", "POST", "OPTIONS"], - handler: async (req: FastifyRequest, reply: FastifyReply) => { - const response = await yoga.fetch(req.url, { - method: req.method, - headers: req.headers, - body: req.method === "POST" ? req.body : undefined, - }); - reply.status(response.status); - const headers: Record = {}; - response.headers.forEach((value, key) => { - headers[key] = value; - }); - reply.headers(headers); - reply.send(response.body); - return reply; - }, + handler: (req, reply) => + yoga.handleNodeRequestAndResponse(req, reply, { + req, + reply, + }), }); // Mount Voyager endpoint diff --git a/infrastructure/evault-core/src/protocol/graphql-server.ts b/infrastructure/evault-core/src/protocol/graphql-server.ts index 6a1c513c7..bde5adde8 100644 --- a/infrastructure/evault-core/src/protocol/graphql-server.ts +++ b/infrastructure/evault-core/src/protocol/graphql-server.ts @@ -9,139 +9,119 @@ import { GraphQLSchema } from "graphql"; import { exampleQueries } from "./examples/examples"; export class GraphQLServer { - private db: DbService; - private accessGuard: VaultAccessGuard; - private schema: GraphQLSchema = createSchema({ - typeDefs, - resolvers: {}, - }); - server?: Server; + private db: DbService; + private accessGuard: VaultAccessGuard; + private schema: GraphQLSchema = createSchema({ + typeDefs, + resolvers: {}, + }); + server?: Server; - constructor(db: DbService) { - this.db = db; - this.accessGuard = new VaultAccessGuard(db); - this.instantiateServer(); - } + constructor(db: DbService) { + this.db = db; + this.accessGuard = new VaultAccessGuard(db); + } - public getSchema(): GraphQLSchema { - return this.schema; - } + public getSchema(): GraphQLSchema { + return this.schema; + } - private instantiateServer() { - const resolvers = { - JSON: require("graphql-type-json"), + init() { + const resolvers = { + JSON: require("graphql-type-json"), - Query: { - getMetaEnvelopeById: this.accessGuard.middleware( - (_: any, { id }: { id: string }) => { - return this.db.findMetaEnvelopeById(id); - }, - ), - findMetaEnvelopesByOntology: this.accessGuard.middleware( - (_: any, { ontology }: { ontology: string }) => { - return this.db.findMetaEnvelopesByOntology(ontology); - }, - ), - searchMetaEnvelopes: this.accessGuard.middleware( - ( - _: any, - { ontology, term }: { ontology: string; term: string }, - ) => { - return this.db.findMetaEnvelopesBySearchTerm( - ontology, - term, - ); - }, - ), - getAllEnvelopes: this.accessGuard.middleware(() => { - return this.db.getAllEnvelopes(); - }), - }, + Query: { + getMetaEnvelopeById: this.accessGuard.middleware( + (_: any, { id }: { id: string }) => { + return this.db.findMetaEnvelopeById(id); + } + ), + findMetaEnvelopesByOntology: this.accessGuard.middleware( + (_: any, { ontology }: { ontology: string }) => { + return this.db.findMetaEnvelopesByOntology(ontology); + } + ), + searchMetaEnvelopes: this.accessGuard.middleware( + (_: any, { ontology, term }: { ontology: string; term: string }) => { + return this.db.findMetaEnvelopesBySearchTerm(ontology, term); + } + ), + getAllEnvelopes: this.accessGuard.middleware(() => { + return this.db.getAllEnvelopes(); + }), + }, - Mutation: { - storeMetaEnvelope: this.accessGuard.middleware( - async ( - _: any, - { - input, - }: { - input: { - ontology: string; - payload: any; - acl: string[]; - }; - }, - ) => { - const result = await this.db.storeMetaEnvelope( - { - ontology: input.ontology, - payload: input.payload, - acl: input.acl, - }, - input.acl, - ); - return result; - }, - ), - deleteMetaEnvelope: this.accessGuard.middleware( - async (_: any, { id }: { id: string }) => { - await this.db.deleteMetaEnvelope(id); - return true; - }, - ), - updateEnvelopeValue: this.accessGuard.middleware( - async ( - _: any, - { - envelopeId, - newValue, - }: { envelopeId: string; newValue: any }, - ) => { - await this.db.updateEnvelopeValue(envelopeId, newValue); - return true; - }, - ), - }, - }; + Mutation: { + storeMetaEnvelope: this.accessGuard.middleware( + async ( + _: any, + { + input, + }: { + input: { + ontology: string; + payload: any; + acl: string[]; + }; + } + ) => { + const result = await this.db.storeMetaEnvelope( + { + ontology: input.ontology, + payload: input.payload, + acl: input.acl, + }, + input.acl + ); + return result; + } + ), + deleteMetaEnvelope: this.accessGuard.middleware( + async (_: any, { id }: { id: string }) => { + await this.db.deleteMetaEnvelope(id); + return true; + } + ), + updateEnvelopeValue: this.accessGuard.middleware( + async ( + _: any, + { envelopeId, newValue }: { envelopeId: string; newValue: any } + ) => { + await this.db.updateEnvelopeValue(envelopeId, newValue); + return true; + } + ), + }, + }; - this.schema = createSchema({ - typeDefs, - resolvers, - }); + this.schema = createSchema({ + typeDefs, + resolvers, + }); - const yoga = createYoga({ - schema: this.schema, - graphiql: { - defaultQuery: exampleQueries, - }, - context: async ({ request }) => { - const authHeader = request.headers.get("authorization") ?? ""; - const token = authHeader.replace("Bearer ", ""); + const yoga = createYoga({ + schema: this.schema, + graphqlEndpoint: "/graphql", + graphiql: { + defaultQuery: exampleQueries, + }, + context: async ({ request }) => { + const authHeader = request.headers.get("authorization") ?? ""; + const token = authHeader.replace("Bearer ", ""); - if (token) { - const id = getJWTHeader(token).kid?.split("#")[0]; - return { - currentUser: id ?? null, - }; - } + if (token) { + const id = getJWTHeader(token).kid?.split("#")[0]; + return { + currentUser: id ?? null, + }; + } - return { - currentUser: null, - }; - }, - }); + return { + currentUser: null, + }; + }, + }); - this.server = createServer((req, res) => { - if (req.url === "/voyager") { - res.writeHead(200, { "Content-Type": "text/html" }); - res.end( - renderVoyagerPage({ - endpointUrl: "/graphql", - }), - ); - } else { - yoga(req, res); - } - }); - } + return yoga; + } } diff --git a/infrastructure/evault-core/src/protocol/vault-access-guard.ts b/infrastructure/evault-core/src/protocol/vault-access-guard.ts index a08b8f07d..867237c2c 100644 --- a/infrastructure/evault-core/src/protocol/vault-access-guard.ts +++ b/infrastructure/evault-core/src/protocol/vault-access-guard.ts @@ -3,113 +3,112 @@ import { DbService } from "../db/db.service"; import { MetaEnvelope } from "../db/types"; export type VaultContext = YogaInitialContext & { - currentUser: string | null; + currentUser: string | null; }; export class VaultAccessGuard { - constructor(private db: DbService) {} + constructor(private db: DbService) {} - /** - * Checks if the current user has access to a meta envelope based on its ACL - * @param metaEnvelopeId - The ID of the meta envelope to check access for - * @param context - The GraphQL context containing the current user - * @returns Promise - Whether the user has access - */ - private async checkAccess( - metaEnvelopeId: string, - context: VaultContext, - ): Promise { - if (!context.currentUser) { - return false; - } - - const metaEnvelope = await this.db.findMetaEnvelopeById(metaEnvelopeId); - if (!metaEnvelope) { - return false; - } - - // If ACL contains "*", anyone can access - if (metaEnvelope.acl.includes("*")) { - return true; - } + /** + * Checks if the current user has access to a meta envelope based on its ACL + * @param metaEnvelopeId - The ID of the meta envelope to check access for + * @param context - The GraphQL context containing the current user + * @returns Promise - Whether the user has access + */ + private async checkAccess( + metaEnvelopeId: string, + context: VaultContext + ): Promise { + if (!context.currentUser) { + const metaEnvelope = await this.db.findMetaEnvelopeById(metaEnvelopeId); + if (metaEnvelope && metaEnvelope.acl.includes("*")) return true; + return false; + } - // Check if the current user's ID is in the ACL - return metaEnvelope.acl.includes(context.currentUser); + const metaEnvelope = await this.db.findMetaEnvelopeById(metaEnvelopeId); + if (!metaEnvelope) { + return false; } - /** - * Filters out ACL from meta envelope responses - * @param metaEnvelope - The meta envelope to filter - * @returns The filtered meta envelope without ACL - */ - private filterACL(metaEnvelope: any) { - if (!metaEnvelope) return null; - const { acl, ...filtered } = metaEnvelope; - return filtered; + // If ACL contains "*", anyone can access + if (metaEnvelope.acl.includes("*")) { + return true; } - /** - * Filters a list of meta envelopes to only include those the user has access to - * @param envelopes - List of meta envelopes to filter - * @param context - The GraphQL context containing the current user - * @returns Promise - Filtered list of meta envelopes - */ - private async filterEnvelopesByAccess( - envelopes: MetaEnvelope[], - context: VaultContext, - ): Promise { - const filteredEnvelopes = []; - for (const envelope of envelopes) { - const hasAccess = envelope.acl.includes("*") || - envelope.acl.includes(context.currentUser ?? ""); - if (hasAccess) { - filteredEnvelopes.push(this.filterACL(envelope)); - } - } - return filteredEnvelopes; + // Check if the current user's ID is in the ACL + return metaEnvelope.acl.includes(context.currentUser); + } + + /** + * Filters out ACL from meta envelope responses + * @param metaEnvelope - The meta envelope to filter + * @returns The filtered meta envelope without ACL + */ + private filterACL(metaEnvelope: any) { + if (!metaEnvelope) return null; + const { acl, ...filtered } = metaEnvelope; + return filtered; + } + + /** + * Filters a list of meta envelopes to only include those the user has access to + * @param envelopes - List of meta envelopes to filter + * @param context - The GraphQL context containing the current user + * @returns Promise - Filtered list of meta envelopes + */ + private async filterEnvelopesByAccess( + envelopes: MetaEnvelope[], + context: VaultContext + ): Promise { + const filteredEnvelopes = []; + for (const envelope of envelopes) { + const hasAccess = + envelope.acl.includes("*") || + envelope.acl.includes(context.currentUser ?? ""); + if (hasAccess) { + filteredEnvelopes.push(this.filterACL(envelope)); + } } + return filteredEnvelopes; + } - /** - * Middleware function to check access before executing a resolver - * @param resolver - The resolver function to wrap - * @returns A wrapped resolver that checks access before executing - */ - public middleware( - resolver: ( - parent: T, - args: Args, - context: VaultContext, - ) => Promise, - ) { - return async (parent: T, args: Args, context: VaultContext) => { - // For operations that don't require a specific meta envelope ID (bulk queries) - if (!args.id && !args.envelopeId) { - const result = await resolver(parent, args, context); + /** + * Middleware function to check access before executing a resolver + * @param resolver - The resolver function to wrap + * @returns A wrapped resolver that checks access before executing + */ + public middleware( + resolver: (parent: T, args: Args, context: VaultContext) => Promise + ) { + return async (parent: T, args: Args, context: VaultContext) => { + // For operations that don't require a specific meta envelope ID (bulk queries) + if (!args.id && !args.envelopeId) { + const result = await resolver(parent, args, context); - // If the result is an array of meta envelopes, filter based on access - if (Array.isArray(result)) { - return this.filterEnvelopesByAccess(result, context); - } + // If the result is an array of meta envelopes, filter based on access + if (Array.isArray(result)) { + return this.filterEnvelopesByAccess(result, context); + } - // If the result is a single meta envelope, filter ACL - return this.filterACL(result); - } + // If the result is a single meta envelope, filter ACL + return this.filterACL(result); + } - // For operations that target a specific meta envelope - const metaEnvelopeId = args.id || args.envelopeId; - if (!metaEnvelopeId) { - const result = await resolver(parent, args, context); - return this.filterACL(result); - } + // For operations that target a specific meta envelope + const metaEnvelopeId = args.id || args.envelopeId; + if (!metaEnvelopeId) { + const result = await resolver(parent, args, context); + return this.filterACL(result); + } - const hasAccess = await this.checkAccess(metaEnvelopeId, context); - if (!hasAccess) { - throw new Error("Access denied"); - } + const hasAccess = await this.checkAccess(metaEnvelopeId, context); + if (!hasAccess) { + throw new Error("Access denied"); + } - // console.log - const result = await resolver(parent, args, context); - return this.filterACL(result); - }; - } + // console.log + const result = await resolver(parent, args, context); + return this.filterACL(result); + }; + } } diff --git a/infrastructure/evault-core/tests/evault.spec.ts b/infrastructure/evault-core/tests/evault.spec.ts deleted file mode 100644 index 63361f668..000000000 --- a/infrastructure/evault-core/tests/evault.spec.ts +++ /dev/null @@ -1,242 +0,0 @@ -import { describe, it, expect, beforeAll, afterAll } from "vitest"; -import { createYoga } from "graphql-yoga"; -import { createServer } from "http"; -import neo4j from "neo4j-driver"; -import { DbService } from "../src/db/db.service"; -import { GraphQLServer } from "../src/protocol/graphql-server"; -import { W3IDBuilder } from "w3id"; -import { VaultContext } from "../src/protocol/vault-access-guard"; -import { MockStorage } from "./utils/mock-storage"; -import { createMockSigner } from "./utils/mock-signer"; -import { Neo4jContainer } from "@testcontainers/neo4j"; -import { createServer as createNetServer } from "net"; - -async function getFreePort() { - return new Promise((resolve, reject) => { - const server = createNetServer(); - server.listen(0, () => { - const address = server.address(); - if (address && typeof address === "object") { - server.close(() => resolve(address.port)); - } else { - server.close(() => reject(new Error("No port found"))); - } - }); - }); -} - -describe("eVault E2E", () => { - let server; - let dbService; - let driver; - let w3id; - let testEnvelopeId; - let port: number; - - const testOntology = "SocialMediaPost"; - const testPayload = { - text: "gm world", - dateCreated: new Date().toISOString(), - }; - - beforeAll(async () => { - const container = await new Neo4jContainer("neo4j:5.15").start(); - const uri = `bolt://localhost:${container.getMappedPort(7687)}`; - driver = neo4j.driver( - uri, - neo4j.auth.basic(container.getUsername(), container.getPassword()), - ); - dbService = new DbService(driver); - - const signer = createMockSigner(); - const repo = new MockStorage(); - w3id = await new W3IDBuilder() - .withSigner(signer) - .withRepository(repo) - .withNextKeyHash("x") - .build(); - - const yoga = createYoga({ - schema: new GraphQLServer(dbService).getSchema(), - context: async ({ request }) => { - const authHeader = request.headers.get("authorization") ?? ""; - const token = authHeader.replace("Bearer ", ""); - return { - currentUser: token ? w3id.id : null, - } satisfies VaultContext; - }, - }); - - const httpServer = createServer(yoga); - port = await getFreePort(); - await new Promise((resolve) => httpServer.listen(port, resolve)); - server = httpServer; - }); - - afterAll(async () => { - await server.close(); - await driver.close(); - }); - - const executeGraphQL = async (query, variables = {}, token) => { - const res = await fetch(`http://localhost:${port}/graphql`, { - method: "POST", - headers: { - "Content-Type": "application/json", - ...(token ? { Authorization: `Bearer ${token}` } : {}), - }, - body: JSON.stringify({ query, variables }), - }); - return res.json(); - }; - - it("should store and retrieve a meta envelope", async () => { - const token = await w3id.signJWT({ sub: w3id.id }); - - const store = await executeGraphQL( - `mutation Store($input: MetaEnvelopeInput!) { - storeMetaEnvelope(input: $input) { - metaEnvelope { id ontology parsed } - envelopes { id ontology value valueType } - } - }`, - { - input: { - ontology: testOntology, - payload: testPayload, - acl: ["*"], - }, - }, - token, - ); - - expect(store.errors).toBeUndefined(); - testEnvelopeId = store.data.storeMetaEnvelope.metaEnvelope.id; - - const read = await executeGraphQL( - `query Read($id: String!) { - getMetaEnvelopeById(id: $id) { - id ontology parsed envelopes { id ontology value } - } - }`, - { id: testEnvelopeId }, - token, - ); - - expect(read.errors).toBeUndefined(); - expect(read.data.getMetaEnvelopeById.ontology).toBe(testOntology); - expect(read.data.getMetaEnvelopeById.parsed.text).toBe("gm world"); - }); - - it("should reject unauthorized access", async () => { - const token = await w3id.signJWT({ sub: w3id.id }); - const store = await executeGraphQL( - `mutation Store($input: MetaEnvelopeInput!) { - storeMetaEnvelope(input: $input) { - metaEnvelope { id ontology parsed } - envelopes { id ontology value valueType } - } - }`, - { - input: { - ontology: testOntology, - payload: testPayload, - acl: ["@001231232"], - }, - }, - token, - ); - - expect(store.errors).toBeUndefined(); - const unauthEnvId = store.data.storeMetaEnvelope.metaEnvelope.id; - - const otherSigner = createMockSigner(); - const otherRepo = new MockStorage(); - const other = await new W3IDBuilder() - .withSigner(otherSigner) - .withRepository(otherRepo) - .withNextKeyHash("z") - .build(); - const otherToken = await other.signJWT({ sub: other.id }); - - const result = await executeGraphQL( - `query Read($id: String!) { - getMetaEnvelopeById(id: $id) { id } - }`, - { id: unauthEnvId }, - otherToken, - ); - - expect(result.data.getMetaEnvelopeById).toBeNull(); - }); - - it("should allow wildcard ACL read", async () => { - const token = await w3id.signJWT({ sub: w3id.id }); - - const store = await executeGraphQL( - `mutation Store($input: MetaEnvelopeInput!) { - storeMetaEnvelope(input: $input) { - metaEnvelope { id } - } - }`, - { - input: { - ontology: testOntology, - payload: testPayload, - acl: ["*"], - }, - }, - token, - ); - - const id = store.data.storeMetaEnvelope.metaEnvelope.id; - - const readerSigner = createMockSigner(); - const reader = await new W3IDBuilder() - .withSigner(readerSigner) - .withRepository(new MockStorage()) - .withNextKeyHash("r") - .build(); - const readerToken = await reader.signJWT({ sub: reader.id }); - - const result = await executeGraphQL( - `query Read($id: String!) { - getMetaEnvelopeById(id: $id) { id ontology parsed } - }`, - { id }, - readerToken, - ); - - expect(result.errors).toBeUndefined(); - expect(result.data.getMetaEnvelopeById.id).toBe(id); - }); - - it("should search meta envelopes by term", async () => { - const token = await w3id.signJWT({ sub: w3id.id }); - const term = "searchable"; - await executeGraphQL( - `mutation Store($input: MetaEnvelopeInput!) { - storeMetaEnvelope(input: $input) { metaEnvelope { id } } - }`, - { - input: { - ontology: "search-test", - payload: { note: term }, - acl: ["*"], - }, - }, - token, - ); - - const result = await executeGraphQL( - `query Search($ontology: String!, $term: String!) { - searchMetaEnvelopes(ontology: $ontology, term: $term) { id parsed } - }`, - { ontology: "search-test", term }, - token, - ); - - expect(result.errors).toBeUndefined(); - expect(result.data.searchMetaEnvelopes[0].parsed.note).toBe(term); - }); -}); diff --git a/infrastructure/web3-adapter/package.json b/infrastructure/web3-adapter/package.json new file mode 100644 index 000000000..645d2f684 --- /dev/null +++ b/infrastructure/web3-adapter/package.json @@ -0,0 +1,34 @@ +{ + "name": "web3-adapter", + "version": "1.0.0", + "description": "Web3 adapter for platform-specific data mapping to universal schema", + "type": "module", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "scripts": { + "build": "tsc", + "test": "vitest", + "lint": "eslint src/**/*.ts" + }, + "dependencies": { + "evault-core": "workspace:*", + "test": "^3.3.0", + "vitest": "^3.1.2" + }, + "devDependencies": { + "@types/jest": "^29.5.0", + "@typescript-eslint/eslint-plugin": "^5.59.0", + "@typescript-eslint/parser": "^5.59.0", + "eslint": "^8.38.0", + "jest": "^29.5.0", + "ts-jest": "^29.1.0", + "typescript": "^5.0.4" + }, + "jest": { + "preset": "ts-jest", + "testEnvironment": "node", + "testMatch": [ + "**/__tests__/**/*.test.ts" + ] + } +} diff --git a/infrastructure/web3-adapter/src/__tests__/adapter.test.ts b/infrastructure/web3-adapter/src/__tests__/adapter.test.ts new file mode 100644 index 000000000..8b7491c94 --- /dev/null +++ b/infrastructure/web3-adapter/src/__tests__/adapter.test.ts @@ -0,0 +1,73 @@ +import { describe, it, expect, beforeEach } from "vitest"; +import { Web3Adapter } from "../adapter.js"; + +describe("Web3Adapter", () => { + let adapter: Web3Adapter; + + beforeEach(() => { + adapter = new Web3Adapter(); + }); + + it("should transform platform data to universal format", () => { + // Register mappings for a platform + adapter.registerMapping("twitter", [ + { sourceField: "tweet", targetField: "content" }, + { sourceField: "likes", targetField: "reactions" }, + { sourceField: "replies", targetField: "comments" }, + ]); + + const twitterData = { + tweet: "Hello world!", + likes: 42, + replies: ["user1", "user2"], + }; + + const universalData = adapter.toUniversal("twitter", twitterData); + expect(universalData).toEqual({ + content: "Hello world!", + reactions: 42, + comments: ["user1", "user2"], + }); + }); + + it("should transform universal data to platform format", () => { + // Register mappings for a platform + adapter.registerMapping("instagram", [ + { sourceField: "caption", targetField: "content" }, + { sourceField: "hearts", targetField: "reactions" }, + { sourceField: "comments", targetField: "comments" }, + ]); + + const universalData = { + content: "Hello world!", + reactions: 42, + comments: ["user1", "user2"], + }; + + const instagramData = adapter.fromUniversal("instagram", universalData); + expect(instagramData).toEqual({ + caption: "Hello world!", + hearts: 42, + comments: ["user1", "user2"], + }); + }); + + it("should handle field transformations", () => { + adapter.registerMapping("custom", [ + { + sourceField: "timestamp", + targetField: "date", + transform: (value: number) => new Date(value).toISOString(), + }, + ]); + + const customData = { + timestamp: 1677721600000, + }; + + const universalData = adapter.toUniversal("custom", customData); + expect(universalData).toEqual({ + date: "2023-03-02T01:46:40.000Z", + }); + }); +}); diff --git a/infrastructure/web3-adapter/src/__tests__/evault.test.ts b/infrastructure/web3-adapter/src/__tests__/evault.test.ts new file mode 100644 index 000000000..06e51e995 --- /dev/null +++ b/infrastructure/web3-adapter/src/__tests__/evault.test.ts @@ -0,0 +1,245 @@ +import { describe, it, expect, beforeEach } from "vitest"; +import { Web3Adapter } from "../adapter.js"; + +const EVaultEndpoint = "http://localhost:4000/graphql"; + +async function queryGraphQL( + query: string, + variables: Record = {} +) { + const response = await fetch(EVaultEndpoint, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ query, variables }), + }); + return response.json(); +} + +describe("eVault Integration", () => { + let adapter: Web3Adapter; + let storedId: string; + + beforeEach(() => { + adapter = new Web3Adapter(); + }); + + it("should store and retrieve data from eVault", async () => { + // Register mappings for a platform + adapter.registerMapping("twitter", [ + { sourceField: "tweet", targetField: "text" }, + { sourceField: "likes", targetField: "userLikes" }, + { sourceField: "replies", targetField: "interactions" }, + { sourceField: "image", targetField: "image" }, + { + sourceField: "timestamp", + targetField: "dateCreated", + transform: (value: number) => new Date(value).toISOString(), + }, + ]); + + // Create platform-specific data + const twitterData = { + tweet: "Hello world!", + likes: ["@user1", "@user2"], + replies: ["reply1", "reply2"], + image: "https://example.com/image.jpg", + }; + + // Convert to universal format + const universalData = adapter.toUniversal("twitter", twitterData); + + // Store in eVault + const storeMutation = ` + mutation StoreMetaEnvelope($input: MetaEnvelopeInput!) { + storeMetaEnvelope(input: $input) { + metaEnvelope { + id + ontology + parsed + } + } + } + `; + + const storeResult = await queryGraphQL(storeMutation, { + input: { + ontology: "SocialMediaPost", + payload: universalData, + acl: ["*"], + }, + }); + + expect(storeResult.errors).toBeUndefined(); + expect(storeResult.data.storeMetaEnvelope.metaEnvelope.id).toBeDefined(); + storedId = storeResult.data.storeMetaEnvelope.metaEnvelope.id; + + // Retrieve from eVault + const retrieveQuery = ` + query GetMetaEnvelope($id: String!) { + getMetaEnvelopeById(id: $id) { + parsed + } + } + `; + + const retrieveResult = await queryGraphQL(retrieveQuery, { id: storedId }); + expect(retrieveResult.errors).toBeUndefined(); + const retrievedData = retrieveResult.data.getMetaEnvelopeById.parsed; + + // Convert back to platform format + const platformData = adapter.fromUniversal("twitter", retrievedData); + }); + + it("should exchange data between different platforms", async () => { + // Register mappings for Platform A (Twitter-like) + adapter.registerMapping("platformA", [ + { sourceField: "post", targetField: "text" }, + { sourceField: "reactions", targetField: "userLikes" }, + { sourceField: "comments", targetField: "interactions" }, + { sourceField: "media", targetField: "image" }, + { + sourceField: "createdAt", + targetField: "dateCreated", + transform: (value: number) => new Date(value).toISOString(), + }, + ]); + + // Register mappings for Platform B (Facebook-like) + adapter.registerMapping("platformB", [ + { sourceField: "content", targetField: "text" }, + { sourceField: "likes", targetField: "userLikes" }, + { sourceField: "responses", targetField: "interactions" }, + { sourceField: "attachment", targetField: "image" }, + { + sourceField: "postedAt", + targetField: "dateCreated", + transform: (value: string) => new Date(value).getTime(), + }, + ]); + + // Create data in Platform A format + const platformAData = { + post: "Cross-platform test post", + reactions: ["user1", "user2"], + comments: ["Great post!", "Thanks for sharing"], + media: "https://example.com/cross-platform.jpg", + createdAt: Date.now(), + }; + + // Convert Platform A data to universal format + const universalData = adapter.toUniversal("platformA", platformAData); + + // Store in eVault + const storeMutation = ` + mutation StoreMetaEnvelope($input: MetaEnvelopeInput!) { + storeMetaEnvelope(input: $input) { + metaEnvelope { + id + ontology + parsed + } + } + } + `; + + const storeResult = await queryGraphQL(storeMutation, { + input: { + ontology: "SocialMediaPost", + payload: universalData, + acl: ["*"], + }, + }); + + expect(storeResult.errors).toBeUndefined(); + expect(storeResult.data.storeMetaEnvelope.metaEnvelope.id).toBeDefined(); + const storedId = storeResult.data.storeMetaEnvelope.metaEnvelope.id; + + // Retrieve from eVault + const retrieveQuery = ` + query GetMetaEnvelope($id: String!) { + getMetaEnvelopeById(id: $id) { + parsed + } + } + `; + + const retrieveResult = await queryGraphQL(retrieveQuery, { id: storedId }); + expect(retrieveResult.errors).toBeUndefined(); + const retrievedData = retrieveResult.data.getMetaEnvelopeById.parsed; + + // Convert to Platform B format + const platformBData = adapter.fromUniversal("platformB", retrievedData); + + // Verify Platform B data structure + expect(platformBData).toEqual({ + content: platformAData.post, + likes: platformAData.reactions, + responses: platformAData.comments, + attachment: platformAData.media, + postedAt: expect.any(Number), // We expect a timestamp + }); + + // Verify data integrity + expect(platformBData.content).toBe(platformAData.post); + expect(platformBData.likes).toEqual(platformAData.reactions); + expect(platformBData.responses).toEqual(platformAData.comments); + expect(platformBData.attachment).toBe(platformAData.media); + }); + + it("should search data in eVault", async () => { + // Register mappings for a platform + adapter.registerMapping("twitter", [ + { sourceField: "tweet", targetField: "text" }, + { sourceField: "likes", targetField: "userLikes" }, + ]); + + // Create and store test data + const twitterData = { + tweet: "Searchable content", + likes: ["@user1"], + }; + + const universalData = adapter.toUniversal("twitter", twitterData); + + const storeMutation = ` + mutation Store($input: MetaEnvelopeInput!) { + storeMetaEnvelope(input: $input) { + metaEnvelope { + id + } + } + } + `; + + await queryGraphQL(storeMutation, { + input: { + ontology: "SocialMediaPost", + payload: universalData, + acl: ["*"], + }, + }); + + // Search in eVault + const searchQuery = ` + query Search($ontology: String!, $term: String!) { + searchMetaEnvelopes(ontology: $ontology, term: $term) { + id + parsed + } + } + `; + + const searchResult = await queryGraphQL(searchQuery, { + ontology: "SocialMediaPost", + term: "Searchable", + }); + + expect(searchResult.errors).toBeUndefined(); + expect(searchResult.data.searchMetaEnvelopes.length).toBeGreaterThan(0); + expect(searchResult.data.searchMetaEnvelopes[0].parsed.text).toBe( + "Searchable content" + ); + }); +}); diff --git a/infrastructure/web3-adapter/src/adapter.ts b/infrastructure/web3-adapter/src/adapter.ts new file mode 100644 index 000000000..1a12b4ae6 --- /dev/null +++ b/infrastructure/web3-adapter/src/adapter.ts @@ -0,0 +1,59 @@ +export type FieldMapping = { + sourceField: string; + targetField: string; + transform?: (value: any) => any; +}; + +export class Web3Adapter { + private mappings: Map; + + constructor() { + this.mappings = new Map(); + } + + public registerMapping(platform: string, mappings: FieldMapping[]): void { + this.mappings.set(platform, mappings); + } + + public toUniversal( + platform: string, + data: Record + ): Record { + const mappings = this.mappings.get(platform); + if (!mappings) { + throw new Error(`No mappings found for platform: ${platform}`); + } + + const result: Record = {}; + for (const mapping of mappings) { + if (data[mapping.sourceField] !== undefined) { + const value = mapping.transform + ? mapping.transform(data[mapping.sourceField]) + : data[mapping.sourceField]; + result[mapping.targetField] = value; + } + } + return result; + } + + public fromUniversal( + platform: string, + data: Record + ): Record { + const mappings = this.mappings.get(platform); + if (!mappings) { + throw new Error(`No mappings found for platform: ${platform}`); + } + + const result: Record = {}; + for (const mapping of mappings) { + if (data[mapping.targetField] !== undefined) { + const value = mapping.transform + ? mapping.transform(data[mapping.targetField]) + : data[mapping.targetField]; + result[mapping.sourceField] = value; + } + } + return result; + } +} diff --git a/infrastructure/web3-adapter/tsconfig.json b/infrastructure/web3-adapter/tsconfig.json new file mode 100644 index 000000000..12ea365d2 --- /dev/null +++ b/infrastructure/web3-adapter/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "ES2020", + "moduleResolution": "node", + "lib": ["ES2020"], + "declaration": true, + "outDir": "./dist", + "rootDir": "./src", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist", "**/*.test.ts"] +} \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4150a3625..34485d2ef 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -62,7 +62,7 @@ importers: version: 8.6.7(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(storybook@8.6.7(prettier@3.5.3)) '@storybook/experimental-addon-test': specifier: ^8.6.7 - version: 8.6.7(@vitest/browser@3.0.9)(@vitest/runner@3.0.9)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(storybook@8.6.7(prettier@3.5.3))(vitest@3.0.9) + version: 8.6.7(@vitest/browser@3.0.9)(@vitest/runner@3.1.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(storybook@8.6.7(prettier@3.5.3))(vitest@3.0.9) '@storybook/svelte': specifier: ^8.6.7 version: 8.6.7(storybook@8.6.7(prettier@3.5.3))(svelte@5.23.2) @@ -125,7 +125,7 @@ importers: version: 5.23.2 svelte-check: specifier: ^4.0.0 - version: 4.1.5(svelte@5.23.2)(typescript@5.6.3) + version: 4.1.5(picomatch@4.0.2)(svelte@5.23.2)(typescript@5.6.3) svelte-gestures: specifier: ^5.1.3 version: 5.1.3 @@ -144,6 +144,9 @@ importers: infrastructure/evault-core: dependencies: + '@fastify/formbody': + specifier: ^8.0.2 + version: 8.0.2 '@fastify/swagger': specifier: ^8.14.0 version: 8.15.0 @@ -277,6 +280,40 @@ importers: specifier: ^3.0.9 version: 3.0.9(@types/node@22.13.10)(@vitest/browser@3.0.9)(jiti@2.4.2)(lightningcss@1.29.2)(msw@2.7.3(@types/node@22.13.10)(typescript@5.8.2))(tsx@4.19.3)(yaml@2.7.1) + infrastructure/web3-adapter: + dependencies: + evault-core: + specifier: workspace:* + version: link:../evault-core + test: + specifier: ^3.3.0 + version: 3.3.0 + vitest: + specifier: ^3.1.2 + version: 3.1.2(@types/node@22.13.10)(jiti@2.4.2)(lightningcss@1.29.2)(msw@2.7.3(@types/node@22.13.10)(typescript@5.8.3))(tsx@4.19.3)(yaml@2.7.1) + devDependencies: + '@types/jest': + specifier: ^29.5.0 + version: 29.5.14 + '@typescript-eslint/eslint-plugin': + specifier: ^5.59.0 + version: 5.62.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1)(typescript@5.8.3) + '@typescript-eslint/parser': + specifier: ^5.59.0 + version: 5.62.0(eslint@8.57.1)(typescript@5.8.3) + eslint: + specifier: ^8.38.0 + version: 8.57.1 + jest: + specifier: ^29.5.0 + version: 29.7.0(@types/node@22.13.10)(babel-plugin-macros@3.1.0) + ts-jest: + specifier: ^29.1.0 + version: 29.3.2(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(jest@29.7.0(@types/node@22.13.10)(babel-plugin-macros@3.1.0))(typescript@5.8.3) + typescript: + specifier: ^5.0.4 + version: 5.8.3 + packages/eslint-config: devDependencies: '@eslint/js': @@ -989,10 +1026,18 @@ packages: resolution: {integrity: sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + '@eslint/eslintrc@2.1.4': + resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + '@eslint/eslintrc@3.3.0': resolution: {integrity: sha512-yaVPAiNAalnCZedKLdR21GOGILMLKPyqSLWaAjQFvYA2i/ciDi8ArYVr69Anohb6cH2Ukhqti4aFnYyPm8wdwQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@eslint/js@8.57.1': + resolution: {integrity: sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + '@eslint/js@9.22.0': resolution: {integrity: sha512-vLFajx9o8d1/oL2ZkpMYbkLv8nDB6yaIwFNt7nI4+I80U/z03SxmfOMsLbvWr3p7C+Wnoh//aOu2pQW8cS0HCQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -1025,6 +1070,9 @@ packages: '@fastify/fast-json-stringify-compiler@4.3.0': resolution: {integrity: sha512-aZAXGYo6m22Fk1zZzEUKBvut/CIIQe/BapEORnxiD5Qr0kPHqqI69NtEMCme74h+at72sPhbkb4ZrLd1W3KRLA==} + '@fastify/formbody@8.0.2': + resolution: {integrity: sha512-84v5J2KrkXzjgBpYnaNRPqwgMsmY7ZDjuj0YVuMR3NXCJRCgKEZy/taSP1wUYGn0onfxJpLyRGDLa+NMaDJtnA==} + '@fastify/jwt@7.2.4': resolution: {integrity: sha512-aWJzVb3iZb9xIPjfut8YOrkNEKrZA9xyF2C2Hv9nTheFp7CQPGIZMNTyf3848BsD27nw0JLk8jVLZ2g2DfJOoQ==} @@ -1124,6 +1172,11 @@ packages: resolution: {integrity: sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==} engines: {node: '>=18.18.0'} + '@humanwhocodes/config-array@0.13.0': + resolution: {integrity: sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==} + engines: {node: '>=10.10.0'} + deprecated: Use @eslint/config-array instead + '@humanwhocodes/config-array@0.9.5': resolution: {integrity: sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==} engines: {node: '>=10.10.0'} @@ -1137,6 +1190,10 @@ packages: resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} deprecated: Use @eslint/object-schema instead + '@humanwhocodes/object-schema@2.0.3': + resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} + deprecated: Use @eslint/object-schema instead + '@humanwhocodes/retry@0.3.1': resolution: {integrity: sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==} engines: {node: '>=18.18'} @@ -2116,6 +2173,9 @@ packages: '@types/react@19.0.12': resolution: {integrity: sha512-V6Ar115dBDrjbtXSrS+/Oruobc+qVbbUxDFC1RSbRqLt5SYvxxyIDrSC85RWml54g+jfNeEMZhEj7wW07ONQhA==} + '@types/semver@7.7.0': + resolution: {integrity: sha512-k107IF4+Xr7UHjwDc7Cfd6PRQfbdkiRabXGRjo07b4WyPahFBZCZ1sE+BNxYIJPPg73UkfOsVOLwqVc/6ETrIA==} + '@types/send@0.17.4': resolution: {integrity: sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==} @@ -2149,6 +2209,17 @@ packages: '@types/yargs@17.0.33': resolution: {integrity: sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==} + '@typescript-eslint/eslint-plugin@5.62.0': + resolution: {integrity: sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + '@typescript-eslint/parser': ^5.0.0 + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + '@typescript-eslint/eslint-plugin@8.26.1': resolution: {integrity: sha512-2X3mwqsj9Bd3Ciz508ZUtoQQYpOhU/kWoUqIf49H8Z0+Vbh6UF/y0OEYp0Q0axOGzaBGs7QxRwq0knSQ8khQNA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -2157,6 +2228,16 @@ packages: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.9.0' + '@typescript-eslint/parser@5.62.0': + resolution: {integrity: sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + '@typescript-eslint/parser@8.26.1': resolution: {integrity: sha512-w6HZUV4NWxqd8BdeFf81t07d7/YV9s7TCWrQQbG5uhuvGUAW+fq1usZ1Hmz9UPNLniFnD8GLSsDpjP0hm1S4lQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -2164,10 +2245,24 @@ packages: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.9.0' + '@typescript-eslint/scope-manager@5.62.0': + resolution: {integrity: sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + '@typescript-eslint/scope-manager@8.26.1': resolution: {integrity: sha512-6EIvbE5cNER8sqBu6V7+KeMZIC1664d2Yjt+B9EWUXrsyWpxx4lEZrmvxgSKRC6gX+efDL/UY9OpPZ267io3mg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/type-utils@5.62.0': + resolution: {integrity: sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: '*' + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + '@typescript-eslint/type-utils@8.26.1': resolution: {integrity: sha512-Kcj/TagJLwoY/5w9JGEFV0dclQdyqw9+VMndxOJKtoFSjfZhLXhYjzsQEeyza03rwHx2vFEGvrJWJBXKleRvZg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -2175,16 +2270,35 @@ packages: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.9.0' + '@typescript-eslint/types@5.62.0': + resolution: {integrity: sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + '@typescript-eslint/types@8.26.1': resolution: {integrity: sha512-n4THUQW27VmQMx+3P+B0Yptl7ydfceUj4ON/AQILAASwgYdZ/2dhfymRMh5egRUrvK5lSmaOm77Ry+lmXPOgBQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/typescript-estree@5.62.0': + resolution: {integrity: sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + '@typescript-eslint/typescript-estree@8.26.1': resolution: {integrity: sha512-yUwPpUHDgdrv1QJ7YQal3cMVBGWfnuCdKbXw1yyjArax3353rEJP1ZA+4F8nOlQ3RfS2hUN/wze3nlY+ZOhvoA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <5.9.0' + '@typescript-eslint/utils@5.62.0': + resolution: {integrity: sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + '@typescript-eslint/utils@8.26.1': resolution: {integrity: sha512-V4Urxa/XtSUroUrnI7q6yUTD3hDtfJ2jzVfeT3VK0ciizfK2q/zGC0iDh1lFMUZR8cImRrep6/q0xd/1ZGPQpg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -2192,10 +2306,17 @@ packages: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.9.0' + '@typescript-eslint/visitor-keys@5.62.0': + resolution: {integrity: sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + '@typescript-eslint/visitor-keys@8.26.1': resolution: {integrity: sha512-AjOC3zfnxd6S4Eiy3jwktJPclqhFHNyd8L6Gycf9WUPoKZpgM5PjkxY1X7uSy61xVpiJDhhk7XT2NVsN3ALTWg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@ungap/structured-clone@1.3.0': + resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} + '@vitest/browser@3.0.9': resolution: {integrity: sha512-P9dcCeMkA3/oYGfUzRFZJLZxiOpApztxhPsQDUiZzAzLoZonWhse2+vPB0xEBP8Q0lX1WCEEmtY7HzBRi4oYBA==} peerDependencies: @@ -2229,6 +2350,9 @@ packages: '@vitest/expect@3.0.9': resolution: {integrity: sha512-5eCqRItYgIML7NNVgJj6TVCmdzE7ZVgJhruW0ziSQV4V7PvLkDL1bBkBdcTs/VuIz0IxPb5da1IDSqc1TR9eig==} + '@vitest/expect@3.1.2': + resolution: {integrity: sha512-O8hJgr+zREopCAqWl3uCVaOdqJwZ9qaDwUP7vy3Xigad0phZe9APxKhPcDNqYYi0rX5oMvwJMSCAXY2afqeTSA==} + '@vitest/mocker@3.0.9': resolution: {integrity: sha512-ryERPIBOnvevAkTq+L1lD+DTFBRcjueL9lOUfXsLfwP92h4e+Heb+PjiqS3/OURWPtywfafK0kj++yDFjWUmrA==} peerDependencies: @@ -2240,6 +2364,17 @@ packages: vite: optional: true + '@vitest/mocker@3.1.2': + resolution: {integrity: sha512-kOtd6K2lc7SQ0mBqYv/wdGedlqPdM/B38paPY+OwJ1XiNi44w3Fpog82UfOibmHaV9Wod18A09I9SCKLyDMqgw==} + peerDependencies: + msw: ^2.4.9 + vite: ^5.0.0 || ^6.0.0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + '@vitest/pretty-format@2.0.5': resolution: {integrity: sha512-h8k+1oWHfwTkyTkb9egzwNMfJAEx4veaPSnMeKbVSjp4euqGSbQlm5+6VHwTr7u4FJslVVsUG5nopCaAYdOmSQ==} @@ -2249,18 +2384,27 @@ packages: '@vitest/pretty-format@3.0.9': resolution: {integrity: sha512-OW9F8t2J3AwFEwENg3yMyKWweF7oRJlMyHOMIhO5F3n0+cgQAJZBjNgrF8dLwFTEXl5jUqBLXd9QyyKv8zEcmA==} + '@vitest/pretty-format@3.1.2': + resolution: {integrity: sha512-R0xAiHuWeDjTSB3kQ3OQpT8Rx3yhdOAIm/JM4axXxnG7Q/fS8XUwggv/A4xzbQA+drYRjzkMnpYnOGAc4oeq8w==} + '@vitest/runner@1.6.1': resolution: {integrity: sha512-3nSnYXkVkf3mXFfE7vVyPmi3Sazhb/2cfZGGs0JRzFsPFvAMBEcrweV1V1GsrstdXeKCTXlJbvnQwGWgEIHmOA==} '@vitest/runner@3.0.9': resolution: {integrity: sha512-NX9oUXgF9HPfJSwl8tUZCMP1oGx2+Sf+ru6d05QjzQz4OwWg0psEzwY6VexP2tTHWdOkhKHUIZH+fS6nA7jfOw==} + '@vitest/runner@3.1.2': + resolution: {integrity: sha512-bhLib9l4xb4sUMPXnThbnhX2Yi8OutBMA8Yahxa7yavQsFDtwY/jrUZwpKp2XH9DhRFJIeytlyGpXCqZ65nR+g==} + '@vitest/snapshot@1.6.1': resolution: {integrity: sha512-WvidQuWAzU2p95u8GAKlRMqMyN1yOJkGHnx3M1PL9Raf7AQ1kwLKg04ADlCa3+OXUZE7BceOhVZiuWAbzCKcUQ==} '@vitest/snapshot@3.0.9': resolution: {integrity: sha512-AiLUiuZ0FuA+/8i19mTYd+re5jqjEc2jZbgJ2up0VY0Ddyyxg/uUtBDpIFAy4uzKaQxOW8gMgBdAJJ2ydhu39A==} + '@vitest/snapshot@3.1.2': + resolution: {integrity: sha512-Q1qkpazSF/p4ApZg1vfZSQ5Yw6OCQxVMVrLjslbLFA1hMDrT2uxtqMaw8Tc/jy5DLka1sNs1Y7rBcftMiaSH/Q==} + '@vitest/spy@1.6.1': resolution: {integrity: sha512-MGcMmpGkZebsMZhbQKkAf9CX5zGvjkBTqf8Zx3ApYWXr3wG+QvEu2eXWfnIIWYSJExIp4V9FCKDEeygzkYrXMw==} @@ -2270,6 +2414,9 @@ packages: '@vitest/spy@3.0.9': resolution: {integrity: sha512-/CcK2UDl0aQ2wtkp3YVWldrpLRNCfVcIOFGlVGKO4R5eajsH393Z1yiXLVQ7vWsj26JOEjeZI0x5sm5P4OGUNQ==} + '@vitest/spy@3.1.2': + resolution: {integrity: sha512-OEc5fSXMws6sHVe4kOFyDSj/+4MSwst0ib4un0DlcYgQvRuYQ0+M2HyqGaauUMnjq87tmUaMNDxKQx7wNfVqPA==} + '@vitest/utils@1.6.1': resolution: {integrity: sha512-jOrrUvXM4Av9ZWiG1EajNto0u96kWAhJ1LmPmJhXXQx/32MecEKd10pOLYgS2BQx1TgkGhloPU1ArDW2vvaY6g==} @@ -2282,6 +2429,9 @@ packages: '@vitest/utils@3.0.9': resolution: {integrity: sha512-ilHM5fHhZ89MCp5aAaM9uhfl1c2JdxVxl3McqsdVyVNN6JffnEen8UMCdRTzOhGXNQGo5GNL9QugHrz727Wnng==} + '@vitest/utils@3.1.2': + resolution: {integrity: sha512-5GGd0ytZ7BH3H6JTj9Kw7Prn1Nbg0wZVrIvou+UWxm54d+WoXXgAgjFJ8wn3LdagWLFSEfpPeyYrByZaGEZHLg==} + '@whatwg-node/disposablestack@0.0.6': resolution: {integrity: sha512-LOtTn+JgJvX8WfBVJtF08TGrdjuFzGJc4mkP8EdDI8ADbvO7kiexYep1o8dwnt0okb0jYclCDXF13xU7Ge4zSw==} engines: {node: '>=18.0.0'} @@ -2423,6 +2573,10 @@ packages: resolution: {integrity: sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==} engines: {node: '>= 0.4'} + array-union@2.1.0: + resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} + engines: {node: '>=8'} + array.prototype.findlast@1.2.5: resolution: {integrity: sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==} engines: {node: '>= 0.4'} @@ -2962,6 +3116,10 @@ packages: resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} engines: {node: '>=0.3.1'} + dir-glob@3.0.1: + resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} + engines: {node: '>=8'} + docker-compose@0.24.8: resolution: {integrity: sha512-plizRs/Vf15H+GCVxq2EUvyPK7ei9b/cVesHvjnX4xaXjM9spHe2Ytq0BitndFgvTJ3E3NljPNUEl7BAN43iZw==} engines: {node: '>= 6.0.0'} @@ -3178,6 +3336,10 @@ packages: eslint: '>6.6.0' turbo: '>2.0.0' + eslint-scope@5.1.1: + resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} + engines: {node: '>=8.0.0'} + eslint-scope@7.2.2: resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -3210,6 +3372,12 @@ packages: deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. hasBin: true + eslint@8.57.1: + resolution: {integrity: sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. + hasBin: true + eslint@9.22.0: resolution: {integrity: sha512-9V/QURhsRN40xuHXWjV64yvrzMjcz7ZyNoF2jJFmy9j/SLk0u1OLSZgXi28MrXjymnjEGSR80WCdab3RGMDveQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -3251,6 +3419,10 @@ packages: resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} engines: {node: '>=4.0'} + estraverse@4.3.0: + resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==} + engines: {node: '>=4.0'} + estraverse@5.3.0: resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} engines: {node: '>=4.0'} @@ -3290,6 +3462,10 @@ packages: resolution: {integrity: sha512-80F22aiJ3GLyVnS/B3HzgR6RelZVumzj9jkL0Rhz4h0xYbNW9PjlQz5h3J/SShErbXBc295vseR4/MIbVmUbeA==} engines: {node: '>=12.0.0'} + expect-type@1.2.1: + resolution: {integrity: sha512-/kP8CAwxzLVEeFrMm4kMmy4CCDlpipyA7MYLVrdJIkV0fYF0UaigQHRsxHiuY/GEea+bh4KSv3TIlgr+2UL6bw==} + engines: {node: '>=12.0.0'} + expect@29.7.0: resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -3351,6 +3527,9 @@ packages: fastify-plugin@4.5.1: resolution: {integrity: sha512-stRHYGeuqpEZTL1Ef0Ovr2ltazUT9g844X5z/zEBFLG8RYlpDiOCIG+ATvYEp+/zmc7sN29mcIMp8gvYplYPIQ==} + fastify-plugin@5.0.1: + resolution: {integrity: sha512-HCxs+YnRaWzCl+cWRYFnHmeRFyR5GVnJTAaCJQiYzQSDwK9MgJdyAsuL3nh0EWRCYMgQ5MeziymvmAhUHYHDUQ==} + fastify@4.29.0: resolution: {integrity: sha512-MaaUHUGcCgC8fXQDsDtioaCcag1fmPJ9j64vAKunqZF4aSub040ZGi/ag8NGE2714yREPOKZuHCfpPzuUD3UQQ==} @@ -3374,6 +3553,14 @@ packages: picomatch: optional: true + fdir@6.4.4: + resolution: {integrity: sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + file-entry-cache@6.0.1: resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} engines: {node: ^10.12.0 || >=12.0.0} @@ -3565,6 +3752,10 @@ packages: resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} engines: {node: '>= 0.4'} + globby@11.1.0: + resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} + engines: {node: '>=10'} + gopd@1.2.0: resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} engines: {node: '>= 0.4'} @@ -3792,6 +3983,10 @@ packages: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} + is-path-inside@3.0.3: + resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} + engines: {node: '>=8'} + is-reference@3.0.3: resolution: {integrity: sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==} @@ -4403,6 +4598,9 @@ packages: engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true + natural-compare-lite@1.4.0: + resolution: {integrity: sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==} + natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} @@ -4616,6 +4814,10 @@ packages: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} + picomatch@4.0.2: + resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} + engines: {node: '>=12'} + pino-abstract-transport@2.0.0: resolution: {integrity: sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw==} @@ -5100,6 +5302,9 @@ packages: std-env@3.8.1: resolution: {integrity: sha512-vj5lIj3Mwf9D79hBkltk5qmkFI+biIKWS2IBxEyEU3AX1tUf7AoL8nSazCOiiqQsGKIq01SClsKEzweu34uwvA==} + std-env@3.9.0: + resolution: {integrity: sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==} + steed@1.1.3: resolution: {integrity: sha512-EUkci0FAUiE4IvGTSKcDJIQ/eRUP2JJb56+fvZ4sdnguLTqIdKjSxUe138poW8mkvKWXW2sFPrgTsxqoISnmoA==} @@ -5144,6 +5349,10 @@ packages: string.prototype.repeat@1.0.0: resolution: {integrity: sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==} + string.prototype.replaceall@1.0.10: + resolution: {integrity: sha512-PKLapcZUZmXUdfIM6rTTTMYOxaj4JiQrgl0SKEeCFug1CdMAuJq8hVZd4eek9yMXAW4ldGUq+TiZRtjLJRU96g==} + engines: {node: '>= 0.4'} + string.prototype.trim@1.2.10: resolution: {integrity: sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==} engines: {node: '>= 0.4'} @@ -5308,6 +5517,10 @@ packages: resolution: {integrity: sha512-pFYqmTw68LXVjeWJMST4+borgQP2AyMNbg1BpZh9LbyhUeNkeaPF9gzfPGUAnSMV3qPYdWUwDIjjCLiSDOl7vg==} engines: {node: '>=18'} + test@3.3.0: + resolution: {integrity: sha512-JKlEohxDIJRjwBH/+BrTcAPHljBALrAHw3Zs99RqZlaC605f6BggqXhxkdqZThbSHgaYPwpNJlf9bTSWkb/1rA==} + hasBin: true + testcontainers@10.24.2: resolution: {integrity: sha512-Don3EXEQuSw14+nFG9pj48fL9ck/jXDfR9Rb0K3acOyn/gg97+gsnfZaLzpdejl9GcPJVKxACNRe3SYVC2uWqg==} @@ -5329,6 +5542,10 @@ packages: tinyexec@0.3.2: resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} + tinyglobby@0.2.13: + resolution: {integrity: sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==} + engines: {node: '>=12.0.0'} + tinypool@0.8.4: resolution: {integrity: sha512-i11VH5gS6IFeLY3gMBQ00/MmLncVP7JLXOw1vlgkytLmJK7QnEr7NXf0LBdxfmNPAeyetukOk0bOYrJrFGjYJQ==} engines: {node: '>=14.0.0'} @@ -5432,9 +5649,18 @@ packages: '@swc/wasm': optional: true + tslib@1.14.1: + resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} + tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + tsutils@3.21.0: + resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} + engines: {node: '>= 6'} + peerDependencies: + typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' + tsx@4.19.3: resolution: {integrity: sha512-4H8vUNGNjQ4V2EOoGw005+c+dGuPSnhpPBPHBtsZdGZBk/iJb4kguGlPWaZTZ3q5nMtFOEsY0nRDlh9PJyd6SQ==} engines: {node: '>=18.0.0'} @@ -5661,6 +5887,11 @@ packages: engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} hasBin: true + vite-node@3.1.2: + resolution: {integrity: sha512-/8iMryv46J3aK13iUXsei5G/A3CUlW4665THCPS+K8xAaqrVWiGB4RfXMQXCLjpK9P2eK//BczrVkn5JLAk6DA==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + hasBin: true + vite@5.4.18: resolution: {integrity: sha512-1oDcnEp3lVyHCuQ2YFelM4Alm2o91xNoMncRm1U7S+JdYfYOvbiGZ3/CxGttrOu2M/KcGz7cRC2DoNUA6urmMA==} engines: {node: ^18.0.0 || >=20.0.0} @@ -5793,6 +6024,34 @@ packages: jsdom: optional: true + vitest@3.1.2: + resolution: {integrity: sha512-WaxpJe092ID1C0mr+LH9MmNrhfzi8I65EX/NRU/Ld016KqQNRgxSOlGNP1hHN+a/F8L15Mh8klwaF77zR3GeDQ==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@types/debug': ^4.1.12 + '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 + '@vitest/browser': 3.1.2 + '@vitest/ui': 3.1.2 + happy-dom: '*' + jsdom: '*' + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@types/debug': + optional: true + '@types/node': + optional: true + '@vitest/browser': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + walker@1.0.8: resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==} @@ -6428,6 +6687,11 @@ snapshots: '@esbuild/win32-x64@0.25.1': optional: true + '@eslint-community/eslint-utils@4.5.0(eslint@8.57.1)': + dependencies: + eslint: 8.57.1 + eslint-visitor-keys: 3.4.3 + '@eslint-community/eslint-utils@4.5.0(eslint@9.22.0(jiti@2.4.2))': dependencies: eslint: 9.22.0(jiti@2.4.2) @@ -6463,6 +6727,20 @@ snapshots: transitivePeerDependencies: - supports-color + '@eslint/eslintrc@2.1.4': + dependencies: + ajv: 6.12.6 + debug: 4.4.0(supports-color@5.5.0) + espree: 9.6.1 + globals: 13.24.0 + ignore: 5.3.2 + import-fresh: 3.3.1 + js-yaml: 4.1.0 + minimatch: 3.1.2 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + '@eslint/eslintrc@3.3.0': dependencies: ajv: 6.12.6 @@ -6477,6 +6755,8 @@ snapshots: transitivePeerDependencies: - supports-color + '@eslint/js@8.57.1': {} + '@eslint/js@9.22.0': {} '@eslint/object-schema@2.1.6': {} @@ -6504,6 +6784,11 @@ snapshots: dependencies: fast-json-stringify: 5.16.1 + '@fastify/formbody@8.0.2': + dependencies: + fast-querystring: 1.1.2 + fastify-plugin: 5.0.1 + '@fastify/jwt@7.2.4': dependencies: '@fastify/error': 3.4.1 @@ -6645,6 +6930,14 @@ snapshots: '@humanfs/core': 0.19.1 '@humanwhocodes/retry': 0.3.1 + '@humanwhocodes/config-array@0.13.0': + dependencies: + '@humanwhocodes/object-schema': 2.0.3 + debug: 4.4.0(supports-color@5.5.0) + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + '@humanwhocodes/config-array@0.9.5': dependencies: '@humanwhocodes/object-schema': 1.2.1 @@ -6657,6 +6950,8 @@ snapshots: '@humanwhocodes/object-schema@1.2.1': {} + '@humanwhocodes/object-schema@2.0.3': {} + '@humanwhocodes/retry@0.3.1': {} '@humanwhocodes/retry@0.4.2': {} @@ -7296,7 +7591,7 @@ snapshots: dependencies: type-fest: 2.19.0 - '@storybook/experimental-addon-test@8.6.7(@vitest/browser@3.0.9)(@vitest/runner@3.0.9)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(storybook@8.6.7(prettier@3.5.3))(vitest@3.0.9)': + '@storybook/experimental-addon-test@8.6.7(@vitest/browser@3.0.9)(@vitest/runner@3.1.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(storybook@8.6.7(prettier@3.5.3))(vitest@3.0.9)': dependencies: '@storybook/global': 5.0.0 '@storybook/icons': 1.4.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0) @@ -7308,7 +7603,7 @@ snapshots: ts-dedent: 2.2.0 optionalDependencies: '@vitest/browser': 3.0.9(@types/node@22.13.10)(playwright@1.51.1)(typescript@5.6.3)(vite@6.2.2(@types/node@22.13.10)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.3)(yaml@2.7.1))(vitest@3.0.9) - '@vitest/runner': 3.0.9 + '@vitest/runner': 3.1.2 vitest: 3.0.9(@types/node@22.13.10)(@vitest/browser@3.0.9)(jiti@2.4.2)(lightningcss@1.29.2)(msw@2.7.3(@types/node@22.13.10)(typescript@5.6.3))(tsx@4.19.3)(yaml@2.7.1) transitivePeerDependencies: - react @@ -7794,6 +8089,8 @@ snapshots: dependencies: csstype: 3.1.3 + '@types/semver@7.7.0': {} + '@types/send@0.17.4': dependencies: '@types/mime': 1.3.5 @@ -7832,6 +8129,25 @@ snapshots: dependencies: '@types/yargs-parser': 21.0.3 + '@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1)(typescript@5.8.3)': + dependencies: + '@eslint-community/regexpp': 4.12.1 + '@typescript-eslint/parser': 5.62.0(eslint@8.57.1)(typescript@5.8.3) + '@typescript-eslint/scope-manager': 5.62.0 + '@typescript-eslint/type-utils': 5.62.0(eslint@8.57.1)(typescript@5.8.3) + '@typescript-eslint/utils': 5.62.0(eslint@8.57.1)(typescript@5.8.3) + debug: 4.4.0(supports-color@5.5.0) + eslint: 8.57.1 + graphemer: 1.4.0 + ignore: 5.3.2 + natural-compare-lite: 1.4.0 + semver: 7.7.1 + tsutils: 3.21.0(typescript@5.8.3) + optionalDependencies: + typescript: 5.8.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/eslint-plugin@8.26.1(@typescript-eslint/parser@8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2))(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)': dependencies: '@eslint-community/regexpp': 4.12.1 @@ -7849,6 +8165,18 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.3)': + dependencies: + '@typescript-eslint/scope-manager': 5.62.0 + '@typescript-eslint/types': 5.62.0 + '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.8.3) + debug: 4.4.0(supports-color@5.5.0) + eslint: 8.57.1 + optionalDependencies: + typescript: 5.8.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/parser@8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)': dependencies: '@typescript-eslint/scope-manager': 8.26.1 @@ -7861,11 +8189,28 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/scope-manager@5.62.0': + dependencies: + '@typescript-eslint/types': 5.62.0 + '@typescript-eslint/visitor-keys': 5.62.0 + '@typescript-eslint/scope-manager@8.26.1': dependencies: '@typescript-eslint/types': 8.26.1 '@typescript-eslint/visitor-keys': 8.26.1 + '@typescript-eslint/type-utils@5.62.0(eslint@8.57.1)(typescript@5.8.3)': + dependencies: + '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.8.3) + '@typescript-eslint/utils': 5.62.0(eslint@8.57.1)(typescript@5.8.3) + debug: 4.4.0(supports-color@5.5.0) + eslint: 8.57.1 + tsutils: 3.21.0(typescript@5.8.3) + optionalDependencies: + typescript: 5.8.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/type-utils@8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)': dependencies: '@typescript-eslint/typescript-estree': 8.26.1(typescript@5.8.2) @@ -7877,8 +8222,24 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/types@5.62.0': {} + '@typescript-eslint/types@8.26.1': {} + '@typescript-eslint/typescript-estree@5.62.0(typescript@5.8.3)': + dependencies: + '@typescript-eslint/types': 5.62.0 + '@typescript-eslint/visitor-keys': 5.62.0 + debug: 4.4.0(supports-color@5.5.0) + globby: 11.1.0 + is-glob: 4.0.3 + semver: 7.7.1 + tsutils: 3.21.0(typescript@5.8.3) + optionalDependencies: + typescript: 5.8.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/typescript-estree@8.26.1(typescript@5.8.2)': dependencies: '@typescript-eslint/types': 8.26.1 @@ -7893,6 +8254,21 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/utils@5.62.0(eslint@8.57.1)(typescript@5.8.3)': + dependencies: + '@eslint-community/eslint-utils': 4.5.0(eslint@8.57.1) + '@types/json-schema': 7.0.15 + '@types/semver': 7.7.0 + '@typescript-eslint/scope-manager': 5.62.0 + '@typescript-eslint/types': 5.62.0 + '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.8.3) + eslint: 8.57.1 + eslint-scope: 5.1.1 + semver: 7.7.1 + transitivePeerDependencies: + - supports-color + - typescript + '@typescript-eslint/utils@8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)': dependencies: '@eslint-community/eslint-utils': 4.5.0(eslint@9.22.0(jiti@2.4.2)) @@ -7904,11 +8280,18 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/visitor-keys@5.62.0': + dependencies: + '@typescript-eslint/types': 5.62.0 + eslint-visitor-keys: 3.4.3 + '@typescript-eslint/visitor-keys@8.26.1': dependencies: '@typescript-eslint/types': 8.26.1 eslint-visitor-keys: 4.2.0 + '@ungap/structured-clone@1.3.0': {} + '@vitest/browser@3.0.9(@types/node@22.13.10)(playwright@1.51.1)(typescript@5.6.3)(vite@6.2.2(@types/node@22.13.10)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.3)(yaml@2.7.1))(vitest@3.0.9)': dependencies: '@testing-library/dom': 10.4.0 @@ -8014,6 +8397,13 @@ snapshots: chai: 5.2.0 tinyrainbow: 2.0.0 + '@vitest/expect@3.1.2': + dependencies: + '@vitest/spy': 3.1.2 + '@vitest/utils': 3.1.2 + chai: 5.2.0 + tinyrainbow: 2.0.0 + '@vitest/mocker@3.0.9(msw@2.7.3(@types/node@22.13.10)(typescript@5.6.3))(vite@6.2.2(@types/node@22.13.10)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.3)(yaml@2.7.1))': dependencies: '@vitest/spy': 3.0.9 @@ -8041,6 +8431,15 @@ snapshots: msw: 2.7.3(@types/node@22.13.10)(typescript@5.8.3) vite: 6.2.2(@types/node@22.13.10)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.3)(yaml@2.7.1) + '@vitest/mocker@3.1.2(msw@2.7.3(@types/node@22.13.10)(typescript@5.8.3))(vite@6.2.2(@types/node@22.13.10)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.3)(yaml@2.7.1))': + dependencies: + '@vitest/spy': 3.1.2 + estree-walker: 3.0.3 + magic-string: 0.30.17 + optionalDependencies: + msw: 2.7.3(@types/node@22.13.10)(typescript@5.8.3) + vite: 6.2.2(@types/node@22.13.10)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.3)(yaml@2.7.1) + '@vitest/pretty-format@2.0.5': dependencies: tinyrainbow: 1.2.0 @@ -8053,6 +8452,10 @@ snapshots: dependencies: tinyrainbow: 2.0.0 + '@vitest/pretty-format@3.1.2': + dependencies: + tinyrainbow: 2.0.0 + '@vitest/runner@1.6.1': dependencies: '@vitest/utils': 1.6.1 @@ -8064,6 +8467,11 @@ snapshots: '@vitest/utils': 3.0.9 pathe: 2.0.3 + '@vitest/runner@3.1.2': + dependencies: + '@vitest/utils': 3.1.2 + pathe: 2.0.3 + '@vitest/snapshot@1.6.1': dependencies: magic-string: 0.30.17 @@ -8076,6 +8484,12 @@ snapshots: magic-string: 0.30.17 pathe: 2.0.3 + '@vitest/snapshot@3.1.2': + dependencies: + '@vitest/pretty-format': 3.1.2 + magic-string: 0.30.17 + pathe: 2.0.3 + '@vitest/spy@1.6.1': dependencies: tinyspy: 2.2.1 @@ -8088,6 +8502,10 @@ snapshots: dependencies: tinyspy: 3.0.2 + '@vitest/spy@3.1.2': + dependencies: + tinyspy: 3.0.2 + '@vitest/utils@1.6.1': dependencies: diff-sequences: 29.6.3 @@ -8114,6 +8532,12 @@ snapshots: loupe: 3.1.3 tinyrainbow: 2.0.0 + '@vitest/utils@3.1.2': + dependencies: + '@vitest/pretty-format': 3.1.2 + loupe: 3.1.3 + tinyrainbow: 2.0.0 + '@whatwg-node/disposablestack@0.0.6': dependencies: '@whatwg-node/promise-helpers': 1.3.1 @@ -8267,6 +8691,8 @@ snapshots: get-intrinsic: 1.3.0 is-string: 1.1.1 + array-union@2.1.0: {} + array.prototype.findlast@1.2.5: dependencies: call-bind: 1.0.8 @@ -8732,6 +9158,21 @@ snapshots: - supports-color - ts-node + create-jest@29.7.0(@types/node@22.13.10)(babel-plugin-macros@3.1.0): + dependencies: + '@jest/types': 29.6.3 + chalk: 4.1.2 + exit: 0.1.2 + graceful-fs: 4.2.11 + jest-config: 29.7.0(@types/node@22.13.10)(babel-plugin-macros@3.1.0) + jest-util: 29.7.0 + prompts: 2.4.2 + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + create-require@1.1.1: {} cross-inspect@1.0.1: @@ -8851,6 +9292,10 @@ snapshots: diff@4.0.2: {} + dir-glob@3.0.1: + dependencies: + path-type: 4.0.0 + docker-compose@0.24.8: dependencies: yaml: 2.7.1 @@ -9194,6 +9639,11 @@ snapshots: eslint: 9.22.0(jiti@2.4.2) turbo: 2.4.4 + eslint-scope@5.1.1: + dependencies: + esrecurse: 4.3.0 + estraverse: 4.3.0 + eslint-scope@7.2.2: dependencies: esrecurse: 4.3.0 @@ -9258,6 +9708,49 @@ snapshots: transitivePeerDependencies: - supports-color + eslint@8.57.1: + dependencies: + '@eslint-community/eslint-utils': 4.5.0(eslint@8.57.1) + '@eslint-community/regexpp': 4.12.1 + '@eslint/eslintrc': 2.1.4 + '@eslint/js': 8.57.1 + '@humanwhocodes/config-array': 0.13.0 + '@humanwhocodes/module-importer': 1.0.1 + '@nodelib/fs.walk': 1.2.8 + '@ungap/structured-clone': 1.3.0 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.6 + debug: 4.4.0(supports-color@5.5.0) + doctrine: 3.0.0 + escape-string-regexp: 4.0.0 + eslint-scope: 7.2.2 + eslint-visitor-keys: 3.4.3 + espree: 9.6.1 + esquery: 1.6.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 6.0.1 + find-up: 5.0.0 + glob-parent: 6.0.2 + globals: 13.24.0 + graphemer: 1.4.0 + ignore: 5.3.2 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + is-path-inside: 3.0.3 + js-yaml: 4.1.0 + json-stable-stringify-without-jsonify: 1.0.1 + levn: 0.4.1 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.4 + strip-ansi: 6.0.1 + text-table: 0.2.0 + transitivePeerDependencies: + - supports-color + eslint@9.22.0(jiti@2.4.2): dependencies: '@eslint-community/eslint-utils': 4.5.0(eslint@9.22.0(jiti@2.4.2)) @@ -9334,6 +9827,8 @@ snapshots: dependencies: estraverse: 5.3.0 + estraverse@4.3.0: {} + estraverse@5.3.0: {} estree-walker@3.0.3: @@ -9376,6 +9871,8 @@ snapshots: expect-type@1.2.0: {} + expect-type@1.2.1: {} + expect@29.7.0: dependencies: '@jest/expect-utils': 29.7.0 @@ -9481,6 +9978,8 @@ snapshots: fastify-plugin@4.5.1: {} + fastify-plugin@5.0.1: {} + fastify@4.29.0: dependencies: '@fastify/ajv-compiler': 3.6.0 @@ -9518,7 +10017,13 @@ snapshots: dependencies: bser: 2.1.1 - fdir@6.4.3: {} + fdir@6.4.3(picomatch@4.0.2): + optionalDependencies: + picomatch: 4.0.2 + + fdir@6.4.4(picomatch@4.0.2): + optionalDependencies: + picomatch: 4.0.2 file-entry-cache@6.0.1: dependencies: @@ -9715,6 +10220,15 @@ snapshots: define-properties: 1.2.1 gopd: 1.2.0 + globby@11.1.0: + dependencies: + array-union: 2.1.0 + dir-glob: 3.0.1 + fast-glob: 3.3.3 + ignore: 5.3.2 + merge2: 1.4.1 + slash: 3.0.0 + gopd@1.2.0: {} graceful-fs@4.2.11: {} @@ -9939,6 +10453,8 @@ snapshots: is-number@7.0.0: {} + is-path-inside@3.0.3: {} + is-reference@3.0.3: dependencies: '@types/estree': 1.0.6 @@ -10118,6 +10634,25 @@ snapshots: - supports-color - ts-node + jest-cli@29.7.0(@types/node@22.13.10)(babel-plugin-macros@3.1.0): + dependencies: + '@jest/core': 29.7.0(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.17.30)(typescript@5.8.3)) + '@jest/test-result': 29.7.0 + '@jest/types': 29.6.3 + chalk: 4.1.2 + create-jest: 29.7.0(@types/node@22.13.10)(babel-plugin-macros@3.1.0) + exit: 0.1.2 + import-local: 3.2.0 + jest-config: 29.7.0(@types/node@22.13.10)(babel-plugin-macros@3.1.0) + jest-util: 29.7.0 + jest-validate: 29.7.0 + yargs: 17.7.2 + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + jest-config@29.7.0(@types/node@20.17.30)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.17.30)(typescript@5.8.3)): dependencies: '@babel/core': 7.26.10 @@ -10149,6 +10684,36 @@ snapshots: - babel-plugin-macros - supports-color + jest-config@29.7.0(@types/node@22.13.10)(babel-plugin-macros@3.1.0): + dependencies: + '@babel/core': 7.26.10 + '@jest/test-sequencer': 29.7.0 + '@jest/types': 29.6.3 + babel-jest: 29.7.0(@babel/core@7.26.10) + chalk: 4.1.2 + ci-info: 3.9.0 + deepmerge: 4.3.1 + glob: 7.2.3 + graceful-fs: 4.2.11 + jest-circus: 29.7.0(babel-plugin-macros@3.1.0) + jest-environment-node: 29.7.0 + jest-get-type: 29.6.3 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-runner: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + micromatch: 4.0.8 + parse-json: 5.2.0 + pretty-format: 29.7.0 + slash: 3.0.0 + strip-json-comments: 3.1.1 + optionalDependencies: + '@types/node': 22.13.10 + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + jest-diff@29.7.0: dependencies: chalk: 4.1.2 @@ -10376,6 +10941,18 @@ snapshots: - supports-color - ts-node + jest@29.7.0(@types/node@22.13.10)(babel-plugin-macros@3.1.0): + dependencies: + '@jest/core': 29.7.0(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.17.30)(typescript@5.8.3)) + '@jest/types': 29.6.3 + import-local: 3.2.0 + jest-cli: 29.7.0(@types/node@22.13.10)(babel-plugin-macros@3.1.0) + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + jiti@2.4.2: {} jose@5.10.0: {} @@ -10753,6 +11330,8 @@ snapshots: nanoid@3.3.11: {} + natural-compare-lite@1.4.0: {} + natural-compare@1.4.0: {} negotiator@0.6.3: {} @@ -10965,6 +11544,8 @@ snapshots: picomatch@2.3.1: {} + picomatch@4.0.2: {} + pino-abstract-transport@2.0.0: dependencies: split2: 4.2.0 @@ -11518,6 +12099,8 @@ snapshots: std-env@3.8.1: {} + std-env@3.9.0: {} + steed@1.1.3: dependencies: fastfall: 1.5.1 @@ -11590,6 +12173,17 @@ snapshots: define-properties: 1.2.1 es-abstract: 1.23.9 + string.prototype.replaceall@1.0.10: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.23.9 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + has-symbols: 1.1.0 + is-regex: 1.2.1 + string.prototype.trim@1.2.10: dependencies: call-bind: 1.0.8 @@ -11661,11 +12255,11 @@ snapshots: supports-preserve-symlinks-flag@1.0.0: {} - svelte-check@4.1.5(svelte@5.23.2)(typescript@5.6.3): + svelte-check@4.1.5(picomatch@4.0.2)(svelte@5.23.2)(typescript@5.6.3): dependencies: '@jridgewell/trace-mapping': 0.3.25 chokidar: 4.0.3 - fdir: 6.4.3 + fdir: 6.4.3(picomatch@4.0.2) picocolors: 1.1.1 sade: 1.8.1 svelte: 5.23.2 @@ -11771,6 +12365,12 @@ snapshots: glob: 10.4.5 minimatch: 9.0.5 + test@3.3.0: + dependencies: + minimist: 1.2.8 + readable-stream: 4.7.0 + string.prototype.replaceall: 1.0.10 + testcontainers@10.24.2: dependencies: '@balena/dockerignore': 1.0.2 @@ -11808,6 +12408,11 @@ snapshots: tinyexec@0.3.2: {} + tinyglobby@0.2.13: + dependencies: + fdir: 6.4.4(picomatch@4.0.2) + picomatch: 4.0.2 + tinypool@0.8.4: {} tinypool@1.0.2: {} @@ -11869,6 +12474,26 @@ snapshots: '@jest/types': 29.6.3 babel-jest: 29.7.0(@babel/core@7.26.10) + ts-jest@29.3.2(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(jest@29.7.0(@types/node@22.13.10)(babel-plugin-macros@3.1.0))(typescript@5.8.3): + dependencies: + bs-logger: 0.2.6 + ejs: 3.1.10 + fast-json-stable-stringify: 2.1.0 + jest: 29.7.0(@types/node@22.13.10)(babel-plugin-macros@3.1.0) + jest-util: 29.7.0 + json5: 2.2.3 + lodash.memoize: 4.1.2 + make-error: 1.3.6 + semver: 7.7.1 + type-fest: 4.40.0 + typescript: 5.8.3 + yargs-parser: 21.1.1 + optionalDependencies: + '@babel/core': 7.26.10 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + babel-jest: 29.7.0(@babel/core@7.26.10) + ts-node@10.9.2(@types/node@20.17.30)(typescript@5.8.3): dependencies: '@cspotcode/source-map-support': 0.8.1 @@ -11887,8 +12512,15 @@ snapshots: v8-compile-cache-lib: 3.0.1 yn: 3.1.1 + tslib@1.14.1: {} + tslib@2.8.1: {} + tsutils@3.21.0(typescript@5.8.3): + dependencies: + tslib: 1.14.1 + typescript: 5.8.3 + tsx@4.19.3: dependencies: esbuild: 0.25.1 @@ -12121,6 +12753,27 @@ snapshots: - tsx - yaml + vite-node@3.1.2(@types/node@22.13.10)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.3)(yaml@2.7.1): + dependencies: + cac: 6.7.14 + debug: 4.4.0(supports-color@5.5.0) + es-module-lexer: 1.6.0 + pathe: 2.0.3 + vite: 6.2.2(@types/node@22.13.10)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.3)(yaml@2.7.1) + transitivePeerDependencies: + - '@types/node' + - jiti + - less + - lightningcss + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - tsx + - yaml + vite@5.4.18(@types/node@20.17.30)(lightningcss@1.29.2): dependencies: esbuild: 0.21.5 @@ -12299,6 +12952,45 @@ snapshots: - tsx - yaml + vitest@3.1.2(@types/node@22.13.10)(jiti@2.4.2)(lightningcss@1.29.2)(msw@2.7.3(@types/node@22.13.10)(typescript@5.8.3))(tsx@4.19.3)(yaml@2.7.1): + dependencies: + '@vitest/expect': 3.1.2 + '@vitest/mocker': 3.1.2(msw@2.7.3(@types/node@22.13.10)(typescript@5.8.3))(vite@6.2.2(@types/node@22.13.10)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.3)(yaml@2.7.1)) + '@vitest/pretty-format': 3.1.2 + '@vitest/runner': 3.1.2 + '@vitest/snapshot': 3.1.2 + '@vitest/spy': 3.1.2 + '@vitest/utils': 3.1.2 + chai: 5.2.0 + debug: 4.4.0(supports-color@5.5.0) + expect-type: 1.2.1 + magic-string: 0.30.17 + pathe: 2.0.3 + std-env: 3.9.0 + tinybench: 2.9.0 + tinyexec: 0.3.2 + tinyglobby: 0.2.13 + tinypool: 1.0.2 + tinyrainbow: 2.0.0 + vite: 6.2.2(@types/node@22.13.10)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.3)(yaml@2.7.1) + vite-node: 3.1.2(@types/node@22.13.10)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.3)(yaml@2.7.1) + why-is-node-running: 2.3.0 + optionalDependencies: + '@types/node': 22.13.10 + transitivePeerDependencies: + - jiti + - less + - lightningcss + - msw + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - tsx + - yaml + walker@1.0.8: dependencies: makeerror: 1.0.12