diff --git a/apps/backend/src/core/table/adapters/sqlite/record-sqlite.repository.ts b/apps/backend/src/core/table/adapters/sqlite/record-sqlite.repository.ts index cd6eec5e5..1c59c4920 100644 --- a/apps/backend/src/core/table/adapters/sqlite/record-sqlite.repository.ts +++ b/apps/backend/src/core/table/adapters/sqlite/record-sqlite.repository.ts @@ -71,4 +71,9 @@ export class NestRecordSqliteRepository extends RecordSqliteRepository { restoreOneById(table: Table, id: string): Promise { return super.restoreOneById(table, id) } + + @UseRequestContext() + updateManyByIds(table: Table, updates: { id: string; spec: IRecordSpec }[]): Promise { + return super.updateManyByIds(table, updates) + } } diff --git a/apps/frontend/package.json b/apps/frontend/package.json index cef280669..d8ec5a76f 100644 --- a/apps/frontend/package.json +++ b/apps/frontend/package.json @@ -98,5 +98,11 @@ "xlsx": "^0.18.5", "zod": "^3.22.4" }, - "type": "module" + "type": "module", + "dependencies": { + "@zag-js/color-picker": "^0.38.1", + "@zag-js/combobox": "^0.38.1", + "@zag-js/number-input": "^0.38.1", + "@zag-js/types": "^0.38.1" + } } diff --git a/apps/frontend/src/lib/cell/CellEditors/base-editor.ts b/apps/frontend/src/lib/cell/CellEditors/base-editor.ts new file mode 100644 index 000000000..2a082a963 --- /dev/null +++ b/apps/frontend/src/lib/cell/CellEditors/base-editor.ts @@ -0,0 +1,44 @@ +import type { Edition, RevoGrid } from '@revolist/revogrid/dist/types/interfaces' +import type { VNode } from '@revolist/revogrid/dist/types/stencil-public-runtime' +import type { BaseField } from '@undb/core' +import { isEmpty } from 'lodash-es' +import { toast } from 'svelte-sonner' + +export type SaveCallback = (value: any, preventFocus: boolean) => void + +export abstract class BaseEditor implements Edition.EditorBase { + element?: E | null | undefined + editCell?: Edition.EditCell | undefined + + componentDidRender(): void {} + disconnectedCallback(): void {} + abstract render(createElement?: RevoGrid.HyperFunc | undefined): string | void | VNode | VNode[] + + constructor( + public column: RevoGrid.ColumnRegular, + protected saveCallback: SaveCallback, + ) {} + + protected get field(): T { + return this.column.field as T + } + + // TODO: describe type + onChange(value: V) { + // TODO: better check updates + if (value === this.editCell?.model[this.editCell.prop]) { + return + } + + if (this.field.required && isEmpty(value)) { + return + } + + const result = this.field.valueSchema.safeParse(value) + if (result.success) { + this.saveCallback(result.data, false) + } else { + toast.warning(result.error.flatten((i) => i.message).formErrors.join('\n')) + } + } +} diff --git a/apps/frontend/src/lib/cell/CellEditors/color-editor.ts b/apps/frontend/src/lib/cell/CellEditors/color-editor.ts new file mode 100644 index 000000000..81f229641 --- /dev/null +++ b/apps/frontend/src/lib/cell/CellEditors/color-editor.ts @@ -0,0 +1,82 @@ +import type { RevoGrid } from '@revolist/revogrid/dist/types/interfaces' +import type { VNode } from '@revolist/revogrid/dist/types/stencil-public-runtime' +import type { ColorField } from '@undb/core' +import * as colorPicker from '@zag-js/color-picker' +import delay from 'delay' +import htm from 'htm' +import { BaseEditor, type SaveCallback } from './base-editor' +import { normalizer } from './normalizer' + +export class ColorEditor extends BaseEditor { + private api: colorPicker.Api + private service: ReturnType + + constructor( + public column: RevoGrid.ColumnRegular, + protected saveCallback: SaveCallback, + ) { + super(column, saveCallback) + + const service = colorPicker.machine({ + id: this.column.prop as string, + open: true, + positioning: { + strategy: 'fixed', + placement: 'bottom-start', + }, + }) + this.service = service + const machine = service.start() + + const api = colorPicker.connect(machine.state, machine.send, normalizer) + this.api = api + } + + private initElement() { + const editCell = this.editCell + if (!editCell) return + + const value = editCell.model[editCell.prop] as string + if (value) { + const parsed = colorPicker.parse(value) + this.api.setValue(parsed) + } + } + + async componentDidRender() { + await delay(0) + this.initElement() + } + + disconnectedCallback(): void { + this.service.stop() + } + + render(createComponent: RevoGrid.HyperFunc) { + const html = htm.bind(createComponent) + const api = this.api + + return html` +
+ + +
+ + +
+ +
+
+
+
+
+
+
+
+
+ ` + } +} diff --git a/apps/frontend/src/lib/cell/CellEditors/date-editor.ts b/apps/frontend/src/lib/cell/CellEditors/date-editor.ts index abbda4268..1aa90aedf 100644 --- a/apps/frontend/src/lib/cell/CellEditors/date-editor.ts +++ b/apps/frontend/src/lib/cell/CellEditors/date-editor.ts @@ -1,34 +1,35 @@ -import type { Edition, RevoGrid } from '@revolist/revogrid/dist/types/interfaces' +import type { RevoGrid } from '@revolist/revogrid/dist/types/interfaces' import type { VNode } from '@revolist/revogrid/dist/types/stencil-public-runtime' +import type { DateField } from '@undb/core' import delay from 'delay' +import htm from 'htm' +import { BaseEditor } from './base-editor' -export type SaveCallback = (value: Edition.SaveData, preventFocus: boolean) => void +export class DateEditor extends BaseEditor { + private initElement() { + const element = this.element + if (!element) return -export class DateEditor implements Edition.EditorBase { - public element: HTMLInputElement | null = null - public editCell: Edition.EditCell | undefined = undefined + element.focus() - constructor( - public column: RevoGrid.ColumnRegular, - private saveCallback: SaveCallback, - ) {} + const editCell = this.editCell + if (!editCell) return + element.value = editCell.model[editCell.prop] as string + } async componentDidRender() { await delay(0) - this.element?.focus() - } - - private onChange(e: Event) { - this.element?.blur() - this.saveCallback((e.target as HTMLInputElement).valueAsDate?.toISOString() ?? '', false) + this.initElement() } render(createComponent: RevoGrid.HyperFunc) { - return createComponent('input', { - type: 'date', - onchange: (e: Event) => this.onChange(e), - class: - 'border-2 border-primary-300 rounded-none text-gray-900 text-sm focus:ring-primary-500 focus:border-primary-500 block w-full p-2.5', - }) + const html = htm.bind(createComponent) + return html` + this.onChange((e.target as HTMLInputElement).valueAsDate?.toISOString() ?? '')} + class="border-2 border-primary-300 rounded-none text-gray-900 text-sm focus:ring-primary-500 focus:border-primary-500 block w-full p-2.5" + /> + ` } } diff --git a/apps/frontend/src/lib/cell/CellEditors/editors.ts b/apps/frontend/src/lib/cell/CellEditors/editors.ts index bdaed4673..9251279e1 100644 --- a/apps/frontend/src/lib/cell/CellEditors/editors.ts +++ b/apps/frontend/src/lib/cell/CellEditors/editors.ts @@ -1,8 +1,17 @@ import type { Components } from '@revolist/revogrid' +import { ColorEditor } from './color-editor' import { DateEditor } from './date-editor' +import { EmailEditor } from './email-editor' +import { NumberEditor } from './number-editor' +import { SelectEditor } from './select-editor' import { StringEditor } from './string-editor' export const editors: Components.RevoGrid['editors'] = { string: StringEditor, date: DateEditor, + email: EmailEditor, + number: NumberEditor, + currency: NumberEditor, + color: ColorEditor, + select: SelectEditor, } diff --git a/apps/frontend/src/lib/cell/CellEditors/email-editor.ts b/apps/frontend/src/lib/cell/CellEditors/email-editor.ts new file mode 100644 index 000000000..bcb5ec379 --- /dev/null +++ b/apps/frontend/src/lib/cell/CellEditors/email-editor.ts @@ -0,0 +1,39 @@ +import type { Edition, RevoGrid } from '@revolist/revogrid/dist/types/interfaces' +import type { VNode } from '@revolist/revogrid/dist/types/stencil-public-runtime' +import type { EmailField } from '@undb/core' +import delay from 'delay' +import htm from 'htm' +import { BaseEditor } from './base-editor' + +export class EmailEditor extends BaseEditor { + public element: HTMLInputElement | null = null + public editCell: Edition.EditCell | undefined = undefined + + private initElement() { + const element = this.element + if (!element) return + + element.focus() + + const editCell = this.editCell + if (!editCell) return + + element.value = editCell.model[editCell.prop] as string + } + + async componentDidRender() { + await delay(0) + this.initElement() + } + + render(createComponent: RevoGrid.HyperFunc) { + const html = htm.bind(createComponent) + return html` + this.onChange((e.target as HTMLInputElement).value)} + placeholder="example@email.com" + class="border-2 border-primary-300 rounded-none text-gray-900 text-sm focus:ring-primary-500 focus:border-primary-500 block w-full p-2.5" + /> + ` + } +} diff --git a/apps/frontend/src/lib/cell/CellEditors/normalizer.ts b/apps/frontend/src/lib/cell/CellEditors/normalizer.ts new file mode 100644 index 000000000..ef3071df4 --- /dev/null +++ b/apps/frontend/src/lib/cell/CellEditors/normalizer.ts @@ -0,0 +1,3 @@ +import { createNormalizer } from '@zag-js/types' + +export const normalizer = createNormalizer((v) => v) diff --git a/apps/frontend/src/lib/cell/CellEditors/number-editor.ts b/apps/frontend/src/lib/cell/CellEditors/number-editor.ts new file mode 100644 index 000000000..10112b936 --- /dev/null +++ b/apps/frontend/src/lib/cell/CellEditors/number-editor.ts @@ -0,0 +1,67 @@ +import type { RevoGrid } from '@revolist/revogrid/dist/types/interfaces' +import type { VNode } from '@revolist/revogrid/dist/types/stencil-public-runtime' +import type { CurrencyField, NumberField } from '@undb/core' +import * as numberInput from '@zag-js/number-input' +import delay from 'delay' +import htm from 'htm' +import { BaseEditor, type SaveCallback } from './base-editor' +import { normalizer } from './normalizer' + +export class NumberEditor extends BaseEditor { + private api: numberInput.Api + private service: ReturnType + + constructor( + public column: RevoGrid.ColumnRegular, + protected saveCallback: SaveCallback, + ) { + super(column, saveCallback) + + const service = numberInput.machine({ + id: this.column.prop as string, + }) + this.service = service + const machine = service.start() + + const api = numberInput.connect(machine.state, machine.send, normalizer) + + this.api = api + } + + private initElement() { + const editCell = this.editCell + if (!editCell) return + + const value = editCell.model[editCell.prop] as string + this.api.setValue(Number(value)) + this.api.focus() + } + + async componentDidRender() { + await delay(0) + this.initElement() + } + + disconnectedCallback(): void { + this.service.stop() + } + + render(createComponent: RevoGrid.HyperFunc) { + const html = htm.bind(createComponent) + const api = this.api + + return html` +
+ { + const value = (e.target as HTMLInputElement).value + return this.onChange(parseInt(value.replace(/,/g, ''), 10)) + }} + class="border-2 border-primary-300 rounded-none text-gray-900 text-sm focus:ring-primary-500 focus:border-primary-500 block w-full p-2.5" + /> +
+ ` + } +} diff --git a/apps/frontend/src/lib/cell/CellEditors/select-editor.ts b/apps/frontend/src/lib/cell/CellEditors/select-editor.ts new file mode 100644 index 000000000..b06d0897a --- /dev/null +++ b/apps/frontend/src/lib/cell/CellEditors/select-editor.ts @@ -0,0 +1,82 @@ +import type { RevoGrid } from '@revolist/revogrid/dist/types/interfaces' +import type { VNode } from '@revolist/revogrid/dist/types/stencil-public-runtime' +import type { SelectField } from '@undb/core' +import * as combobox from '@zag-js/combobox' +import delay from 'delay' +import htm from 'htm' +import { BaseEditor, type SaveCallback } from './base-editor' +import { normalizer } from './normalizer' + +export class SelectEditor extends BaseEditor { + private api: combobox.Api + private service: ReturnType + + private get options() { + return this.field.options.options.map((o) => o.toJSON()) + } + constructor( + public column: RevoGrid.ColumnRegular, + protected saveCallback: SaveCallback, + ) { + super(column, saveCallback) + + const collection = combobox.collection({ + items: this.options, + itemToValue: (o) => o.key, + itemToString: (o) => o.name, + }) + const service = combobox.machine({ + id: this.column.prop as string, + collection, + }) + + this.service = service + const machine = service.start() + + const api = combobox.connect(machine.state, machine.send, normalizer) + this.api = api + } + + private initElement() { + const editCell = this.editCell + if (!editCell) return + + const value = editCell.model[editCell.prop] as string | null + if (value) { + this.api.setValue([value]) + } + } + + disconnectedCallback(): void { + this.service.stop() + } + + async componentDidRender() { + await delay(0) + this.initElement() + } + + render(createComponent: RevoGrid.HyperFunc) { + const html = htm.bind(createComponent) + const { api, options } = this + return html` +
+
+ +
+ + +
+
+
    + ${options.map((item) => { + return html`
  • ${item.name}
  • ` + })} +
+ } +
+
+
+ ` + } +} diff --git a/apps/frontend/src/lib/cell/CellEditors/string-editor.ts b/apps/frontend/src/lib/cell/CellEditors/string-editor.ts index a54e08cdd..07b3dcedb 100644 --- a/apps/frontend/src/lib/cell/CellEditors/string-editor.ts +++ b/apps/frontend/src/lib/cell/CellEditors/string-editor.ts @@ -1,33 +1,35 @@ -import type { Edition, RevoGrid } from '@revolist/revogrid/dist/types/interfaces' +import type { RevoGrid } from '@revolist/revogrid/dist/types/interfaces' import type { VNode } from '@revolist/revogrid/dist/types/stencil-public-runtime' +import type { StringField } from '@undb/core' import delay from 'delay' +import htm from 'htm' +import { BaseEditor } from './base-editor' -export type SaveCallback = (value: Edition.SaveData, preventFocus: boolean) => void +export class StringEditor extends BaseEditor { + private initElement() { + const element = this.element + if (!element) return -export class StringEditor implements Edition.EditorBase { - public element: HTMLInputElement | null = null - public editCell: Edition.EditCell | undefined = undefined + element.focus() - constructor( - public column: RevoGrid.ColumnRegular, - private saveCallback: SaveCallback, - ) {} + const editCell = this.editCell + if (!editCell) return - async componentDidRender() { - await delay(0) - this.element?.focus() + element.value = editCell.model[editCell.prop] as string } - private onChange(e: Event) { - this.element?.blur() - this.saveCallback((e.target as HTMLInputElement).value, false) + async componentDidRender() { + await delay(0) + this.initElement() } render(createComponent: RevoGrid.HyperFunc) { - return createComponent('input', { - onchange: (e: Event) => this.onChange(e), - class: - 'border-2 border-primary-300 rounded-none text-gray-900 text-sm focus:ring-primary-500 focus:border-primary-500 block w-full p-2.5', - }) + const html = htm.bind(createComponent) + return html` + this.onChange((e.target as HTMLInputElement).value)} + class="border-2 border-primary-300 rounded-none text-gray-900 text-sm focus:ring-primary-500 focus:border-primary-500 block w-full p-2.5" + /> + ` } } diff --git a/apps/frontend/src/lib/record/CreateRecord.svelte b/apps/frontend/src/lib/record/CreateRecord.svelte index 6e0188a77..0a1d43dad 100644 --- a/apps/frontend/src/lib/record/CreateRecord.svelte +++ b/apps/frontend/src/lib/record/CreateRecord.svelte @@ -10,7 +10,7 @@ import * as Dialog from '$lib/components/ui/dialog' import { Button } from '$lib/components/ui/button' import { createRecordForm } from '$lib/store/table' - import { RecordFactory, type Field, WithRecordId, RecordId } from '@undb/core' + import { RecordFactory, type Field, WithRecordId, RecordId, Record } from '@undb/core' import Badge from '$components/ui/badge/badge.svelte' import CreateRecordItem from './CreateRecordItem.svelte' import { me } from '$lib/store/me' @@ -69,7 +69,10 @@ $: values = pick($form, keys($tainted)) const id = RecordId.create() - $: tempRecord = RecordFactory.temp($table, values, $me.userId, new WithRecordId(id)) + let tempRecord: Record | undefined + $: if ($me) { + tempRecord = RecordFactory.temp($table, values, $me.userId, new WithRecordId(id)) + } @@ -92,9 +95,11 @@
- {#each fields as field (field.id.value)} - - {/each} + {#if tempRecord} + {#each fields as field (field.id.value)} + + {/each} + {/if}
diff --git a/apps/frontend/src/lib/table/TableView.svelte b/apps/frontend/src/lib/table/TableView.svelte index da3589d36..aeeaf2772 100644 --- a/apps/frontend/src/lib/table/TableView.svelte +++ b/apps/frontend/src/lib/table/TableView.svelte @@ -3,7 +3,7 @@ import { clickOutside, cn } from '$lib/utils' import { RevoGrid } from '@revolist/svelte-datagrid' import * as DropdownMenu from '$lib/components/ui/dropdown-menu' - import type { RevoGrid as RevoGridType } from '@revolist/revogrid/dist/types/interfaces' + import type { Edition, RevoGrid as RevoGridType } from '@revolist/revogrid/dist/types/interfaces' import type { Components, RevoGridCustomEvent } from '@revolist/revogrid' import { defineCustomElements } from '@revolist/revogrid/loader' import { cellTemplateMap } from '$lib/cell/CellComponents/cell-template' @@ -29,13 +29,14 @@ import { confirmDeleteField, createFieldModal } from '$lib/store/modal' import LoadingTable from './LoadingTable.svelte' import TableViewToast from './TableViewToast.svelte' - import { recordSelection, selectedCount, selectedRecords } from '$lib/store/record' + import { recordSelection, selectedCount } from '$lib/store/record' import { getColumnTemplate } from '$lib/field/field-template' import { hasPermission } from '$lib/store/authz' import * as AlertDialog from '$lib/components/ui/alert-dialog' import ConfirmBulkDeleteRecord from '$lib/record/ConfirmBulkDeleteRecord.svelte' import ConfirmBulkDuplicateRecord from '$lib/record/ConfirmBulkDuplicateRecord.svelte' - import htm from 'htm' + import { toast } from 'svelte-sonner' + import { has } from 'lodash-es' const pinnedPositionMap: Record = { left: 'colPinStart', @@ -193,6 +194,7 @@ size: $view.getFieldWidth(field.id.value), pin: position ? pinnedPositionMap[position] : undefined, autoSize: true, + readonly: $readonly, cellTemplate: cellTemplateMap[field.type], columnTemplate: (h, c) => getColumnTemplate(h, c, $readonly), columnProperties: (column: RevoGridType.ColumnRegular) => { @@ -306,6 +308,58 @@ } } + const updateRecord = trpc().record.update.mutation({ + async onSuccess() { + toast.success($t('RECORD.UPDATED', { ns: 'success' })) + currentRecordId.set(undefined) + }, + onError(error, variables, context) { + toast.error(error.message) + }, + }) + + const updateRecords = trpc().record.bulkUpdate.mutation({ + async onSuccess() { + toast.success($t('RECORD.UPDATED', { ns: 'success' })) + currentRecordId.set(undefined) + }, + onError(error, variables, context) { + toast.error(error.message) + }, + }) + + const onAfterEdit = async ( + event: RevoGridCustomEvent, + ) => { + if ($readonly) return + const detail = event.detail + const isSingleEdit = (data: any): data is Edition.BeforeSaveDataDetails => has(data, 'model') + + if (isSingleEdit(detail)) { + $updateRecord.mutate({ + tableId: $table.id.value, + id: detail.model.id, + values: { + [detail.prop]: detail.val, + }, + }) + } else { + $updateRecords.mutate({ + tableId: $table.id.value, + records: Object.entries(detail.data).flatMap(([index, d]) => { + return Object.entries(d).map(([fieldId, value]) => { + return { + id: detail.models[Number(index)].id, + values: { + [fieldId]: value, + }, + } + }) + }), + }) + } + } + $: hasRecord = !!$records.length const deleteField = trpc().table.field.delete.mutation({ @@ -337,10 +391,11 @@ theme="compact" range rowClass="id" - readonly + readonly={$readonly} {rowDefinitions} {editors} on:aftercolumnresize={onAfterColumnResize} + on:afteredit={onAfterEdit} /> {#if isLoading}
diff --git a/apps/frontend/src/lib/trpc/client.ts b/apps/frontend/src/lib/trpc/client.ts index 6fca3a4a6..e9413f087 100644 --- a/apps/frontend/src/lib/trpc/client.ts +++ b/apps/frontend/src/lib/trpc/client.ts @@ -1,9 +1,14 @@ import type { AppRouter } from '@undb/trpc' -import { createTRPCSvelte, httpBatchLink } from 'trpc-svelte-query' +import { createTRPCSvelte, httpBatchLink, loggerLink } from 'trpc-svelte-query' export const trpc = () => createTRPCSvelte({ links: [ + loggerLink({ + enabled: (opts) => + (process.env.NODE_ENV === 'development' && typeof window !== 'undefined') || + (opts.direction === 'down' && opts.result instanceof Error), + }), httpBatchLink({ url: '/api/trpc', }), diff --git a/packages/core/src/table/field/fields/email/email-field.ts b/packages/core/src/table/field/fields/email/email-field.ts index 8891b3dbc..e7caab56f 100644 --- a/packages/core/src/table/field/fields/email/email-field.ts +++ b/packages/core/src/table/field/fields/email/email-field.ts @@ -48,7 +48,7 @@ export class EmailField extends BaseField { } get valueSchema() { - const email = z.string() - return this.required ? email.email() : email.nullable() + const email = z.string().email() + return this.required ? email : email.nullable() } } diff --git a/packages/trpc/src/router/record.router.ts b/packages/trpc/src/router/record.router.ts index 02b2579a3..ef4785c0e 100644 --- a/packages/trpc/src/router/record.router.ts +++ b/packages/trpc/src/router/record.router.ts @@ -12,6 +12,7 @@ import { GetRecordsQuery, RestoreRecordCommand, UpdateRecordCommand, + UpdateRecordsCommand, bulkDeleteRecordsCommandInput, bulkDuplicateRecordsCommandInput, createRecordCommandOutput, @@ -75,6 +76,14 @@ export const createRecordRouter = const cmd = new UpdateRecordCommand(input) return commandBus.execute(cmd) }), + bulkUpdate: procedure + .use(authz('record:update')) + .input(z.any()) + .output(z.void()) + .mutation(({ input }) => { + const cmd = new UpdateRecordsCommand(input) + return commandBus.execute(cmd) + }), delete: procedure .use(authz('record:delete')) .input(deleteRecordCommandInput) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 22abed73a..a7899e1a4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -465,6 +465,19 @@ importers: version: 1.1.0 apps/frontend: + dependencies: + '@zag-js/color-picker': + specifier: ^0.38.1 + version: 0.38.1 + '@zag-js/combobox': + specifier: ^0.38.1 + version: 0.38.1 + '@zag-js/number-input': + specifier: ^0.38.1 + version: 0.38.1 + '@zag-js/types': + specifier: ^0.38.1 + version: 0.38.1 devDependencies: '@playwright/test': specifier: ^1.40.1 @@ -757,7 +770,7 @@ importers: version: link:../tsconfig tsup: specifier: ^8.0.1 - version: 8.0.1(typescript@5.3.3) + version: 8.0.1(@swc/core@1.4.2)(ts-node@10.9.2)(typescript@5.3.3) typescript: specifier: ^5.3.3 version: 5.3.3 @@ -824,7 +837,7 @@ importers: version: link:../tsconfig tsup: specifier: ^8.0.1 - version: 8.0.1(typescript@5.3.3) + version: 8.0.1(@swc/core@1.4.2)(ts-node@10.9.2)(typescript@5.3.3) type-fest: specifier: ^4.8.3 version: 4.8.3 @@ -891,7 +904,7 @@ importers: version: link:../tsconfig tsup: specifier: ^8.0.1 - version: 8.0.1(typescript@5.3.3) + version: 8.0.1(@swc/core@1.4.2)(ts-node@10.9.2)(typescript@5.3.3) typescript: specifier: ^5.3.3 version: 5.3.3 @@ -925,7 +938,7 @@ importers: version: link:../../tsconfig tsup: specifier: ^8.0.1 - version: 8.0.1(typescript@5.3.3) + version: 8.0.1(@swc/core@1.4.2)(ts-node@10.9.2)(typescript@5.3.3) typescript: specifier: ^5.3.3 version: 5.3.3 @@ -1068,7 +1081,7 @@ importers: version: link:../tsconfig tsup: specifier: ^8.0.1 - version: 8.0.1(typescript@5.3.3) + version: 8.0.1(@swc/core@1.4.2)(ts-node@10.9.2)(typescript@5.3.3) type-fest: specifier: ^4.8.3 version: 4.8.3 @@ -1127,7 +1140,7 @@ importers: version: link:../tsconfig tsup: specifier: ^8.0.1 - version: 8.0.1(typescript@5.3.3) + version: 8.0.1(@swc/core@1.4.2)(ts-node@10.9.2)(typescript@5.3.3) typescript: specifier: ^5.3.3 version: 5.3.3 @@ -1179,7 +1192,7 @@ importers: version: link:../tsconfig tsup: specifier: ^8.0.1 - version: 8.0.1(typescript@5.3.3) + version: 8.0.1(@swc/core@1.4.2)(ts-node@10.9.2)(typescript@5.3.3) typescript: specifier: ^5.3.3 version: 5.3.3 @@ -1204,7 +1217,7 @@ importers: version: link:../tsconfig tsup: specifier: ^8.0.1 - version: 8.0.1(typescript@5.3.3) + version: 8.0.1(@swc/core@1.4.2)(ts-node@10.9.2)(typescript@5.3.3) typescript: specifier: ^5.3.3 version: 5.3.3 @@ -1271,7 +1284,7 @@ importers: version: link:../tsconfig tsup: specifier: ^8.0.1 - version: 8.0.1(typescript@5.3.3) + version: 8.0.1(@swc/core@1.4.2)(ts-node@10.9.2)(typescript@5.3.3) typescript: specifier: ^5.3.3 version: 5.3.3 @@ -1314,7 +1327,7 @@ importers: version: link:../tsconfig tsup: specifier: ^8.0.1 - version: 8.0.1(typescript@5.3.3) + version: 8.0.1(@swc/core@1.4.2)(ts-node@10.9.2)(typescript@5.3.3) typescript: specifier: ^5.3.3 version: 5.3.3 @@ -1357,7 +1370,7 @@ importers: version: link:../tsconfig tsup: specifier: ^8.0.1 - version: 8.0.1(typescript@5.3.3) + version: 8.0.1(@swc/core@1.4.2)(ts-node@10.9.2)(typescript@5.3.3) typescript: specifier: ^5.3.3 version: 5.3.3 @@ -2795,18 +2808,15 @@ packages: resolution: {integrity: sha512-PcF++MykgmTj3CIyOQbKA/hDzOAiqI3mhuoN44WRCopIs1sgoDoU4oty4Jtqaj/y3oDU6fnVSm4QG0a3t5i0+g==} dependencies: '@floating-ui/utils': 0.2.1 - dev: true /@floating-ui/dom@1.6.3: resolution: {integrity: sha512-RnDthu3mzPlQ31Ss/BTwQ1zjzIhr3lk1gZB1OC56h/1vEtaXkESrOqL5fQVMfXpwGtRwX+YsZBdyHtJMQnkArw==} dependencies: '@floating-ui/core': 1.6.0 '@floating-ui/utils': 0.2.1 - dev: true /@floating-ui/utils@0.2.1: resolution: {integrity: sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q==} - dev: true /@fortawesome/fontawesome-common-types@6.5.1: resolution: {integrity: sha512-GkWzv+L6d2bI5f/Vk6ikJ9xtl7dfXtoRu3YGE6nq0p/FFqA1ebMOAWg3XgRyb0I6LYyYkiAo+3/KrwuBp8xG7A==} @@ -2940,6 +2950,12 @@ packages: '@swc/helpers': 0.5.6 dev: true + /@internationalized/number@3.5.1: + resolution: {integrity: sha512-N0fPU/nz15SwR9IbfJ5xaS9Ss/O5h1sVXMZf43vc9mxEG48ovglvvzBjF53aHlq20uoR6c+88CrIXipU/LSzwg==} + dependencies: + '@swc/helpers': 0.5.6 + dev: false + /@ioredis/commands@1.2.0: resolution: {integrity: sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg==} @@ -6136,7 +6152,6 @@ packages: resolution: {integrity: sha512-aYX01Ke9hunpoCexYAgQucEpARGQ5w/cqHFrIR+e9gdKb1QWTsVJuTJ2ozQzIAxLyRQe/m+2RqzkyOOGiMKRQA==} dependencies: tslib: 2.6.2 - dev: true /@swc/types@0.1.5: resolution: {integrity: sha512-myfUej5naTBWnqOCc/MdVOLVjXUXtIA+NpDrDBKJtLLg2shUjBu3cZmB/85RyitKc55+lUUyl7oRfLOvkr2hsw==} @@ -6547,7 +6562,7 @@ packages: /@types/ioredis@4.28.10: resolution: {integrity: sha512-69LyhUgrXdgcNDv7ogs1qXZomnfOEnSmrmMFqKgt1XMJxmoOSG/u3wYy13yACIfKuMJ8IhKgHafDO3sx19zVQQ==} dependencies: - '@types/node': 20.10.5 + '@types/node': 20.11.20 dev: false /@types/istanbul-lib-coverage@2.0.4: @@ -6706,7 +6721,6 @@ packages: resolution: {integrity: sha512-7/rR21OS+fq8IyHTgtLkDK949uzsa6n8BkziAKtPVpugIkO6D+/ooXMvzXxDnZrmtXVfjb1bKQafYpb8s89LOg==} dependencies: undici-types: 5.26.5 - dev: true /@types/nodemailer@6.4.14: resolution: {integrity: sha512-fUWthHO9k9DSdPCSPRqcu6TWhYyxTBg382vlNIttSe9M7XfsT06y0f24KHXtbnijPGGRIcVvdKHTNikOI6qiHA==} @@ -7305,6 +7319,169 @@ packages: /@xtuc/long@4.2.2: resolution: {integrity: sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==} + /@zag-js/anatomy@0.38.1: + resolution: {integrity: sha512-y6foq9vX+EfjfCwi9DMt5gI9eU7kshFjioidACI+u8TjBG2Z3nOjvEq+3Ct+dy5v/aRwsvSquaXpB555e0OLNQ==} + dev: false + + /@zag-js/aria-hidden@0.38.1: + resolution: {integrity: sha512-n0qP/w8tXxvpZp0F2U+I4WYDW24/yqp49eP6kSo+Av9M4E9F8/o17yGxu30/dli3/KthsCjkde+0cfZqHs/Duw==} + dependencies: + '@zag-js/dom-query': 0.38.1 + dev: false + + /@zag-js/collection@0.38.1: + resolution: {integrity: sha512-Z+73tmgLS/KgKVJiTQQX9ujTo2MaYhx5G9yMvZ15G3zLZx8DoFGcKmFl3RvuDgmnTGjcLpV+Tn76O5mZKpHOkA==} + dev: false + + /@zag-js/color-picker@0.38.1: + resolution: {integrity: sha512-Ae0ivxHAqX9+gJWRnci8iPYR/HQvyTQOxc1kCwSY077XiW0BqlQACf0DYVBOw/dXQSoBRsgHzyOJ71M1e1PFoA==} + dependencies: + '@zag-js/anatomy': 0.38.1 + '@zag-js/color-utils': 0.38.1 + '@zag-js/core': 0.38.1 + '@zag-js/dismissable': 0.38.1 + '@zag-js/dom-event': 0.38.1 + '@zag-js/dom-query': 0.38.1 + '@zag-js/form-utils': 0.38.1 + '@zag-js/popper': 0.38.1 + '@zag-js/tabbable': 0.38.1 + '@zag-js/text-selection': 0.38.1 + '@zag-js/types': 0.38.1 + '@zag-js/utils': 0.38.1 + '@zag-js/visually-hidden': 0.38.1 + dev: false + + /@zag-js/color-utils@0.38.1: + resolution: {integrity: sha512-y/8mKFlPqiNNSPdb22qEUYDqeYm/S/j8IvdkHUg2zdyCIeShUd2D5y7u1oSQUQphskzmIoGp8y7HrQ0xVKY93g==} + dependencies: + '@zag-js/numeric-range': 0.38.1 + dev: false + + /@zag-js/combobox@0.38.1: + resolution: {integrity: sha512-S01hBrYcUPRrmzT0GDYMrRIxggUXBL9Fn5FlBvNVBqVHHJUyTVBSMB8Va7omKRK/Y2gspEhrodggxSzwwOZvEg==} + dependencies: + '@zag-js/anatomy': 0.38.1 + '@zag-js/aria-hidden': 0.38.1 + '@zag-js/collection': 0.38.1 + '@zag-js/core': 0.38.1 + '@zag-js/dismissable': 0.38.1 + '@zag-js/dom-event': 0.38.1 + '@zag-js/dom-query': 0.38.1 + '@zag-js/mutation-observer': 0.38.1 + '@zag-js/popper': 0.38.1 + '@zag-js/types': 0.38.1 + '@zag-js/utils': 0.38.1 + dev: false + + /@zag-js/core@0.38.1: + resolution: {integrity: sha512-v1WKbIzOWN2yN450zxVA1QCnI8np1vvcpPwsor9ZLM8OnION6yeiKCyjI7DqmLebCMhN9wnjExkjcb8ZAmNDuA==} + dependencies: + '@zag-js/store': 0.38.1 + klona: 2.0.6 + dev: false + + /@zag-js/dismissable@0.38.1: + resolution: {integrity: sha512-a7PxUb3+gS27RKRAKJv8voj5BZ4mHpZeMJqECjpYTTlsDjmzHnW4rLCB1m/uq/odiVAaLqJs55jZyskezdOoyg==} + dependencies: + '@zag-js/dom-event': 0.38.1 + '@zag-js/dom-query': 0.38.1 + '@zag-js/interact-outside': 0.38.1 + '@zag-js/utils': 0.38.1 + dev: false + + /@zag-js/dom-event@0.38.1: + resolution: {integrity: sha512-+EkCNsS9oE8ZtgUU7G9EVXrZKcCaIJlSEVCliFjYUpDgo3Jxl1sOwbSIqaIi/yKIuJSl/lswz3jCxue0BW2bWw==} + dependencies: + '@zag-js/text-selection': 0.38.1 + '@zag-js/types': 0.38.1 + dev: false + + /@zag-js/dom-query@0.38.1: + resolution: {integrity: sha512-bGtc3hfBY4ngxHNTohT2XAwHpKkbPMeUF5JggSETMMtfv9e+FLy4F79j7OWjJjvQZKKcVesrw/1s0TlhkvZioA==} + dev: false + + /@zag-js/form-utils@0.38.1: + resolution: {integrity: sha512-o4G80b/XHhGUy4pJnTdJW9TwfOREXhiafSv6YQ5Zpk0EPi5lk1IroYL6ZJT6/vuvirc+HVzE+znvlYOfDl5PVQ==} + dependencies: + '@zag-js/mutation-observer': 0.38.1 + dev: false + + /@zag-js/interact-outside@0.38.1: + resolution: {integrity: sha512-VAsYIFVZk6ceTBAGBsFEo1Rqt9IMGzFYRn8NnBeGgbAOamDyJMCfU80QfBOma5xqcTtcBajsT6svIupKxTem9w==} + dependencies: + '@zag-js/dom-event': 0.38.1 + '@zag-js/dom-query': 0.38.1 + '@zag-js/tabbable': 0.38.1 + '@zag-js/utils': 0.38.1 + dev: false + + /@zag-js/mutation-observer@0.38.1: + resolution: {integrity: sha512-y3JdkLTxE+5J1BWIkVwyc+IDCSUW2DgHxR9UHUUW/uRPe3SG5/MDQGupdVy/dUH4WTi/bcFwXkpfBxBP1+idFw==} + dev: false + + /@zag-js/number-input@0.38.1: + resolution: {integrity: sha512-zjnAvF9IYHeg7aOcDbmXAKLOEykaHhBmkCzggAITHtL6JrZRCp6UftI8OpwltETsHpSMi+ANwj4oLdS0PWEhkg==} + dependencies: + '@internationalized/number': 3.5.1 + '@zag-js/anatomy': 0.38.1 + '@zag-js/core': 0.38.1 + '@zag-js/dom-event': 0.38.1 + '@zag-js/dom-query': 0.38.1 + '@zag-js/form-utils': 0.38.1 + '@zag-js/mutation-observer': 0.38.1 + '@zag-js/number-utils': 0.38.1 + '@zag-js/types': 0.38.1 + '@zag-js/utils': 0.38.1 + dev: false + + /@zag-js/number-utils@0.38.1: + resolution: {integrity: sha512-4DHzyxSxlRFhKoY7hUz3s2rRcjZhiqSBLQ8CE/QRQyQoHww/QaCFqZT6NT0d1ZOU0IRPvUszVr/2I8PbIr9LSA==} + dev: false + + /@zag-js/numeric-range@0.38.1: + resolution: {integrity: sha512-X3sn4pz3iHed/LGg7foXsSIpDD7P9OmMF/NsfCQMP7/BpexlX6gNNcTmayWxzW+dut4YNyeKg8oivlk5maUI8Q==} + dev: false + + /@zag-js/popper@0.38.1: + resolution: {integrity: sha512-S/yqW2IpdM3VybGmiD+dOg8YEPIsSI9qKbnL1Mw1ntTEsp2NLOUDuShDbFvU/khTCax9ehGQiqB7g8+pXiClMw==} + dependencies: + '@floating-ui/dom': 1.6.3 + '@zag-js/dom-query': 0.38.1 + '@zag-js/utils': 0.38.1 + dev: false + + /@zag-js/store@0.38.1: + resolution: {integrity: sha512-gaOsP8jjqZnivZSmzj3xHtpd8Vm9KMo3ESp41iinyry5suSgEn7BV12dTGG90+DBAfuCggqYv/dLjQCxbqQeMA==} + dependencies: + proxy-compare: 2.6.0 + dev: false + + /@zag-js/tabbable@0.38.1: + resolution: {integrity: sha512-xPrC4FmRlrupYf+KQ3+yN3bXaJa2TxUQAY/IWubYm7lRJnEsxhELV7IpbxUHsTRFrLvwTjs61y8TFtnY6CfWIQ==} + dependencies: + '@zag-js/dom-query': 0.38.1 + dev: false + + /@zag-js/text-selection@0.38.1: + resolution: {integrity: sha512-FNcYOIlH21rBdiZCaFsaCRDtbmr5WBNEXiqfS8dFWx/x1MxNZ9iyDnBLRGy7OQnTGsyLdpCdHTtGjX65EkKGAw==} + dependencies: + '@zag-js/dom-query': 0.38.1 + dev: false + + /@zag-js/types@0.38.1: + resolution: {integrity: sha512-kSpjSE+d+5bucALf5DYaHloekk5V0OjlyOowqEEUEjCipGpPLWPxRXSKjiSxQIFftZij07sLxjn609b8PTKrEw==} + dependencies: + csstype: 3.1.3 + dev: false + + /@zag-js/utils@0.38.1: + resolution: {integrity: sha512-kJ15yxO5tWCxZSMVIBSYPE8nfHA9zqtaOlZ8IiFDPPPi137SJDjKz/VIXlSUyCd/af7kQTCnxqVyNFLiyxGaRw==} + dev: false + + /@zag-js/visually-hidden@0.38.1: + resolution: {integrity: sha512-8l1lYn9ilq8EAP2wZOHnlTqK3MJvIfrzMvxXQd5UMbTiQEDzjEwFFqROedjVvDhAZJ/riCGmlvFy4P0a6J2adA==} + dev: false + /JSONStream@1.3.5: resolution: {integrity: sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==} hasBin: true @@ -9190,6 +9367,10 @@ packages: cssom: 0.3.8 dev: true + /csstype@3.1.3: + resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + dev: false + /cz-conventional-changelog@3.3.0(@types/node@20.10.5)(typescript@5.3.3): resolution: {integrity: sha512-U466fIzU5U22eES5lTNiNbZ+d8dfcHcssH4o7QsdWaCcRs/feIPCxKYSWkYBNs5mny7MvEfwpTLWjvbm94hecw==} engines: {node: '>= 10'} @@ -12669,6 +12850,11 @@ packages: engines: {node: '>=6'} dev: true + /klona@2.0.6: + resolution: {integrity: sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==} + engines: {node: '>= 8'} + dev: false + /knex@2.5.1(better-sqlite3@8.7.0): resolution: {integrity: sha512-z78DgGKUr4SE/6cm7ku+jHvFT0X97aERh/f0MUKAKgFnwCYBEW4TFBqtHWFYiJFid7fMrtpZ/gxJthvz5mEByA==} engines: {node: '>=12'} @@ -15392,22 +15578,6 @@ packages: yaml: 1.10.2 dev: true - /postcss-load-config@4.0.2: - resolution: {integrity: sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==} - engines: {node: '>= 14'} - peerDependencies: - postcss: '>=8.0.9' - ts-node: '>=9.0.0' - peerDependenciesMeta: - postcss: - optional: true - ts-node: - optional: true - dependencies: - lilconfig: 3.0.0 - yaml: 2.3.4 - dev: true - /postcss-load-config@4.0.2(postcss@8.4.32): resolution: {integrity: sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==} engines: {node: '>= 14'} @@ -15751,6 +15921,10 @@ packages: - supports-color dev: false + /proxy-compare@2.6.0: + resolution: {integrity: sha512-8xuCeM3l8yqdmbPoYeLbrAXCBWu19XEYc5/F28f5qOaoAIMyfmBUkl5axiK+x9olUvRlcekvnm98AP9RDngOIw==} + dev: false + /proxy-from-env@1.1.0: resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} dev: false @@ -18294,45 +18468,6 @@ packages: - ts-node dev: true - /tsup@8.0.1(typescript@5.3.3): - resolution: {integrity: sha512-hvW7gUSG96j53ZTSlT4j/KL0q1Q2l6TqGBFc6/mu/L46IoNWqLLUzLRLP1R8Q7xrJTmkDxxDoojV5uCVs1sVOg==} - engines: {node: '>=18'} - hasBin: true - peerDependencies: - '@microsoft/api-extractor': ^7.36.0 - '@swc/core': ^1 - postcss: ^8.4.12 - typescript: '>=4.5.0' - peerDependenciesMeta: - '@microsoft/api-extractor': - optional: true - '@swc/core': - optional: true - postcss: - optional: true - typescript: - optional: true - dependencies: - bundle-require: 4.0.1(esbuild@0.19.7) - cac: 6.7.14 - chokidar: 3.5.3 - debug: 4.3.4(supports-color@5.5.0) - esbuild: 0.19.7 - execa: 5.1.1 - globby: 11.1.0 - joycon: 3.1.1 - postcss-load-config: 4.0.2 - resolve-from: 5.0.0 - rollup: 4.5.1 - source-map: 0.8.0-beta.0 - sucrase: 3.32.0 - tree-kill: 1.2.2 - typescript: 5.3.3 - transitivePeerDependencies: - - supports-color - - ts-node - dev: true - /tuf-js@2.1.0: resolution: {integrity: sha512-eD7YPPjVlMzdggrOeE8zwoegUaG/rt6Bt3jwoQPunRiNVzgcCE009UDFJKJjG+Gk9wFu6W/Vi+P5d/5QpdD9jA==} engines: {node: ^16.14.0 || >=18.0.0}