diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 864f9837..6b062a23 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -81,6 +81,40 @@ jobs: - name: Run ESLint (astro-payload-richtext-lexical) run: cd astro-payload-richtext-lexical && pnpm lint + test-geocoding: + runs-on: ubuntu-latest + needs: format + name: test-geocoding + + steps: + - name: Checkout code + uses: actions/checkout@v6 + + - name: Setup environment variables + run: | + echo "PAYLOAD_SECRET=test-secret-not-for-production" > geocoding/dev/.env + echo "SQLITE_URL=file:./payload-test.db" >> geocoding/dev/.env + echo "NEXT_PUBLIC_GOOGLE_MAPS_API_KEY=test-api-key" >> geocoding/dev/.env + + - name: Setup pnpm + uses: pnpm/action-setup@v5 + with: + version: ^9.0.0 + + - name: Setup Node.js + uses: actions/setup-node@v6 + with: + node-version: '22' + cache: 'pnpm' + + - name: Install dependencies + run: pnpm install:all + + - name: Run tests + run: cd geocoding && pnpm test:sqlite + env: + PAYLOAD_DATABASE: sqlite + test-pages-localized: runs-on: ubuntu-latest needs: format diff --git a/.prettierrc.json b/.prettierrc.json index eb7b3c1e..4d7e90c9 100644 --- a/.prettierrc.json +++ b/.prettierrc.json @@ -10,6 +10,12 @@ "options": { "requirePragma": true } + }, + { + "files": "*.md", + "options": { + "parser": "markdown" + } } ] } diff --git a/geocoding/CHANGELOG.md b/geocoding/CHANGELOG.md index 353d73b4..bf408016 100644 --- a/geocoding/CHANGELOG.md +++ b/geocoding/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## 0.3.0 + +- **BREAKING**: Replaced `react-google-places-autocomplete` with the Google Maps Places API (New) `AutocompleteSuggestion` API. This resolves the deprecation warning for `google.maps.places.AutocompleteService` (deprecated as of March 2025). The `react-google-places-autocomplete` dependency has been removed. +- **BREAKING**: The **Places API (New)** must be enabled in your Google Cloud project. Enable it at: https://console.developers.google.com/apis/api/places.googleapis.com/overview +- **BREAKING**: The `_googlePlacesData` JSON field has been renamed to `_meta` and now stores a flat `{ name, formattedAddress, googlePlaceId, types }` object instead of the previous `react-google-places-autocomplete` format. Existing documents will need to be migrated — see [`migrations/migrate-to-0.3.0.ts`](./migrations/migrate-to-0.3.0.ts). +- **BREAKING**: The `geoDataFieldOverride` config option has been renamed to `locationMetaOverride`. + ## 0.2.0 - **BREAKING**: The Google Maps API key is now a required plugin configuration option: @@ -12,7 +19,7 @@ plugins: [payloadGeocodingPlugin({})] plugins: [ payloadGeocodingPlugin({ googleMapsApiKey: process.env.NEXT_PUBLIC_GOOGLE_MAPS_API_KEY!, - }) + }), ] ``` diff --git a/geocoding/README.md b/geocoding/README.md index ab9922e5..98cf222f 100644 --- a/geocoding/README.md +++ b/geocoding/README.md @@ -25,11 +25,11 @@ plugins: [ To use this plugin, you'll need a Google Maps API key. To get one, follow these steps: 1. Set up a Google Cloud account and create a project -2. Enable the Maps JavaScript API in your Google Cloud project -3. Create an API key with `Maps JavaScript API`, `Places API` and `Geocoding API` access +2. Enable the **Maps JavaScript API** and the **Places API (New)** in your Google Cloud project +3. Create an API key with access to these APIs 4. Pass the API key to the plugin configuration (as shown above). -Note: Since this API key is exposed to the frontend (Payload Admin panel), it is strongly recommended to restrict its usage by setting up domain restrictions and only enabling the `Maps JavaScript API`, `Places API`, and `Geocoding API` in the Google Cloud Console under API Keys & Credentials +Note: Since this API key is exposed to the frontend (Payload Admin panel), it is strongly recommended to restrict its usage by setting up domain restrictions in the Google Cloud Console under API Keys & Credentials. ## Usage @@ -44,9 +44,9 @@ geocodingField({ }) ``` -This will add a `location_googlePlacesData` JSON field to the collection. This field will store the raw geocoding data from the Google Places API. +This will add a `location_meta` JSON field to the collection that stores metadata about the selected location (display name, formatted address, and Google Place ID (`googlePlaceId`)). -If needed you can adjust the `location_googlePlacesData` field name by passing a `name` property to the `geocodingField` function. +You can customize the metadata field by passing a `locationMetaOverride` option: ```ts geocodingField({ @@ -54,8 +54,8 @@ geocodingField({ name: 'location', type: 'point', }, - geoDataFieldOverride: { - label: 'JSON Geodata Field', + locationMetaOverride: { + label: 'Location Metadata', access: { read: () => true, update: () => true, @@ -63,22 +63,89 @@ geocodingField({ }, admin: { readOnly: false, - description: 'This field stores the geocoding data from the Google Places API.', }, }, }), ``` +## Usage with AI Agents / API + +The default UI-based autocomplete requires a browser, which makes it unusable for AI agents and other API consumers. The plugin provides two server-side mechanisms to solve this. + +### Geocoding Search Endpoint + +The plugin registers a `GET /api/geocoding-plugin/search` endpoint that geocodes addresses server-side. It is authenticated by default (requires a logged-in user), and supports a custom access function: + +```ts +plugins: [ + payloadGeocodingPlugin({ + googleMapsApiKey: process.env.NEXT_PUBLIC_GOOGLE_MAPS_API_KEY!, + // Optional: customize who can access the endpoint + geocodingEndpoint: { + access: ({ req }) => Boolean(req.user), + }, + }), +] +``` + +An agent can then search for locations and use the results to populate fields: + +```bash +# 1. Search for an address +GET /api/geocoding-plugin/search?q=Alexanderplatz,+Berlin + +# Response: +{ + "results": [ + { + "name": "Alexanderplatz", + "formattedAddress": "Alexanderplatz, 10178 Berlin, Germany", + "googlePlaceId": "ChIJp1l4uWBRqEcR2SPNRBMhtAI", + "location": { "lat": 52.5219, "lng": 13.4132 }, + "types": [...] + } + ] +} + +# 2. Use the result to create/update a document +POST /api/pages +{ + "title": "My Page", + "location": [13.4132, 52.5219], + "location_meta": { + "name": "Alexanderplatz", + "formattedAddress": "Alexanderplatz, 10178 Berlin, Germany", + "googlePlaceId": "ChIJp1l4uWBRqEcR2SPNRBMhtAI", + "types": ["point_of_interest", "establishment"] + } +} +``` + +### Server-Side Address Geocoding (beforeChange Hook) + +Every `geocodingField` automatically includes a hidden `{fieldName}_address` text field. When an address string is submitted via the API, a `beforeChange` hook geocodes it server-side and populates the point and meta fields. + +An agent can simply submit an address string — the coordinates and metadata are resolved automatically: + +```bash +POST /api/pages +{ + "title": "My Page", + "location_address": "Alexanderplatz, Berlin" +} +``` + +The hook geocodes the address, sets the `location` point field to `[lng, lat]`, and populates `location_meta` with the location metadata. + ## About this plugin -This plugin uses the [react-google-places-autocomplete](https://www.npmjs.com/package/react-google-places-autocomplete) library to provide a Select/Search input for finding an address. The result of the Google Places API request is stored in a JSON field and the coordinates are stored in a Point Field. +This plugin uses the Google Maps Places API (New) `AutocompleteSuggestion` API to provide a search input for finding an address. The selected location's metadata is stored in a JSON field and the coordinates are stored in a Point Field. ## Roadmap > ⚠️ **Warning**: This plugin is actively evolving and may undergo significant changes. While it is functional, please thoroughly test before using in production environments. -- Use the native Payload `SelectField` instead of the field provided by `react-google-places-autocomplete` -- Extend the field config to accept `GooglePlacesAutocomplete` options like debounce time, API options, etc. +- Extend the field config to accept options like debounce time, API options, etc. - Add support for other geocoding services (Mapbox, HERE, etc.) Have a suggestion for the plugin? Any feedback is welcome! diff --git a/geocoding/dev/.gitignore b/geocoding/dev/.gitignore index 60259b83..5ebf18be 100644 --- a/geocoding/dev/.gitignore +++ b/geocoding/dev/.gitignore @@ -370,4 +370,5 @@ $RECYCLE.BIN/ /media *.db tsconfig.tsbuildinfo -/dist \ No newline at end of file +/dist +src/test/databaseAdapter.ts \ No newline at end of file diff --git a/geocoding/dev/package.json b/geocoding/dev/package.json index a6f34bbc..d9646117 100644 --- a/geocoding/dev/package.json +++ b/geocoding/dev/package.json @@ -1,6 +1,6 @@ { - "name": "payload-plugin-test-app", - "description": "A test app for the plugin", + "name": "payload-geocoding-plugin-test-app", + "description": "A test app for the geocoding plugin", "version": "0.0.1", "license": "MIT", "type": "module", @@ -12,14 +12,19 @@ "start": "cross-env NODE_OPTIONS=--no-deprecation next start", "format": "prettier --write src", "payload": "payload", - "generate:types": "payload generate:types", + "generate:types": "cross-env PAYLOAD_DATABASE=sqlite payload generate:types", "generate:schema": "payload-graphql generate:schema", - "generate:importmap": "payload generate:importmap" + "generate:importmap": "payload generate:importmap", + "test": "pnpm test:sqlite", + "test:sqlite": "cross-env PAYLOAD_DATABASE=sqlite vitest run", + "test:watch": "vitest watch" }, "dependencies": { "@jhb.software/payload-geocoding-plugin": "workspace:*", "@payloadcms/db-mongodb": "^3.81.0", + "@payloadcms/db-sqlite": "^3.81.0", "@payloadcms/next": "^3.81.0", + "@payloadcms/richtext-lexical": "3.81.0", "@payloadcms/ui": "^3.81.0", "next": "15.4.11", "payload": "^3.81.0", @@ -30,6 +35,7 @@ "copyfiles": "^2.4.1", "cross-env": "^10.1.0", "dotenv": "^17.4.1", - "typescript": "5.9.3" + "vite": "^8.0.0", + "vitest": "^4.1.0" } } diff --git a/geocoding/dev/plugin.spec.ts b/geocoding/dev/plugin.spec.ts deleted file mode 100644 index 9391d33c..00000000 --- a/geocoding/dev/plugin.spec.ts +++ /dev/null @@ -1,30 +0,0 @@ -import type { Server } from 'http' -import mongoose from 'mongoose' -import payload from 'payload' -import { start } from './src/server' - -describe('Plugin tests', () => { - let server: Server - - beforeAll(async () => { - await start({ local: true }) - }) - - afterAll(async () => { - await mongoose.connection.dropDatabase() - await mongoose.connection.close() - server.close() - }) - - // Add tests to ensure that the plugin works as expected - - // Example test to check for seeded data - it('seeds data accordingly', async () => { - const newCollectionQuery = await payload.find({ - collection: 'new-collection', - sort: 'createdAt', - }) - - expect(newCollectionQuery.totalDocs).toEqual(1) - }) -}) diff --git a/geocoding/dev/plugin.test.ts b/geocoding/dev/plugin.test.ts new file mode 100644 index 00000000..7051db6b --- /dev/null +++ b/geocoding/dev/plugin.test.ts @@ -0,0 +1,328 @@ +import payload, { type CollectionSlug, type SanitizedConfig } from 'payload' +import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, test, vi } from 'vitest' +import config from './src/payload.config' + +const MOCK_GOOGLE_RESPONSE = { + results: [ + { + address_components: [ + { long_name: 'Alexanderplatz', short_name: 'Alexanderplatz', types: ['point_of_interest'] }, + { long_name: 'Berlin', short_name: 'Berlin', types: ['locality'] }, + ], + formatted_address: 'Alexanderplatz, 10178 Berlin, Germany', + geometry: { + location: { lat: 52.5219, lng: 13.4132 }, + }, + place_id: 'ChIJp1l4uWBRqEcR2SPNRBMhtAI', + types: ['point_of_interest', 'establishment'], + }, + ], + status: 'OK', +} + +/** + * The Pages collection has `location1` (required point) and `location2` (required point + required meta). + * These must be provided in every create call to satisfy validation. + */ +const requiredFields = { + location1: [0, 0] as [number, number], + location2: [0, 0] as [number, number], + location2_meta: { name: 'Test', formattedAddress: 'Test', googlePlaceId: 'test', types: ['test'] }, +} + +/** Returns a fresh mock Response for each call (avoids "Body already read" errors). */ +function mockGoogleGeocodingFetch() { + return vi.spyOn(globalThis, 'fetch').mockImplementation(async () => { + return new Response(JSON.stringify(MOCK_GOOGLE_RESPONSE), { status: 200 }) + }) +} + +beforeAll(async () => { + await payload.init({ + config: config, + }) + + await deleteAllCollections(config, ['users']) +}) + +afterAll(async () => { + await deleteAllCollections(config) + + if (payload.db && typeof payload.db.destroy === 'function') { + await payload.db.destroy() + } +}) + +afterEach(() => { + vi.restoreAllMocks() +}) + +describe('Geocoding plugin field structure', () => { + beforeEach(async () => await deleteCollection('pages')) + + test('creates a page with point and meta fields via the local API', async () => { + const meta = { name: 'Berlin', formattedAddress: 'Berlin, Germany', googlePlaceId: 'abc', types: ['locality'] } + const page = await payload.create({ + collection: 'pages', + data: { + title: 'Test Page', + location: [13.4132, 52.5219], + location_meta: meta, + ...requiredFields, + }, + }) + + expect(page.location).toEqual([13.4132, 52.5219]) + expect(page.location_meta).toEqual(meta) + }) + + test('creates a page with only the required fields', async () => { + const page = await payload.create({ + collection: 'pages', + data: { + title: 'Minimal Page', + ...requiredFields, + }, + }) + + expect(page.title).toBe('Minimal Page') + expect(page.location).toBeUndefined() + }) + + test('geocoding fields work inside a group', async () => { + const meta = { name: 'Place', formattedAddress: 'Somewhere', googlePlaceId: 'xyz', types: ['locality'] } + const page = await payload.create({ + collection: 'pages', + data: { + title: 'Group Test', + locationGroup: { + location: [10.0, 50.0], + location_meta: meta, + }, + ...requiredFields, + }, + }) + + expect(page.locationGroup?.location).toEqual([10.0, 50.0]) + expect(page.locationGroup?.location_meta).toEqual(meta) + }) + + test('geocoding fields work inside an array', async () => { + const metaA = { name: 'A', formattedAddress: 'Place A', googlePlaceId: 'a', types: ['locality'] } + const metaB = { name: 'B', formattedAddress: 'Place B', googlePlaceId: 'b', types: ['locality'] } + const page = await payload.create({ + collection: 'pages', + data: { + title: 'Array Test', + locations: [ + { location: [8.0, 48.0], location_meta: metaA }, + { location: [9.0, 49.0], location_meta: metaB }, + ], + ...requiredFields, + }, + }) + + expect(page.locations).toHaveLength(2) + expect(page.locations![0].location).toEqual([8.0, 48.0]) + expect(page.locations![1].location).toEqual([9.0, 49.0]) + }) +}) + +describe('Server-side address geocoding (beforeChange hook)', () => { + beforeEach(async () => await deleteCollection('pages')) + + test('auto-geocodes an address string submitted via location_address', async () => { + mockGoogleGeocodingFetch() + + const page = await payload.create({ + collection: 'pages', + data: { + title: 'Geocoded Page', + location_address: 'Alexanderplatz, Berlin', + ...requiredFields, + }, + }) + + // Point field should be populated with [lng, lat] + expect(page.location).toEqual([13.4132, 52.5219]) + + // Meta field should contain the geocoding result in LocationMeta shape + expect(page.location_meta).toMatchObject({ + formattedAddress: 'Alexanderplatz, 10178 Berlin, Germany', + googlePlaceId: 'ChIJp1l4uWBRqEcR2SPNRBMhtAI', + name: 'Alexanderplatz', + }) + + // The address field should NOT be persisted (virtual: true) + const fetched = await payload.findByID({ + collection: 'pages', + id: page.id, + }) + expect((fetched as Record).location_address).toBeFalsy() + }) + + test('does not geocode when no address is provided', async () => { + const fetchSpy = vi.spyOn(globalThis, 'fetch') + + await payload.create({ + collection: 'pages', + data: { + title: 'No Address Page', + location: [1.0, 2.0], + ...requiredFields, + }, + }) + + expect(fetchSpy).not.toHaveBeenCalled() + }) + + test('auto-geocodes address on update', async () => { + const page = await payload.create({ + collection: 'pages', + data: { + title: 'Update Test', + location: [0, 0], + ...requiredFields, + }, + }) + + mockGoogleGeocodingFetch() + + const updated = await payload.update({ + collection: 'pages', + id: page.id, + data: { + location_address: 'Alexanderplatz, Berlin', + }, + }) + + expect(updated.location).toEqual([13.4132, 52.5219]) + expect(updated.location_meta).toMatchObject({ + formattedAddress: 'Alexanderplatz, 10178 Berlin, Germany', + }) + }) +}) + +describe('Geocoding field inside a Lexical block', () => { + beforeEach(async () => await deleteCollection('articles')) + + test('creates an article with a locationBlock containing point and meta', async () => { + const article = await payload.create({ + collection: 'articles', + data: { + title: 'Article with Location Block', + content: { + root: { + type: 'root', + version: 1, + direction: 'ltr', + children: [ + { + type: 'block', + version: 1, + fields: { + id: 'loc-block-1', + blockName: 'Berlin Office', + blockType: 'locationBlock', + label: 'Berlin HQ', + location: [13.4132, 52.5219], + location_meta: { name: 'Berlin', formattedAddress: 'Berlin, Germany', googlePlaceId: 'abc', types: ['locality'] }, + }, + }, + ], + }, + }, + }, + }) + + const block = (article.content?.root?.children as any[])?.[0] + expect(block).toBeDefined() + expect(block.fields.blockType).toBe('locationBlock') + expect(block.fields.location).toEqual([13.4132, 52.5219]) + expect(block.fields.location_meta).toMatchObject({ name: 'Berlin' }) + }) + + test('auto-geocodes an address inside a Lexical block', async () => { + mockGoogleGeocodingFetch() + + const article = await payload.create({ + collection: 'articles', + data: { + title: 'Geocoded Block Article', + content: { + root: { + type: 'root', + version: 1, + direction: 'ltr', + children: [ + { + type: 'block', + version: 1, + fields: { + id: 'loc-block-2', + blockName: 'Auto-geocoded Location', + blockType: 'locationBlock', + label: 'Berlin Office', + location_address: 'Alexanderplatz, Berlin', + }, + }, + ], + }, + }, + }, + }) + + const block = (article.content?.root?.children as any[])?.[0] + expect(block).toBeDefined() + + expect(block.fields.location).toEqual([13.4132, 52.5219]) + expect(block.fields.location_meta).toMatchObject({ + formattedAddress: 'Alexanderplatz, 10178 Berlin, Germany', + googlePlaceId: 'ChIJp1l4uWBRqEcR2SPNRBMhtAI', + }) + + // Known Payload bug: virtual fields inside Lexical blocks are still stored in the block's JSON. + // The address field has virtual: true, which correctly prevents a DB column for regular fields, + // but Lexical blocks serialize all field data as JSON and ignore the virtual flag. + // expect(block.fields.location_address).toBeFalsy() + }) +}) + +describe('Geocoding search endpoint', () => { + test('is registered at /api/geocoding-plugin/search', () => { + const endpoints = payload.config.endpoints + const geocodingEndpoint = endpoints?.find((e) => e.path === '/geocoding-plugin/search') + + expect(geocodingEndpoint).toBeDefined() + expect(geocodingEndpoint!.method).toBe('get') + }) +}) + +// --- Helpers --- + +const deleteCollection = async (collection: CollectionSlug) => { + await payload.db.deleteMany({ + collection: collection, + where: {}, + }) + + try { + await payload.db.deleteVersions({ + collection: collection, + where: {}, + }) + } catch {} +} + +const deleteAllCollections = async ( + config: Promise, + except: CollectionSlug[] = [], +) => { + const collections = (await config).collections?.filter((c) => !except.includes(c.slug)) ?? [] + + for (const collection of collections) { + if (!except.includes(collection.slug)) { + await deleteCollection(collection.slug) + } + } +} diff --git a/geocoding/dev/src/collection/articles.ts b/geocoding/dev/src/collection/articles.ts new file mode 100644 index 00000000..d10b9037 --- /dev/null +++ b/geocoding/dev/src/collection/articles.ts @@ -0,0 +1,49 @@ +import { geocodingField } from '../../../src/fields/geocodingField' + +import type { CollectionConfig } from 'payload' + +import { lexicalEditor, BlocksFeature } from '@payloadcms/richtext-lexical' + +/** + * A collection for testing the geocoding field inside a Lexical editor block. + */ +export const Articles: CollectionConfig = { + slug: 'articles', + admin: { + useAsTitle: 'title', + }, + fields: [ + { + name: 'title', + type: 'text', + required: true, + }, + { + name: 'content', + type: 'richText', + editor: lexicalEditor({ + features: [ + BlocksFeature({ + blocks: [ + { + slug: 'locationBlock', + fields: [ + { + name: 'label', + type: 'text', + }, + geocodingField({ + pointField: { + name: 'location', + type: 'point', + }, + }), + ], + }, + ], + }), + ], + }), + }, + ], +} diff --git a/geocoding/dev/src/collection/pages.ts b/geocoding/dev/src/collection/pages.ts index aed49d53..1ee4f7ea 100644 --- a/geocoding/dev/src/collection/pages.ts +++ b/geocoding/dev/src/collection/pages.ts @@ -50,18 +50,18 @@ export const Pages: CollectionConfig = { type: 'point', required: true, }, - geoDataFieldOverride: { + locationMetaOverride: { required: true, }, }), - // With geoDataFieldOverride + // With locationMetaOverride geocodingField({ pointField: { name: 'location3', type: 'point', }, - geoDataFieldOverride: { + locationMetaOverride: { label: 'Geodata (Custom label)', access: { read: () => true, diff --git a/geocoding/dev/src/payload-types.ts b/geocoding/dev/src/payload-types.ts index bb5f3bda..4914ac89 100644 --- a/geocoding/dev/src/payload-types.ts +++ b/geocoding/dev/src/payload-types.ts @@ -69,6 +69,7 @@ export interface Config { collections: { users: User; pages: Page; + articles: Article; 'payload-kv': PayloadKv; 'payload-locked-documents': PayloadLockedDocument; 'payload-preferences': PayloadPreference; @@ -78,13 +79,14 @@ export interface Config { collectionsSelect: { users: UsersSelect | UsersSelect; pages: PagesSelect | PagesSelect; + articles: ArticlesSelect | ArticlesSelect; 'payload-kv': PayloadKvSelect | PayloadKvSelect; 'payload-locked-documents': PayloadLockedDocumentsSelect | PayloadLockedDocumentsSelect; 'payload-preferences': PayloadPreferencesSelect | PayloadPreferencesSelect; 'payload-migrations': PayloadMigrationsSelect | PayloadMigrationsSelect; }; db: { - defaultIDType: string; + defaultIDType: number; }; fallbackLocale: null; globals: {}; @@ -122,7 +124,7 @@ export interface UserAuthOperations { * via the `definition` "users". */ export interface User { - id: string; + id: number; updatedAt: string; createdAt: string; email: string; @@ -147,122 +149,133 @@ export interface User { * via the `definition` "pages". */ export interface Page { - id: string; + id: number; title?: string | null; - location_googlePlacesData?: - | { - [k: string]: unknown; - } - | unknown[] - | string - | number - | boolean - | null; + location_meta?: { + name: string; + formattedAddress: string; + googlePlaceId: string; + types: string[]; + }; /** * @minItems 2 * @maxItems 2 */ location?: [number, number] | null; - location0_googlePlacesData?: - | { - [k: string]: unknown; - } - | unknown[] - | string - | number - | boolean - | null; + location_address?: string | null; + location0_meta?: { + name: string; + formattedAddress: string; + googlePlaceId: string; + types: string[]; + }; /** * @minItems 2 * @maxItems 2 */ location0?: [number, number] | null; - location1_googlePlacesData?: - | { - [k: string]: unknown; - } - | unknown[] - | string - | number - | boolean - | null; + location0_address?: string | null; + location1_meta?: { + name: string; + formattedAddress: string; + googlePlaceId: string; + types: string[]; + }; /** * @minItems 2 * @maxItems 2 */ location1: [number, number]; - location2_googlePlacesData: - | { - [k: string]: unknown; - } - | unknown[] - | string - | number - | boolean - | null; + location1_address?: string | null; + location2_meta: { + name: string; + formattedAddress: string; + googlePlaceId: string; + types: string[]; + }; /** * @minItems 2 * @maxItems 2 */ location2: [number, number]; - location3_googlePlacesData?: - | { - [k: string]: unknown; - } - | unknown[] - | string - | number - | boolean - | null; + location2_address?: string | null; + location3_meta?: { + name: string; + formattedAddress: string; + googlePlaceId: string; + types: string[]; + }; /** * @minItems 2 * @maxItems 2 */ location3?: [number, number] | null; + location3_address?: string | null; locationGroup?: { - location_googlePlacesData?: - | { - [k: string]: unknown; - } - | unknown[] - | string - | number - | boolean - | null; + location_meta?: { + name: string; + formattedAddress: string; + googlePlaceId: string; + types: string[]; + }; /** * @minItems 2 * @maxItems 2 */ location?: [number, number] | null; + location_address?: string | null; }; locations?: | { - location_googlePlacesData?: - | { - [k: string]: unknown; - } - | unknown[] - | string - | number - | boolean - | null; + location_meta?: { + name: string; + formattedAddress: string; + googlePlaceId: string; + types: string[]; + }; /** * @minItems 2 * @maxItems 2 */ location?: [number, number] | null; + location_address?: string | null; id?: string | null; }[] | null; updatedAt: string; createdAt: string; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "articles". + */ +export interface Article { + id: number; + title: string; + content?: { + root: { + type: string; + children: { + type: any; + version: number; + [k: string]: unknown; + }[]; + direction: ('ltr' | 'rtl') | null; + format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''; + indent: number; + version: number; + }; + [k: string]: unknown; + } | null; + updatedAt: string; + createdAt: string; +} /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "payload-kv". */ export interface PayloadKv { - id: string; + id: number; key: string; data: | { @@ -279,20 +292,24 @@ export interface PayloadKv { * via the `definition` "payload-locked-documents". */ export interface PayloadLockedDocument { - id: string; + id: number; document?: | ({ relationTo: 'users'; - value: string | User; + value: number | User; } | null) | ({ relationTo: 'pages'; - value: string | Page; + value: number | Page; + } | null) + | ({ + relationTo: 'articles'; + value: number | Article; } | null); globalSlug?: string | null; user: { relationTo: 'users'; - value: string | User; + value: number | User; }; updatedAt: string; createdAt: string; @@ -302,10 +319,10 @@ export interface PayloadLockedDocument { * via the `definition` "payload-preferences". */ export interface PayloadPreference { - id: string; + id: number; user: { relationTo: 'users'; - value: string | User; + value: number | User; }; key?: string | null; value?: @@ -325,7 +342,7 @@ export interface PayloadPreference { * via the `definition` "payload-migrations". */ export interface PayloadMigration { - id: string; + id: number; name?: string | null; batch?: number | null; updatedAt: string; @@ -359,32 +376,49 @@ export interface UsersSelect { */ export interface PagesSelect { title?: T; - location_googlePlacesData?: T; + location_meta?: T; location?: T; - location0_googlePlacesData?: T; + location_address?: T; + location0_meta?: T; location0?: T; - location1_googlePlacesData?: T; + location0_address?: T; + location1_meta?: T; location1?: T; - location2_googlePlacesData?: T; + location1_address?: T; + location2_meta?: T; location2?: T; - location3_googlePlacesData?: T; + location2_address?: T; + location3_meta?: T; location3?: T; + location3_address?: T; locationGroup?: | T | { - location_googlePlacesData?: T; + location_meta?: T; location?: T; + location_address?: T; }; locations?: | T | { - location_googlePlacesData?: T; + location_meta?: T; location?: T; + location_address?: T; id?: T; }; updatedAt?: T; createdAt?: T; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "articles_select". + */ +export interface ArticlesSelect { + title?: T; + content?: T; + updatedAt?: T; + createdAt?: T; +} /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "payload-kv_select". diff --git a/geocoding/dev/src/payload.config.ts b/geocoding/dev/src/payload.config.ts index 0e585564..988a1347 100644 --- a/geocoding/dev/src/payload.config.ts +++ b/geocoding/dev/src/payload.config.ts @@ -1,10 +1,11 @@ import { payloadGeocodingPlugin } from '@jhb.software/payload-geocoding-plugin' -import { mongooseAdapter } from '@payloadcms/db-mongodb' import path from 'path' import { buildConfig } from 'payload' import { fileURLToPath } from 'url' +import { Articles } from './collection/articles' import { Pages } from './collection/pages' import { testEmailAdapter } from './emailAdapter' +import { databaseAdapter } from './test/databaseAdapter' const filename = fileURLToPath(import.meta.url) const dirname = path.dirname(filename) @@ -24,18 +25,17 @@ export default buildConfig({ fields: [], }, Pages, + Articles, ], - db: mongooseAdapter({ - url: process.env.DATABASE_URI!, - }), + db: databaseAdapter, email: testEmailAdapter, - secret: process.env.PAYLOAD_SECRET!, + secret: process.env.PAYLOAD_SECRET || 'test-secret-for-ci', typescript: { outputFile: path.resolve(dirname, 'payload-types.ts'), }, plugins: [ payloadGeocodingPlugin({ - googleMapsApiKey: process.env.NEXT_PUBLIC_GOOGLE_MAPS_API_KEY!, + googleMapsApiKey: process.env.NEXT_PUBLIC_GOOGLE_MAPS_API_KEY || 'test-api-key', }), ], async onInit(payload) { diff --git a/geocoding/dev/src/test/generateDatabaseAdapter.ts b/geocoding/dev/src/test/generateDatabaseAdapter.ts new file mode 100644 index 00000000..51a000a0 --- /dev/null +++ b/geocoding/dev/src/test/generateDatabaseAdapter.ts @@ -0,0 +1,57 @@ +// NOTE: this pattern is inspired by https://github.com/payloadcms/payload/blob/main/test/generateDatabaseAdapter.ts + +import fs from 'fs' +import path from 'path' +import { fileURLToPath } from 'url' + +const filename = fileURLToPath(import.meta.url) +const dirname = path.dirname(filename) + +export type DatabaseAdapter = 'mongodb' | 'sqlite' + +const databaseAdapters: Record = { + mongodb: ` +import { mongooseAdapter } from '@payloadcms/db-mongodb' + +export const databaseAdapter = mongooseAdapter({ + url: process.env.MONGODB_URL!, +}) +`, + sqlite: ` +import { sqliteAdapter } from '@payloadcms/db-sqlite' + +export const databaseAdapter = sqliteAdapter({ + client: { + url: process.env.SQLITE_URL!, + }, +}) +`, +} + +/** + * Generates a database adapter file based on the PAYLOAD_DATABASE environment variable. + * This allows the same tests to run against different databases without code duplication. + */ +export function generateDatabaseAdapter(dbAdapter: DatabaseAdapter = 'mongodb'): string { + const adapterCode = databaseAdapters[dbAdapter] + if (!adapterCode) { + throw new Error( + `Unknown database adapter: ${dbAdapter}. Valid options are: ${Object.keys(databaseAdapters).join(', ')}`, + ) + } + + const outputPath = path.resolve(dirname, 'databaseAdapter.ts') + + fs.writeFileSync( + outputPath, + `// DO NOT MODIFY. This file is automatically generated. +// Generated for database: ${dbAdapter} +${adapterCode} +`, + ) + + console.log( + `\n##############################\n## Generated database adapter for: ${dbAdapter} ##\n##############################\n`, + ) + return adapterCode +} diff --git a/geocoding/dev/src/test/vitest.setup.ts b/geocoding/dev/src/test/vitest.setup.ts new file mode 100644 index 00000000..0d085cc2 --- /dev/null +++ b/geocoding/dev/src/test/vitest.setup.ts @@ -0,0 +1,6 @@ +import { generateDatabaseAdapter, type DatabaseAdapter } from './generateDatabaseAdapter.js' + +// Default to SQLite if no database specified +const dbAdapter = (process.env.PAYLOAD_DATABASE as DatabaseAdapter) || 'sqlite' + +generateDatabaseAdapter(dbAdapter) diff --git a/geocoding/dev/vite.config.ts b/geocoding/dev/vite.config.ts new file mode 100644 index 00000000..43184db0 --- /dev/null +++ b/geocoding/dev/vite.config.ts @@ -0,0 +1,18 @@ +import path from 'path' +import { loadEnv } from 'vite' +import { fileURLToPath } from 'url' +import { defineConfig } from 'vitest/config' + +const filename = fileURLToPath(import.meta.url) +const dirname = path.dirname(filename) + +export default defineConfig(({ mode }) => { + return { + test: { + env: loadEnv(mode, process.cwd(), ''), // Load environment variables + hookTimeout: 30000, // Increase hook timeout to 30 seconds + testTimeout: 30000, // Increase test timeout to 30 seconds + setupFiles: [path.resolve(dirname, 'src/test/vitest.setup.ts')], + }, + } +}) diff --git a/geocoding/migrations/migrate-to-0.3.0.ts b/geocoding/migrations/migrate-to-0.3.0.ts new file mode 100644 index 00000000..b87865c4 --- /dev/null +++ b/geocoding/migrations/migrate-to-0.3.0.ts @@ -0,0 +1,149 @@ +/** + * Migration script for @jhb.software/payload-geocoding-plugin v0.3.0 + * + * This migration handles: + * 1. Renaming `_googlePlacesData` fields to `_meta` + * 2. Transforming the stored data shape from the old react-google-places-autocomplete + * format to the new flat format + * + * Old format (v0.2.x): + * { label: string, value: { description: string, place_id: string, structured_formatting: { main_text: string } } } + * + * New format (v0.3.0): + * { displayName: string, formattedAddress: string, googlePlaceId: string } + * + * Usage: + * 1. Copy this file into your project + * 2. Update COLLECTIONS_TO_MIGRATE with your collection slugs and point field names + * 3. Run with: npx tsx migrations/migrate-to-0.3.0.ts + * + * Alternatively, integrate the `migrateCollection` function into a Payload migration. + */ + +import type { BasePayload, CollectionSlug } from 'payload' + +// ===================================================================== +// CONFIGURE THESE: Add your collection slugs and point field names +// ===================================================================== +const COLLECTIONS_TO_MIGRATE: { collection: CollectionSlug; pointFieldName: string }[] = [ + // Example: + // { collection: 'pages', pointFieldName: 'location' }, + // { collection: 'events', pointFieldName: 'venue' }, +] + +interface OldGeoData { + label?: string + value?: { + description?: string + place_id?: string + structured_formatting?: { + main_text?: string + } + } +} + +interface NewLocationMeta { + formattedAddress: string + googlePlaceId: string + name: string + types: string[] +} + +function transformGeoData(old: OldGeoData): NewLocationMeta | null { + if (!old?.value?.place_id) { + return null + } + + return { + formattedAddress: old.value.description ?? old.label ?? '', + googlePlaceId: old.value.place_id, + name: old.value.structured_formatting?.main_text ?? old.value.description ?? '', + types: [], // types were not stored in the old format + } +} + +export async function migrateCollection( + payload: BasePayload, + collection: CollectionSlug, + pointFieldName: string, +): Promise<{ migrated: number; skipped: number }> { + const oldFieldName = `${pointFieldName}_googlePlacesData` + const newFieldName = `${pointFieldName}_meta` + + let migrated = 0 + let skipped = 0 + let hasMore = true + let page = 1 + + while (hasMore) { + const result = await payload.find({ + collection, + depth: 0, + limit: 100, + page, + select: { [oldFieldName]: true }, + where: { + [oldFieldName]: { exists: true }, + }, + }) + + for (const doc of result.docs) { + const oldData = (doc as Record)[oldFieldName] as OldGeoData | undefined + if (!oldData) { + skipped++ + continue + } + + const newData = transformGeoData(oldData) + if (!newData) { + skipped++ + continue + } + + await payload.update({ + id: doc.id, + collection, + data: { [newFieldName]: newData }, + }) + + migrated++ + } + + hasMore = result.hasNextPage + page++ + } + + return { migrated, skipped } +} + +/** + * Run this script standalone with: npx tsx migrations/migrate-to-0.3.0.ts + */ +async function main() { + if (COLLECTIONS_TO_MIGRATE.length === 0) { + console.error('No collections configured. Edit COLLECTIONS_TO_MIGRATE in this file.') + process.exit(1) + } + + // Import your Payload config — adjust the path as needed + const { getPayload } = await import('payload') + + const payload = await getPayload({ + // Adjust this import path to point to your payload.config.ts + config: (await import('../payload.config')).default, + }) + + for (const { collection, pointFieldName } of COLLECTIONS_TO_MIGRATE) { + console.log(`Migrating ${collection}.${pointFieldName}...`) + const result = await migrateCollection(payload, collection, pointFieldName) + console.log(` Done: ${result.migrated} migrated, ${result.skipped} skipped`) + } + + console.log('Migration complete.') + process.exit(0) +} + +main().catch((err) => { + console.error('Migration failed:', err) + process.exit(1) +}) diff --git a/geocoding/package.json b/geocoding/package.json index dcb891fa..cf61e563 100644 --- a/geocoding/package.json +++ b/geocoding/package.json @@ -6,16 +6,8 @@ "license": "MIT", "bugs": "https://github.com/jhb-software/payload-plugins/issues", "repository": "https://github.com/jhb-software/payload-plugins", - "keywords": [ - "payload", - "plugin", - "geocoding" - ], - "files": [ - "dist", - "LICENSE.md", - "README.md" - ], + "keywords": ["payload", "plugin", "geocoding"], + "files": ["dist", "LICENSE.md", "README.md"], "main": "./src/index.ts", "types": "./src/index.ts", "type": "module", @@ -30,10 +22,9 @@ "lint": "eslint src", "lint:fix": "eslint src --fix", "prepack": "pnpm prepublishOnly", - "prepublishOnly": "pnpm build && pnpm copyfiles" - }, - "dependencies": { - "react-google-places-autocomplete": "^4.1.0" + "prepublishOnly": "pnpm build && pnpm copyfiles", + "test": "cd dev && pnpm test", + "test:sqlite": "cd dev && pnpm test:sqlite" }, "peerDependencies": { "@payloadcms/ui": "^3.81.0", @@ -44,6 +35,7 @@ }, "devDependencies": { "@payloadcms/eslint-config": "^3.28.0", + "@types/google.maps": "^3.58.1", "@swc/cli": "^0.8.1", "@swc/core": "^1.15.24", "@types/react": "19.2.14", @@ -52,7 +44,8 @@ "eslint": "^9.0.0", "prettier": "^3.8.1", "rimraf": "6.1.3", - "typescript": "5.9.3" + "typescript": "5.9.3", + "vitest": "^4.1.2" }, "publishConfig": { "main": "./dist/index.js", diff --git a/geocoding/pnpm-lock.yaml b/geocoding/pnpm-lock.yaml index 6c635de9..cb705691 100644 --- a/geocoding/pnpm-lock.yaml +++ b/geocoding/pnpm-lock.yaml @@ -23,9 +23,6 @@ importers: react-dom: specifier: 19.2.4 version: 19.2.4(react@19.2.4) - react-google-places-autocomplete: - specifier: ^4.1.0 - version: 4.1.0(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) devDependencies: '@payloadcms/eslint-config': specifier: ^3.28.0 @@ -36,6 +33,9 @@ importers: '@swc/core': specifier: ^1.15.24 version: 1.15.24 + '@types/google.maps': + specifier: ^3.58.1 + version: 3.58.1 '@types/react': specifier: 19.2.14 version: 19.2.14 @@ -57,6 +57,9 @@ importers: typescript: specifier: 5.9.3 version: 5.9.3 + vitest: + specifier: ^4.1.2 + version: 4.1.2(happy-dom@20.8.9)(vite@8.0.5(@emnapi/core@1.9.2)(@emnapi/runtime@1.7.1)(esbuild@0.27.3)(sass@1.77.4)(tsx@4.21.0)) dev: dependencies: @@ -66,9 +69,15 @@ importers: '@payloadcms/db-mongodb': specifier: ^3.81.0 version: 3.81.0(@aws-sdk/credential-providers@3.666.0(@aws-sdk/client-sso-oidc@3.666.0(@aws-sdk/client-sts@3.666.0)))(payload@3.81.0(graphql@16.9.0)(typescript@5.9.3))(socks@2.8.3) + '@payloadcms/db-sqlite': + specifier: ^3.81.0 + version: 3.81.0(payload@3.81.0(graphql@16.9.0)(typescript@5.9.3)) '@payloadcms/next': specifier: ^3.81.0 version: 3.81.0(@types/react@19.2.14)(graphql@16.9.0)(monaco-editor@0.52.0)(next@15.4.11(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.77.4))(payload@3.81.0(graphql@16.9.0)(typescript@5.9.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3) + '@payloadcms/richtext-lexical': + specifier: 3.81.0 + version: 3.81.0(@faceless-ui/modal@3.0.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@faceless-ui/scroll-info@2.0.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@payloadcms/next@3.81.0(@types/react@19.2.14)(graphql@16.9.0)(monaco-editor@0.52.0)(next@15.4.11(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.77.4))(payload@3.81.0(graphql@16.9.0)(typescript@5.9.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(@types/react@19.2.14)(monaco-editor@0.52.0)(next@15.4.11(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.77.4))(payload@3.81.0(graphql@16.9.0)(typescript@5.9.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(yjs@13.6.30) '@payloadcms/ui': specifier: ^3.81.0 version: 3.81.0(@types/react@19.2.14)(monaco-editor@0.52.0)(next@15.4.11(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.77.4))(payload@3.81.0(graphql@16.9.0)(typescript@5.9.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3) @@ -94,9 +103,12 @@ importers: dotenv: specifier: ^17.4.1 version: 17.4.1 - typescript: - specifier: 5.9.3 - version: 5.9.3 + vite: + specifier: ^8.0.0 + version: 8.0.5(@emnapi/core@1.9.2)(@emnapi/runtime@1.7.1)(esbuild@0.25.12)(sass@1.77.4)(tsx@4.21.0) + vitest: + specifier: ^4.1.0 + version: 4.1.2(happy-dom@20.8.9)(vite@8.0.5(@emnapi/core@1.9.2)(@emnapi/runtime@1.7.1)(esbuild@0.25.12)(sass@1.77.4)(tsx@4.21.0)) packages: @@ -304,9 +316,18 @@ packages: peerDependencies: react: '>=16.8.0' + '@drizzle-team/brocli@0.10.2': + resolution: {integrity: sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w==} + + '@emnapi/core@1.9.2': + resolution: {integrity: sha512-UC+ZhH3XtczQYfOlu3lNEkdW/p4dsJ1r/bP7H8+rhao3TTTMO1ATq/4DdIi23XuGoFY+Cz0JmCbdVl0hz9jZcA==} + '@emnapi/runtime@1.7.1': resolution: {integrity: sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==} + '@emnapi/wasi-threads@1.2.1': + resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==} + '@emotion/babel-plugin@11.13.5': resolution: {integrity: sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==} @@ -351,156 +372,452 @@ packages: '@epic-web/invariant@1.0.0': resolution: {integrity: sha512-lrTPqgvfFQtR/eY/qkIzp98OGdNJu0m5ji3q/nJI8v3SXkRKEnWiOxMmbvcSoAIzv/cGiuvRy57k4suKQSAdwA==} + '@esbuild-kit/core-utils@3.3.2': + resolution: {integrity: sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ==} + deprecated: 'Merged into tsx: https://tsx.is' + + '@esbuild-kit/esm-loader@2.6.5': + resolution: {integrity: sha512-FxEMIkJKnodyA1OaCUoEvbYRkoZlLZ4d/eXFu9Fh8CbBBgP5EmZxrfTRyN0qpXZ4vOvqnE5YdRdcrmUUXuU+dA==} + deprecated: 'Merged into tsx: https://tsx.is' + + '@esbuild/aix-ppc64@0.25.12': + resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + '@esbuild/aix-ppc64@0.27.3': resolution: {integrity: sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] + '@esbuild/android-arm64@0.18.20': + resolution: {integrity: sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm64@0.25.12': + resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + '@esbuild/android-arm64@0.27.3': resolution: {integrity: sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==} engines: {node: '>=18'} cpu: [arm64] os: [android] + '@esbuild/android-arm@0.18.20': + resolution: {integrity: sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + + '@esbuild/android-arm@0.25.12': + resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + '@esbuild/android-arm@0.27.3': resolution: {integrity: sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==} engines: {node: '>=18'} cpu: [arm] os: [android] + '@esbuild/android-x64@0.18.20': + resolution: {integrity: sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + + '@esbuild/android-x64@0.25.12': + resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + '@esbuild/android-x64@0.27.3': resolution: {integrity: sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==} engines: {node: '>=18'} cpu: [x64] os: [android] + '@esbuild/darwin-arm64@0.18.20': + resolution: {integrity: sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-arm64@0.25.12': + resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + '@esbuild/darwin-arm64@0.27.3': resolution: {integrity: sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] + '@esbuild/darwin-x64@0.18.20': + resolution: {integrity: sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + + '@esbuild/darwin-x64@0.25.12': + resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + '@esbuild/darwin-x64@0.27.3': resolution: {integrity: sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==} engines: {node: '>=18'} cpu: [x64] os: [darwin] + '@esbuild/freebsd-arm64@0.18.20': + resolution: {integrity: sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-arm64@0.25.12': + resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + '@esbuild/freebsd-arm64@0.27.3': resolution: {integrity: sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] + '@esbuild/freebsd-x64@0.18.20': + resolution: {integrity: sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.25.12': + resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + '@esbuild/freebsd-x64@0.27.3': resolution: {integrity: sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] + '@esbuild/linux-arm64@0.18.20': + resolution: {integrity: sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm64@0.25.12': + resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + '@esbuild/linux-arm64@0.27.3': resolution: {integrity: sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==} engines: {node: '>=18'} cpu: [arm64] os: [linux] + '@esbuild/linux-arm@0.18.20': + resolution: {integrity: sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-arm@0.25.12': + resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + '@esbuild/linux-arm@0.27.3': resolution: {integrity: sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==} engines: {node: '>=18'} cpu: [arm] os: [linux] + '@esbuild/linux-ia32@0.18.20': + resolution: {integrity: sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-ia32@0.25.12': + resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + '@esbuild/linux-ia32@0.27.3': resolution: {integrity: sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==} engines: {node: '>=18'} cpu: [ia32] os: [linux] + '@esbuild/linux-loong64@0.18.20': + resolution: {integrity: sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-loong64@0.25.12': + resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + '@esbuild/linux-loong64@0.27.3': resolution: {integrity: sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==} engines: {node: '>=18'} cpu: [loong64] os: [linux] + '@esbuild/linux-mips64el@0.18.20': + resolution: {integrity: sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-mips64el@0.25.12': + resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + '@esbuild/linux-mips64el@0.27.3': resolution: {integrity: sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] + '@esbuild/linux-ppc64@0.18.20': + resolution: {integrity: sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-ppc64@0.25.12': + resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + '@esbuild/linux-ppc64@0.27.3': resolution: {integrity: sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] + '@esbuild/linux-riscv64@0.18.20': + resolution: {integrity: sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-riscv64@0.25.12': + resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + '@esbuild/linux-riscv64@0.27.3': resolution: {integrity: sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] + '@esbuild/linux-s390x@0.18.20': + resolution: {integrity: sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-s390x@0.25.12': + resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + '@esbuild/linux-s390x@0.27.3': resolution: {integrity: sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==} engines: {node: '>=18'} cpu: [s390x] os: [linux] + '@esbuild/linux-x64@0.18.20': + resolution: {integrity: sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + + '@esbuild/linux-x64@0.25.12': + resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + '@esbuild/linux-x64@0.27.3': resolution: {integrity: sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==} engines: {node: '>=18'} cpu: [x64] os: [linux] + '@esbuild/netbsd-arm64@0.25.12': + resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + '@esbuild/netbsd-arm64@0.27.3': resolution: {integrity: sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] + '@esbuild/netbsd-x64@0.18.20': + resolution: {integrity: sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.25.12': + resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + '@esbuild/netbsd-x64@0.27.3': resolution: {integrity: sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] + '@esbuild/openbsd-arm64@0.25.12': + resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + '@esbuild/openbsd-arm64@0.27.3': resolution: {integrity: sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] + '@esbuild/openbsd-x64@0.18.20': + resolution: {integrity: sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.25.12': + resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + '@esbuild/openbsd-x64@0.27.3': resolution: {integrity: sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] + '@esbuild/openharmony-arm64@0.25.12': + resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + '@esbuild/openharmony-arm64@0.27.3': resolution: {integrity: sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==} engines: {node: '>=18'} cpu: [arm64] os: [openharmony] + '@esbuild/sunos-x64@0.18.20': + resolution: {integrity: sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + + '@esbuild/sunos-x64@0.25.12': + resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + '@esbuild/sunos-x64@0.27.3': resolution: {integrity: sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==} engines: {node: '>=18'} cpu: [x64] os: [sunos] + '@esbuild/win32-arm64@0.18.20': + resolution: {integrity: sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-arm64@0.25.12': + resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + '@esbuild/win32-arm64@0.27.3': resolution: {integrity: sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==} engines: {node: '>=18'} cpu: [arm64] os: [win32] + '@esbuild/win32-ia32@0.18.20': + resolution: {integrity: sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-ia32@0.25.12': + resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + '@esbuild/win32-ia32@0.27.3': resolution: {integrity: sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==} engines: {node: '>=18'} cpu: [ia32] os: [win32] + '@esbuild/win32-x64@0.18.20': + resolution: {integrity: sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + + '@esbuild/win32-x64@0.25.12': + resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + '@esbuild/win32-x64@0.27.3': resolution: {integrity: sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==} engines: {node: '>=18'} @@ -613,6 +930,18 @@ packages: react: '>=16.8.0' react-dom: '>=16.8.0' + '@floating-ui/react-dom@2.1.8': + resolution: {integrity: sha512-cC52bHwM/n/CxS87FH0yWdngEZrjdtLW/qVruo68qg+prK7ZQ4YGdut2GyDVpoGeAYe/h899rVeOVm6Oi40k2A==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + + '@floating-ui/react@0.27.19': + resolution: {integrity: sha512-31B8h5mm8YxotlE7/AU/PhNAl8eWxAmjL/v2QOxroDNkTFLk3Uu82u63N3b6TXa4EGJeeZLVcd/9AlNlVqzeog==} + peerDependencies: + react: '>=17.0.0' + react-dom: '>=17.0.0' + '@floating-ui/react@0.27.3': resolution: {integrity: sha512-CLHnes3ixIFFKVQDdICjel8muhFLOBdQH7fgtHNPY8UbCNqbeKZ262G7K66lGQOUQWWnYocf7ZbUsLJgGfsLHg==} peerDependencies: @@ -622,9 +951,6 @@ packages: '@floating-ui/utils@0.2.11': resolution: {integrity: sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==} - '@googlemaps/js-api-loader@1.16.10': - resolution: {integrity: sha512-c2erv2k7P2ilYzMmtYcMgAR21AULosQuUHJbStnrvRk2dG93k5cqptDrh9A8p+ZNlyhiqEOgHW7N9PAizdUM7Q==} - '@humanfs/core@0.19.1': resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} engines: {node: '>=18.18.0'} @@ -809,6 +1135,9 @@ packages: '@jridgewell/sourcemap-codec@1.5.0': resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + '@jridgewell/trace-mapping@0.3.25': resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} @@ -818,6 +1147,134 @@ packages: '@keyv/serialize@1.1.1': resolution: {integrity: sha512-dXn3FZhPv0US+7dtJsIi2R+c7qWYiReoEh5zUntWCf4oSpMNib8FDhSoed6m3QyZdx5hK7iLFkYk3rNxwt8vTA==} + '@lexical/clipboard@0.41.0': + resolution: {integrity: sha512-Ex5lPkb4NBBX1DCPzOAIeHBJFH1bJcmATjREaqpnTfxCbuOeQkt44wchezUA0oDl+iAxNZ3+pLLWiUju9icoSA==} + + '@lexical/code@0.41.0': + resolution: {integrity: sha512-0hoNi1KC9/N3SBOGcOcFqnT0OpwmcRRAhfxTKMGqfCtCvAMzULVwZ8RWc9/NV9bKYESgBTW5D9xkDANP2mspHg==} + + '@lexical/devtools-core@0.41.0': + resolution: {integrity: sha512-FzJtluBhBc8bKS11TUZe72KoZN/hnzIyiiM0SPJAsPwGpoXuM01jqpXQGybWf/1bWB+bmmhOae7O4Nywi/Csuw==} + peerDependencies: + react: '>=17.x' + react-dom: '>=17.x' + + '@lexical/dragon@0.41.0': + resolution: {integrity: sha512-gBEqkk8Q6ZPruvDaRcOdF1EK9suCVBODzOCcR+EnoJTaTjfDkCM7pkPAm4w90Wa1wCZEtFHvCfas+jU9MDSumg==} + + '@lexical/extension@0.41.0': + resolution: {integrity: sha512-sF4SPiP72yXvIGchmmIZ7Yg2XZTxNLOpFEIIzdqG7X/1fa1Ham9P/T7VbrblWpF6Ei5LJtK9JgNVB0hb4l3o1g==} + + '@lexical/hashtag@0.41.0': + resolution: {integrity: sha512-tFWM74RW4KU0E/sj2aowfWl26vmLUTp331CgVESnhQKcZBfT40KJYd57HEqBDTfQKn4MUhylQCCA0hbpw6EeFQ==} + + '@lexical/headless@0.41.0': + resolution: {integrity: sha512-MH8oDuUKdM/Jq0c9vlEEkCL9pEQg4SwyrABBGIbFf+87VBJ5EWDdG9g1vJq7fKSDxfhFux7F5+i+zgUnxOQR/g==} + + '@lexical/history@0.41.0': + resolution: {integrity: sha512-kGoVWsiOn62+RMjRolRa+NXZl8jFwxav6GNDiHH8yzivtoaH8n1SwUfLJELXCzeqzs81HySqD4q30VLJVTGoDg==} + + '@lexical/html@0.41.0': + resolution: {integrity: sha512-3RyZy+H/IDKz2D66rNN/NqYx87xVFrngfEbyu1OWtbY963RUFnopiVHCQvsge/8kT04QSZ7U/DzjVFqeNS6clg==} + + '@lexical/link@0.41.0': + resolution: {integrity: sha512-Rjtx5cGWAkKcnacncbVsZ1TqRnUB2Wm4eEVKpaAEG41+kHgqghzM2P+UGT15yROroxJu8KvAC9ISiYFiU4XE1w==} + + '@lexical/list@0.41.0': + resolution: {integrity: sha512-RXvB+xcbzVoQLGRDOBRCacztG7V+bI95tdoTwl8pz5xvgPtAaRnkZWMDP+yMNzMJZsqEChdtpxbf0NgtMkun6g==} + + '@lexical/mark@0.41.0': + resolution: {integrity: sha512-UO5WVs9uJAYIKHSlYh4Z1gHrBBchTOi21UCYBIZ7eAs4suK84hPzD+3/LAX5CB7ZltL6ke5Sly3FOwNXv/wfpA==} + + '@lexical/markdown@0.41.0': + resolution: {integrity: sha512-bzI73JMXpjGFhqUWNV6KqfjWcgAWzwFT+J3RHtbCF5rysC8HLldBYojOgAAtPfXqfxyv2mDzsY7SoJ75s9uHZA==} + + '@lexical/offset@0.41.0': + resolution: {integrity: sha512-2RHBXZqC8gm3X9C0AyRb0M8w7zJu5dKiasrif+jSKzsxPjAUeF1m95OtIOsWs1XLNUgASOSUqGovDZxKJslZfA==} + + '@lexical/overflow@0.41.0': + resolution: {integrity: sha512-Iy6ZiJip8X14EBYt1zKPOrXyQ4eG9JLBEoPoSVBTiSbVd+lYicdUvaOThT0k0/qeVTN9nqTaEltBjm56IrVKCQ==} + + '@lexical/plain-text@0.41.0': + resolution: {integrity: sha512-HIsGgmFUYRUNNyvckun33UQfU7LRzDlxymHUq67+Bxd5bXqdZOrStEKJXuDX+LuLh/GXZbaWNbDLqwLBObfbQg==} + + '@lexical/react@0.41.0': + resolution: {integrity: sha512-7+GUdZUm6sofWm+zdsWAs6cFBwKNsvsHezZTrf6k8jrZxL461ZQmbz/16b4DvjCGL9r5P1fR7md9/LCmk8TiCg==} + peerDependencies: + react: '>=17.x' + react-dom: '>=17.x' + + '@lexical/rich-text@0.41.0': + resolution: {integrity: sha512-yUcr7ZaaVTZNi8bow4CK1M8jy2qyyls1Vr+5dVjwBclVShOL/F/nFyzBOSb6RtXXRbd3Ahuk9fEleppX/RNIdw==} + + '@lexical/selection@0.41.0': + resolution: {integrity: sha512-1s7/kNyRzcv5uaTwsUL28NpiisqTf5xZ1zNukLsCN1xY+TWbv9RE9OxIv+748wMm4pxNczQe/UbIBODkbeknLw==} + + '@lexical/table@0.41.0': + resolution: {integrity: sha512-d3SPThBAr+oZ8O74TXU0iXM3rLbrAVC7/HcOnSAq7/AhWQW8yMutT51JQGN+0fMLP9kqoWSAojNtkdvzXfU/+A==} + + '@lexical/text@0.41.0': + resolution: {integrity: sha512-gGA+Anc7ck110EXo4KVKtq6Ui3M7Vz3OpGJ4QE6zJHWW8nV5h273koUGSutAMeoZgRVb6t01Izh3ORoFt/j1CA==} + + '@lexical/utils@0.41.0': + resolution: {integrity: sha512-Wlsokr5NQCq83D+7kxZ9qs5yQ3dU3Qaf2M+uXxLRoPoDaXqW8xTWZq1+ZFoEzsHzx06QoPa4Vu/40BZR91uQPg==} + + '@lexical/yjs@0.41.0': + resolution: {integrity: sha512-PaKTxSbVC4fpqUjQ7vUL9RkNF1PjL8TFl5jRe03PqoPYpE33buf3VXX6+cOUEfv9+uknSqLCPHoBS/4jN3a97w==} + peerDependencies: + yjs: '>=13.5.22' + + '@libsql/client@0.14.0': + resolution: {integrity: sha512-/9HEKfn6fwXB5aTEEoMeFh4CtG0ZzbncBb1e++OCdVpgKZ/xyMsIVYXm0w7Pv4RUel803vE6LwniB3PqD72R0Q==} + + '@libsql/core@0.14.0': + resolution: {integrity: sha512-nhbuXf7GP3PSZgdCY2Ecj8vz187ptHlZQ0VRc751oB2C1W8jQUXKKklvt7t1LJiUTQBVJuadF628eUk+3cRi4Q==} + + '@libsql/darwin-arm64@0.4.7': + resolution: {integrity: sha512-yOL742IfWUlUevnI5PdnIT4fryY3LYTdLm56bnY0wXBw7dhFcnjuA7jrH3oSVz2mjZTHujxoITgAE7V6Z+eAbg==} + cpu: [arm64] + os: [darwin] + + '@libsql/darwin-x64@0.4.7': + resolution: {integrity: sha512-ezc7V75+eoyyH07BO9tIyJdqXXcRfZMbKcLCeF8+qWK5nP8wWuMcfOVywecsXGRbT99zc5eNra4NEx6z5PkSsA==} + cpu: [x64] + os: [darwin] + + '@libsql/hrana-client@0.7.0': + resolution: {integrity: sha512-OF8fFQSkbL7vJY9rfuegK1R7sPgQ6kFMkDamiEccNUvieQ+3urzfDFI616oPl8V7T9zRmnTkSjMOImYCAVRVuw==} + + '@libsql/isomorphic-fetch@0.3.1': + resolution: {integrity: sha512-6kK3SUK5Uu56zPq/Las620n5aS9xJq+jMBcNSOmjhNf/MUvdyji4vrMTqD7ptY7/4/CAVEAYDeotUz60LNQHtw==} + engines: {node: '>=18.0.0'} + + '@libsql/isomorphic-ws@0.1.5': + resolution: {integrity: sha512-DtLWIH29onUYR00i0GlQ3UdcTRC6EP4u9w/h9LxpUZJWRMARk6dQwZ6Jkd+QdwVpuAOrdxt18v0K2uIYR3fwFg==} + + '@libsql/linux-arm64-gnu@0.4.7': + resolution: {integrity: sha512-WlX2VYB5diM4kFfNaYcyhw5y+UJAI3xcMkEUJZPtRDEIu85SsSFrQ+gvoKfcVh76B//ztSeEX2wl9yrjF7BBCA==} + cpu: [arm64] + os: [linux] + + '@libsql/linux-arm64-musl@0.4.7': + resolution: {integrity: sha512-6kK9xAArVRlTCpWeqnNMCoXW1pe7WITI378n4NpvU5EJ0Ok3aNTIC2nRPRjhro90QcnmLL1jPcrVwO4WD1U0xw==} + cpu: [arm64] + os: [linux] + + '@libsql/linux-x64-gnu@0.4.7': + resolution: {integrity: sha512-CMnNRCmlWQqqzlTw6NeaZXzLWI8bydaXDke63JTUCvu8R+fj/ENsLrVBtPDlxQ0wGsYdXGlrUCH8Qi9gJep0yQ==} + cpu: [x64] + os: [linux] + + '@libsql/linux-x64-musl@0.4.7': + resolution: {integrity: sha512-nI6tpS1t6WzGAt1Kx1n1HsvtBbZ+jHn0m7ogNNT6pQHZQj7AFFTIMeDQw/i/Nt5H38np1GVRNsFe99eSIMs9XA==} + cpu: [x64] + os: [linux] + + '@libsql/win32-x64-msvc@0.4.7': + resolution: {integrity: sha512-7pJzOWzPm6oJUxml+PCDRzYQ4A1hTMHAciTAHfFK4fkbDZX33nWPVG7Y3vqdKtslcwAzwmrNDc6sXy2nwWnbiw==} + cpu: [x64] + os: [win32] + '@monaco-editor/loader@1.5.0': resolution: {integrity: sha512-hKoGSM+7aAc7eRTRjpqAZucPmoNOC4UUbknb/VNoTkEIkCPhqV8LfbsgM1webRM7S/z21eHEx9Fkwx8Z/C/+Xw==} @@ -944,6 +1401,15 @@ packages: resolution: {integrity: sha512-xJIPs+bYuc9ASBl+cvGsKbGrJmS6fAKaSZCnT0lhahT5rhA2VVy9/EcIgd2JhtEuFOJNx7UHNn/qiTPTY4nrQw==} engines: {node: '>= 10'} + '@napi-rs/wasm-runtime@1.1.2': + resolution: {integrity: sha512-sNXv5oLJ7ob93xkZ1XnxisYhGYXfaG9f65/ZgYuAu3qt7b3NadcOEhLvx28hv31PgX8SZJRYrAIPQilQmFpLVw==} + peerDependencies: + '@emnapi/core': ^1.7.1 + '@emnapi/runtime': ^1.7.1 + + '@neon-rs/load@0.0.4': + resolution: {integrity: sha512-kTPhdZyTQxB+2wpiRcFWrDcejc4JI6tkPuS7UZCG4l6Zvc5kU/gGQ/ozvHTh1XR5tS+UlfAfGuPajjzQjCiHCw==} + '@next/env@15.4.11': resolution: {integrity: sha512-mIYp/091eYfPFezKX7ZPTWqrmSXq+ih6+LcUyKvLmeLQGhlPtot33kuEOd4U+xAA7sFfj21+OtCpIZx0g5SpvQ==} @@ -1014,11 +1480,24 @@ packages: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} + '@oxc-project/types@0.122.0': + resolution: {integrity: sha512-oLAl5kBpV4w69UtFZ9xqcmTi+GENWOcPF7FCrczTiBbmC0ibXxCwyvZGbO39rCVEuLGAZM84DH0pUIyyv/YJzA==} + '@payloadcms/db-mongodb@3.81.0': resolution: {integrity: sha512-6joKE/ytLOOuTtVc6N7qxbCLIbkEyR5Oi8CNVE0vqMoxBDz9/lLzTcm/9zpI9vzo0z+StOpytq9zx+GcxUOdGA==} peerDependencies: payload: 3.81.0 + '@payloadcms/db-sqlite@3.81.0': + resolution: {integrity: sha512-TgRUhl1mlPIa5O0Gw1caaXtfF319bZ798oRFNG0sU5vroR1PZIh3Cm7Wjvht/kAryu5lAVJo6V4aEerftGkxUw==} + peerDependencies: + payload: 3.81.0 + + '@payloadcms/drizzle@3.81.0': + resolution: {integrity: sha512-0hheoLFbxk1piSLtMaiTUc34HOhS3GOMnGw2hYJkYckrFMTjcJjM2nB4IEbRmk94CueS4LGitSt8xu7XwdZbkA==} + peerDependencies: + payload: 3.81.0 + '@payloadcms/eslint-config@3.28.0': resolution: {integrity: sha512-BiGtowdT4uLdGaM1yxP3oZRZrRMi27FiIU2eJuRqiGqdCVfKYRtlNAHq5knf2ExmdV/U3yZivH4linR2DNT2eA==} @@ -1040,6 +1519,17 @@ packages: next: '>=15.2.9 <15.3.0 || >=15.3.9 <15.4.0 || >=15.4.11 <15.5.0 || >=16.2.0-canary.10 <17.0.0' payload: 3.81.0 + '@payloadcms/richtext-lexical@3.81.0': + resolution: {integrity: sha512-qpAiWb2M9iARp8H/C1ewi9WNyTSpwId9IGFfHTDuU1oDL8Ke53sY9svUG+L7BViEuxKivWaUwfdo35RIrwPNQA==} + engines: {node: ^18.20.2 || >=20.9.0} + peerDependencies: + '@faceless-ui/modal': 3.0.0 + '@faceless-ui/scroll-info': 2.0.0 + '@payloadcms/next': 3.81.0 + payload: 3.81.0 + react: ^19.0.1 || ^19.1.2 || ^19.2.1 + react-dom: ^19.0.1 || ^19.1.2 || ^19.2.1 + '@payloadcms/translations@3.81.0': resolution: {integrity: sha512-ruFKoYrTErl3Va5rOAyKn7Txh7wr6ZRw/KUZdj7YPOjI4LQpbtWYl3IQtcnS36x674GjeJOeWuEZJ50Xs3ofrQ==} @@ -1055,6 +1545,107 @@ packages: '@pinojs/redact@0.4.0': resolution: {integrity: sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==} + '@preact/signals-core@1.14.1': + resolution: {integrity: sha512-vxPpfXqrwUe9lpjqfYNjAF/0RF/eFGeLgdJzdmIIZjpOnTmGmAB4BjWone562mJGMRP4frU6iZ6ei3PDsu52Ng==} + + '@rolldown/binding-android-arm64@1.0.0-rc.12': + resolution: {integrity: sha512-pv1y2Fv0JybcykuiiD3qBOBdz6RteYojRFY1d+b95WVuzx211CRh+ytI/+9iVyWQ6koTh5dawe4S/yRfOFjgaA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + + '@rolldown/binding-darwin-arm64@1.0.0-rc.12': + resolution: {integrity: sha512-cFYr6zTG/3PXXF3pUO+umXxt1wkRK/0AYT8lDwuqvRC+LuKYWSAQAQZjCWDQpAH172ZV6ieYrNnFzVVcnSflAg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + + '@rolldown/binding-darwin-x64@1.0.0-rc.12': + resolution: {integrity: sha512-ZCsYknnHzeXYps0lGBz8JrF37GpE9bFVefrlmDrAQhOEi4IOIlcoU1+FwHEtyXGx2VkYAvhu7dyBf75EJQffBw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + + '@rolldown/binding-freebsd-x64@1.0.0-rc.12': + resolution: {integrity: sha512-dMLeprcVsyJsKolRXyoTH3NL6qtsT0Y2xeuEA8WQJquWFXkEC4bcu1rLZZSnZRMtAqwtrF/Ib9Ddtpa/Gkge9Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.12': + resolution: {integrity: sha512-YqWjAgGC/9M1lz3GR1r1rP79nMgo3mQiiA+Hfo+pvKFK1fAJ1bCi0ZQVh8noOqNacuY1qIcfyVfP6HoyBRZ85Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.12': + resolution: {integrity: sha512-/I5AS4cIroLpslsmzXfwbe5OmWvSsrFuEw3mwvbQ1kDxJ822hFHIx+vsN/TAzNVyepI/j/GSzrtCIwQPeKCLIg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-arm64-musl@1.0.0-rc.12': + resolution: {integrity: sha512-V6/wZztnBqlx5hJQqNWwFdxIKN0m38p8Jas+VoSfgH54HSj9tKTt1dZvG6JRHcjh6D7TvrJPWFGaY9UBVOaWPw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.12': + resolution: {integrity: sha512-AP3E9BpcUYliZCxa3w5Kwj9OtEVDYK6sVoUzy4vTOJsjPOgdaJZKFmN4oOlX0Wp0RPV2ETfmIra9x1xuayFB7g==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.12': + resolution: {integrity: sha512-nWwpvUSPkoFmZo0kQazZYOrT7J5DGOJ/+QHHzjvNlooDZED8oH82Yg67HvehPPLAg5fUff7TfWFHQS8IV1n3og==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-x64-gnu@1.0.0-rc.12': + resolution: {integrity: sha512-RNrafz5bcwRy+O9e6P8Z/OCAJW/A+qtBczIqVYwTs14pf4iV1/+eKEjdOUta93q2TsT/FI0XYDP3TCky38LMAg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-x64-musl@1.0.0-rc.12': + resolution: {integrity: sha512-Jpw/0iwoKWx3LJ2rc1yjFrj+T7iHZn2JDg1Yny1ma0luviFS4mhAIcd1LFNxK3EYu3DHWCps0ydXQ5i/rrJ2ig==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [musl] + + '@rolldown/binding-openharmony-arm64@1.0.0-rc.12': + resolution: {integrity: sha512-vRugONE4yMfVn0+7lUKdKvN4D5YusEiPilaoO2sgUWpCvrncvWgPMzK00ZFFJuiPgLwgFNP5eSiUlv2tfc+lpA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + + '@rolldown/binding-wasm32-wasi@1.0.0-rc.12': + resolution: {integrity: sha512-ykGiLr/6kkiHc0XnBfmFJuCjr5ZYKKofkx+chJWDjitX+KsJuAmrzWhwyOMSHzPhzOHOy7u9HlFoa5MoAOJ/Zg==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + + '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.12': + resolution: {integrity: sha512-5eOND4duWkwx1AzCxadcOrNeighiLwMInEADT0YM7xeEOOFcovWZCq8dadXgcRHSf3Ulh1kFo/qvzoFiCLOL1Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + + '@rolldown/binding-win32-x64-msvc@1.0.0-rc.12': + resolution: {integrity: sha512-PyqoipaswDLAZtot351MLhrlrh6lcZPo2LSYE+VDxbVk24LVKAGOuE4hb8xZQmrPAuEtTZW8E6D2zc5EUZX4Lw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + + '@rolldown/pluginutils@1.0.0-rc.12': + resolution: {integrity: sha512-HHMwmarRKvoFsJorqYlFeFRzXZqCt2ETQlEDOb9aqssrnVBB1/+xgTGtuTrIk5vzLNX1MjMtTf7W9z3tsSbrxw==} + '@sec-ant/readable-stream@0.4.1': resolution: {integrity: sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==} @@ -1233,6 +1824,9 @@ packages: resolution: {integrity: sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==} engines: {node: '>=16.0.0'} + '@standard-schema/spec@1.1.0': + resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} + '@swc/cli@0.8.1': resolution: {integrity: sha512-L+ACCGHCiS0VqHVep/INLVnvRvJ2XooQFLZq4L8snhxw1jsqz+XRcY313UsyPVturPPE1shW3jic7rt3qEQTSQ==} engines: {node: '>= 20.19.0'} @@ -1347,21 +1941,42 @@ packages: '@tokenizer/token@0.3.0': resolution: {integrity: sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==} + '@tybys/wasm-util@0.10.1': + resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} + + '@types/acorn@4.0.6': + resolution: {integrity: sha512-veQTnWP+1D/xbxVrPC3zHnCZRjSrKfhbMUlEA43iMZLu7EsnTtkJklIuwrCPbOi8YkvDQAiW05VQQFvvz9oieQ==} + '@types/busboy@1.5.4': resolution: {integrity: sha512-kG7WrUuAKK0NoyxfQHsVE6j1m01s6kMma64E+OZenQABMQyTJop1DumUWcLwAQ2JzpefU7PDYoRDKl8uZosFjw==} + '@types/chai@5.2.3': + resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} + + '@types/debug@4.1.13': + resolution: {integrity: sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==} + + '@types/deep-eql@4.0.2': + resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} + '@types/doctrine@0.0.9': resolution: {integrity: sha512-eOIHzCUSH7SMfonMG1LsC2f8vxBFtho6NGBznK41R84YzPuvSBzrhEps33IsQiOW9+VL6NQ9DbjQJznk/S4uRA==} '@types/eslint@9.6.1': resolution: {integrity: sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==} + '@types/estree-jsx@1.0.5': + resolution: {integrity: sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==} + '@types/estree@1.0.8': resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} '@types/google.maps@3.58.1': resolution: {integrity: sha512-X9QTSvGJ0nCfMzYOnaVs/k6/4L+7F5uCS+4iUmkLEls6J9S/Phv+m/i3mDeyc49ZBgwab3EFO1HEoBY7k98EGQ==} + '@types/hast@3.0.4': + resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} + '@types/http-cache-semantics@4.2.0': resolution: {integrity: sha512-L3LgimLHXtGkWikKnsPg0/VFx9OGZaC+eN1u4r+OB1XRqH3meBIAVC2zr1WdMH+RHmnRkqliQAOHNJ/E0j/e0Q==} @@ -1371,6 +1986,12 @@ packages: '@types/lodash@4.17.13': resolution: {integrity: sha512-lfx+dftrEZcdBPczf9d0Qv0x+j/rfNCMuC6OcfXmO8gkfeNAY88PgKUbvG56whcN23gc27yenwF6oJZXGFpYxg==} + '@types/mdast@4.0.4': + resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} + + '@types/ms@2.1.0': + resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} + '@types/node@22.10.1': resolution: {integrity: sha512-qKgsUwfHZV2WCWLAnVP1JqnpE6Im6h3Y0+fYgMTasNQ7V++CBX5OT1as0g0f+OyubbFqhf6XVNIsmN4IIhEgGQ==} @@ -1390,12 +2011,27 @@ packages: '@types/react@19.2.14': resolution: {integrity: sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==} + '@types/unist@2.0.11': + resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==} + + '@types/unist@3.0.3': + resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} + + '@types/uuid@10.0.0': + resolution: {integrity: sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==} + '@types/webidl-conversions@7.0.3': resolution: {integrity: sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==} + '@types/whatwg-mimetype@3.0.2': + resolution: {integrity: sha512-c2AKvDT8ToxLIOUlN51gTiHXflsfIFisS4pO7pDPoKouJCESkhZnEy623gwP9laCy5lnLDAw1vAzu2vM2YLOrA==} + '@types/whatwg-url@11.0.5': resolution: {integrity: sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ==} + '@types/ws@8.18.1': + resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==} + '@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} @@ -1487,6 +2123,35 @@ packages: resolution: {integrity: sha512-XJ9UD9+bbDo4a4epraTwG3TsNPeiB9aShrUneAVXy8q4LuwowN+qu89/6ByLMINqvIMeI9H9hOHQtg/ijrYXzQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@vitest/expect@4.1.2': + resolution: {integrity: sha512-gbu+7B0YgUJ2nkdsRJrFFW6X7NTP44WlhiclHniUhxADQJH5Szt9mZ9hWnJPJ8YwOK5zUOSSlSvyzRf0u1DSBQ==} + + '@vitest/mocker@4.1.2': + resolution: {integrity: sha512-Ize4iQtEALHDttPRCmN+FKqOl2vxTiNUhzobQFFt/BM1lRUTG7zRCLOykG/6Vo4E4hnUdfVLo5/eqKPukcWW7Q==} + peerDependencies: + msw: ^2.4.9 + vite: ^6.0.0 || ^7.0.0 || ^8.0.0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + + '@vitest/pretty-format@4.1.2': + resolution: {integrity: sha512-dwQga8aejqeuB+TvXCMzSQemvV9hNEtDDpgUKDzOmNQayl2OG241PSWeJwKRH3CiC+sESrmoFd49rfnq7T4RnA==} + + '@vitest/runner@4.1.2': + resolution: {integrity: sha512-Gr+FQan34CdiYAwpGJmQG8PgkyFVmARK8/xSijia3eTFgVfpcpztWLuP6FttGNfPLJhaZVP/euvujeNYar36OQ==} + + '@vitest/snapshot@4.1.2': + resolution: {integrity: sha512-g7yfUmxYS4mNxk31qbOYsSt2F4m1E02LFqO53Xpzg3zKMhLAPZAjjfyl9e6z7HrW6LvUdTwAQR3HHfLjpko16A==} + + '@vitest/spy@4.1.2': + resolution: {integrity: sha512-DU4fBnbVCJGNBwVA6xSToNXrkZNSiw59H8tcuUspVMsBDBST4nfvsPsEHDHGtWRRnqBERBQu7TrTKskmjqTXKA==} + + '@vitest/utils@4.1.2': + resolution: {integrity: sha512-xw2/TiX82lQHA06cgbqRKFb5lCAy3axQ4H4SoUFhUsg+wztiet+co86IAMDtF6Vm1hc7J6j09oh/rgDn+JdKIQ==} + '@xhmikosr/archive-type@8.0.1': resolution: {integrity: sha512-toXuiWChyfOpEiCPsIw6HGHaNji5LVkvB6EREL548vGWr+hGaehwxG4LzN20vm9aGFXwnA/Jty8yW2/SmV+1zQ==} engines: {node: '>=20'} @@ -1585,6 +2250,10 @@ packages: resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==} engines: {node: '>= 0.4'} + assertion-error@2.0.1: + resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} + engines: {node: '>=12'} + ast-types-flow@0.0.8: resolution: {integrity: sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==} @@ -1683,6 +2352,9 @@ packages: buffer-crc32@0.2.13: resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==} + buffer-from@1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + buffer@5.7.1: resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} @@ -1721,10 +2393,29 @@ packages: caniuse-lite@1.0.30001760: resolution: {integrity: sha512-7AAMPcueWELt1p3mi13HR/LHH0TJLT11cnwDJEs3xA4+CK/PLKeO9Kl1oru24htkyUKtkGCvAx4ohB0Ttry8Dw==} + ccount@2.0.1: + resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} + + chai@6.2.2: + resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} + engines: {node: '>=18'} + chalk@4.1.2: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} + character-entities-html4@2.1.0: + resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==} + + character-entities-legacy@3.0.0: + resolution: {integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==} + + character-entities@2.0.2: + resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==} + + character-reference-invalid@2.0.1: + resolution: {integrity: sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==} + charenc@0.0.2: resolution: {integrity: sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==} @@ -1791,6 +2482,9 @@ packages: convert-source-map@1.9.0: resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + copyfiles@2.4.1: resolution: {integrity: sha512-fereAvAvxDrQDOXybk3Qu3dPbOoKoysFMWtkY3mv5BsL8//OSZVL5DCLYqgRfY5cWirgRzlC+WSrxp6Bo3eNZg==} hasBin: true @@ -1821,12 +2515,19 @@ packages: cssfilter@0.0.10: resolution: {integrity: sha512-FAaLDaplstoRsDR8XGYH51znUN0UY7nMc6Z9/fvE8EXGwvJE9hu7W2vHwx1+bd6gCYnln9nLbzxFTrcO9YQDZw==} + csstype@3.1.3: + resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + csstype@3.2.3: resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} damerau-levenshtein@1.0.8: resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==} + data-uri-to-buffer@4.0.1: + resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==} + engines: {node: '>= 12'} + data-view-buffer@1.0.2: resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==} engines: {node: '>= 0.4'} @@ -1868,6 +2569,9 @@ packages: supports-color: optional: true + decode-named-character-reference@1.3.0: + resolution: {integrity: sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==} + decompress-response@10.0.0: resolution: {integrity: sha512-oj7KWToJuuxlPr7VV0vabvxEIiqNMo+q0NueIiL3XhtwC6FVOX7Hr1c0C4eD0bmf7Zr+S/dSf2xvkH3Ad6sU3Q==} engines: {node: '>=20'} @@ -1895,10 +2599,17 @@ packages: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} + detect-libc@2.0.2: + resolution: {integrity: sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==} + engines: {node: '>=8'} + detect-libc@2.1.2: resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} + devlop@1.1.0: + resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} + doctrine@3.0.0: resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} engines: {node: '>=6.0.0'} @@ -1910,6 +2621,102 @@ packages: resolution: {integrity: sha512-k8DaKGP6r1G30Lx8V4+pCsLzKr8vLmV2paqEj1Y55GdAgJuIqpRp5FfajGF8KtwMxCz9qJc6wUIJnm053d/WCw==} engines: {node: '>=12'} + drizzle-kit@0.31.7: + resolution: {integrity: sha512-hOzRGSdyKIU4FcTSFYGKdXEjFsncVwHZ43gY3WU5Bz9j5Iadp6Rh6hxLSQ1IWXpKLBKt/d5y1cpSPcV+FcoQ1A==} + hasBin: true + + drizzle-orm@0.44.7: + resolution: {integrity: sha512-quIpnYznjU9lHshEOAYLoZ9s3jweleHlZIAWR/jX9gAWNg/JhQ1wj0KGRf7/Zm+obRrYd9GjPVJg790QY9N5AQ==} + peerDependencies: + '@aws-sdk/client-rds-data': '>=3' + '@cloudflare/workers-types': '>=4' + '@electric-sql/pglite': '>=0.2.0' + '@libsql/client': '>=0.10.0' + '@libsql/client-wasm': '>=0.10.0' + '@neondatabase/serverless': '>=0.10.0' + '@op-engineering/op-sqlite': '>=2' + '@opentelemetry/api': ^1.4.1 + '@planetscale/database': '>=1.13' + '@prisma/client': '*' + '@tidbcloud/serverless': '*' + '@types/better-sqlite3': '*' + '@types/pg': '*' + '@types/sql.js': '*' + '@upstash/redis': '>=1.34.7' + '@vercel/postgres': '>=0.8.0' + '@xata.io/client': '*' + better-sqlite3: '>=7' + bun-types: '*' + expo-sqlite: '>=14.0.0' + gel: '>=2' + knex: '*' + kysely: '*' + mysql2: '>=2' + pg: '>=8' + postgres: '>=3' + prisma: '*' + sql.js: '>=1' + sqlite3: '>=5' + peerDependenciesMeta: + '@aws-sdk/client-rds-data': + optional: true + '@cloudflare/workers-types': + optional: true + '@electric-sql/pglite': + optional: true + '@libsql/client': + optional: true + '@libsql/client-wasm': + optional: true + '@neondatabase/serverless': + optional: true + '@op-engineering/op-sqlite': + optional: true + '@opentelemetry/api': + optional: true + '@planetscale/database': + optional: true + '@prisma/client': + optional: true + '@tidbcloud/serverless': + optional: true + '@types/better-sqlite3': + optional: true + '@types/pg': + optional: true + '@types/sql.js': + optional: true + '@upstash/redis': + optional: true + '@vercel/postgres': + optional: true + '@xata.io/client': + optional: true + better-sqlite3: + optional: true + bun-types: + optional: true + expo-sqlite: + optional: true + gel: + optional: true + knex: + optional: true + kysely: + optional: true + mysql2: + optional: true + pg: + optional: true + postgres: + optional: true + prisma: + optional: true + sql.js: + optional: true + sqlite3: + optional: true + dunder-proto@1.0.1: resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} engines: {node: '>= 0.4'} @@ -1927,6 +2734,10 @@ packages: resolution: {integrity: sha512-Qohcme7V1inbAfvjItgw0EaxVX5q2rdVEZHRBrEQdRZTssLDGsL8Lwrznl8oQ/6kuTJONLaDcGjkNP247XEhcA==} engines: {node: '>=10.13.0'} + entities@7.0.1: + resolution: {integrity: sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==} + engines: {node: '>=0.12'} + error-ex@1.3.2: resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} @@ -1942,6 +2753,9 @@ packages: resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} engines: {node: '>= 0.4'} + es-module-lexer@2.0.0: + resolution: {integrity: sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==} + es-object-atoms@1.1.1: resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} engines: {node: '>= 0.4'} @@ -1958,6 +2772,21 @@ packages: resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} engines: {node: '>= 0.4'} + esbuild-register@3.6.0: + resolution: {integrity: sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg==} + peerDependencies: + esbuild: '>=0.12 <1' + + esbuild@0.18.20: + resolution: {integrity: sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==} + engines: {node: '>=12'} + hasBin: true + + esbuild@0.25.12: + resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==} + engines: {node: '>=18'} + hasBin: true + esbuild@0.27.3: resolution: {integrity: sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==} engines: {node: '>=18'} @@ -1967,6 +2796,9 @@ packages: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} + escape-html@1.0.3: + resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} + escape-string-regexp@4.0.0: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} @@ -2151,6 +2983,15 @@ packages: resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} engines: {node: '>=4.0'} + estree-util-is-identifier-name@3.0.0: + resolution: {integrity: sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==} + + estree-util-visit@2.0.0: + resolution: {integrity: sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww==} + + estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + esutils@2.0.3: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} @@ -2166,6 +3007,10 @@ packages: resolution: {integrity: sha512-9Be3ZoN4LmYR90tUoVu2te2BsbzHfhJyfEiAVfz7N5/zv+jduIfLrV2xdQXOHbaD6KgpGdO9PRPM1Y4Q9QkPkA==} engines: {node: ^18.19.0 || >=20.5.0} + expect-type@1.3.0: + resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} + engines: {node: '>=12.0.0'} + ext-list@2.2.2: resolution: {integrity: sha512-u+SQgsubraE6zItfVA0tBuCBhfU9ogSRnsvygI7wht9TS510oLkBRXBsqopeUG/GBOIQyKZO9wjTqIu/sf5zFA==} engines: {node: '>=0.10.0'} @@ -2215,6 +3060,10 @@ packages: picomatch: optional: true + fetch-blob@3.2.0: + resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==} + engines: {node: ^12.20 || >= 14.13} + figures@6.1.0: resolution: {integrity: sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==} engines: {node: '>=18'} @@ -2268,6 +3117,10 @@ packages: resolution: {integrity: sha512-G6NsmEW15s0Uw9XnCg+33H3ViYRyiM0hMrMhhqQOR8NFc5GhYrI+6I3u7OTw7b91J2g8rtvMBZJDbcGb2YUniw==} engines: {node: '>= 18'} + formdata-polyfill@4.0.10: + resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==} + engines: {node: '>=12.20.0'} + fs.realpath@1.0.0: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} @@ -2389,6 +3242,10 @@ packages: resolution: {integrity: sha512-GGTKBX4SD7Wdb8mqeDLni2oaRGYQWjWHGKPQ24ZMnUtKfcsVoiv4uX8+LJr1K6U5VW2Lu1BwJnj7uiori0YtRw==} engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} + happy-dom@20.8.9: + resolution: {integrity: sha512-Tz23LR9T9jOGVZm2x1EPdXqwA37G/owYMxRwU0E4miurAtFsPMQ1d2Jc2okUaSjZqAFz2oEn3FLXC5a0a+siyA==} + engines: {node: '>=20.0.0'} + has-bigints@1.1.0: resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==} engines: {node: '>= 0.4'} @@ -2486,6 +3343,12 @@ packages: resolution: {integrity: sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==} engines: {node: '>= 10'} + is-alphabetical@2.0.1: + resolution: {integrity: sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==} + + is-alphanumerical@2.0.1: + resolution: {integrity: sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==} + is-array-buffer@3.0.5: resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} engines: {node: '>= 0.4'} @@ -2528,6 +3391,9 @@ packages: resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==} engines: {node: '>= 0.4'} + is-decimal@2.0.1: + resolution: {integrity: sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==} + is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} @@ -2548,6 +3414,9 @@ packages: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} + is-hexadecimal@2.0.1: + resolution: {integrity: sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==} + is-map@2.0.3: resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} engines: {node: '>= 0.4'} @@ -2636,6 +3505,9 @@ packages: resolution: {integrity: sha512-FFUtZMpoZ8RqHS3XeXEmHWLA4thH+ZxCv2lOiPIn1Xc7CxrqhWzNSDzD+/chS/zbYezmiwWLdQC09JdQKmthOw==} engines: {node: '>=20'} + isomorphic.js@0.2.5: + resolution: {integrity: sha512-PIeMbHqMt4DnUP3MA/Flc0HElYjMXArsw1qwJZcm9sqR8mq3l8NYizFMty0pWwE/tzIGH3EKK5+jes5mAr85yw==} + jose@5.10.0: resolution: {integrity: sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg==} @@ -2643,6 +3515,9 @@ packages: resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} engines: {node: '>=10'} + js-base64@3.7.8: + resolution: {integrity: sha512-hNngCeKxIUQiEUN3GPJOkz4wF/YvdUdbNL9hsBcMQTkKzboD7T/q3OYOuuPZLUE6dBxSGpwhk5mwuDud7JVAow==} + js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -2682,6 +3557,10 @@ packages: json-stable-stringify-without-jsonify@1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + jsox@1.2.121: + resolution: {integrity: sha512-9Ag50tKhpTwS6r5wh3MJSAvpSof0UBr39Pto8OnzFT32Z/pAbxAsKHzyvsyMEHVslELvHyO/4/jaQELHk8wDcw==} + hasBin: true + jsx-ast-utils@3.3.5: resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} engines: {node: '>=4.0'} @@ -2707,13 +3586,100 @@ packages: language-subtag-registry@0.3.23: resolution: {integrity: sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==} - language-tags@1.0.9: - resolution: {integrity: sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==} - engines: {node: '>=0.10'} + language-tags@1.0.9: + resolution: {integrity: sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==} + engines: {node: '>=0.10'} + + levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + + lexical@0.41.0: + resolution: {integrity: sha512-pNIm5+n+hVnJHB9gYPDYsIO5Y59dNaDU9rJmPPsfqQhP2ojKFnUoPbcRnrI9FJLXB14sSumcY8LUw7Sq70TZqA==} + + lib0@0.2.117: + resolution: {integrity: sha512-DeXj9X5xDCjgKLU/7RR+/HQEVzuuEUiwldwOGsHK/sfAfELGWEyTcf0x+uOvCvK3O2zPmZePXWL85vtia6GyZw==} + engines: {node: '>=16'} + hasBin: true + + libsql@0.4.7: + resolution: {integrity: sha512-T9eIRCs6b0J1SHKYIvD8+KCJMcWZ900iZyxdnSCdqxN12Z1ijzT+jY5nrk72Jw4B0HGzms2NgpryArlJqvc3Lw==} + cpu: [x64, arm64, wasm32] + os: [darwin, linux, win32] + + lightningcss-android-arm64@1.32.0: + resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + + lightningcss-darwin-arm64@1.32.0: + resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.32.0: + resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.32.0: + resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.32.0: + resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.32.0: + resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + lightningcss-linux-arm64-musl@1.32.0: + resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [musl] + + lightningcss-linux-x64-gnu@1.32.0: + resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [glibc] + + lightningcss-linux-x64-musl@1.32.0: + resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [musl] + + lightningcss-win32-arm64-msvc@1.32.0: + resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] - levn@0.4.1: - resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} - engines: {node: '>= 0.8.0'} + lightningcss-win32-x64-msvc@1.32.0: + resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss@1.32.0: + resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} + engines: {node: '>= 12.0.0'} lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} @@ -2728,6 +3694,9 @@ packages: lodash@4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + longest-streak@3.1.0: + resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} + loose-envify@1.4.0: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true @@ -2740,6 +3709,9 @@ packages: resolution: {integrity: sha512-sr8xPKE25m6vJVcrdn6NxtC0fVfuPowbscLypegRgOm0yXSqr5JNHCAY3hnusdJ7HRBW04j6Ip4khvHU778DuQ==} engines: {node: 20 || >=22} + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + make-asynchronous@1.1.0: resolution: {integrity: sha512-ayF7iT+44LXdxJLTrTd3TLQpFDDvPCBxXxbv+pMUSuHA5Q8zyAfwkRP6aHHwNVFBUFWtxAHqwNJxF8vMZLAbVg==} engines: {node: '>=18'} @@ -2751,6 +3723,21 @@ packages: md5@2.3.0: resolution: {integrity: sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==} + mdast-util-from-markdown@2.0.2: + resolution: {integrity: sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==} + + mdast-util-mdx-jsx@3.1.3: + resolution: {integrity: sha512-bfOjvNt+1AcbPLTFMFWY149nJz0OjmewJs3LQQ5pIyVGxP4CdOqNVJL6kTaM5c68p8q82Xv3nCyFfUnuEcH3UQ==} + + mdast-util-phrasing@4.1.0: + resolution: {integrity: sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==} + + mdast-util-to-markdown@2.1.2: + resolution: {integrity: sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==} + + mdast-util-to-string@4.0.0: + resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==} + memoize-one@6.0.0: resolution: {integrity: sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==} @@ -2764,6 +3751,78 @@ packages: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} + micromark-core-commonmark@2.0.3: + resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==} + + micromark-extension-mdx-jsx@3.0.1: + resolution: {integrity: sha512-vNuFb9czP8QCtAQcEJn0UJQJZA8Dk6DXKBqx+bg/w0WGuSxDxNr7hErW89tHUY31dUW4NqEOWwmEUNhjTFmHkg==} + + micromark-factory-destination@2.0.1: + resolution: {integrity: sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==} + + micromark-factory-label@2.0.1: + resolution: {integrity: sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==} + + micromark-factory-mdx-expression@2.0.3: + resolution: {integrity: sha512-kQnEtA3vzucU2BkrIa8/VaSAsP+EJ3CKOvhMuJgOEGg9KDC6OAY6nSnNDVRiVNRqj7Y4SlSzcStaH/5jge8JdQ==} + + micromark-factory-space@2.0.1: + resolution: {integrity: sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==} + + micromark-factory-title@2.0.1: + resolution: {integrity: sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==} + + micromark-factory-whitespace@2.0.1: + resolution: {integrity: sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==} + + micromark-util-character@2.1.1: + resolution: {integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==} + + micromark-util-chunked@2.0.1: + resolution: {integrity: sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==} + + micromark-util-classify-character@2.0.1: + resolution: {integrity: sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==} + + micromark-util-combine-extensions@2.0.1: + resolution: {integrity: sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==} + + micromark-util-decode-numeric-character-reference@2.0.2: + resolution: {integrity: sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==} + + micromark-util-decode-string@2.0.1: + resolution: {integrity: sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==} + + micromark-util-encode@2.0.1: + resolution: {integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==} + + micromark-util-events-to-acorn@2.0.3: + resolution: {integrity: sha512-jmsiEIiZ1n7X1Rr5k8wVExBQCg5jy4UXVADItHmNk1zkwEVhBuIUKRu3fqv+hs4nxLISi2DQGlqIOGiFxgbfHg==} + + micromark-util-html-tag-name@2.0.1: + resolution: {integrity: sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==} + + micromark-util-normalize-identifier@2.0.1: + resolution: {integrity: sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==} + + micromark-util-resolve-all@2.0.1: + resolution: {integrity: sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==} + + micromark-util-sanitize-uri@2.0.1: + resolution: {integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==} + + micromark-util-subtokenize@2.1.0: + resolution: {integrity: sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==} + + micromark-util-symbol@2.0.1: + resolution: {integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==} + + micromark-util-types@2.0.2: + resolution: {integrity: sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==} + + micromark@4.0.2: + resolution: {integrity: sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==} + micromatch@4.0.8: resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} @@ -2855,6 +3914,11 @@ packages: ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + nanoid@3.3.11: + resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + nanoid@3.3.8: resolution: {integrity: sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} @@ -2887,10 +3951,19 @@ packages: sass: optional: true + node-domexception@1.0.0: + resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} + engines: {node: '>=10.5.0'} + deprecated: Use your platform's native DOMException instead + node-exports-info@1.6.0: resolution: {integrity: sha512-pyFS63ptit/P5WqUkt+UUfe+4oevH+bFeIiPPdfb0pFeYEu/1ELnJu5l+5EcTKYL5M7zaAa7S8ddywgXypqKCw==} engines: {node: '>= 0.4'} + node-fetch@3.3.2: + resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + noms@0.0.0: resolution: {integrity: sha512-lNDU9VJaOPxUmXcLb+HQFeUgQQPtMI24Gt6hgfuMHRJgMRHMF/qZ4HJD3GDru4sSw9IQl2jPjAYnQrdIeLbwow==} @@ -2941,6 +4014,9 @@ packages: resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==} engines: {node: '>= 0.4'} + obug@2.1.1: + resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} + on-exit-leak-free@2.1.2: resolution: {integrity: sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==} engines: {node: '>=14.0.0'} @@ -2987,6 +4063,9 @@ packages: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} + parse-entities@4.0.2: + resolution: {integrity: sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==} + parse-json@5.2.0: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} engines: {node: '>=8'} @@ -3025,6 +4104,9 @@ packages: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + payload@3.81.0: resolution: {integrity: sha512-vnJYPTZQ54BuB3ZPNYSeaggPyvIye016DO+xAxDSlEocK2Gh7UZOFqtws2+G+0z7hIedLN57+/idqevQRFhcuA==} engines: {node: ^18.20.2 || >=20.9.0} @@ -3075,6 +4157,10 @@ packages: resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} engines: {node: ^10 || ^12 || >=14} + postcss@8.5.8: + resolution: {integrity: sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==} + engines: {node: ^10 || ^12 || >=14} + prelude-ls@1.2.1: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} @@ -3088,12 +4174,19 @@ packages: resolution: {integrity: sha512-gjVS5hOP+M3wMm5nmNOucbIrqudzs9v/57bWRHQWLYklXqoXKrVfYW2W9+glfGsqtPgpiz5WwyEEB+ksXIx3gQ==} engines: {node: '>=18'} + prismjs@1.30.0: + resolution: {integrity: sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==} + engines: {node: '>=6'} + process-nextick-args@2.0.1: resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} process-warning@5.0.0: resolution: {integrity: sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==} + promise-limit@2.7.0: + resolution: {integrity: sha512-7nJ6v5lnJsXwGprnGXga4wx6d1POjvi5Qmf1ivTRxTjH4Z/9Czja/UCMLVmB9N93GeWOU93XaFaEt6jbuoagNw==} + prompts@2.4.2: resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} engines: {node: '>= 6'} @@ -3137,11 +4230,15 @@ packages: peerDependencies: react: ^19.2.4 - react-google-places-autocomplete@4.1.0: - resolution: {integrity: sha512-C+BOJ/2667DLAFpd9To/OZJm1+1MOp7J6fQihys/W89tDcXb0O7i5ea7zOZ58ZE0mydnz788WxWKpqBqQJHjJg==} + react-error-boundary@4.1.2: + resolution: {integrity: sha512-GQDxZ5Jd+Aq/qUxbCm1UtzmL/s++V7zKgE8yMktJiCQXCCFZnMZh9ng+6/Ne6PjNSXH0L9CjeOEREfRnq6Duag==} + peerDependencies: + react: '>=16.13.1' + + react-error-boundary@6.1.1: + resolution: {integrity: sha512-BrYwPOdXi5mqkk5lw+Uvt0ThHx32rCt3BkukS4X23A2AIWDPSGX6iaWTc0y9TU/mHDA/6qOSGel+B2ERkOvD1w==} peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^18.0.0 || ^19.0.0 react-image-crop@10.1.8: resolution: {integrity: sha512-4rb8XtXNx7ZaOZarKKnckgz4xLMvds/YrU6mpJfGhGAsy2Mg4mIw1x+DCCGngVGq2soTBVVOxx2s/C6mTX9+pA==} @@ -3151,12 +4248,6 @@ packages: react-is@16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} - react-select@5.10.2: - resolution: {integrity: sha512-Z33nHdEFWq9tfnfVXaiM12rbJmk+QjFEztWLtmXqQhz6Al4UZZ9xc0wiatmGtUOCCnHN0WizL3tCMYRENX4rVQ==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - react-select@5.9.0: resolution: {integrity: sha512-nwRKGanVHGjdccsnzhFte/PULziueZxGD8LL2WojON78Mvnq7LdAMEtu2frrwld1fr3geixg3iiMBIc/LLAZpw==} peerDependencies: @@ -3248,6 +4339,11 @@ packages: engines: {node: 20 || >=22} hasBin: true + rolldown@1.0.0-rc.12: + resolution: {integrity: sha512-yP4USLIMYrwpPHEFB5JGH1uxhcslv6/hL0OyvTuY+3qlOSJvZ7ntYnoWpehBxufkgN0cvXxppuTu5hHa/zPh+A==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} @@ -3355,6 +4451,9 @@ packages: sift@17.1.3: resolution: {integrity: sha512-Rtlj66/b0ICeFzYTuNvX/EF1igRbbnGSvEyT79McoZa/DeGhMyC5pWKOEsZKnpkqtSeovd5FL/bjHWC3CIIvCQ==} + siginfo@2.0.0: + resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + signal-exit@4.1.0: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} @@ -3398,10 +4497,17 @@ packages: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} + source-map-support@0.5.21: + resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + source-map@0.5.7: resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==} engines: {node: '>=0.10.0'} + source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + source-map@0.7.6: resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==} engines: {node: '>= 12'} @@ -3419,9 +4525,15 @@ packages: stable-hash@0.0.4: resolution: {integrity: sha512-LjdcbuBeLcdETCrPn9i8AYAZ1eCtu4ECAWtP7UleOiZ9LzVxRzzUZEoZ8zB24nhkQnDWyET0I+3sWokSDS3E7g==} + stackback@0.0.2: + resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + state-local@1.0.7: resolution: {integrity: sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w==} + std-env@4.0.0: + resolution: {integrity: sha512-zUMPtQ/HBY3/50VbpkupYHbRroTRZJPRLvreamgErJVys0ceuzMkD44J/QjqhHjOzK42GQ3QZIeFG1OYfOtKqQ==} + stop-iteration-iterator@1.1.0: resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} engines: {node: '>= 0.4'} @@ -3462,6 +4574,9 @@ packages: string_decoder@1.1.1: resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} + stringify-entities@4.0.4: + resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==} + strip-ansi@6.0.1: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} @@ -3546,14 +4661,34 @@ packages: resolution: {integrity: sha512-75voc/9G4rDIJleOo4jPvN4/YC4GRZrY8yy1uU4lwrB3XEQbWve8zXoO5No4eFrGcTAMYyoY67p8jRQdtA1HbA==} engines: {node: '>=12'} + tinybench@2.9.0: + resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + + tinyexec@1.0.4: + resolution: {integrity: sha512-u9r3uZC0bdpGOXtlxUIdwf9pkmvhqJdrVCH9fapQtgy/OeTTMZ1nqH7agtvEfmGui6e1XxjcdrlxvxJvc3sMqw==} + engines: {node: '>=18'} + tinyglobby@0.2.15: resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} engines: {node: '>=12.0.0'} + tinyrainbow@3.1.0: + resolution: {integrity: sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==} + engines: {node: '>=14.0.0'} + + to-no-case@1.0.2: + resolution: {integrity: sha512-Z3g735FxuZY8rodxV4gH7LxClE4H0hTIyHNIHdk+vpQxjLm0cwnKXq/OFVZ76SOQmto7txVcwSCwkU5kqp+FKg==} + to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} + to-snake-case@1.0.0: + resolution: {integrity: sha512-joRpzBAk1Bhi2eGEYBjukEWHOe/IvclOkiJl3DtA91jV6NwQ3MwXA4FHYeqk8BNp/D8bmi9tcNbRu/SozP0jbQ==} + + to-space-case@1.0.0: + resolution: {integrity: sha512-rLdvwXZ39VOn1IxGL3V6ZstoTbwLRckQmn/U8ZDLuWwIXNpuZDhQ3AiRUlhTbOXFVE9C+dR51wM0CBDhk31VcA==} + token-types@6.1.2: resolution: {integrity: sha512-dRXchy+C0IgK8WPC6xvCHFRIWYUbqqdEIKPaKo/AcTUNzwLTK6AH7RjdLWsEZcAN/TBdtfUw3PYEgPr5VPr6ww==} engines: {node: '>=14.16'} @@ -3653,6 +4788,21 @@ packages: resolution: {integrity: sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==} engines: {node: '>=18'} + unist-util-is@6.0.1: + resolution: {integrity: sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==} + + unist-util-position-from-estree@2.0.0: + resolution: {integrity: sha512-KaFVRjoqLyF6YXCbVLNad/eS4+OfPQQn2yOd7zF/h5T/CSL2v8NpN6a5TPvtbXthAGw5nG+PuTtq+DdIZr+cRQ==} + + unist-util-stringify-position@4.0.0: + resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==} + + unist-util-visit-parents@6.0.2: + resolution: {integrity: sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==} + + unist-util-visit@5.1.0: + resolution: {integrity: sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==} + untildify@4.0.0: resolution: {integrity: sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==} engines: {node: '>=8'} @@ -3666,11 +4816,6 @@ packages: react: '>=18.0.0' scheduler: '>=0.19.0' - use-debounce@3.4.3: - resolution: {integrity: sha512-nxy+opOxDccWfhMl36J5BSCTpvcj89iaQk2OZWLAtBJQj7ISCtx1gh+rFbdjGfMl6vtCZf6gke/kYvrkVfHMoA==} - peerDependencies: - react: '>=16.8.0' - use-isomorphic-layout-effect@1.2.1: resolution: {integrity: sha512-tpZZ+EX0gaghDAiFR37hj5MgY6ZN55kLiPkJsKxBMZ6GZdOSPJXiOzPM984oPYZ5AnehYx5WQp1+ME8I/P/pRA==} peerDependencies: @@ -3690,10 +4835,99 @@ packages: resolution: {integrity: sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==} hasBin: true + uuid@9.0.0: + resolution: {integrity: sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==} + hasBin: true + uuid@9.0.1: resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} hasBin: true + vfile-message@4.0.3: + resolution: {integrity: sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==} + + vite@8.0.5: + resolution: {integrity: sha512-nmu43Qvq9UopTRfMx2jOYW5l16pb3iDC1JH6yMuPkpVbzK0k+L7dfsEDH4jRgYFmsg0sTAqkojoZgzLMlwHsCQ==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + '@vitejs/devtools': ^0.1.0 + esbuild: ^0.27.0 || ^0.28.0 + jiti: '>=1.21.0' + less: ^4.0.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + '@vitejs/devtools': + optional: true + esbuild: + optional: true + jiti: + optional: true + less: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + vitest@4.1.2: + resolution: {integrity: sha512-xjR1dMTVHlFLh98JE3i/f/WePqJsah4A0FK9cc8Ehp9Udk0AZk6ccpIZhh1qJ/yxVWRZ+Q54ocnD8TXmkhspGg==} + engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@opentelemetry/api': ^1.9.0 + '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 + '@vitest/browser-playwright': 4.1.2 + '@vitest/browser-preview': 4.1.2 + '@vitest/browser-webdriverio': 4.1.2 + '@vitest/ui': 4.1.2 + happy-dom: '*' + jsdom: '*' + vite: ^6.0.0 || ^7.0.0 || ^8.0.0 + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@opentelemetry/api': + optional: true + '@types/node': + optional: true + '@vitest/browser-playwright': + optional: true + '@vitest/browser-preview': + optional: true + '@vitest/browser-webdriverio': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + + web-streams-polyfill@3.3.3: + resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==} + engines: {node: '>= 8'} + web-worker@1.5.0: resolution: {integrity: sha512-RiMReJrTAiA+mBjGONMnjVDP2u3p9R1vkcGz6gDIrOMT3oGuYwX2WRMYI9ipkphSuE5XKEhydbhNEJh4NY9mlw==} @@ -3701,6 +4935,10 @@ packages: resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} engines: {node: '>=12'} + whatwg-mimetype@3.0.0: + resolution: {integrity: sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==} + engines: {node: '>=12'} + whatwg-url@14.2.0: resolution: {integrity: sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==} engines: {node: '>=18'} @@ -3726,6 +4964,11 @@ packages: engines: {node: '>= 8'} hasBin: true + why-is-node-running@2.3.0: + resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} + engines: {node: '>=8'} + hasBin: true + word-wrap@1.2.5: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} @@ -3778,6 +5021,10 @@ packages: resolution: {integrity: sha512-PtGEvEP30p7sbIBJKUBjUnqgTVOyMURc4dLo9iNyAJnNIEz9pm88cCXF21w94Kg3k6RXkeZh5DHOGS0qEONvNQ==} engines: {node: '>=12'} + yjs@13.6.30: + resolution: {integrity: sha512-vv/9h42eCMC81ZHDFswuu/MKzkl/vyq1BhaNGfHyOonwlG4CJbQF4oiBBJPvfdeCt/PlVDWh7Nov9D34YY09uQ==} + engines: {node: '>=16.0.0', npm: '>=8.0.0'} + yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} @@ -3786,6 +5033,9 @@ packages: resolution: {integrity: sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==} engines: {node: '>=18'} + zwitch@2.0.4: + resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} + snapshots: '@apidevtools/json-schema-ref-parser@11.7.2': @@ -4328,11 +5578,24 @@ snapshots: react: 19.2.4 tslib: 2.8.1 + '@drizzle-team/brocli@0.10.2': {} + + '@emnapi/core@1.9.2': + dependencies: + '@emnapi/wasi-threads': 1.2.1 + tslib: 2.8.1 + optional: true + '@emnapi/runtime@1.7.1': dependencies: tslib: 2.8.1 optional: true + '@emnapi/wasi-threads@1.2.1': + dependencies: + tslib: 2.8.1 + optional: true + '@emotion/babel-plugin@11.13.5': dependencies: '@babel/helper-module-imports': 7.25.9 @@ -4399,79 +5662,233 @@ snapshots: '@epic-web/invariant@1.0.0': {} + '@esbuild-kit/core-utils@3.3.2': + dependencies: + esbuild: 0.18.20 + source-map-support: 0.5.21 + + '@esbuild-kit/esm-loader@2.6.5': + dependencies: + '@esbuild-kit/core-utils': 3.3.2 + get-tsconfig: 4.13.7 + + '@esbuild/aix-ppc64@0.25.12': + optional: true + '@esbuild/aix-ppc64@0.27.3': optional: true + '@esbuild/android-arm64@0.18.20': + optional: true + + '@esbuild/android-arm64@0.25.12': + optional: true + '@esbuild/android-arm64@0.27.3': optional: true + '@esbuild/android-arm@0.18.20': + optional: true + + '@esbuild/android-arm@0.25.12': + optional: true + '@esbuild/android-arm@0.27.3': optional: true + '@esbuild/android-x64@0.18.20': + optional: true + + '@esbuild/android-x64@0.25.12': + optional: true + '@esbuild/android-x64@0.27.3': optional: true + '@esbuild/darwin-arm64@0.18.20': + optional: true + + '@esbuild/darwin-arm64@0.25.12': + optional: true + '@esbuild/darwin-arm64@0.27.3': optional: true + '@esbuild/darwin-x64@0.18.20': + optional: true + + '@esbuild/darwin-x64@0.25.12': + optional: true + '@esbuild/darwin-x64@0.27.3': optional: true + '@esbuild/freebsd-arm64@0.18.20': + optional: true + + '@esbuild/freebsd-arm64@0.25.12': + optional: true + '@esbuild/freebsd-arm64@0.27.3': optional: true - '@esbuild/freebsd-x64@0.27.3': + '@esbuild/freebsd-x64@0.18.20': + optional: true + + '@esbuild/freebsd-x64@0.25.12': + optional: true + + '@esbuild/freebsd-x64@0.27.3': + optional: true + + '@esbuild/linux-arm64@0.18.20': + optional: true + + '@esbuild/linux-arm64@0.25.12': + optional: true + + '@esbuild/linux-arm64@0.27.3': + optional: true + + '@esbuild/linux-arm@0.18.20': + optional: true + + '@esbuild/linux-arm@0.25.12': + optional: true + + '@esbuild/linux-arm@0.27.3': + optional: true + + '@esbuild/linux-ia32@0.18.20': + optional: true + + '@esbuild/linux-ia32@0.25.12': + optional: true + + '@esbuild/linux-ia32@0.27.3': + optional: true + + '@esbuild/linux-loong64@0.18.20': + optional: true + + '@esbuild/linux-loong64@0.25.12': + optional: true + + '@esbuild/linux-loong64@0.27.3': + optional: true + + '@esbuild/linux-mips64el@0.18.20': + optional: true + + '@esbuild/linux-mips64el@0.25.12': + optional: true + + '@esbuild/linux-mips64el@0.27.3': + optional: true + + '@esbuild/linux-ppc64@0.18.20': + optional: true + + '@esbuild/linux-ppc64@0.25.12': + optional: true + + '@esbuild/linux-ppc64@0.27.3': + optional: true + + '@esbuild/linux-riscv64@0.18.20': + optional: true + + '@esbuild/linux-riscv64@0.25.12': + optional: true + + '@esbuild/linux-riscv64@0.27.3': + optional: true + + '@esbuild/linux-s390x@0.18.20': + optional: true + + '@esbuild/linux-s390x@0.25.12': + optional: true + + '@esbuild/linux-s390x@0.27.3': + optional: true + + '@esbuild/linux-x64@0.18.20': + optional: true + + '@esbuild/linux-x64@0.25.12': + optional: true + + '@esbuild/linux-x64@0.27.3': + optional: true + + '@esbuild/netbsd-arm64@0.25.12': + optional: true + + '@esbuild/netbsd-arm64@0.27.3': + optional: true + + '@esbuild/netbsd-x64@0.18.20': + optional: true + + '@esbuild/netbsd-x64@0.25.12': + optional: true + + '@esbuild/netbsd-x64@0.27.3': + optional: true + + '@esbuild/openbsd-arm64@0.25.12': optional: true - '@esbuild/linux-arm64@0.27.3': + '@esbuild/openbsd-arm64@0.27.3': optional: true - '@esbuild/linux-arm@0.27.3': + '@esbuild/openbsd-x64@0.18.20': optional: true - '@esbuild/linux-ia32@0.27.3': + '@esbuild/openbsd-x64@0.25.12': optional: true - '@esbuild/linux-loong64@0.27.3': + '@esbuild/openbsd-x64@0.27.3': optional: true - '@esbuild/linux-mips64el@0.27.3': + '@esbuild/openharmony-arm64@0.25.12': optional: true - '@esbuild/linux-ppc64@0.27.3': + '@esbuild/openharmony-arm64@0.27.3': optional: true - '@esbuild/linux-riscv64@0.27.3': + '@esbuild/sunos-x64@0.18.20': optional: true - '@esbuild/linux-s390x@0.27.3': + '@esbuild/sunos-x64@0.25.12': optional: true - '@esbuild/linux-x64@0.27.3': + '@esbuild/sunos-x64@0.27.3': optional: true - '@esbuild/netbsd-arm64@0.27.3': + '@esbuild/win32-arm64@0.18.20': optional: true - '@esbuild/netbsd-x64@0.27.3': + '@esbuild/win32-arm64@0.25.12': optional: true - '@esbuild/openbsd-arm64@0.27.3': + '@esbuild/win32-arm64@0.27.3': optional: true - '@esbuild/openbsd-x64@0.27.3': + '@esbuild/win32-ia32@0.18.20': optional: true - '@esbuild/openharmony-arm64@0.27.3': + '@esbuild/win32-ia32@0.25.12': optional: true - '@esbuild/sunos-x64@0.27.3': + '@esbuild/win32-ia32@0.27.3': optional: true - '@esbuild/win32-arm64@0.27.3': + '@esbuild/win32-x64@0.18.20': optional: true - '@esbuild/win32-ia32@0.27.3': + '@esbuild/win32-x64@0.25.12': optional: true '@esbuild/win32-x64@0.27.3': @@ -4651,6 +6068,20 @@ snapshots: react: 19.2.4 react-dom: 19.2.4(react@19.2.4) + '@floating-ui/react-dom@2.1.8(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@floating-ui/dom': 1.7.6 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@floating-ui/react@0.27.19(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@floating-ui/react-dom': 2.1.8(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@floating-ui/utils': 0.2.11 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + tabbable: 6.2.0 + '@floating-ui/react@0.27.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: '@floating-ui/react-dom': 2.1.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -4661,8 +6092,6 @@ snapshots: '@floating-ui/utils@0.2.11': {} - '@googlemaps/js-api-loader@1.16.10': {} - '@humanfs/core@0.19.1': {} '@humanfs/node@0.16.7': @@ -4783,6 +6212,8 @@ snapshots: '@jridgewell/sourcemap-codec@1.5.0': {} + '@jridgewell/sourcemap-codec@1.5.5': {} + '@jridgewell/trace-mapping@0.3.25': dependencies: '@jridgewell/resolve-uri': 3.1.2 @@ -4792,6 +6223,229 @@ snapshots: '@keyv/serialize@1.1.1': {} + '@lexical/clipboard@0.41.0': + dependencies: + '@lexical/html': 0.41.0 + '@lexical/list': 0.41.0 + '@lexical/selection': 0.41.0 + '@lexical/utils': 0.41.0 + lexical: 0.41.0 + + '@lexical/code@0.41.0': + dependencies: + '@lexical/utils': 0.41.0 + lexical: 0.41.0 + prismjs: 1.30.0 + + '@lexical/devtools-core@0.41.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@lexical/html': 0.41.0 + '@lexical/link': 0.41.0 + '@lexical/mark': 0.41.0 + '@lexical/table': 0.41.0 + '@lexical/utils': 0.41.0 + lexical: 0.41.0 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@lexical/dragon@0.41.0': + dependencies: + '@lexical/extension': 0.41.0 + lexical: 0.41.0 + + '@lexical/extension@0.41.0': + dependencies: + '@lexical/utils': 0.41.0 + '@preact/signals-core': 1.14.1 + lexical: 0.41.0 + + '@lexical/hashtag@0.41.0': + dependencies: + '@lexical/text': 0.41.0 + '@lexical/utils': 0.41.0 + lexical: 0.41.0 + + '@lexical/headless@0.41.0': + dependencies: + happy-dom: 20.8.9 + lexical: 0.41.0 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + '@lexical/history@0.41.0': + dependencies: + '@lexical/extension': 0.41.0 + '@lexical/utils': 0.41.0 + lexical: 0.41.0 + + '@lexical/html@0.41.0': + dependencies: + '@lexical/selection': 0.41.0 + '@lexical/utils': 0.41.0 + lexical: 0.41.0 + + '@lexical/link@0.41.0': + dependencies: + '@lexical/extension': 0.41.0 + '@lexical/utils': 0.41.0 + lexical: 0.41.0 + + '@lexical/list@0.41.0': + dependencies: + '@lexical/extension': 0.41.0 + '@lexical/selection': 0.41.0 + '@lexical/utils': 0.41.0 + lexical: 0.41.0 + + '@lexical/mark@0.41.0': + dependencies: + '@lexical/utils': 0.41.0 + lexical: 0.41.0 + + '@lexical/markdown@0.41.0': + dependencies: + '@lexical/code': 0.41.0 + '@lexical/link': 0.41.0 + '@lexical/list': 0.41.0 + '@lexical/rich-text': 0.41.0 + '@lexical/text': 0.41.0 + '@lexical/utils': 0.41.0 + lexical: 0.41.0 + + '@lexical/offset@0.41.0': + dependencies: + lexical: 0.41.0 + + '@lexical/overflow@0.41.0': + dependencies: + lexical: 0.41.0 + + '@lexical/plain-text@0.41.0': + dependencies: + '@lexical/clipboard': 0.41.0 + '@lexical/dragon': 0.41.0 + '@lexical/selection': 0.41.0 + '@lexical/utils': 0.41.0 + lexical: 0.41.0 + + '@lexical/react@0.41.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(yjs@13.6.30)': + dependencies: + '@floating-ui/react': 0.27.19(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@lexical/devtools-core': 0.41.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@lexical/dragon': 0.41.0 + '@lexical/extension': 0.41.0 + '@lexical/hashtag': 0.41.0 + '@lexical/history': 0.41.0 + '@lexical/link': 0.41.0 + '@lexical/list': 0.41.0 + '@lexical/mark': 0.41.0 + '@lexical/markdown': 0.41.0 + '@lexical/overflow': 0.41.0 + '@lexical/plain-text': 0.41.0 + '@lexical/rich-text': 0.41.0 + '@lexical/table': 0.41.0 + '@lexical/text': 0.41.0 + '@lexical/utils': 0.41.0 + '@lexical/yjs': 0.41.0(yjs@13.6.30) + lexical: 0.41.0 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + react-error-boundary: 6.1.1(react@19.2.4) + transitivePeerDependencies: + - yjs + + '@lexical/rich-text@0.41.0': + dependencies: + '@lexical/clipboard': 0.41.0 + '@lexical/dragon': 0.41.0 + '@lexical/selection': 0.41.0 + '@lexical/utils': 0.41.0 + lexical: 0.41.0 + + '@lexical/selection@0.41.0': + dependencies: + lexical: 0.41.0 + + '@lexical/table@0.41.0': + dependencies: + '@lexical/clipboard': 0.41.0 + '@lexical/extension': 0.41.0 + '@lexical/utils': 0.41.0 + lexical: 0.41.0 + + '@lexical/text@0.41.0': + dependencies: + lexical: 0.41.0 + + '@lexical/utils@0.41.0': + dependencies: + '@lexical/selection': 0.41.0 + lexical: 0.41.0 + + '@lexical/yjs@0.41.0(yjs@13.6.30)': + dependencies: + '@lexical/offset': 0.41.0 + '@lexical/selection': 0.41.0 + lexical: 0.41.0 + yjs: 13.6.30 + + '@libsql/client@0.14.0': + dependencies: + '@libsql/core': 0.14.0 + '@libsql/hrana-client': 0.7.0 + js-base64: 3.7.8 + libsql: 0.4.7 + promise-limit: 2.7.0 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + '@libsql/core@0.14.0': + dependencies: + js-base64: 3.7.8 + + '@libsql/darwin-arm64@0.4.7': + optional: true + + '@libsql/darwin-x64@0.4.7': + optional: true + + '@libsql/hrana-client@0.7.0': + dependencies: + '@libsql/isomorphic-fetch': 0.3.1 + '@libsql/isomorphic-ws': 0.1.5 + js-base64: 3.7.8 + node-fetch: 3.3.2 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + '@libsql/isomorphic-fetch@0.3.1': {} + + '@libsql/isomorphic-ws@0.1.5': + dependencies: + '@types/ws': 8.18.1 + ws: 8.18.3 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + '@libsql/linux-arm64-gnu@0.4.7': + optional: true + + '@libsql/linux-arm64-musl@0.4.7': + optional: true + + '@libsql/linux-x64-gnu@0.4.7': + optional: true + + '@libsql/linux-x64-musl@0.4.7': + optional: true + + '@libsql/win32-x64-msvc@0.4.7': + optional: true + '@monaco-editor/loader@1.5.0': dependencies: state-local: 1.0.7 @@ -4879,6 +6533,15 @@ snapshots: '@napi-rs/nice-win32-x64-msvc': 1.1.1 optional: true + '@napi-rs/wasm-runtime@1.1.2(@emnapi/core@1.9.2)(@emnapi/runtime@1.7.1)': + dependencies: + '@emnapi/core': 1.9.2 + '@emnapi/runtime': 1.7.1 + '@tybys/wasm-util': 0.10.1 + optional: true + + '@neon-rs/load@0.0.4': {} + '@next/env@15.4.11': {} '@next/env@15.5.9': {} @@ -4919,6 +6582,8 @@ snapshots: '@nodelib/fs.scandir': 2.1.5 fastq: 1.20.1 + '@oxc-project/types@0.122.0': {} + '@payloadcms/db-mongodb@3.81.0(@aws-sdk/credential-providers@3.666.0(@aws-sdk/client-sso-oidc@3.666.0(@aws-sdk/client-sts@3.666.0)))(payload@3.81.0(graphql@16.9.0)(typescript@5.9.3))(socks@2.8.3)': dependencies: mongoose: 8.15.1(@aws-sdk/credential-providers@3.666.0(@aws-sdk/client-sso-oidc@3.666.0(@aws-sdk/client-sts@3.666.0)))(socks@2.8.3) @@ -4936,6 +6601,90 @@ snapshots: - socks - supports-color + '@payloadcms/db-sqlite@3.81.0(payload@3.81.0(graphql@16.9.0)(typescript@5.9.3))': + dependencies: + '@libsql/client': 0.14.0 + '@payloadcms/drizzle': 3.81.0(@libsql/client@0.14.0)(payload@3.81.0(graphql@16.9.0)(typescript@5.9.3)) + console-table-printer: 2.12.1 + drizzle-kit: 0.31.7 + drizzle-orm: 0.44.7(@libsql/client@0.14.0) + payload: 3.81.0(graphql@16.9.0)(typescript@5.9.3) + prompts: 2.4.2 + to-snake-case: 1.0.0 + uuid: 9.0.0 + transitivePeerDependencies: + - '@aws-sdk/client-rds-data' + - '@cloudflare/workers-types' + - '@electric-sql/pglite' + - '@libsql/client-wasm' + - '@neondatabase/serverless' + - '@op-engineering/op-sqlite' + - '@opentelemetry/api' + - '@planetscale/database' + - '@prisma/client' + - '@tidbcloud/serverless' + - '@types/better-sqlite3' + - '@types/pg' + - '@types/sql.js' + - '@upstash/redis' + - '@vercel/postgres' + - '@xata.io/client' + - better-sqlite3 + - bufferutil + - bun-types + - expo-sqlite + - gel + - knex + - kysely + - mysql2 + - pg + - postgres + - prisma + - sql.js + - sqlite3 + - supports-color + - utf-8-validate + + '@payloadcms/drizzle@3.81.0(@libsql/client@0.14.0)(payload@3.81.0(graphql@16.9.0)(typescript@5.9.3))': + dependencies: + console-table-printer: 2.12.1 + dequal: 2.0.3 + drizzle-orm: 0.44.7(@libsql/client@0.14.0) + payload: 3.81.0(graphql@16.9.0)(typescript@5.9.3) + prompts: 2.4.2 + to-snake-case: 1.0.0 + uuid: 9.0.0 + transitivePeerDependencies: + - '@aws-sdk/client-rds-data' + - '@cloudflare/workers-types' + - '@electric-sql/pglite' + - '@libsql/client' + - '@libsql/client-wasm' + - '@neondatabase/serverless' + - '@op-engineering/op-sqlite' + - '@opentelemetry/api' + - '@planetscale/database' + - '@prisma/client' + - '@tidbcloud/serverless' + - '@types/better-sqlite3' + - '@types/pg' + - '@types/sql.js' + - '@upstash/redis' + - '@vercel/postgres' + - '@xata.io/client' + - better-sqlite3 + - bun-types + - expo-sqlite + - gel + - knex + - kysely + - mysql2 + - pg + - postgres + - prisma + - sql.js + - sqlite3 + '@payloadcms/eslint-config@3.28.0(@typescript-eslint/eslint-plugin@8.26.1(@typescript-eslint/parser@8.26.1(eslint@9.22.0)(typescript@5.9.3))(eslint@9.22.0)(typescript@5.9.3))(ts-api-utils@2.5.0(typescript@5.9.3))': dependencies: '@eslint-react/eslint-plugin': 1.31.0(eslint@9.22.0)(ts-api-utils@2.5.0(typescript@5.9.3))(typescript@5.7.3) @@ -5037,6 +6786,52 @@ snapshots: - supports-color - typescript + '@payloadcms/richtext-lexical@3.81.0(@faceless-ui/modal@3.0.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@faceless-ui/scroll-info@2.0.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@payloadcms/next@3.81.0(@types/react@19.2.14)(graphql@16.9.0)(monaco-editor@0.52.0)(next@15.4.11(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.77.4))(payload@3.81.0(graphql@16.9.0)(typescript@5.9.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(@types/react@19.2.14)(monaco-editor@0.52.0)(next@15.4.11(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.77.4))(payload@3.81.0(graphql@16.9.0)(typescript@5.9.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(yjs@13.6.30)': + dependencies: + '@faceless-ui/modal': 3.0.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@faceless-ui/scroll-info': 2.0.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@lexical/clipboard': 0.41.0 + '@lexical/headless': 0.41.0 + '@lexical/html': 0.41.0 + '@lexical/link': 0.41.0 + '@lexical/list': 0.41.0 + '@lexical/mark': 0.41.0 + '@lexical/react': 0.41.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(yjs@13.6.30) + '@lexical/rich-text': 0.41.0 + '@lexical/selection': 0.41.0 + '@lexical/table': 0.41.0 + '@lexical/utils': 0.41.0 + '@payloadcms/next': 3.81.0(@types/react@19.2.14)(graphql@16.9.0)(monaco-editor@0.52.0)(next@15.4.11(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.77.4))(payload@3.81.0(graphql@16.9.0)(typescript@5.9.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3) + '@payloadcms/translations': 3.81.0 + '@payloadcms/ui': 3.81.0(@types/react@19.2.14)(monaco-editor@0.52.0)(next@15.4.11(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.77.4))(payload@3.81.0(graphql@16.9.0)(typescript@5.9.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3) + '@types/uuid': 10.0.0 + acorn: 8.16.0 + bson-objectid: 2.0.4 + csstype: 3.1.3 + dequal: 2.0.3 + escape-html: 1.0.3 + jsox: 1.2.121 + lexical: 0.41.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-mdx-jsx: 3.1.3 + micromark-extension-mdx-jsx: 3.0.1 + payload: 3.81.0(graphql@16.9.0)(typescript@5.9.3) + qs-esm: 8.0.1 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + react-error-boundary: 4.1.2(react@19.2.4) + ts-essentials: 10.0.3(typescript@5.9.3) + uuid: 10.0.0 + transitivePeerDependencies: + - '@types/react' + - bufferutil + - monaco-editor + - next + - supports-color + - typescript + - utf-8-validate + - yjs + '@payloadcms/translations@3.81.0': dependencies: date-fns: 4.1.0 @@ -5078,6 +6873,60 @@ snapshots: '@pinojs/redact@0.4.0': {} + '@preact/signals-core@1.14.1': {} + + '@rolldown/binding-android-arm64@1.0.0-rc.12': + optional: true + + '@rolldown/binding-darwin-arm64@1.0.0-rc.12': + optional: true + + '@rolldown/binding-darwin-x64@1.0.0-rc.12': + optional: true + + '@rolldown/binding-freebsd-x64@1.0.0-rc.12': + optional: true + + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.12': + optional: true + + '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.12': + optional: true + + '@rolldown/binding-linux-arm64-musl@1.0.0-rc.12': + optional: true + + '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.12': + optional: true + + '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.12': + optional: true + + '@rolldown/binding-linux-x64-gnu@1.0.0-rc.12': + optional: true + + '@rolldown/binding-linux-x64-musl@1.0.0-rc.12': + optional: true + + '@rolldown/binding-openharmony-arm64@1.0.0-rc.12': + optional: true + + '@rolldown/binding-wasm32-wasi@1.0.0-rc.12(@emnapi/core@1.9.2)(@emnapi/runtime@1.7.1)': + dependencies: + '@napi-rs/wasm-runtime': 1.1.2(@emnapi/core@1.9.2)(@emnapi/runtime@1.7.1) + transitivePeerDependencies: + - '@emnapi/core' + - '@emnapi/runtime' + optional: true + + '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.12': + optional: true + + '@rolldown/binding-win32-x64-msvc@1.0.0-rc.12': + optional: true + + '@rolldown/pluginutils@1.0.0-rc.12': {} + '@sec-ant/readable-stream@0.4.1': {} '@sindresorhus/is@7.2.0': {} @@ -5402,6 +7251,8 @@ snapshots: tslib: 2.8.1 optional: true + '@standard-schema/spec@1.1.0': {} + '@swc/cli@0.8.1(@swc/core@1.15.24)': dependencies: '@swc/core': 1.15.24 @@ -5492,10 +7343,30 @@ snapshots: '@tokenizer/token@0.3.0': {} + '@tybys/wasm-util@0.10.1': + dependencies: + tslib: 2.8.1 + optional: true + + '@types/acorn@4.0.6': + dependencies: + '@types/estree': 1.0.8 + '@types/busboy@1.5.4': dependencies: '@types/node': 22.10.1 + '@types/chai@5.2.3': + dependencies: + '@types/deep-eql': 4.0.2 + assertion-error: 2.0.1 + + '@types/debug@4.1.13': + dependencies: + '@types/ms': 2.1.0 + + '@types/deep-eql@4.0.2': {} + '@types/doctrine@0.0.9': {} '@types/eslint@9.6.1': @@ -5503,16 +7374,30 @@ snapshots: '@types/estree': 1.0.8 '@types/json-schema': 7.0.15 + '@types/estree-jsx@1.0.5': + dependencies: + '@types/estree': 1.0.8 + '@types/estree@1.0.8': {} '@types/google.maps@3.58.1': {} + '@types/hast@3.0.4': + dependencies: + '@types/unist': 3.0.3 + '@types/http-cache-semantics@4.2.0': {} '@types/json-schema@7.0.15': {} '@types/lodash@4.17.13': {} + '@types/mdast@4.0.4': + dependencies: + '@types/unist': 3.0.3 + + '@types/ms@2.1.0': {} + '@types/node@22.10.1': dependencies: undici-types: 6.20.0 @@ -5531,13 +7416,25 @@ snapshots: dependencies: csstype: 3.2.3 + '@types/unist@2.0.11': {} + + '@types/unist@3.0.3': {} + + '@types/uuid@10.0.0': {} + '@types/webidl-conversions@7.0.3': {} + '@types/whatwg-mimetype@3.0.2': {} + '@types/whatwg-url@11.0.5': dependencies: '@types/webidl-conversions': 7.0.3 - '@typescript-eslint/eslint-plugin@8.26.1(@typescript-eslint/parser@8.26.1(eslint@9.22.0)(typescript@5.7.3))(eslint@9.22.0)(typescript@5.7.3)': + '@types/ws@8.18.1': + dependencies: + '@types/node': 22.10.1 + + '@typescript-eslint/eslint-plugin@8.26.1(@typescript-eslint/parser@8.26.1(eslint@9.22.0)(typescript@5.9.3))(eslint@9.22.0)(typescript@5.7.3)': dependencies: '@eslint-community/regexpp': 4.12.2 '@typescript-eslint/parser': 8.26.1(eslint@9.22.0)(typescript@5.7.3) @@ -5734,6 +7631,55 @@ snapshots: '@typescript-eslint/types': 8.58.0 eslint-visitor-keys: 5.0.1 + '@vitest/expect@4.1.2': + dependencies: + '@standard-schema/spec': 1.1.0 + '@types/chai': 5.2.3 + '@vitest/spy': 4.1.2 + '@vitest/utils': 4.1.2 + chai: 6.2.2 + tinyrainbow: 3.1.0 + + '@vitest/mocker@4.1.2(vite@8.0.5(@emnapi/core@1.9.2)(@emnapi/runtime@1.7.1)(esbuild@0.25.12)(sass@1.77.4)(tsx@4.21.0))': + dependencies: + '@vitest/spy': 4.1.2 + estree-walker: 3.0.3 + magic-string: 0.30.21 + optionalDependencies: + vite: 8.0.5(@emnapi/core@1.9.2)(@emnapi/runtime@1.7.1)(esbuild@0.25.12)(sass@1.77.4)(tsx@4.21.0) + + '@vitest/mocker@4.1.2(vite@8.0.5(@emnapi/core@1.9.2)(@emnapi/runtime@1.7.1)(esbuild@0.27.3)(sass@1.77.4)(tsx@4.21.0))': + dependencies: + '@vitest/spy': 4.1.2 + estree-walker: 3.0.3 + magic-string: 0.30.21 + optionalDependencies: + vite: 8.0.5(@emnapi/core@1.9.2)(@emnapi/runtime@1.7.1)(esbuild@0.27.3)(sass@1.77.4)(tsx@4.21.0) + + '@vitest/pretty-format@4.1.2': + dependencies: + tinyrainbow: 3.1.0 + + '@vitest/runner@4.1.2': + dependencies: + '@vitest/utils': 4.1.2 + pathe: 2.0.3 + + '@vitest/snapshot@4.1.2': + dependencies: + '@vitest/pretty-format': 4.1.2 + '@vitest/utils': 4.1.2 + magic-string: 0.30.21 + pathe: 2.0.3 + + '@vitest/spy@4.1.2': {} + + '@vitest/utils@4.1.2': + dependencies: + '@vitest/pretty-format': 4.1.2 + convert-source-map: 2.0.0 + tinyrainbow: 3.1.0 + '@xhmikosr/archive-type@8.0.1': dependencies: file-type: 21.3.4 @@ -5906,6 +7852,8 @@ snapshots: get-intrinsic: 1.3.0 is-array-buffer: 3.0.5 + assertion-error@2.0.1: {} + ast-types-flow@0.0.8: {} async-function@1.0.0: {} @@ -5979,6 +7927,8 @@ snapshots: buffer-crc32@0.2.13: {} + buffer-from@1.1.2: {} + buffer@5.7.1: dependencies: base64-js: 1.5.1 @@ -6023,11 +7973,23 @@ snapshots: caniuse-lite@1.0.30001760: {} + ccount@2.0.1: {} + + chai@6.2.2: {} + chalk@4.1.2: dependencies: ansi-styles: 4.3.0 supports-color: 7.2.0 + character-entities-html4@2.1.0: {} + + character-entities-legacy@3.0.0: {} + + character-entities@2.0.2: {} + + character-reference-invalid@2.0.1: {} + charenc@0.0.2: {} chokidar@3.6.0: @@ -6084,6 +8046,8 @@ snapshots: convert-source-map@1.9.0: {} + convert-source-map@2.0.0: {} + copyfiles@2.4.1: dependencies: glob: 7.2.3 @@ -6121,10 +8085,14 @@ snapshots: cssfilter@0.0.10: {} + csstype@3.1.3: {} + csstype@3.2.3: {} damerau-levenshtein@1.0.8: {} + data-uri-to-buffer@4.0.1: {} + data-view-buffer@1.0.2: dependencies: call-bound: 1.0.4 @@ -6159,6 +8127,10 @@ snapshots: dependencies: ms: 2.1.3 + decode-named-character-reference@1.3.0: + dependencies: + character-entities: 2.0.2 + decompress-response@10.0.0: dependencies: mimic-response: 4.0.0 @@ -6183,8 +8155,13 @@ snapshots: dequal@2.0.3: {} - detect-libc@2.1.2: - optional: true + detect-libc@2.0.2: {} + + detect-libc@2.1.2: {} + + devlop@1.1.0: + dependencies: + dequal: 2.0.3 doctrine@3.0.0: dependencies: @@ -6197,6 +8174,19 @@ snapshots: dotenv@17.4.1: {} + drizzle-kit@0.31.7: + dependencies: + '@drizzle-team/brocli': 0.10.2 + '@esbuild-kit/esm-loader': 2.6.5 + esbuild: 0.25.12 + esbuild-register: 3.6.0(esbuild@0.25.12) + transitivePeerDependencies: + - supports-color + + drizzle-orm@0.44.7(@libsql/client@0.14.0): + optionalDependencies: + '@libsql/client': 0.14.0 + dunder-proto@1.0.1: dependencies: call-bind-apply-helpers: 1.0.2 @@ -6216,6 +8206,8 @@ snapshots: graceful-fs: 4.2.11 tapable: 2.3.2 + entities@7.0.1: {} + error-ex@1.3.2: dependencies: is-arrayish: 0.2.1 @@ -6281,6 +8273,8 @@ snapshots: es-errors@1.3.0: {} + es-module-lexer@2.0.0: {} + es-object-atoms@1.1.1: dependencies: es-errors: 1.3.0 @@ -6302,6 +8296,67 @@ snapshots: is-date-object: 1.1.0 is-symbol: 1.1.1 + esbuild-register@3.6.0(esbuild@0.25.12): + dependencies: + debug: 4.4.3 + esbuild: 0.25.12 + transitivePeerDependencies: + - supports-color + + esbuild@0.18.20: + optionalDependencies: + '@esbuild/android-arm': 0.18.20 + '@esbuild/android-arm64': 0.18.20 + '@esbuild/android-x64': 0.18.20 + '@esbuild/darwin-arm64': 0.18.20 + '@esbuild/darwin-x64': 0.18.20 + '@esbuild/freebsd-arm64': 0.18.20 + '@esbuild/freebsd-x64': 0.18.20 + '@esbuild/linux-arm': 0.18.20 + '@esbuild/linux-arm64': 0.18.20 + '@esbuild/linux-ia32': 0.18.20 + '@esbuild/linux-loong64': 0.18.20 + '@esbuild/linux-mips64el': 0.18.20 + '@esbuild/linux-ppc64': 0.18.20 + '@esbuild/linux-riscv64': 0.18.20 + '@esbuild/linux-s390x': 0.18.20 + '@esbuild/linux-x64': 0.18.20 + '@esbuild/netbsd-x64': 0.18.20 + '@esbuild/openbsd-x64': 0.18.20 + '@esbuild/sunos-x64': 0.18.20 + '@esbuild/win32-arm64': 0.18.20 + '@esbuild/win32-ia32': 0.18.20 + '@esbuild/win32-x64': 0.18.20 + + esbuild@0.25.12: + optionalDependencies: + '@esbuild/aix-ppc64': 0.25.12 + '@esbuild/android-arm': 0.25.12 + '@esbuild/android-arm64': 0.25.12 + '@esbuild/android-x64': 0.25.12 + '@esbuild/darwin-arm64': 0.25.12 + '@esbuild/darwin-x64': 0.25.12 + '@esbuild/freebsd-arm64': 0.25.12 + '@esbuild/freebsd-x64': 0.25.12 + '@esbuild/linux-arm': 0.25.12 + '@esbuild/linux-arm64': 0.25.12 + '@esbuild/linux-ia32': 0.25.12 + '@esbuild/linux-loong64': 0.25.12 + '@esbuild/linux-mips64el': 0.25.12 + '@esbuild/linux-ppc64': 0.25.12 + '@esbuild/linux-riscv64': 0.25.12 + '@esbuild/linux-s390x': 0.25.12 + '@esbuild/linux-x64': 0.25.12 + '@esbuild/netbsd-arm64': 0.25.12 + '@esbuild/netbsd-x64': 0.25.12 + '@esbuild/openbsd-arm64': 0.25.12 + '@esbuild/openbsd-x64': 0.25.12 + '@esbuild/openharmony-arm64': 0.25.12 + '@esbuild/sunos-x64': 0.25.12 + '@esbuild/win32-arm64': 0.25.12 + '@esbuild/win32-ia32': 0.25.12 + '@esbuild/win32-x64': 0.25.12 + esbuild@0.27.3: optionalDependencies: '@esbuild/aix-ppc64': 0.27.3 @@ -6333,6 +8388,8 @@ snapshots: escalade@3.2.0: {} + escape-html@1.0.3: {} + escape-string-regexp@4.0.0: {} eslint-config-prettier@10.1.1(eslint@9.22.0): @@ -6616,6 +8673,17 @@ snapshots: estraverse@5.3.0: {} + estree-util-is-identifier-name@3.0.0: {} + + estree-util-visit@2.0.0: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/unist': 3.0.3 + + estree-walker@3.0.3: + dependencies: + '@types/estree': 1.0.8 + esutils@2.0.3: {} events-universal@1.0.1: @@ -6651,6 +8719,8 @@ snapshots: strip-final-newline: 4.0.0 yoctocolors: 2.1.2 + expect-type@1.3.0: {} + ext-list@2.2.2: dependencies: mime-db: 1.54.0 @@ -6695,6 +8765,11 @@ snapshots: optionalDependencies: picomatch: 4.0.4 + fetch-blob@3.2.0: + dependencies: + node-domexception: 1.0.0 + web-streams-polyfill: 3.3.3 + figures@6.1.0: dependencies: is-unicode-supported: 2.1.0 @@ -6751,6 +8826,10 @@ snapshots: form-data-encoder@4.1.0: {} + formdata-polyfill@4.0.10: + dependencies: + fetch-blob: 3.2.0 + fs.realpath@1.0.0: {} fsevents@2.3.3: @@ -6884,6 +8963,18 @@ snapshots: graphql@16.9.0: {} + happy-dom@20.8.9: + dependencies: + '@types/node': 22.10.1 + '@types/whatwg-mimetype': 3.0.2 + '@types/ws': 8.18.1 + entities: 7.0.1 + whatwg-mimetype: 3.0.0 + ws: 8.18.3 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + has-bigints@1.1.0: {} has-flag@4.0.0: {} @@ -6965,6 +9056,13 @@ snapshots: ipaddr.js@2.2.0: {} + is-alphabetical@2.0.1: {} + + is-alphanumerical@2.0.1: + dependencies: + is-alphabetical: 2.0.1 + is-decimal: 2.0.1 + is-array-buffer@3.0.5: dependencies: call-bind: 1.0.8 @@ -7013,6 +9111,8 @@ snapshots: call-bound: 1.0.4 has-tostringtag: 1.0.2 + is-decimal@2.0.1: {} + is-extglob@2.1.1: {} is-finalizationregistry@1.1.1: @@ -7033,6 +9133,8 @@ snapshots: dependencies: is-extglob: 2.1.1 + is-hexadecimal@2.0.1: {} + is-map@2.0.3: {} is-negative-zero@2.0.3: {} @@ -7103,10 +9205,14 @@ snapshots: isexe@4.0.0: {} + isomorphic.js@0.2.5: {} + jose@5.10.0: {} joycon@3.1.1: {} + js-base64@3.7.8: {} + js-tokens@4.0.0: {} js-yaml@4.1.1: @@ -7142,6 +9248,8 @@ snapshots: json-stable-stringify-without-jsonify@1.0.1: {} + jsox@1.2.121: {} + jsx-ast-utils@3.3.5: dependencies: array-includes: 3.1.9 @@ -7174,6 +9282,74 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 + lexical@0.41.0: {} + + lib0@0.2.117: + dependencies: + isomorphic.js: 0.2.5 + + libsql@0.4.7: + dependencies: + '@neon-rs/load': 0.0.4 + detect-libc: 2.0.2 + optionalDependencies: + '@libsql/darwin-arm64': 0.4.7 + '@libsql/darwin-x64': 0.4.7 + '@libsql/linux-arm64-gnu': 0.4.7 + '@libsql/linux-arm64-musl': 0.4.7 + '@libsql/linux-x64-gnu': 0.4.7 + '@libsql/linux-x64-musl': 0.4.7 + '@libsql/win32-x64-msvc': 0.4.7 + + lightningcss-android-arm64@1.32.0: + optional: true + + lightningcss-darwin-arm64@1.32.0: + optional: true + + lightningcss-darwin-x64@1.32.0: + optional: true + + lightningcss-freebsd-x64@1.32.0: + optional: true + + lightningcss-linux-arm-gnueabihf@1.32.0: + optional: true + + lightningcss-linux-arm64-gnu@1.32.0: + optional: true + + lightningcss-linux-arm64-musl@1.32.0: + optional: true + + lightningcss-linux-x64-gnu@1.32.0: + optional: true + + lightningcss-linux-x64-musl@1.32.0: + optional: true + + lightningcss-win32-arm64-msvc@1.32.0: + optional: true + + lightningcss-win32-x64-msvc@1.32.0: + optional: true + + lightningcss@1.32.0: + dependencies: + detect-libc: 2.1.2 + optionalDependencies: + lightningcss-android-arm64: 1.32.0 + lightningcss-darwin-arm64: 1.32.0 + lightningcss-darwin-x64: 1.32.0 + lightningcss-freebsd-x64: 1.32.0 + lightningcss-linux-arm-gnueabihf: 1.32.0 + lightningcss-linux-arm64-gnu: 1.32.0 + lightningcss-linux-arm64-musl: 1.32.0 + lightningcss-linux-x64-gnu: 1.32.0 + lightningcss-linux-x64-musl: 1.32.0 + lightningcss-win32-arm64-msvc: 1.32.0 + lightningcss-win32-x64-msvc: 1.32.0 + lines-and-columns@1.2.4: {} locate-path@6.0.0: @@ -7184,6 +9360,8 @@ snapshots: lodash@4.17.21: {} + longest-streak@3.1.0: {} + loose-envify@1.4.0: dependencies: js-tokens: 4.0.0 @@ -7192,6 +9370,10 @@ snapshots: lru-cache@11.3.0: {} + magic-string@0.30.21: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + make-asynchronous@1.1.0: dependencies: p-event: 6.0.1 @@ -7206,6 +9388,61 @@ snapshots: crypt: 0.0.2 is-buffer: 1.1.6 + mdast-util-from-markdown@2.0.2: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + decode-named-character-reference: 1.3.0 + devlop: 1.1.0 + mdast-util-to-string: 4.0.0 + micromark: 4.0.2 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-decode-string: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + unist-util-stringify-position: 4.0.0 + transitivePeerDependencies: + - supports-color + + mdast-util-mdx-jsx@3.1.3: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + ccount: 2.0.1 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + parse-entities: 4.0.2 + stringify-entities: 4.0.4 + unist-util-stringify-position: 4.0.0 + vfile-message: 4.0.3 + transitivePeerDependencies: + - supports-color + + mdast-util-phrasing@4.1.0: + dependencies: + '@types/mdast': 4.0.4 + unist-util-is: 6.0.1 + + mdast-util-to-markdown@2.1.2: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + longest-streak: 3.1.0 + mdast-util-phrasing: 4.1.0 + mdast-util-to-string: 4.0.0 + micromark-util-classify-character: 2.0.1 + micromark-util-decode-string: 2.0.1 + unist-util-visit: 5.1.0 + zwitch: 2.0.4 + + mdast-util-to-string@4.0.0: + dependencies: + '@types/mdast': 4.0.4 + memoize-one@6.0.0: {} memory-pager@1.5.0: {} @@ -7214,6 +9451,175 @@ snapshots: merge2@1.4.1: {} + micromark-core-commonmark@2.0.3: + dependencies: + decode-named-character-reference: 1.3.0 + devlop: 1.1.0 + micromark-factory-destination: 2.0.1 + micromark-factory-label: 2.0.1 + micromark-factory-space: 2.0.1 + micromark-factory-title: 2.0.1 + micromark-factory-whitespace: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-classify-character: 2.0.1 + micromark-util-html-tag-name: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-subtokenize: 2.1.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-mdx-jsx@3.0.1: + dependencies: + '@types/acorn': 4.0.6 + '@types/estree': 1.0.8 + devlop: 1.1.0 + estree-util-is-identifier-name: 3.0.0 + micromark-factory-mdx-expression: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-events-to-acorn: 2.0.3 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + vfile-message: 4.0.3 + + micromark-factory-destination@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-label@2.0.1: + dependencies: + devlop: 1.1.0 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-mdx-expression@2.0.3: + dependencies: + '@types/estree': 1.0.8 + devlop: 1.1.0 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-events-to-acorn: 2.0.3 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + unist-util-position-from-estree: 2.0.0 + vfile-message: 4.0.3 + + micromark-factory-space@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-types: 2.0.2 + + micromark-factory-title@2.0.1: + dependencies: + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-whitespace@2.0.1: + dependencies: + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-character@2.1.1: + dependencies: + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-chunked@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-classify-character@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-combine-extensions@2.0.1: + dependencies: + micromark-util-chunked: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-decode-numeric-character-reference@2.0.2: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-decode-string@2.0.1: + dependencies: + decode-named-character-reference: 1.3.0 + micromark-util-character: 2.1.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-symbol: 2.0.1 + + micromark-util-encode@2.0.1: {} + + micromark-util-events-to-acorn@2.0.3: + dependencies: + '@types/estree': 1.0.8 + '@types/unist': 3.0.3 + devlop: 1.1.0 + estree-util-visit: 2.0.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + vfile-message: 4.0.3 + + micromark-util-html-tag-name@2.0.1: {} + + micromark-util-normalize-identifier@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-resolve-all@2.0.1: + dependencies: + micromark-util-types: 2.0.2 + + micromark-util-sanitize-uri@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-encode: 2.0.1 + micromark-util-symbol: 2.0.1 + + micromark-util-subtokenize@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-util-chunked: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-symbol@2.0.1: {} + + micromark-util-types@2.0.2: {} + + micromark@4.0.2: + dependencies: + '@types/debug': 4.1.13 + debug: 4.4.3 + decode-named-character-reference: 1.3.0 + devlop: 1.1.0 + micromark-core-commonmark: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-combine-extensions: 2.0.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-encode: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-subtokenize: 2.1.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + transitivePeerDependencies: + - supports-color + micromatch@4.0.8: dependencies: braces: 3.0.3 @@ -7290,6 +9696,8 @@ snapshots: ms@2.1.3: {} + nanoid@3.3.11: {} + nanoid@3.3.8: {} natural-compare-lite@1.4.0: {} @@ -7320,6 +9728,8 @@ snapshots: - '@babel/core' - babel-plugin-macros + node-domexception@1.0.0: {} + node-exports-info@1.6.0: dependencies: array.prototype.flatmap: 1.3.3 @@ -7327,6 +9737,12 @@ snapshots: object.entries: 1.1.9 semver: 6.3.1 + node-fetch@3.3.2: + dependencies: + data-uri-to-buffer: 4.0.1 + fetch-blob: 3.2.0 + formdata-polyfill: 4.0.10 + noms@0.0.0: dependencies: inherits: 2.0.4 @@ -7383,6 +9799,8 @@ snapshots: define-properties: 1.2.1 es-object-atoms: 1.1.1 + obug@2.1.1: {} + on-exit-leak-free@2.1.2: {} once@1.4.0: @@ -7430,6 +9848,16 @@ snapshots: dependencies: callsites: 3.1.0 + parse-entities@4.0.2: + dependencies: + '@types/unist': 2.0.11 + character-entities-legacy: 3.0.0 + character-reference-invalid: 2.0.1 + decode-named-character-reference: 1.3.0 + is-alphanumerical: 2.0.1 + is-decimal: 2.0.1 + is-hexadecimal: 2.0.1 + parse-json@5.2.0: dependencies: '@babel/code-frame': 7.26.2 @@ -7458,6 +9886,8 @@ snapshots: path-type@4.0.0: {} + pathe@2.0.3: {} + payload@3.81.0(graphql@16.9.0)(typescript@5.9.3): dependencies: '@next/env': 15.5.9 @@ -7556,6 +9986,12 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 + postcss@8.5.8: + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + prelude-ls@1.2.1: {} prettier@3.8.1: {} @@ -7564,10 +10000,14 @@ snapshots: dependencies: parse-ms: 4.0.0 + prismjs@1.30.0: {} + process-nextick-args@2.0.1: {} process-warning@5.0.0: {} + promise-limit@2.7.0: {} + prompts@2.4.2: dependencies: kleur: 3.0.3 @@ -7609,40 +10049,20 @@ snapshots: react: 19.2.4 scheduler: 0.27.0 - react-google-places-autocomplete@4.1.0(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + react-error-boundary@4.1.2(react@19.2.4): dependencies: - '@googlemaps/js-api-loader': 1.16.10 - '@types/google.maps': 3.58.1 + '@babel/runtime': 7.29.2 react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - react-select: 5.10.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - use-debounce: 3.4.3(react@19.2.4) - transitivePeerDependencies: - - '@types/react' - - supports-color - react-image-crop@10.1.8(react@19.2.4): + react-error-boundary@6.1.1(react@19.2.4): dependencies: react: 19.2.4 - react-is@16.13.1: {} - - react-select@5.10.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + react-image-crop@10.1.8(react@19.2.4): dependencies: - '@babel/runtime': 7.29.2 - '@emotion/cache': 11.14.0 - '@emotion/react': 11.14.0(@types/react@19.2.14)(react@19.2.4) - '@floating-ui/dom': 1.7.6 - '@types/react-transition-group': 4.4.12(@types/react@19.2.14) - memoize-one: 6.0.0 - prop-types: 15.8.1 react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - react-transition-group: 4.4.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - use-isomorphic-layout-effect: 1.2.1(@types/react@19.2.14)(react@19.2.4) - transitivePeerDependencies: - - '@types/react' - - supports-color + + react-is@16.13.1: {} react-select@5.9.0(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4): dependencies: @@ -7762,6 +10182,30 @@ snapshots: glob: 13.0.6 package-json-from-dist: 1.0.1 + rolldown@1.0.0-rc.12(@emnapi/core@1.9.2)(@emnapi/runtime@1.7.1): + dependencies: + '@oxc-project/types': 0.122.0 + '@rolldown/pluginutils': 1.0.0-rc.12 + optionalDependencies: + '@rolldown/binding-android-arm64': 1.0.0-rc.12 + '@rolldown/binding-darwin-arm64': 1.0.0-rc.12 + '@rolldown/binding-darwin-x64': 1.0.0-rc.12 + '@rolldown/binding-freebsd-x64': 1.0.0-rc.12 + '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-rc.12 + '@rolldown/binding-linux-arm64-gnu': 1.0.0-rc.12 + '@rolldown/binding-linux-arm64-musl': 1.0.0-rc.12 + '@rolldown/binding-linux-ppc64-gnu': 1.0.0-rc.12 + '@rolldown/binding-linux-s390x-gnu': 1.0.0-rc.12 + '@rolldown/binding-linux-x64-gnu': 1.0.0-rc.12 + '@rolldown/binding-linux-x64-musl': 1.0.0-rc.12 + '@rolldown/binding-openharmony-arm64': 1.0.0-rc.12 + '@rolldown/binding-wasm32-wasi': 1.0.0-rc.12(@emnapi/core@1.9.2)(@emnapi/runtime@1.7.1) + '@rolldown/binding-win32-arm64-msvc': 1.0.0-rc.12 + '@rolldown/binding-win32-x64-msvc': 1.0.0-rc.12 + transitivePeerDependencies: + - '@emnapi/core' + - '@emnapi/runtime' + run-parallel@1.2.0: dependencies: queue-microtask: 1.2.3 @@ -7915,6 +10359,8 @@ snapshots: sift@17.1.3: {} + siginfo@2.0.0: {} + signal-exit@4.1.0: {} simple-wcswidth@1.0.1: {} @@ -7951,8 +10397,15 @@ snapshots: source-map-js@1.2.1: {} + source-map-support@0.5.21: + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + source-map@0.5.7: {} + source-map@0.6.1: {} + source-map@0.7.6: {} sparse-bitfield@3.0.3: @@ -7966,8 +10419,12 @@ snapshots: stable-hash@0.0.4: {} + stackback@0.0.2: {} + state-local@1.0.7: {} + std-env@4.0.0: {} + stop-iteration-iterator@1.1.0: dependencies: es-errors: 1.3.0 @@ -8027,6 +10484,11 @@ snapshots: dependencies: safe-buffer: 5.1.2 + stringify-entities@4.0.4: + dependencies: + character-entities-html4: 2.1.0 + character-entities-legacy: 3.0.0 + strip-ansi@6.0.1: dependencies: ansi-regex: 5.0.1 @@ -8104,15 +10566,31 @@ snapshots: dependencies: convert-hrtime: 5.0.0 + tinybench@2.9.0: {} + + tinyexec@1.0.4: {} + tinyglobby@0.2.15: dependencies: fdir: 6.5.0(picomatch@4.0.4) picomatch: 4.0.4 + tinyrainbow@3.1.0: {} + + to-no-case@1.0.2: {} + to-regex-range@5.0.1: dependencies: is-number: 7.0.0 + to-snake-case@1.0.0: + dependencies: + to-space-case: 1.0.0 + + to-space-case@1.0.0: + dependencies: + to-no-case: 1.0.2 + token-types@6.1.2: dependencies: '@borewit/text-codec': 0.2.2 @@ -8192,7 +10670,7 @@ snapshots: typescript-eslint@8.26.1(eslint@9.22.0)(typescript@5.7.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.26.1(@typescript-eslint/parser@8.26.1(eslint@9.22.0)(typescript@5.7.3))(eslint@9.22.0)(typescript@5.7.3) + '@typescript-eslint/eslint-plugin': 8.26.1(@typescript-eslint/parser@8.26.1(eslint@9.22.0)(typescript@5.9.3))(eslint@9.22.0)(typescript@5.7.3) '@typescript-eslint/parser': 8.26.1(eslint@9.22.0)(typescript@5.7.3) '@typescript-eslint/utils': 8.26.1(eslint@9.22.0)(typescript@5.7.3) eslint: 9.22.0 @@ -8224,6 +10702,29 @@ snapshots: unicorn-magic@0.3.0: {} + unist-util-is@6.0.1: + dependencies: + '@types/unist': 3.0.3 + + unist-util-position-from-estree@2.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-stringify-position@4.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-visit-parents@6.0.2: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + + unist-util-visit@5.1.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + unist-util-visit-parents: 6.0.2 + untildify@4.0.0: {} uri-js@4.4.1: @@ -8235,10 +10736,6 @@ snapshots: react: 19.2.4 scheduler: 0.25.0 - use-debounce@3.4.3(react@19.2.4): - dependencies: - react: 19.2.4 - use-isomorphic-layout-effect@1.2.1(@types/react@19.2.14)(react@19.2.4): dependencies: react: 19.2.4 @@ -8251,13 +10748,110 @@ snapshots: uuid@10.0.0: {} + uuid@9.0.0: {} + uuid@9.0.1: optional: true + vfile-message@4.0.3: + dependencies: + '@types/unist': 3.0.3 + unist-util-stringify-position: 4.0.0 + + vite@8.0.5(@emnapi/core@1.9.2)(@emnapi/runtime@1.7.1)(esbuild@0.25.12)(sass@1.77.4)(tsx@4.21.0): + dependencies: + lightningcss: 1.32.0 + picomatch: 4.0.4 + postcss: 8.5.8 + rolldown: 1.0.0-rc.12(@emnapi/core@1.9.2)(@emnapi/runtime@1.7.1) + tinyglobby: 0.2.15 + optionalDependencies: + esbuild: 0.25.12 + fsevents: 2.3.3 + sass: 1.77.4 + tsx: 4.21.0 + transitivePeerDependencies: + - '@emnapi/core' + - '@emnapi/runtime' + + vite@8.0.5(@emnapi/core@1.9.2)(@emnapi/runtime@1.7.1)(esbuild@0.27.3)(sass@1.77.4)(tsx@4.21.0): + dependencies: + lightningcss: 1.32.0 + picomatch: 4.0.4 + postcss: 8.5.8 + rolldown: 1.0.0-rc.12(@emnapi/core@1.9.2)(@emnapi/runtime@1.7.1) + tinyglobby: 0.2.15 + optionalDependencies: + esbuild: 0.27.3 + fsevents: 2.3.3 + sass: 1.77.4 + tsx: 4.21.0 + transitivePeerDependencies: + - '@emnapi/core' + - '@emnapi/runtime' + + vitest@4.1.2(happy-dom@20.8.9)(vite@8.0.5(@emnapi/core@1.9.2)(@emnapi/runtime@1.7.1)(esbuild@0.25.12)(sass@1.77.4)(tsx@4.21.0)): + dependencies: + '@vitest/expect': 4.1.2 + '@vitest/mocker': 4.1.2(vite@8.0.5(@emnapi/core@1.9.2)(@emnapi/runtime@1.7.1)(esbuild@0.25.12)(sass@1.77.4)(tsx@4.21.0)) + '@vitest/pretty-format': 4.1.2 + '@vitest/runner': 4.1.2 + '@vitest/snapshot': 4.1.2 + '@vitest/spy': 4.1.2 + '@vitest/utils': 4.1.2 + es-module-lexer: 2.0.0 + expect-type: 1.3.0 + magic-string: 0.30.21 + obug: 2.1.1 + pathe: 2.0.3 + picomatch: 4.0.4 + std-env: 4.0.0 + tinybench: 2.9.0 + tinyexec: 1.0.4 + tinyglobby: 0.2.15 + tinyrainbow: 3.1.0 + vite: 8.0.5(@emnapi/core@1.9.2)(@emnapi/runtime@1.7.1)(esbuild@0.25.12)(sass@1.77.4)(tsx@4.21.0) + why-is-node-running: 2.3.0 + optionalDependencies: + happy-dom: 20.8.9 + transitivePeerDependencies: + - msw + + vitest@4.1.2(happy-dom@20.8.9)(vite@8.0.5(@emnapi/core@1.9.2)(@emnapi/runtime@1.7.1)(esbuild@0.27.3)(sass@1.77.4)(tsx@4.21.0)): + dependencies: + '@vitest/expect': 4.1.2 + '@vitest/mocker': 4.1.2(vite@8.0.5(@emnapi/core@1.9.2)(@emnapi/runtime@1.7.1)(esbuild@0.27.3)(sass@1.77.4)(tsx@4.21.0)) + '@vitest/pretty-format': 4.1.2 + '@vitest/runner': 4.1.2 + '@vitest/snapshot': 4.1.2 + '@vitest/spy': 4.1.2 + '@vitest/utils': 4.1.2 + es-module-lexer: 2.0.0 + expect-type: 1.3.0 + magic-string: 0.30.21 + obug: 2.1.1 + pathe: 2.0.3 + picomatch: 4.0.4 + std-env: 4.0.0 + tinybench: 2.9.0 + tinyexec: 1.0.4 + tinyglobby: 0.2.15 + tinyrainbow: 3.1.0 + vite: 8.0.5(@emnapi/core@1.9.2)(@emnapi/runtime@1.7.1)(esbuild@0.27.3)(sass@1.77.4)(tsx@4.21.0) + why-is-node-running: 2.3.0 + optionalDependencies: + happy-dom: 20.8.9 + transitivePeerDependencies: + - msw + + web-streams-polyfill@3.3.3: {} + web-worker@1.5.0: {} webidl-conversions@7.0.0: {} + whatwg-mimetype@3.0.0: {} + whatwg-url@14.2.0: dependencies: tr46: 5.1.1 @@ -8308,6 +10902,11 @@ snapshots: dependencies: isexe: 2.0.0 + why-is-node-running@2.3.0: + dependencies: + siginfo: 2.0.0 + stackback: 0.0.2 + word-wrap@1.2.5: {} wrap-ansi@7.0.0: @@ -8348,6 +10947,12 @@ snapshots: buffer-crc32: 0.2.13 pend: 1.2.0 + yjs@13.6.30: + dependencies: + lib0: 0.2.117 + yocto-queue@0.1.0: {} yoctocolors@2.1.2: {} + + zwitch@2.0.4: {} diff --git a/geocoding/src/components/GeocodingFieldClient.tsx b/geocoding/src/components/GeocodingFieldClient.tsx index 14b36ba8..3809efec 100644 --- a/geocoding/src/components/GeocodingFieldClient.tsx +++ b/geocoding/src/components/GeocodingFieldClient.tsx @@ -1,16 +1,20 @@ 'use client' +/// import type { FieldBaseClient } from 'payload' -import { FieldError, FieldLabel, useField } from '@payloadcms/ui' -import GooglePlacesAutocompleteImport, { - geocodeByPlaceId, - getLatLng, -} from 'react-google-places-autocomplete' +import { FieldError, FieldLabel, ReactSelect, useField } from '@payloadcms/ui' +import { useEffect, useRef, useState } from 'react' -// Workaround for TypeScript moduleResolution: "nodenext" with React 19 -const GooglePlacesAutocomplete = - // eslint-disable-next-line @typescript-eslint/no-explicit-any - GooglePlacesAutocompleteImport as unknown as React.ComponentType +import { loadGoogleMapsPlaces } from './loadGoogleMapsPlaces.js' + +type SelectOption = { label: string; value: unknown } + +interface LocationMeta { + formattedAddress: string + googlePlaceId: string + name: string + types: string[] +} interface GeocodingFieldComponentProps { field: Pick @@ -18,53 +22,135 @@ interface GeocodingFieldComponentProps { path: string } -/** - * A custom client component that shows the Google Places Autocomplete component and - * fills the point and geodata fields with the received data from the Google Places API. - */ +function toSelectOption(meta: LocationMeta): SelectOption { + const label = + meta.name && meta.formattedAddress && !meta.formattedAddress.startsWith(meta.name) + ? `${meta.name}, ${meta.formattedAddress}` + : meta.formattedAddress || meta.name + return { label, value: meta.googlePlaceId } +} + export const GeocodingFieldClient = ({ field, googleMapsApiKey, path, }: GeocodingFieldComponentProps) => { - const pointFieldPath = path.replace('_googlePlacesData', '') + const pointFieldPath = path.replace('_meta', '') - const { setValue: setGeoData, value: geoData } = useField({ + const { setValue: setLocationMeta, value: locationMeta } = useField({ path, }) const { setValue: setPoint } = useField>({ path: pointFieldPath }) + const [options, setOptions] = useState([]) + const [isLoading, setIsLoading] = useState(false) + const [error, setError] = useState(null) + const sessionTokenRef = useRef(null) + const debounceRef = useRef>(null) + + useEffect(() => { + let cancelled = false + loadGoogleMapsPlaces(googleMapsApiKey).catch((e) => { + if (!cancelled) { + setError(e instanceof Error ? e.message : 'Failed to load Google Maps') + } + }) + return () => { + cancelled = true + if (debounceRef.current) { + clearTimeout(debounceRef.current) + } + } + }, [googleMapsApiKey]) + + const handleInputChange = (inputValue: string) => { + if (debounceRef.current) { + clearTimeout(debounceRef.current) + } + if (!inputValue || inputValue.length < 2) { + setOptions([]) + setIsLoading(false) + return + } + + debounceRef.current = setTimeout(async () => { + setIsLoading(true) + try { + if (!sessionTokenRef.current) { + sessionTokenRef.current = new google.maps.places.AutocompleteSessionToken() + } + + const { suggestions } = + await google.maps.places.AutocompleteSuggestion.fetchAutocompleteSuggestions({ + input: inputValue, + sessionToken: sessionTokenRef.current, + }) + + setOptions( + suggestions + .filter((s) => s.placePrediction != null) + .map((s) => ({ + label: s.placePrediction!.text.text, + value: s.placePrediction!.placeId, + })), + ) + } catch { + setOptions([]) + } finally { + setIsLoading(false) + } + }, 300) + } + + const handleChange = (option: null | SelectOption | SelectOption[]) => { + if (!option || Array.isArray(option)) { + setPoint(null) + setLocationMeta(null) + return + } + + const placeId = option.value as string + new google.maps.places.Place({ id: placeId }) + .fetchFields({ + fields: ['displayName', 'formattedAddress', 'location', 'types'], + sessionToken: sessionTokenRef.current, + } as { sessionToken: unknown } & google.maps.places.FetchFieldsRequest) + .then(({ place }) => { + sessionTokenRef.current = null + if (place.location) { + setPoint([place.location.lng(), place.location.lat()]) + setLocationMeta({ + name: place.displayName, + formattedAddress: place.formattedAddress, + googlePlaceId: placeId, + types: place.types ?? [], + }) + } + }) + .catch(() => setError('Failed to fetch place details')) + } + return (
- { - if (geoData) { - const placeId = (geoData as { value: { place_id: string } }).value.place_id - const geocode = (await geocodeByPlaceId(placeId)).at(0) - - if (!geocode) { - return - } - const latLng = await getLatLng(geocode) - - setPoint([latLng.lng, latLng.lat]) - setGeoData(geoData) - } else { - // reset the fields when it was cleared - setPoint([]) - setGeoData(null) - } - }, - value: geoData as unknown, - }} - /> + {error ? ( +
{error}
+ ) : ( + true} + isClearable + isLoading={isLoading} + isSearchable + onChange={(val) => handleChange(val as null | SelectOption)} + onInputChange={handleInputChange} + options={options} + placeholder="Search for a place..." + value={locationMeta ? toSelectOption(locationMeta) : undefined} + /> + )}
) } diff --git a/geocoding/src/components/loadGoogleMapsPlaces.ts b/geocoding/src/components/loadGoogleMapsPlaces.ts new file mode 100644 index 00000000..287a53fa --- /dev/null +++ b/geocoding/src/components/loadGoogleMapsPlaces.ts @@ -0,0 +1,48 @@ +/// + +let mapsLoadPromise: null | Promise = null + +/** + * Loads the Google Maps Places library. Uses a module-level singleton + * so concurrent callers share the same load. Resets on error to allow retry. + */ +export function loadGoogleMapsPlaces(apiKey: string): Promise { + if (mapsLoadPromise) { + return mapsLoadPromise + } + + if (typeof google !== 'undefined' && typeof google.maps?.importLibrary === 'function') { + mapsLoadPromise = google.maps.importLibrary('places').then(() => {}) + return mapsLoadPromise + } + + mapsLoadPromise = new Promise((resolve, reject) => { + const w = window as unknown as { google: { maps: Record } } + const g = w.google || (w.google = {} as { maps: Record }) + if (!g.maps) { + g.maps = {} + } + + const script = document.createElement('script') + const params = new URLSearchParams({ + callback: '__gmcb', + key: apiKey, + libraries: 'places', + }) + script.src = `https://maps.googleapis.com/maps/api/js?${params}` + script.async = true + // eslint-disable-next-line @typescript-eslint/no-explicit-any + ;(window as any).__gmcb = () => { + resolve() + // eslint-disable-next-line @typescript-eslint/no-explicit-any + delete (window as any).__gmcb + } + script.onerror = () => { + mapsLoadPromise = null + reject(new Error('Failed to load Google Maps API')) + } + document.head.appendChild(script) + }) + + return mapsLoadPromise +} diff --git a/geocoding/src/endpoints/geocodingSearch.test.ts b/geocoding/src/endpoints/geocodingSearch.test.ts new file mode 100644 index 00000000..28bd5d5d --- /dev/null +++ b/geocoding/src/endpoints/geocodingSearch.test.ts @@ -0,0 +1,104 @@ +import type { PayloadRequest } from 'payload' + +import { beforeEach, describe, expect, it, vi } from 'vitest' + +import * as geocodingService from '../services/googleGeocoding.js' +import { createGeocodingSearchEndpoint } from './geocodingSearch.js' + +const MOCK_API_KEY = 'test-api-key' + +const MOCK_RESULT = { + name: 'Berlin', + formattedAddress: 'Berlin, Germany', + googlePlaceId: 'ChIJAVkDPzdOqEcRcDteW0YgIQQ', + location: { lat: 52.52, lng: 13.405 }, + types: ['locality'], +} + +function createMockRequest(overrides: { url: string } & Partial): PayloadRequest { + return { user: { id: '1', email: 'test@test.com' }, ...overrides } as unknown as PayloadRequest +} + +describe('createGeocodingSearchEndpoint', () => { + beforeEach(() => { + vi.restoreAllMocks() + }) + + it('returns 401 when user is not authenticated (default access)', async () => { + const endpoint = createGeocodingSearchEndpoint({ apiKey: MOCK_API_KEY }) + const req = createMockRequest({ + url: 'http://localhost/api/geocoding-plugin/search?q=Berlin', + user: null as any, + }) + + const response = await endpoint.handler(req) + expect(response.status).toBe(401) + }) + + it('returns 200 with results for authenticated user', async () => { + vi.spyOn(geocodingService, 'geocodeAddress').mockResolvedValue([MOCK_RESULT]) + + const endpoint = createGeocodingSearchEndpoint({ apiKey: MOCK_API_KEY }) + const req = createMockRequest({ url: 'http://localhost/api/geocoding-plugin/search?q=Berlin' }) + + const response = await endpoint.handler(req) + expect(response.status).toBe(200) + + const body = await response.json() + expect(body.results).toHaveLength(1) + expect(body.results[0].formattedAddress).toBe('Berlin, Germany') + expect(body.results[0].location).toEqual({ lat: 52.52, lng: 13.405 }) + }) + + it('returns 400 when q parameter is missing', async () => { + const endpoint = createGeocodingSearchEndpoint({ apiKey: MOCK_API_KEY }) + const req = createMockRequest({ url: 'http://localhost/api/geocoding-plugin/search' }) + + const response = await endpoint.handler(req) + expect(response.status).toBe(400) + }) + + it('returns 400 when q parameter is empty', async () => { + const endpoint = createGeocodingSearchEndpoint({ apiKey: MOCK_API_KEY }) + const req = createMockRequest({ url: 'http://localhost/api/geocoding-plugin/search?q=%20' }) + + const response = await endpoint.handler(req) + expect(response.status).toBe(400) + }) + + it('uses custom access function when provided', async () => { + vi.spyOn(geocodingService, 'geocodeAddress').mockResolvedValue([MOCK_RESULT]) + + const customAccess = vi.fn().mockResolvedValue(true) + const endpoint = createGeocodingSearchEndpoint({ access: customAccess, apiKey: MOCK_API_KEY }) + const req = createMockRequest({ + url: 'http://localhost/api/geocoding-plugin/search?q=Berlin', + user: null as any, + }) + + const response = await endpoint.handler(req) + expect(response.status).toBe(200) + expect(customAccess).toHaveBeenCalledWith({ req }) + }) + + it('denies access when custom access function returns false', async () => { + const customAccess = vi.fn().mockResolvedValue(false) + const endpoint = createGeocodingSearchEndpoint({ access: customAccess, apiKey: MOCK_API_KEY }) + const req = createMockRequest({ url: 'http://localhost/api/geocoding-plugin/search?q=Berlin' }) + + const response = await endpoint.handler(req) + expect(response.status).toBe(401) + }) + + it('returns 502 when geocoding service fails', async () => { + vi.spyOn(geocodingService, 'geocodeAddress').mockRejectedValue( + new Error('Google Geocoding API error: REQUEST_DENIED'), + ) + + const endpoint = createGeocodingSearchEndpoint({ apiKey: MOCK_API_KEY }) + const req = createMockRequest({ url: 'http://localhost/api/geocoding-plugin/search?q=Berlin' }) + + const response = await endpoint.handler(req) + expect(response.status).toBe(502) + }) +}) diff --git a/geocoding/src/endpoints/geocodingSearch.ts b/geocoding/src/endpoints/geocodingSearch.ts new file mode 100644 index 00000000..1d726f52 --- /dev/null +++ b/geocoding/src/endpoints/geocodingSearch.ts @@ -0,0 +1,45 @@ +import type { Endpoint, PayloadRequest } from 'payload' + +import type { GeocodingEndpointAccess } from '../types/GeoCodingPluginConfig.js' + +import { geocodeAddress } from '../services/googleGeocoding.js' + +/** + * Creates a Payload endpoint for server-side geocoding. + * Enables agents and API consumers to geocode addresses without the browser UI. + * + * Usage: GET /api/geocoding-plugin/search?q=Berlin + */ +export const createGeocodingSearchEndpoint = (options: { + access?: GeocodingEndpointAccess + apiKey: string +}): Endpoint => ({ + handler: async (req: PayloadRequest) => { + // Authentication: require a logged-in user by default + const hasAccess = options.access ? await options.access({ req }) : Boolean(req.user) + + if (!hasAccess) { + return Response.json({ errors: [{ message: 'Unauthorized' }] }, { status: 401 }) + } + + const url = new URL(req.url!) + const query = url.searchParams.get('q') + + if (!query || query.trim() === '') { + return Response.json( + { errors: [{ message: 'Query parameter "q" is required' }] }, + { status: 400 }, + ) + } + + try { + const results = await geocodeAddress(query, options.apiKey) + return Response.json({ results }) + } catch (error) { + const message = error instanceof Error ? error.message : 'Geocoding failed' + return Response.json({ errors: [{ message }] }, { status: 502 }) + } + }, + method: 'get', + path: '/geocoding-plugin/search', +}) diff --git a/geocoding/src/fields/geocodingField.test.ts b/geocoding/src/fields/geocodingField.test.ts new file mode 100644 index 00000000..62c7ba9b --- /dev/null +++ b/geocoding/src/fields/geocodingField.test.ts @@ -0,0 +1,59 @@ +import type { JSONField, PointField, RowField, TextField } from 'payload' + +import { describe, expect, it } from 'vitest' + +import { geocodingField } from './geocodingField.js' + +describe('geocodingField', () => { + it('creates a row field with meta, point, and address fields', () => { + const field = geocodingField({ + pointField: { name: 'location', type: 'point' }, + }) as RowField + + expect(field.type).toBe('row') + expect(field.fields).toHaveLength(3) + }) + + it('adds a hidden virtual address text field for server-side geocoding', () => { + const field = geocodingField({ + pointField: { name: 'location', type: 'point' }, + }) as RowField + + const addressField = field.fields.find( + (f) => 'name' in f && f.name === 'location_address', + ) as TextField + expect(addressField).toBeDefined() + expect(addressField.type).toBe('text') + expect(addressField.admin?.hidden).toBe(true) + expect(addressField.virtual).toBe(true) + }) + + it('adds beforeChange hooks to both meta and point fields', () => { + const field = geocodingField({ + pointField: { name: 'location', type: 'point' }, + }) as RowField + + const metaField = field.fields.find( + (f) => 'name' in f && f.name === 'location_meta', + ) as JSONField + expect(metaField.hooks?.beforeChange).toHaveLength(1) + + const pointField = field.fields.find((f) => 'name' in f && f.name === 'location') as PointField + expect(pointField.hooks?.beforeChange).toHaveLength(1) + }) + + it('preserves existing point field hooks', () => { + const existingHook = () => undefined + const field = geocodingField({ + pointField: { + name: 'location', + type: 'point', + hooks: { beforeChange: [existingHook] }, + }, + }) as RowField + + const pointField = field.fields.find((f) => 'name' in f && f.name === 'location') as PointField + expect(pointField.hooks?.beforeChange).toHaveLength(2) + expect(pointField.hooks!.beforeChange![0]).toBe(existingHook) + }) +}) diff --git a/geocoding/src/fields/geocodingField.ts b/geocoding/src/fields/geocodingField.ts index 44e81f46..f702ba09 100644 --- a/geocoding/src/fields/geocodingField.ts +++ b/geocoding/src/fields/geocodingField.ts @@ -1,38 +1,87 @@ -import type { Field } from 'payload' +import type { Field, PointField } from 'payload' import type { GeoCodingFieldConfig } from '../types/GeoCodingFieldConfig.js' +import { + createMetaBeforeChangeHook, + createPointBeforeChangeHook, +} from '../hooks/geocodeBeforeChange.js' + /** * Creates a row field containing: * 1. The provided point field for storing the coordinates from the Google Places API - * 2. A JSON field that stores the raw Google Places API geocoding data + * 2. A JSON field that stores location metadata (display name, address, googlePlaceId) + * 3. A hidden virtual text field `{pointFieldName}_address` for server-side geocoding via the API + * + * Agents and API consumers can submit an address string via the `_address` field, + * and the beforeChange hooks will auto-geocode it and populate the point and meta fields. */ export const geocodingField = (config: GeoCodingFieldConfig): Field => { + const pointFieldName = config.pointField.name + + const metaField: Field = { + name: pointFieldName + '_meta', + type: 'json', + access: config.locationMetaOverride?.access ?? {}, + admin: { + // overridable props: + readOnly: true, + + ...config.locationMetaOverride?.admin, + + // non-overridable props: + components: { + Field: '@jhb.software/payload-geocoding-plugin/server#GeocodingField', + }, + }, + hooks: { + beforeChange: [createMetaBeforeChangeHook({ pointFieldName })], + }, + jsonSchema: { + fileMatch: ['a://b/foo.json'], + schema: { + type: 'object', + additionalProperties: false, + properties: { + name: { type: 'string' }, + formattedAddress: { type: 'string' }, + googlePlaceId: { type: 'string' }, + types: { type: 'array', items: { type: 'string' } }, + }, + required: ['formattedAddress', 'googlePlaceId', 'name', 'types'], + }, + uri: 'a://b/foo.json', + }, + label: config.locationMetaOverride?.label ?? 'Location', + required: config.locationMetaOverride?.required, + } + + const pointField: PointField = { + ...config.pointField, + hooks: { + ...config.pointField.hooks, + beforeChange: [ + ...(config.pointField.hooks?.beforeChange ?? []), + createPointBeforeChangeHook({ pointFieldName }), + ], + }, + } + + const addressField: Field = { + name: pointFieldName + '_address', + type: 'text', + admin: { + hidden: true, + }, + label: 'Address (for server-side geocoding)', + virtual: true, + } + return { type: 'row', admin: { position: config.pointField.admin?.position ?? undefined, }, - fields: [ - { - name: config.pointField.name + '_googlePlacesData', - type: 'json', - access: config.geoDataFieldOverride?.access ?? {}, - admin: { - // overridable props: - readOnly: true, - - ...config.geoDataFieldOverride?.admin, - - // non-overridable props: - components: { - Field: '@jhb.software/payload-geocoding-plugin/server#GeocodingField', - }, - }, - label: config.geoDataFieldOverride?.label ?? 'Location', - required: config.geoDataFieldOverride?.required, - }, - config.pointField, - ], + fields: [metaField, pointField, addressField], } } diff --git a/geocoding/src/hooks/geocodeBeforeChange.test.ts b/geocoding/src/hooks/geocodeBeforeChange.test.ts new file mode 100644 index 00000000..44f25a29 --- /dev/null +++ b/geocoding/src/hooks/geocodeBeforeChange.test.ts @@ -0,0 +1,150 @@ +import type { FieldHookArgs } from 'payload' + +import { beforeEach, describe, expect, it, vi } from 'vitest' + +import * as geocodingService from '../services/googleGeocoding.js' +import { createMetaBeforeChangeHook, createPointBeforeChangeHook } from './geocodeBeforeChange.js' + +const MOCK_API_KEY = 'test-api-key' + +const MOCK_RESULT = { + name: 'Alexanderplatz', + formattedAddress: 'Alexanderplatz, 10178 Berlin, Germany', + googlePlaceId: 'ChIJp1l4uWBRqEcR2SPNRBMhtAI', + location: { lat: 52.5219, lng: 13.4132 }, + types: ['point_of_interest'], +} + +function createMockReq() { + return { + payload: { + config: { + custom: { + payloadGeocodingPlugin: { + googleMapsApiKey: MOCK_API_KEY, + }, + }, + }, + }, + } +} + +function createMockHookArgs(overrides: Partial): FieldHookArgs { + return { + blockData: undefined, + collection: null, + context: {}, + data: {}, + field: {} as any, + operation: 'create', + originalDoc: undefined, + path: [] as any, + req: createMockReq() as any, + schemaPath: [] as any, + siblingData: {}, + value: undefined, + ...overrides, + } as FieldHookArgs +} + +describe('createMetaBeforeChangeHook', () => { + beforeEach(() => { + vi.restoreAllMocks() + }) + + it('geocodes an address string and returns location metadata', async () => { + vi.spyOn(geocodingService, 'geocodeAddress').mockResolvedValue([MOCK_RESULT]) + + const hook = createMetaBeforeChangeHook({ pointFieldName: 'location' }) + + const result = await hook( + createMockHookArgs({ + siblingData: { location_address: 'Alexanderplatz, Berlin' }, + }), + ) + + expect(result).toEqual({ + name: 'Alexanderplatz', + formattedAddress: 'Alexanderplatz, 10178 Berlin, Germany', + googlePlaceId: 'ChIJp1l4uWBRqEcR2SPNRBMhtAI', + types: ['point_of_interest'], + }) + }) + + it('returns undefined when no address is provided', async () => { + const hook = createMetaBeforeChangeHook({ pointFieldName: 'location' }) + const result = await hook(createMockHookArgs({ siblingData: {} })) + expect(result).toBeUndefined() + }) + + it('returns undefined when address is empty string', async () => { + const hook = createMetaBeforeChangeHook({ pointFieldName: 'location' }) + const result = await hook(createMockHookArgs({ siblingData: { location_address: ' ' } })) + expect(result).toBeUndefined() + }) + + it('returns undefined when geocoding returns no results', async () => { + vi.spyOn(geocodingService, 'geocodeAddress').mockResolvedValue([]) + const hook = createMetaBeforeChangeHook({ pointFieldName: 'location' }) + const result = await hook( + createMockHookArgs({ siblingData: { location_address: 'xyznonexistent' } }), + ) + expect(result).toBeUndefined() + }) + + it('throws when API key is not configured', async () => { + const hook = createMetaBeforeChangeHook({ pointFieldName: 'location' }) + await expect( + hook( + createMockHookArgs({ + req: { payload: { config: { custom: {} } } } as any, + siblingData: { location_address: 'Berlin' }, + }), + ), + ).rejects.toThrow('Geocoding plugin API key not configured') + }) +}) + +describe('createPointBeforeChangeHook', () => { + beforeEach(() => { + vi.restoreAllMocks() + }) + + it('returns [lng, lat] from geocoded address', async () => { + vi.spyOn(geocodingService, 'geocodeAddress').mockResolvedValue([MOCK_RESULT]) + + const hook = createPointBeforeChangeHook({ pointFieldName: 'location' }) + const result = await hook( + createMockHookArgs({ + siblingData: { location_address: 'Berlin' }, + }), + ) + + expect(result).toEqual([13.4132, 52.5219]) + }) + + it('returns existing value when no address is provided', async () => { + const hook = createPointBeforeChangeHook({ pointFieldName: 'location' }) + const result = await hook(createMockHookArgs({ siblingData: {}, value: [1, 2] })) + expect(result).toEqual([1, 2]) + }) + + it('shares cached geocoding result via context', async () => { + const geocodeSpy = vi.spyOn(geocodingService, 'geocodeAddress').mockResolvedValue([MOCK_RESULT]) + + const context: Record = {} + const hookArgs = { context, siblingData: { location_address: 'Berlin' } } + + const metaHook = createMetaBeforeChangeHook({ pointFieldName: 'location' }) + const pointHook = createPointBeforeChangeHook({ pointFieldName: 'location' }) + + const [metaResult, pointResult] = await Promise.all([ + metaHook(createMockHookArgs(hookArgs)), + pointHook(createMockHookArgs(hookArgs)), + ]) + + expect(metaResult).toHaveProperty('formattedAddress') + expect(pointResult).toEqual([13.4132, 52.5219]) + expect(geocodeSpy).toHaveBeenCalledTimes(1) + }) +}) diff --git a/geocoding/src/hooks/geocodeBeforeChange.ts b/geocoding/src/hooks/geocodeBeforeChange.ts new file mode 100644 index 00000000..c90e243b --- /dev/null +++ b/geocoding/src/hooks/geocodeBeforeChange.ts @@ -0,0 +1,112 @@ +import type { FieldHook } from 'payload' + +import type { GeocodingResult } from '../services/googleGeocoding.js' + +import { geocodeAddress } from '../services/googleGeocoding.js' + +/** + * Gets (or triggers) the geocoding result for the given address, caching it in + * `req.context` so that the meta and point field hooks share a single API call. + * + * Both hooks may fire concurrently (Payload processes row fields in parallel), + * so the promise itself is cached — whichever hook runs first starts the fetch, + * and the other awaits the same promise. + */ +function getCachedGeocodingResult( + cacheKey: string, + address: string, + apiKey: string, + context: Record, +): Promise { + if (!context[cacheKey]) { + context[cacheKey] = geocodeAddress(address.trim(), apiKey) + } + return context[cacheKey] as Promise +} + +function getApiKey(req: { payload: { config: { custom?: Record } } }): string { + const apiKey = ( + req.payload.config.custom?.payloadGeocodingPlugin as { googleMapsApiKey?: string } | undefined + )?.googleMapsApiKey + + if (!apiKey) { + throw new Error( + 'Geocoding plugin API key not configured. Ensure payloadGeocodingPlugin is added to your Payload config with a googleMapsApiKey.', + ) + } + + return apiKey +} + +function getAddress( + addressFieldName: string, + siblingData?: Record, + data?: Record, +): string | undefined { + const address = siblingData?.[addressFieldName] ?? data?.[addressFieldName] + if (!address || typeof address !== 'string' || address.trim() === '') { + return undefined + } + return address +} + +/** + * beforeChange hook for the **location metadata JSON field**. + * + * When `{pointFieldName}_address` contains a string, geocodes it server-side + * and returns the location metadata as the field value. + */ +export const createMetaBeforeChangeHook = (options: { pointFieldName: string }): FieldHook => { + return async ({ context, data, req, siblingData }) => { + const addressFieldName = options.pointFieldName + '_address' + const address = getAddress(addressFieldName, siblingData, data) + + if (!address) { + return undefined + } + + const apiKey = getApiKey(req) + const cacheKey = `geocoding_${options.pointFieldName}` + const results = await getCachedGeocodingResult(cacheKey, address, apiKey, context) + + if (results.length === 0) { + return undefined + } + + const firstResult = results[0] + return { + name: firstResult.name, + formattedAddress: firstResult.formattedAddress, + googlePlaceId: firstResult.googlePlaceId, + types: firstResult.types, + } + } +} + +/** + * beforeChange hook for the **point field**. + * + * When `{pointFieldName}_address` contains a string, geocodes it server-side + * and returns `[lng, lat]` as the field value. + */ +export const createPointBeforeChangeHook = (options: { pointFieldName: string }): FieldHook => { + return async ({ context, data, req, siblingData, value }) => { + const addressFieldName = options.pointFieldName + '_address' + const address = getAddress(addressFieldName, siblingData, data) + + if (!address) { + return value + } + + const apiKey = getApiKey(req) + const cacheKey = `geocoding_${options.pointFieldName}` + const results = await getCachedGeocodingResult(cacheKey, address, apiKey, context) + + if (results.length === 0) { + return value + } + + const firstResult = results[0] + return [firstResult.location.lng, firstResult.location.lat] + } +} diff --git a/geocoding/src/index.ts b/geocoding/src/index.ts index 53c84cd5..490dfd80 100644 --- a/geocoding/src/index.ts +++ b/geocoding/src/index.ts @@ -1,4 +1,9 @@ export { geocodingField } from './fields/geocodingField.js' export { payloadGeocodingPlugin } from './plugin.js' +export { geocodeAddress } from './services/googleGeocoding.js' +export type { GeocodingResult } from './services/googleGeocoding.js' export type { GeoCodingFieldConfig } from './types/GeoCodingFieldConfig.js' -export type { GeocodingPluginConfig } from './types/GeoCodingPluginConfig.js' +export type { + GeocodingEndpointAccess, + GeocodingPluginConfig, +} from './types/GeoCodingPluginConfig.js' diff --git a/geocoding/src/plugin.test.ts b/geocoding/src/plugin.test.ts new file mode 100644 index 00000000..6604157f --- /dev/null +++ b/geocoding/src/plugin.test.ts @@ -0,0 +1,60 @@ +import type { Config } from 'payload' + +import { describe, expect, it } from 'vitest' + +import { payloadGeocodingPlugin } from './plugin.js' + +const BASE_CONFIG: Config = { + collections: [], + db: {} as any, + secret: 'test', +} + +describe('payloadGeocodingPlugin', () => { + it('registers the geocoding search endpoint when enabled', () => { + const plugin = payloadGeocodingPlugin({ + googleMapsApiKey: 'test-key', + }) + const config = plugin(BASE_CONFIG) + + expect(config.endpoints).toBeDefined() + expect(config.endpoints).toHaveLength(1) + expect(config.endpoints![0]).toMatchObject({ + method: 'get', + path: '/geocoding-plugin/search', + }) + }) + + it('does not register endpoint when plugin is disabled', () => { + const plugin = payloadGeocodingPlugin({ + enabled: false, + googleMapsApiKey: 'test-key', + }) + const config = plugin(BASE_CONFIG) + + expect(config.endpoints ?? []).toHaveLength(0) + }) + + it('stores the API key in config.custom', () => { + const plugin = payloadGeocodingPlugin({ + googleMapsApiKey: 'my-api-key', + }) + const config = plugin(BASE_CONFIG) + + expect(config.custom?.payloadGeocodingPlugin?.googleMapsApiKey).toBe('my-api-key') + }) + + it('preserves existing endpoints from incoming config', () => { + const existingEndpoint = { + handler: () => Response.json({ ok: true }), + method: 'get' as const, + path: '/health', + } + const plugin = payloadGeocodingPlugin({ + googleMapsApiKey: 'test-key', + }) + const config = plugin({ ...BASE_CONFIG, endpoints: [existingEndpoint] }) + + expect(config.endpoints).toHaveLength(2) + }) +}) diff --git a/geocoding/src/plugin.ts b/geocoding/src/plugin.ts index cfc93e1f..09cf9b94 100644 --- a/geocoding/src/plugin.ts +++ b/geocoding/src/plugin.ts @@ -2,6 +2,8 @@ import type { Config } from 'payload' import type { GeocodingPluginConfig } from './types/GeoCodingPluginConfig.js' +import { createGeocodingSearchEndpoint } from './endpoints/geocodingSearch.js' + /** * Payload plugin which extends the point field with geocoding functionality. */ @@ -13,6 +15,11 @@ export const payloadGeocodingPlugin = return incomingConfig } + const geocodingEndpoint = createGeocodingSearchEndpoint({ + access: pluginOptions.geocodingEndpoint?.access, + apiKey: pluginOptions.googleMapsApiKey, + }) + // Store API key in config.custom for server component access const config: Config = { ...incomingConfig, @@ -22,6 +29,7 @@ export const payloadGeocodingPlugin = googleMapsApiKey: pluginOptions.googleMapsApiKey, }, }, + endpoints: [...(incomingConfig.endpoints ?? []), geocodingEndpoint], } return config diff --git a/geocoding/src/services/googleGeocoding.test.ts b/geocoding/src/services/googleGeocoding.test.ts new file mode 100644 index 00000000..970d1014 --- /dev/null +++ b/geocoding/src/services/googleGeocoding.test.ts @@ -0,0 +1,82 @@ +import { beforeEach, describe, expect, it, vi } from 'vitest' + +import { geocodeAddress } from './googleGeocoding.js' + +const MOCK_API_KEY = 'test-api-key' + +const MOCK_GOOGLE_RESPONSE = { + results: [ + { + address_components: [ + { long_name: 'Alexanderplatz', short_name: 'Alexanderplatz', types: ['point_of_interest'] }, + { long_name: 'Berlin', short_name: 'Berlin', types: ['locality'] }, + ], + formatted_address: 'Alexanderplatz, 10178 Berlin, Germany', + geometry: { + location: { lat: 52.5219, lng: 13.4132 }, + }, + place_id: 'ChIJp1l4uWBRqEcR2SPNRBMhtAI', + types: ['point_of_interest', 'establishment'], + }, + ], + status: 'OK', +} + +describe('geocodeAddress', () => { + beforeEach(() => { + vi.restoreAllMocks() + }) + + it('returns geocoded results for a valid address', async () => { + vi.spyOn(globalThis, 'fetch').mockResolvedValue( + new Response(JSON.stringify(MOCK_GOOGLE_RESPONSE), { status: 200 }), + ) + + const results = await geocodeAddress('Alexanderplatz, Berlin', MOCK_API_KEY) + + expect(results).toHaveLength(1) + expect(results[0]).toEqual({ + name: 'Alexanderplatz', + formattedAddress: 'Alexanderplatz, 10178 Berlin, Germany', + googlePlaceId: 'ChIJp1l4uWBRqEcR2SPNRBMhtAI', + location: { lat: 52.5219, lng: 13.4132 }, + types: ['point_of_interest', 'establishment'], + }) + + const fetchCall = vi.mocked(fetch).mock.calls[0][0] as string + expect(fetchCall).toContain('address=Alexanderplatz') + expect(fetchCall).toContain(`key=${MOCK_API_KEY}`) + }) + + it('returns empty array for ZERO_RESULTS', async () => { + vi.spyOn(globalThis, 'fetch').mockResolvedValue( + new Response(JSON.stringify({ results: [], status: 'ZERO_RESULTS' }), { status: 200 }), + ) + + const results = await geocodeAddress('xyznonexistent12345', MOCK_API_KEY) + expect(results).toEqual([]) + }) + + it('throws on API error status', async () => { + vi.spyOn(globalThis, 'fetch').mockResolvedValue( + new Response( + JSON.stringify({ error_message: 'Invalid key', results: [], status: 'REQUEST_DENIED' }), + { status: 200 }, + ), + ) + + await expect(geocodeAddress('Berlin', MOCK_API_KEY)).rejects.toThrow( + 'Google Geocoding API error: REQUEST_DENIED - Invalid key', + ) + }) + + it('throws on HTTP failure', async () => { + vi.spyOn(globalThis, 'fetch').mockResolvedValue( + new Response('Server Error', { status: 500, statusText: 'Internal Server Error' }), + ) + + await expect(geocodeAddress('Berlin', MOCK_API_KEY)).rejects.toThrow( + 'Google Geocoding API request failed: 500 Internal Server Error', + ) + }) +}) diff --git a/geocoding/src/services/googleGeocoding.ts b/geocoding/src/services/googleGeocoding.ts new file mode 100644 index 00000000..4d20b486 --- /dev/null +++ b/geocoding/src/services/googleGeocoding.ts @@ -0,0 +1,69 @@ +export type GeocodingResult = { + formattedAddress: string + googlePlaceId: string + location: { + lat: number + lng: number + } + name: string + types: string[] +} + +type GoogleGeocodingApiResponse = { + error_message?: string + results: Array<{ + address_components: Array<{ + long_name: string + short_name: string + types: string[] + }> + formatted_address: string + geometry: { + location: { + lat: number + lng: number + } + } + place_id: string + types: string[] + }> + status: string +} + +/** + * Server-side geocoding using the Google Geocoding HTTP API. + * This enables agents and API consumers to geocode addresses without the browser-based Places UI. + */ +export async function geocodeAddress(address: string, apiKey: string): Promise { + const url = new URL('https://maps.googleapis.com/maps/api/geocode/json') + url.searchParams.set('address', address) + url.searchParams.set('key', apiKey) + + const response = await fetch(url.toString()) + + if (!response.ok) { + throw new Error( + `Google Geocoding API request failed: ${response.status} ${response.statusText}`, + ) + } + + const data: GoogleGeocodingApiResponse = await response.json() + + if (data.status === 'ZERO_RESULTS') { + return [] + } + + if (data.status !== 'OK') { + throw new Error( + `Google Geocoding API error: ${data.status} - ${data.error_message ?? 'Unknown error'}`, + ) + } + + return data.results.map((result) => ({ + name: result.address_components[0]?.long_name ?? result.formatted_address, + formattedAddress: result.formatted_address, + googlePlaceId: result.place_id, + location: result.geometry.location, + types: result.types, + })) +} diff --git a/geocoding/src/types/GeoCodingFieldConfig.ts b/geocoding/src/types/GeoCodingFieldConfig.ts index 1f44a8ed..b99c2620 100644 --- a/geocoding/src/types/GeoCodingFieldConfig.ts +++ b/geocoding/src/types/GeoCodingFieldConfig.ts @@ -2,7 +2,7 @@ import type { JSONField, PointField } from 'payload' /** Configuration for the geocoding fields. */ export type GeoCodingFieldConfig = { - geoDataFieldOverride?: { + locationMetaOverride?: { access?: JSONField['access'] admin?: JSONField['admin'] label?: string diff --git a/geocoding/src/types/GeoCodingPluginConfig.ts b/geocoding/src/types/GeoCodingPluginConfig.ts index f778e8f8..8beb08f1 100644 --- a/geocoding/src/types/GeoCodingPluginConfig.ts +++ b/geocoding/src/types/GeoCodingPluginConfig.ts @@ -1,7 +1,21 @@ +import type { PayloadRequest } from 'payload' + +/** Access function for the geocoding endpoint. */ +export type GeocodingEndpointAccess = (args: { req: PayloadRequest }) => boolean | Promise + /** Configuration options for the geocoding plugin. */ export type GeocodingPluginConfig = { /** Whether the geocoding plugin is enabled. */ enabled?: boolean + /** Configuration for the server-side geocoding search endpoint (GET /api/geocoding-plugin/search). */ + geocodingEndpoint?: { + /** + * Custom access function to control who can use the geocoding endpoint. + * Receives the Payload request object. Return true to allow access. + * Defaults to requiring an authenticated user (i.e. `req.user` must be truthy). + */ + access?: GeocodingEndpointAccess + } /** Google Maps API key for geocoding functionality. */ googleMapsApiKey: string } diff --git a/geocoding/tsconfig.json b/geocoding/tsconfig.json index 169db5ed..a7a8eeb9 100644 --- a/geocoding/tsconfig.json +++ b/geocoding/tsconfig.json @@ -2,6 +2,7 @@ "compilerOptions": { "baseUrl": ".", "lib": ["DOM", "DOM.Iterable", "ES2022"], + "typeRoots": ["./node_modules/@types", "./node_modules/.pnpm/node_modules/@types"], "rootDir": "./", "allowJs": true, "skipLibCheck": true, diff --git a/package.json b/package.json index 92d2e104..2a07c55a 100644 --- a/package.json +++ b/package.json @@ -62,6 +62,7 @@ "lint-staged": { "*.{js,jsx,ts,tsx}": "prettier --write", "*.json": "prettier --write --parser json", - "*.{css,md,yaml,yml}": "prettier --write" + "*.md": "prettier --write --parser markdown", + "*.{css,yaml,yml}": "prettier --write" } }