diff --git a/.changeset/dependabot-update-12768.md b/.changeset/dependabot-update-12768.md new file mode 100644 index 000000000000..e5b173e033e7 --- /dev/null +++ b/.changeset/dependabot-update-12768.md @@ -0,0 +1,12 @@ +--- +"miniflare": patch +"wrangler": patch +--- + +Update dependencies of "miniflare", "wrangler" + +The following dependency versions have been updated: + +| Dependency | From | To | +| ---------- | ------------ | ------------ | +| workerd | 1.20260301.1 | 1.20260305.1 | diff --git a/.changeset/young-facts-grin.md b/.changeset/young-facts-grin.md new file mode 100644 index 000000000000..42c0287c972c --- /dev/null +++ b/.changeset/young-facts-grin.md @@ -0,0 +1,9 @@ +--- +"@cloudflare/local-explorer-ui": minor +--- + +Add schema editor to data studio + +Adds a visual schema editor to the data studio that allows you to create new database tables and edit existing table schemas. The editor provides column management (add, edit, remove), constraint editing (primary keys, unique constraints), and generates the corresponding SQL statements for review before committing changes. + +This is a WIP experimental feature. diff --git a/packages/local-explorer-ui/package.json b/packages/local-explorer-ui/package.json index 5dd65ba00a0b..dc1f388518f6 100644 --- a/packages/local-explorer-ui/package.json +++ b/packages/local-explorer-ui/package.json @@ -36,6 +36,7 @@ "@phosphor-icons/react": "^2.1.10", "@tailwindcss/vite": "^4.0.15", "@tanstack/react-router": "^1.158.0", + "immer": "^11.1.4", "react": "^19.2.0", "react-dom": "^19.2.0", "tailwindcss": "^4.0.15" diff --git a/packages/local-explorer-ui/src/components/studio/Explain/SQLiteExplainTab.tsx b/packages/local-explorer-ui/src/components/studio/Explain/SQLiteExplainTab.tsx index 414aaae147ca..9ca6e0a77b33 100644 --- a/packages/local-explorer-ui/src/components/studio/Explain/SQLiteExplainTab.tsx +++ b/packages/local-explorer-ui/src/components/studio/Explain/SQLiteExplainTab.tsx @@ -116,7 +116,7 @@ function describeExplainNode(d: string): { label: (
SCAN - + {d.substring("SCAN ".length)} diff --git a/packages/local-explorer-ui/src/components/studio/Modal/DropTableConfirmation.tsx b/packages/local-explorer-ui/src/components/studio/Modal/DropTableConfirmation.tsx new file mode 100644 index 000000000000..465a562af9ea --- /dev/null +++ b/packages/local-explorer-ui/src/components/studio/Modal/DropTableConfirmation.tsx @@ -0,0 +1,107 @@ +import { Button, Dialog, Text } from "@cloudflare/kumo"; +import { useState } from "react"; +import type { IStudioDriver } from "../../../types/studio"; +import type { SubmitEvent } from "react"; + +interface DropTableConfirmationModalProps { + closeModal: () => void; + driver: IStudioDriver; + isOpen: boolean; + onSuccess?: () => void; + schemaName: string; + tableName: string; +} + +export function DropTableConfirmationModal({ + closeModal, + driver, + isOpen, + onSuccess, + schemaName, + tableName, +}: DropTableConfirmationModalProps): JSX.Element { + const [challengeInput, setChallengeInput] = useState(""); + const [error, setError] = useState(null); + const [isDeleting, setIsDeleting] = useState(false); + + const isValid = challengeInput === tableName; + + const handleSubmit = async (e: SubmitEvent) => { + e.preventDefault(); + setIsDeleting(true); + setError(null); + + try { + await driver.dropTable(schemaName, tableName); + onSuccess?.(); + closeModal(); + } catch (err) { + setIsDeleting(false); + setError(err instanceof Error ? err.message : "Failed to delete table"); + } + }; + + return ( + { + if (!open) { + closeModal(); + } + }} + open={isOpen} + > + +
+ {/* @ts-expect-error - Type mismatch due to pnpm monorepo @types/react version conflict */} + + Delete table? + +
+ +
+
+ {/* @ts-expect-error - Type mismatch due to pnpm monorepo @types/react version conflict */} + + Are you sure you want to delete the table{" "} + {tableName}? This action cannot be undone. + + +
+ + Type {tableName} to confirm + + setChallengeInput(e.target.value)} + value={challengeInput} + /> +
+ + {error && ( +
+ {error} +
+ )} +
+ +
+ + + +
+
+
+
+ ); +} diff --git a/packages/local-explorer-ui/src/components/studio/SkeletonBlock.tsx b/packages/local-explorer-ui/src/components/studio/SkeletonBlock.tsx new file mode 100644 index 000000000000..23c90a6a7cb6 --- /dev/null +++ b/packages/local-explorer-ui/src/components/studio/SkeletonBlock.tsx @@ -0,0 +1,40 @@ +import { cn } from "@cloudflare/kumo"; +import type { HTMLAttributes } from "react"; + +interface SkeletonBlockProps extends HTMLAttributes { + height?: number | string; + mb?: number; + p?: number; + width?: number | string; +} + +export function SkeletonBlock({ + className, + height, + mb, + p, + style, + width, + ...props +}: SkeletonBlockProps) { + return ( +
+ {/* Non-breaking space for sizing */} +   +
+ ); +} diff --git a/packages/local-explorer-ui/src/components/studio/TabRegister.tsx b/packages/local-explorer-ui/src/components/studio/TabRegister.tsx index b2427fbd42b5..84902d8ff052 100644 --- a/packages/local-explorer-ui/src/components/studio/TabRegister.tsx +++ b/packages/local-explorer-ui/src/components/studio/TabRegister.tsx @@ -1,4 +1,5 @@ -import { BinocularsIcon, TableIcon } from "@phosphor-icons/react"; +import { BinocularsIcon, PencilIcon, TableIcon } from "@phosphor-icons/react"; +import { StudioCreateUpdateTableTab } from "./Tabs/CreateUpdateTable"; import { StudioQueryTab } from "./Tabs/Query"; import { StudioTableExplorerTab } from "./Tabs/TableExplorer"; import type { Icon } from "@phosphor-icons/react"; @@ -26,7 +27,31 @@ const TableTab: TabDefinition<{ type: "table", }; -const RegisteredTabDefinition = [QueryTab, TableTab]; +const EditTableTab: TabDefinition<{ + schemaName: string; + tableName: string; + type: "edit-table"; +}> = { + icon: PencilIcon, + makeComponent: ({ schemaName, tableName }) => ( + + ), + makeIdentifier: (tab) => `edit-table/${tab.schemaName}.${tab.tableName}`, + makeTitle: ({ tableName }) => tableName, + type: "edit-table", +}; + +const NewTableTab: TabDefinition<{ + type: "create-table"; +}> = { + icon: PencilIcon, + makeComponent: () => , + makeIdentifier: () => `create-table`, + makeTitle: () => "Create table", + type: "create-table", +}; + +const RegisteredTabDefinition = [QueryTab, TableTab, EditTableTab, NewTableTab]; export interface TabDefinition { icon: Icon; diff --git a/packages/local-explorer-ui/src/components/studio/Table/ActionsDropdown.tsx b/packages/local-explorer-ui/src/components/studio/Table/ActionsDropdown.tsx new file mode 100644 index 000000000000..8511447eb139 --- /dev/null +++ b/packages/local-explorer-ui/src/components/studio/Table/ActionsDropdown.tsx @@ -0,0 +1,90 @@ +import { Button, DropdownMenu } from "@cloudflare/kumo"; +import { CopyIcon, TableIcon, TextTIcon } from "@phosphor-icons/react"; +import { useCallback } from "react"; +import type { IStudioDriver } from "../../../types/studio"; + +export interface TableTarget { + schemaName: string; + tableName: string; +} + +interface TableActionsDropdownProps { + /** + * The currently selected table. When null/undefined, the dropdown trigger is disabled. + */ + currentTable: string | null | undefined; + + /** + * The database driver used to perform operations like fetching schema and dropping tables. + */ + driver: IStudioDriver; + + /** + * The schema name for the current table. + * + * @default 'main' + */ + schemaName?: string; +} + +export function StudioTableActionsDropdown({ + currentTable, + driver, + schemaName = "main", +}: TableActionsDropdownProps): JSX.Element { + const handleCopyTableName = useCallback(async (): Promise => { + if (!currentTable) { + return; + } + + await window.navigator.clipboard.writeText(currentTable); + }, [currentTable]); + + const handleCopyTableSchema = useCallback(async (): Promise => { + if (!currentTable) { + return; + } + + const tableSchema = await driver.tableSchema(schemaName, currentTable); + if (!tableSchema.createScript) { + return; + } + + await window.navigator.clipboard.writeText(tableSchema.createScript); + }, [currentTable, driver, schemaName]); + + return ( + <> + + + } + /> + + + + Copy table name + + + + Copy table schema + + + + + ); +} diff --git a/packages/local-explorer-ui/src/components/studio/Table/Result/EditableCell.tsx b/packages/local-explorer-ui/src/components/studio/Table/Result/EditableCell.tsx index f8ff3e3fa9b5..c928d67c4341 100644 --- a/packages/local-explorer-ui/src/components/studio/Table/Result/EditableCell.tsx +++ b/packages/local-explorer-ui/src/components/studio/Table/Result/EditableCell.tsx @@ -94,7 +94,7 @@ function InputCellEditor({ {popover && createPortal(
>; + readOnlyExistingColumns?: boolean; + value: StudioTableSchemaChange; +} + +/** + * Renders a single editable row in the table schema editor for a specific column. + * + * Features: + * - Toggle primary key participation via icon button + * - Toggle NULL/NOT NULL via checkbox + * - Displays column name, type, default value, and constraints + * - Provides dropdown menu for editing or removing the column + * + * It uses immutable updates with `produce` to keep the parent schema state consistent. + */ +export function StudioColumnSchemaEditor({ + columnIndex, + highlightSchemaChanges, + onChange, + readOnlyExistingColumns, + value, +}: StudioColumnSchemaEditorProps): JSX.Element | null { + const { openModal } = useModal(); + const column = value.columns[columnIndex]; + + const isPrimaryKey = + column?.new?.constraint?.primaryKey || + value.constraints.some((constraint) => + (constraint.new?.primaryColumns ?? []).includes(column?.new?.name ?? "") + ); + + const editableColumn = column?.new; + + const onPrimaryKeyClicked = useCallback((): void => { + if (!editableColumn) { + return; + } + + onChange((prev) => + produce(prev, (draft) => { + const pkConstraint = draft.constraints.find((c) => c.new?.primaryKey); + + if (isPrimaryKey) { + // Remove column from primary key list + if (pkConstraint?.new?.primaryColumns) { + pkConstraint.new.primaryColumns = + pkConstraint.new.primaryColumns.filter( + (name) => name !== editableColumn.name + ); + + if (pkConstraint.new.primaryColumns.length === 0) { + draft.constraints = draft.constraints.filter( + (c) => c.key !== pkConstraint?.key + ); + } + } + return; + } + + // Add column to primary key list or create constraint if none exists + if (pkConstraint?.new) { + pkConstraint.new.primaryColumns = [ + ...(pkConstraint.new.primaryColumns ?? []), + editableColumn.name, + ]; + return; + } + + draft.constraints.push({ + new: { + primaryKey: true, + primaryColumns: [editableColumn.name], + }, + old: null, + key: window.crypto.randomUUID(), + }); + }) + ); + }, [editableColumn, onChange, isPrimaryKey]); + + const onNullClicked = useCallback( + (checkedState: boolean): void => { + if (!column) { + return; + } + + onChange((prev) => + produce(prev, (draft) => { + const draftColumn = draft.columns.find((c) => c.key === column.key); + if (!draftColumn?.new) { + return; + } + + if (!draftColumn.new.constraint) { + draftColumn.new.constraint = {}; + } + + draftColumn.new.constraint.notNull = !checkedState; + }) + ); + }, + [column, onChange] + ); + + const handleEditColumn = useCallback((): void => { + if (!column?.new) { + return; + } + + openModal(StudioColumnEditorModal, { + defaultValue: column.new, + onConfirm: (newColumnDef: StudioTableColumn) => { + onChange((prev) => + produce(prev, (draft) => { + const targetColumn = draft.columns.find( + (draftColumn) => draftColumn.key === column?.key + ); + if (!targetColumn) { + return; + } + + targetColumn.new = newColumnDef; + }) + ); + }, + schemaChanges: value, + }); + }, [onChange, value, column, openModal]); + + const handleRemoveColumn = useCallback((): void => { + onChange((prev) => + produce(prev, (draft) => { + draft.columns = draft.columns.filter((c) => c.key !== column?.key); + }) + ); + }, [onChange, column]); + + if (!column || !editableColumn) { + return null; + } + + return ( + + + {columnIndex + 1} + + + + {isPrimaryKey ? ( + + ) : ( + !readOnlyExistingColumns && ( + + ) + )} + + + + {editableColumn.name} + + + {editableColumn.type} + + + + + + + {JSON.stringify(editableColumn.constraint?.defaultValue)} + + + + + + + + + + + + } + /> + + + + Edit column + + + + Remove column + + + + + + ); +} + +interface ColumnConstraintDescriptionProps { + column: StudioTableColumn; + constraints: StudioTableConstraintChange[]; +} + +/** + * Displays constraint badges for a specific column, including: + * - Inline column constraints such as CHECK and GENERATED expressions + * - Foreign key references, whether defined directly on the column or + * as part of a table-level constraint that involves the column + * + * The component checks both column-level and table-level constraints + * to accurately resolve foreign key references for display. + */ +function ColumnConstraintDescription({ + column, + constraints, +}: ColumnConstraintDescriptionProps): JSX.Element { + // Check if it contains foreign key + let referenceTableName = column.constraint?.foreignKey?.foreignTableName; + let referenceColumnName = column.constraint?.foreignKey?.foreignColumns?.[0]; + + // Check if the reference is inside the table constraint + for (const constraint of constraints ?? []) { + const tableConstraint = constraint?.new; + + if ( + tableConstraint && + tableConstraint.foreignKey && + tableConstraint.foreignKey.columns && + tableConstraint.foreignKey.foreignColumns + ) { + const foundIndex = tableConstraint.foreignKey.columns.indexOf( + column.name + ); + + if (foundIndex >= 0) { + referenceTableName = tableConstraint.foreignKey.foreignTableName; + referenceColumnName = + tableConstraint.foreignKey.foreignColumns[foundIndex]; + } + } + } + + return ( +
+ {column.constraint?.generatedExpression && ( + + {column.constraint.generatedExpression} + + )} + + {column.constraint?.checkExpression && ( + + {column.constraint.checkExpression} + + )} + + {referenceTableName && referenceColumnName && ( + + {referenceTableName}.{referenceColumnName} + + )} +
+ ); +} + +interface ColumnConstraintBadgeProps extends PropsWithChildren { + icon?: Icon; + name: string; +} + +function ColumnConstraintBadge({ + children, + icon: IconComponent, + name, +}: ColumnConstraintBadgeProps): JSX.Element { + return ( +
+
+ {IconComponent && } {name} +
+ +
{children}
+
+ ); +} + +interface StudioColumnEditiorDrawerProps { + closeModal?: () => void; + defaultValue?: StudioTableColumn; + isOpen?: boolean; + onConfirm: (value: StudioTableColumn) => void; + schemaChanges: StudioTableSchemaChange; +} + +export function StudioColumnEditorModal({ + closeModal, + defaultValue, + isOpen, + onConfirm, + schemaChanges, +}: StudioColumnEditiorDrawerProps): JSX.Element { + const [value, setValue] = useState(() => + defaultValue + ? structuredClone(defaultValue) + : { + name: "", + type: "", + } + ); + + const isColumnNameDuplicated = !!schemaChanges.columns.find( + (column) => + column.new !== defaultValue && + column.new?.name.toLowerCase() === value.name.toLowerCase() + ); + + const isValid = !!value.name && !!value.type && !isColumnNameDuplicated; + + const handleSubmit = (): void => { + if (!isValid) { + return; + } + + onConfirm(value); + closeModal?.(); + }; + + return ( + { + if (!open) { + closeModal?.(); + } + }} + open={isOpen} + > + +
+ {/* @ts-expect-error - Type mismatch due to pnpm monorepo @types/react version conflict */} + + {defaultValue ? "Edit Column" : "Add Column"} + +
+ + {/* @ts-expect-error - Type mismatch due to pnpm monorepo @types/react version conflict */} + + {defaultValue + ? "Edit the column details below." + : "Enter the column details below."} + + +
+
+ + { + setValue( + produce(value, (draft) => { + draft.name = e.target.value; + }) + ); + }} + placeholder="e.g., user_id" + value={value.name} + /> +
+ +
+ + +
+
+ +
+ + +
+
+
+ ); +} diff --git a/packages/local-explorer-ui/src/components/studio/Table/SchemaEditor/ConstraintListEditor.tsx b/packages/local-explorer-ui/src/components/studio/Table/SchemaEditor/ConstraintListEditor.tsx new file mode 100644 index 000000000000..4b824744decc --- /dev/null +++ b/packages/local-explorer-ui/src/components/studio/Table/SchemaEditor/ConstraintListEditor.tsx @@ -0,0 +1,198 @@ +import { closestCenter, DndContext } from "@dnd-kit/core"; +import { + arrayMove, + SortableContext, + useSortable, + verticalListSortingStrategy, +} from "@dnd-kit/sortable"; +import { CSS } from "@dnd-kit/utilities"; +import { ArrowRightIcon } from "@phosphor-icons/react"; +import { produce } from "immer"; +import { useCallback } from "react"; +import type { StudioTableSchemaChange } from "../../../../types/studio"; +import type { DragEndEvent } from "@dnd-kit/core"; +import type { Dispatch, SetStateAction } from "react"; + +interface StudioConstraintListEditorProps { + onChange: Dispatch>; + value: StudioTableSchemaChange; +} + +export function StudioConstraintListEditor({ + onChange, + value, +}: StudioConstraintListEditorProps): JSX.Element | null { + if (value.constraints.length === 0) { + return null; + } + + return ( + <> +
Constraints
+ + + + + + + + + + + {(value.constraints ?? []).map( + (constraintChange, constriantIndex): JSX.Element | null => { + const constraint = constraintChange.new || constraintChange.old; + if (!constraint) { + return null; + } + + let constraintType = ""; + + if (constraint.unique) { + constraintType = "Unique"; + } + + if (constraint.foreignKey) { + constraintType = "Foreign Key"; + } + + if (constraint.primaryKey) { + constraintType = "Primary Key"; + } + + if (constraint.checkExpression) { + constraintType = "Check"; + } + + return ( + + + + + + ); + } + )} + +
# + Type +
+ {constriantIndex + 1} + {constraintType} + {constraint.foreignKey && ( +
+ {(constraint.foreignKey.columns ?? []).map( + (column, columnIndex) => ( +
+ {column} {" "} + {constraint.foreignKey?.foreignTableName}. + { + constraint.foreignKey?.foreignColumns?.[ + columnIndex + ] + } +
+ ) + )} +
+ )} + + {constraint.primaryKey && ( + { + onChange((prev) => + produce(prev, (draft) => { + draft.constraints.forEach((c) => { + if ( + c.key === constraintChange.key && + c.new?.primaryColumns + ) { + c.new.primaryColumns = newPrimaryColumns; + } + }); + }) + ); + }} + value={constraint.primaryColumns ?? []} + /> + )} +
+ + ); +} + +interface SortableColumnListProps { + disabledRearrange?: boolean; + onChange: (newValue: string[]) => void; + value: string[]; +} + +function SortableColumnList({ + disabledRearrange, + onChange, + value, +}: SortableColumnListProps): JSX.Element { + const handleDragEnd = useCallback( + (event: DragEndEvent): void => { + const { active, over } = event; + + if (!active || !over) { + return; + } + + if (active.id !== over.id) { + const oldIndex = value.indexOf(active.id.toString()); + const newIndex = value.indexOf(over.id.toString()); + onChange(arrayMove(value, oldIndex, newIndex)); + } + }, + [onChange, value] + ); + + return ( +
+ + + {value.map((columnName) => ( + + ))} + + +
+ ); +} + +interface SortableColumnItemProps { + id: string; +} + +function SortableColumnItem({ id }: SortableColumnItemProps): JSX.Element { + const { attributes, listeners, setNodeRef, transform, transition } = + useSortable({ id }); + + return ( +
+ {id} +
+ ); +} diff --git a/packages/local-explorer-ui/src/components/studio/Table/SchemaEditor/index.tsx b/packages/local-explorer-ui/src/components/studio/Table/SchemaEditor/index.tsx new file mode 100644 index 000000000000..fbff3bba24a2 --- /dev/null +++ b/packages/local-explorer-ui/src/components/studio/Table/SchemaEditor/index.tsx @@ -0,0 +1,275 @@ +import { Button } from "@cloudflare/kumo"; +import { SplitPane } from "@cloudflare/workers-editor-shared"; +import { KeyIcon } from "@phosphor-icons/react"; +import { produce } from "immer"; +import { useCallback, useEffect, useMemo, useRef } from "react"; +import { isEqual } from "../../../../utils/is-equal"; +import { useModal } from "../../Modal"; +import { StudioCommitConfirmation } from "../../Modal/CommitConfirmation"; +import { StudioSQLEditor } from "../../SQLEditor"; +import { StudioColumnEditorModal, StudioColumnSchemaEditor } from "./Column"; +import { StudioConstraintListEditor } from "./ConstraintListEditor"; +import type { + IStudioDriver, + StudioTableColumn, + StudioTableIndex, + StudioTableSchemaChange, +} from "../../../../types/studio"; +import type { StudioCodeMirrorReference } from "../../Code/Mirror"; +import type { Dispatch, SetStateAction } from "react"; + +interface StudioTableSchemaEditorProps { + disabledAddColumn?: boolean; + driver: IStudioDriver; + highlightSchemaChanges?: boolean; + onChange: Dispatch>; + onSaveChange: (statements: string[]) => Promise; + readOnlyExistingColumns?: boolean; + value: StudioTableSchemaChange; +} + +export function StudioTableSchemaEditor({ + disabledAddColumn, + driver, + highlightSchemaChanges, + onChange, + onSaveChange, + readOnlyExistingColumns, + value, +}: StudioTableSchemaEditorProps): JSX.Element { + const { openModal } = useModal(); + + const editorRef = useRef(null); + + const handleNameChange = useCallback( + (newName: string): void => { + onChange((prev) => + produce(prev, (draft) => { + draft.name.new = newName; + }) + ); + }, + [onChange] + ); + + const isSchemaDirty = useMemo( + (): boolean => + value.name.new !== value.name.old || + value.columns.some((change) => !isEqual(change.new, change.old)) || + value.constraints.some((change) => !isEqual(change.new, change.old)), + [value] + ); + + const isSaveEnabled = useMemo( + // Enable save only if there's at least one column, a table name, and some change detected + (): boolean => + isSchemaDirty && !!value.name.new && value.columns.length > 0, + [isSchemaDirty, value] + ); + + const handleAddColumn = useCallback((): void => { + openModal(StudioColumnEditorModal, { + onConfirm: (newColumn: StudioTableColumn) => { + onChange((prev) => + produce(prev, (draft) => { + draft.columns.push({ + key: window.crypto.randomUUID(), + old: null, + new: newColumn, + }); + }) + ); + }, + schemaChanges: value, + }); + }, [onChange, value, openModal]); + + useEffect((): void => { + if (!editorRef.current) { + return; + } + + try { + editorRef.current.setValue( + driver.generateTableSchemaStatement(value).join("\n") + ); + } catch (e) { + console.log("Some error", e); + } + }, [driver, value, editorRef]); + + const handleSaveChange = useCallback((): void => { + try { + const previewStatements = driver.generateTableSchemaStatement(value); + openModal(StudioCommitConfirmation, { + onConfirm: async () => { + await onSaveChange(previewStatements); + }, + statements: previewStatements, + }); + } catch { + console.log("Cannot generate statements"); + } + }, [driver, value, openModal, onSaveChange]); + + const handleDiscard = useCallback((): void => { + onChange((prev) => + produce(prev, (draft) => { + draft.name.new = draft.name.old; + draft.columns = draft.columns + .filter((draftColumn) => draftColumn.old) + .map((draftColumn) => ({ + ...draftColumn, + new: draftColumn.old, + })); + + draft.constraints = draft.constraints + .filter((draftConstraint) => draftConstraint.old) + .map((draftConstraint) => ({ + ...draftConstraint, + new: draftConstraint.old, + })); + }) + ); + }, [onChange]); + + return ( + +
+
+ handleNameChange(e.target.value)} + placeholder="Table name" + value={value.name.new ?? ""} + /> +
+
+ {isSchemaDirty && ( + + )} + +
+
+ +
+
+ + + + + + + + + + + + + + + {value.columns.map((_, columnIndex) => ( + + ))} + +
+ # + + + + Column Name + + Type + + NULL + + Default Value +
+ + {!disabledAddColumn && ( + + )} + + + +
+
+
+
+ +
+ + ); +} + +interface IndexListProps { + indexList: StudioTableIndex[]; +} + +function IndexList({ indexList }: IndexListProps): JSX.Element | null { + if (indexList.length === 0) { + return null; + } + + return ( + <> +
Indexes
+ + + + + + + + + + + + + {indexList.map((index, indexIdx) => { + return ( + + + + + + + ); + })} + +
# + Index Name + Type
{indexIdx + 1}{index.name}{index.type} + {index.columns.join(", ")} +
+ + ); +} diff --git a/packages/local-explorer-ui/src/components/studio/Tabs/CreateUpdateTable.tsx b/packages/local-explorer-ui/src/components/studio/Tabs/CreateUpdateTable.tsx new file mode 100644 index 000000000000..14fa83622ca1 --- /dev/null +++ b/packages/local-explorer-ui/src/components/studio/Tabs/CreateUpdateTable.tsx @@ -0,0 +1,181 @@ +import { useCallback, useEffect, useState } from "react"; +import { useStudioContext } from "../Context"; +import { SkeletonBlock } from "../SkeletonBlock"; +import { StudioTableSchemaEditor } from "../Table/SchemaEditor"; +import { useStudioCurrentWindowTab } from "../WindowTab/Context"; +import type { + StudioTableSchema, + StudioTableSchemaChange, +} from "../../../types/studio"; + +interface StudioEditTableTabProps { + schemaName?: string; + tableName?: string; +} + +const LAYOUT_CLASSES = "overflow-auto w-full h-full bg-surface"; + +export function StudioCreateUpdateTableTab({ + schemaName, + tableName, +}: StudioEditTableTabProps): JSX.Element { + const { driver, refreshSchema, replaceStudioTab } = useStudioContext(); + const { identifier: tabIdentifier } = useStudioCurrentWindowTab(); + + const [loading, setLoading] = useState(!!schemaName && !!tableName); + const [value, setValue] = useState({ + columns: [], + constraints: [], + indexes: [], + name: { + new: "", + old: "", + }, + schemaName: "main", + }); + + // Determines if the editor is in create mode (no previous table name) + const isCreateMode = !value.name.old; + + useEffect((): void => { + async function updateValue(): Promise { + if (!schemaName || !tableName) { + return; + } + + try { + const tableSchema = await driver.tableSchema(schemaName, tableName); + setValue(transformTableSchematableSchema(tableSchema)); + } catch (err) { + console.error(err); + } finally { + setLoading(false); + } + } + + void updateValue(); + }, [driver, schemaName, tableName]); + + const onSaveChange = useCallback( + async (statements: string[]): Promise => { + if (!value.schemaName || !value.name.new) { + return; + } + + await driver.transaction(statements); + + setValue( + transformTableSchematableSchema( + await driver.tableSchema(value.schemaName, value.name.new) + ) + ); + + replaceStudioTab( + tabIdentifier, + { + schemaName: value.schemaName, + tableName: value.name.new, + type: "edit-table", + }, + { + withoutReplaceComponent: true, + } + ); + + refreshSchema(); + }, + [value, driver, refreshSchema, tabIdentifier, replaceStudioTab] + ); + + if (loading) { + return ( +
+
+ +
+
+ ); + } + + return ( +
+ +
+ ); +} + +function transformTableSchematableSchema(tableSchema: StudioTableSchema) { + const constraintsList = structuredClone(tableSchema.constraints ?? []); + + const columnList = tableSchema.columns.map((column) => { + const columnCopy = { ...column }; + + /** + * Promote primary key and foreign key constraints from column-level to table-level. + * + * In SQLite, constraints like PRIMARY KEY and FOREIGN KEY can be defined at the column level: + * + * CREATE TABLE ( + * PRIMARY KEY + * ); + * + * For consistency and simplicity in our editor, we convert these to table-level constraints: + * + * CREATE TABLE ( + * , + * PRIMARY KEY (, ...) + * ); + * + * Table-level constraints are more flexible (e.g., allowing composite keys), + * and this approach allows us to handle all constraints in a single, unified way in the UI logic. + */ + if (columnCopy.constraint?.primaryKey) { + delete columnCopy.constraint.primaryKey; + delete columnCopy.constraint.primaryKeyConflict; + delete columnCopy.constraint.primaryKeyOrder; + delete columnCopy.constraint.primaryColumns; + + const existingPkConstraint = constraintsList.find( + (constraint) => constraint.primaryKey === true + ); + if (existingPkConstraint) { + existingPkConstraint.primaryColumns?.push(columnCopy.name); + return columnCopy; + } + + constraintsList.unshift({ + primaryKey: true, + primaryColumns: [columnCopy.name], + }); + } + + return columnCopy; + }); + + return { + columns: columnList.map((column) => ({ + key: window.crypto.randomUUID(), + new: structuredClone(column), + old: structuredClone(column), + })), + constraints: constraintsList.map((constraint) => ({ + key: window.crypto.randomUUID(), + new: structuredClone(constraint), + old: structuredClone(constraint), + })), + indexes: tableSchema.indexes ?? [], + name: { + old: tableSchema.tableName ?? null, + new: tableSchema.tableName ?? null, + }, + schemaName: tableSchema.schemaName, + }; +} diff --git a/packages/local-explorer-ui/src/components/studio/Tabs/TableExplorer.tsx b/packages/local-explorer-ui/src/components/studio/Tabs/TableExplorer.tsx index 938a36975ab0..de4732f70afd 100644 --- a/packages/local-explorer-ui/src/components/studio/Tabs/TableExplorer.tsx +++ b/packages/local-explorer-ui/src/components/studio/Tabs/TableExplorer.tsx @@ -398,13 +398,16 @@ export function StudioTableExplorerTab({ - -
diff --git a/packages/local-explorer-ui/src/components/studio/index.tsx b/packages/local-explorer-ui/src/components/studio/index.tsx index f9c4ad0f2592..eea0cda75119 100644 --- a/packages/local-explorer-ui/src/components/studio/index.tsx +++ b/packages/local-explorer-ui/src/components/studio/index.tsx @@ -21,6 +21,7 @@ import type { StudioSchemas, } from "../../types/studio"; import type { StudioContextValue } from "./Context"; +import type { TableTarget } from "./Table/ActionsDropdown"; import type { StudioTabDefinitionMetadata } from "./TabRegister"; import type { StudioWindowTabItem } from "./WindowTab/types"; @@ -30,6 +31,27 @@ import type { StudioWindowTabItem } from "./WindowTab/types"; const DEFAULT_SCHEMA_NAME = "main"; export interface StudioRef { + /** + * Closes all tabs (table viewer and edit-table) associated with a specific table. + */ + closeTableTabs: (schemaName: string, tableName: string) => void; + + /** + * Returns the currently active table context (from table or edit-table tabs), + * or null if no table is selected. + */ + currentTable: TableTarget | null; + + /** + * Opens the create-table tab. + */ + openCreateTableTab: () => void; + + /** + * Opens the edit-table tab for the specified table. + */ + openEditTableTab: (schemaName: string, tableName: string) => void; + /** * Refreshes the database schema, re-fetching table and view information. */ @@ -96,8 +118,6 @@ export const Studio = forwardRef(function Studio( } }, [driver]); - useImperativeHandle(ref, () => ({ refreshSchema }), [refreshSchema]); - useEffect((): void => { void refreshSchema(); }, [refreshSchema]); @@ -202,6 +222,117 @@ export const Studio = forwardRef(function Studio( [setSelectedTabKey, tabs] ); + /** + * Opens the edit-table tab for a specific table. + */ + const openEditTableTab = useCallback( + (schemaName: string, tableName: string) => { + openStudioTab({ + schemaName, + tableName, + type: "edit-table", + }); + }, + [openStudioTab] + ); + + /** + * Returns the currently active table context from the selected tab. + * + * Works for both "table" and "edit-table" tab types. + */ + const getCurrentTable = useCallback((): TableTarget | null => { + const selectedTab = tabs.find((tab) => tab.key === selectedTabKey); + if (!selectedTab) { + return null; + } + + // Match both "table" and "edit-table" identifier patterns + // Format: "{type}/{schemaName}.{tableName}" + const match = selectedTab.identifier.match( + /^(?:table|edit-table)\/([^.]+)\.(.+)$/ + ); + if (!match || !match[1] || !match[2]) { + return null; + } + + return { + schemaName: match[1], + tableName: match[2], + }; + }, [selectedTabKey, tabs]); + + const openCreateTableTab = useCallback((): void => { + openStudioTab({ + type: "create-table", + }); + }, [openStudioTab]); + + /** + * Closes all tabs (table viewer and edit-table) associated with a specific table. + */ + const closeTableTabs = useCallback( + (schemaName: string, tableName: string): void => { + const identifiersToClose = [ + `table/${schemaName}.${tableName}`, + `edit-table/${schemaName}.${tableName}`, + ] satisfies string[]; + + setTabs((previousTabs) => { + const tabsToClose = previousTabs.filter((tab) => + identifiersToClose.includes(tab.identifier) + ); + if (tabsToClose.length === 0) { + return previousTabs; + } + + const filteredTabs = previousTabs.filter( + (tab) => !identifiersToClose.includes(tab.identifier) + ); + const selectedTabIsClosing = tabsToClose.some( + (tab) => tab.key === selectedTabKeyRef.current + ); + if (selectedTabIsClosing && filteredTabs.length > 0) { + const firstClosedIndex = previousTabs.findIndex((tab) => + identifiersToClose.includes(tab.identifier) + ); + const newSelectedIndex = Math.min( + filteredTabs.length - 1, + firstClosedIndex + ); + + const newSelectedTab = filteredTabs[newSelectedIndex]; + if (newSelectedTab) { + setSelectedTabKey(newSelectedTab.key); + } + } + + return filteredTabs; + }); + }, + [] + ); + + useImperativeHandle( + ref, + () => ({ + closeTableTabs, + get currentTable() { + return getCurrentTable(); + }, + openCreateTableTab, + openEditTableTab, + refreshSchema, + }), + [ + closeTableTabs, + getCurrentTable, + openCreateTableTab, + openEditTableTab, + refreshSchema, + ] + ); + /** * Updates the status properties (e.g. `isDirty`, `isTemp`) of an existing studio tab. */ @@ -279,11 +410,12 @@ export const Studio = forwardRef(function Studio( return; } - const tableMatch = selectedTab.identifier.match(/^table\/[^.]+\.(.+)$/); - if (!tableMatch) { - lastOpenedTable.current = null; - } - onTableChange(tableMatch ? tableMatch[1] : undefined); + // Match both "table" and "edit-table" tab types + const tableMatch = selectedTab.identifier.match( + /^(?:table|edit-table)\/[^.]+\.(.+)$/ + ); + lastOpenedTable.current = tableMatch ? tableMatch[1] ?? null : null; + onTableChange(tableMatch?.[1]); }, [initialTable, loadingSchema, onTableChange, selectedTabKey, tabs]); /** diff --git a/packages/local-explorer-ui/src/routes/d1/$databaseId.tsx b/packages/local-explorer-ui/src/routes/d1/$databaseId.tsx index 8c2a28536713..a4d3a91d5804 100644 --- a/packages/local-explorer-ui/src/routes/d1/$databaseId.tsx +++ b/packages/local-explorer-ui/src/routes/d1/$databaseId.tsx @@ -5,7 +5,10 @@ import { CaretUpDownIcon, CheckIcon, DatabaseIcon, + PencilIcon, + PlusIcon, TableIcon, + TrashIcon, } from "@phosphor-icons/react"; import { createFileRoute, @@ -16,9 +19,12 @@ import { import { useCallback, useMemo, useRef, useState } from "react"; import { Breadcrumbs } from "../../components/Breadcrumbs"; import { Studio } from "../../components/studio"; +import { DropTableConfirmationModal } from "../../components/studio/Modal/DropTableConfirmation"; +import { StudioTableActionsDropdown } from "../../components/studio/Table/ActionsDropdown"; import { LocalD1Driver } from "../../drivers/d1"; import type { StudioRef } from "../../components/studio"; import type { StudioResource } from "../../types/studio"; +import type { RefObject } from "react"; export const Route = createFileRoute("/d1/$databaseId")({ component: DatabaseView, @@ -49,7 +55,14 @@ function DatabaseView(): JSX.Element { const lastSyncedTable = useRef(searchParams.table); const studioRef = useRef(null); + const [currentTable, setCurrentTable] = useState( + searchParams.table + ); const [isRefreshing, setIsRefreshing] = useState(false); + const [deleteTarget, setDeleteTarget] = useState<{ + schemaName: string; + tableName: string; + } | null>(null); const driver = useMemo( () => new LocalD1Driver(params.databaseId), @@ -66,7 +79,9 @@ function DatabaseView(): JSX.Element { const handleTableChange = useCallback( (tableName: string | undefined) => { - // Skip if the table hasn't changed to avoid unnecessary navigation + setCurrentTable(tableName); + + // Skip URL navigation if the table hasn't changed if (lastSyncedTable.current === tableName) { return; } @@ -99,6 +114,44 @@ function DatabaseView(): JSX.Element { } }, [router]); + const handleTableDeleted = useCallback(async (): Promise => { + await handleTableRefresh(); + void navigate({ + replace: true, + search: { + table: undefined, + }, + to: ".", + }); + }, [handleTableRefresh, navigate]); + + const handleDeleteClick = useCallback((): void => { + if (!currentTable) { + return; + } + + setDeleteTarget({ + schemaName: "main", + tableName: currentTable, + }); + }, [currentTable]); + + const handleCloseDeleteModal = useCallback((): void => { + setDeleteTarget(null); + }, []); + + const handleDeleteSuccess = useCallback((): void => { + if (!deleteTarget) { + return; + } + + studioRef.current?.closeTableTabs( + deleteTarget.schemaName, + deleteTarget.tableName + ); + void handleTableDeleted(); + }, [deleteTarget, handleTableDeleted]); + return (
{params.databaseId} , - , + , ]} > +
+ + + + + + + + {deleteTarget && ( + + )} +
; +} + +function TableSelect({ studioRef }: TableSelectProps): JSX.Element { const data = Route.useLoaderData(); const navigate = useNavigate(); const searchParams = Route.useSearch(); + const [open, setOpen] = useState(false); const handleTableChange = useCallback( (tableName: string | null) => { @@ -164,18 +263,17 @@ function TableSelect(): JSX.Element { [navigate] ); - if (data.tables.length <= 0) { - return ( - - No tables - - ); - } + const handleCreateTable = useCallback((): void => { + setOpen(false); + studioRef.current?.openCreateTableTab(); + }, [studioRef]); return ( @@ -193,24 +291,45 @@ function TableSelect(): JSX.Element { sideOffset={4} > +
+ +
+ +
+ - {data.tables.map((table) => { - const Icon = - searchParams.table === table.value ? CheckIcon : TableIcon; - - return ( - - - - - {table.label} - - ); - })} + {data.tables.length > 0 ? ( + data.tables.map((table) => { + const Icon = + searchParams.table === table.value ? CheckIcon : TableIcon; + + return ( + + + + + {table.label} + + ); + }) + ) : ( + + No tables + + )} diff --git a/packages/local-explorer-ui/src/routes/do/$className/$objectId.tsx b/packages/local-explorer-ui/src/routes/do/$className/$objectId.tsx index 3021e955df2d..5dcd52b126e0 100644 --- a/packages/local-explorer-ui/src/routes/do/$className/$objectId.tsx +++ b/packages/local-explorer-ui/src/routes/do/$className/$objectId.tsx @@ -5,7 +5,10 @@ import { CaretUpDownIcon, CheckIcon, CubeIcon, + PencilIcon, + PlusIcon, TableIcon, + TrashIcon, } from "@phosphor-icons/react"; import { createFileRoute, @@ -17,9 +20,12 @@ import { useCallback, useMemo, useRef, useState } from "react"; import { durableObjectsNamespaceListNamespaces } from "../../../api"; import { Breadcrumbs } from "../../../components/Breadcrumbs"; import { Studio } from "../../../components/studio"; +import { DropTableConfirmationModal } from "../../../components/studio/Modal/DropTableConfirmation"; +import { StudioTableActionsDropdown } from "../../../components/studio/Table/ActionsDropdown"; import { LocalDODriver } from "../../../drivers/do"; import type { StudioRef } from "../../../components/studio"; import type { StudioResource } from "../../../types/studio"; +import type { RefObject } from "react"; export const Route = createFileRoute("/do/$className/$objectId")({ component: ObjectView, @@ -66,7 +72,14 @@ function ObjectView(): JSX.Element { const lastSyncedTable = useRef(searchParams.table); const studioRef = useRef(null); + const [currentTable, setCurrentTable] = useState( + searchParams.table + ); const [isRefreshing, setIsRefreshing] = useState(false); + const [deleteTarget, setDeleteTarget] = useState<{ + schemaName: string; + tableName: string; + } | null>(null); const { namespaceId } = loaderData; @@ -86,7 +99,9 @@ function ObjectView(): JSX.Element { const handleTableChange = useCallback( (tableName: string | undefined) => { - // Skip if the table hasn't changed to avoid unnecessary navigation + setCurrentTable(tableName); + + // Skip URL navigation if the table hasn't changed if (lastSyncedTable.current === tableName) { return; } @@ -119,6 +134,44 @@ function ObjectView(): JSX.Element { } }, [router]); + const handleTableDeleted = useCallback(async (): Promise => { + await handleTableRefresh(); + void navigate({ + replace: true, + search: { + table: undefined, + }, + to: ".", + }); + }, [handleTableRefresh, navigate]); + + const handleDeleteClick = useCallback((): void => { + if (!currentTable) { + return; + } + + setDeleteTarget({ + schemaName: "main", + tableName: currentTable, + }); + }, [currentTable]); + + const handleCloseDeleteModal = useCallback((): void => { + setDeleteTarget(null); + }, []); + + const handleDeleteSuccess = useCallback((): void => { + if (!deleteTarget) { + return; + } + + studioRef.current?.closeTableTabs( + deleteTarget.schemaName, + deleteTarget.tableName + ); + void handleTableDeleted(); + }, [deleteTarget, handleTableDeleted]); + // Truncate the object ID for display const shortObjectId = params.objectId.length > 16 @@ -145,24 +198,65 @@ function ObjectView(): JSX.Element { > {shortObjectId} , - , + , ]} title="Durable Objects" > +
+ + + + + + + + {deleteTarget && ( + + )} +
; +} + +function TableSelect({ studioRef }: TableSelectProps): JSX.Element { const data = Route.useLoaderData(); const navigate = useNavigate(); const searchParams = Route.useSearch(); + const [open, setOpen] = useState(false); const handleTableChange = useCallback( (tableName: string | null) => { @@ -198,18 +297,17 @@ function TableSelect(): JSX.Element { [navigate] ); - if (data.tables.length <= 0) { - return ( - - No tables - - ); - } + const handleCreateTable = useCallback((): void => { + setOpen(false); + studioRef.current?.openCreateTableTab(); + }, [studioRef]); return ( @@ -227,24 +325,45 @@ function TableSelect(): JSX.Element { sideOffset={4} > +
+ +
+ +
+ - {data.tables.map((table) => { - const Icon = - searchParams.table === table.value ? CheckIcon : TableIcon; - - return ( - - - - - {table.label} - - ); - })} + {data.tables.length > 0 ? ( + data.tables.map((table) => { + const Icon = + searchParams.table === table.value ? CheckIcon : TableIcon; + + return ( + + + + + {table.label} + + ); + }) + ) : ( + + No tables + + )} diff --git a/packages/miniflare/package.json b/packages/miniflare/package.json index cbf77d04f6a8..52c769aa60df 100644 --- a/packages/miniflare/package.json +++ b/packages/miniflare/package.json @@ -50,7 +50,7 @@ "@cspotcode/source-map-support": "0.8.1", "sharp": "^0.34.5", "undici": "catalog:default", - "workerd": "1.20260301.1", + "workerd": "1.20260305.1", "ws": "catalog:default", "youch": "4.1.0-beta.10" }, diff --git a/packages/wrangler/package.json b/packages/wrangler/package.json index 9625683fbd7c..89c44eccf85a 100644 --- a/packages/wrangler/package.json +++ b/packages/wrangler/package.json @@ -73,7 +73,7 @@ "miniflare": "workspace:*", "path-to-regexp": "6.3.0", "unenv": "2.0.0-rc.24", - "workerd": "1.20260301.1" + "workerd": "1.20260305.1" }, "devDependencies": { "@aws-sdk/client-s3": "^3.721.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f852e4ab3297..0f2ef4611a82 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -10,8 +10,8 @@ catalogs: specifier: ^0.10.11 version: 0.10.15 '@cloudflare/workers-types': - specifier: ^4.20260226.1 - version: 4.20260305.0 + specifier: ^4.20260305.1 + version: 4.20260305.1 '@typescript-eslint/eslint-plugin': specifier: ^8.35.1 version: 8.46.3 @@ -172,7 +172,7 @@ importers: version: link:../../packages/workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 '@fixture/shared': specifier: workspace:* version: link:../shared @@ -223,7 +223,7 @@ importers: version: link:../../packages/workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 ts-dedent: specifier: ^2.2.0 version: 2.2.0 @@ -244,7 +244,7 @@ importers: version: link:../../packages/workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 typescript: specifier: catalog:default version: 5.8.3 @@ -268,7 +268,7 @@ importers: version: link:../../packages/workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 typescript: specifier: catalog:default version: 5.8.3 @@ -295,7 +295,7 @@ importers: version: link:../../packages/workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 typescript: specifier: catalog:default version: 5.8.3 @@ -337,7 +337,7 @@ importers: version: link:../../packages/workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 undici: specifier: catalog:default version: 7.18.2 @@ -352,7 +352,7 @@ importers: devDependencies: '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 '@types/mimetext': specifier: ^2.0.4 version: 2.0.4 @@ -397,7 +397,7 @@ importers: version: link:../../packages/workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 '@types/jest-image-snapshot': specifier: ^6.4.0 version: 6.4.0 @@ -427,7 +427,7 @@ importers: version: link:../../packages/workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 miniflare: specifier: workspace:* version: link:../../packages/miniflare @@ -503,7 +503,7 @@ importers: version: link:../../packages/workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 '@types/node': specifier: ^20.19.9 version: 20.19.9 @@ -527,7 +527,7 @@ importers: version: link:../../packages/workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 '@types/is-even': specifier: ^1.0.2 version: 1.0.2 @@ -570,7 +570,7 @@ importers: version: link:../../packages/workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 typescript: specifier: catalog:default version: 5.8.3 @@ -601,7 +601,7 @@ importers: version: link:../../packages/workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 '@types/node': specifier: ^20.19.9 version: 20.19.9 @@ -634,7 +634,7 @@ importers: version: link:../../packages/workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 undici: specifier: catalog:default version: 7.18.2 @@ -655,7 +655,7 @@ importers: version: link:../../packages/workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 '@types/debug': specifier: 4.1.12 version: 4.1.12 @@ -691,7 +691,7 @@ importers: version: link:../../packages/workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 typescript: specifier: catalog:default version: 5.8.3 @@ -715,7 +715,7 @@ importers: version: link:../../packages/workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 typescript: specifier: catalog:default version: 5.8.3 @@ -743,7 +743,7 @@ importers: version: link:../../packages/workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 '@fixture/pages-plugin': specifier: workspace:* version: link:../pages-plugin-example @@ -770,7 +770,7 @@ importers: version: link:../../packages/workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 typescript: specifier: catalog:default version: 5.8.3 @@ -815,7 +815,7 @@ importers: version: link:../../packages/workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 typescript: specifier: catalog:default version: 5.8.3 @@ -839,7 +839,7 @@ importers: version: link:../../packages/workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 typescript: specifier: catalog:default version: 5.8.3 @@ -863,7 +863,7 @@ importers: version: link:../../packages/workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 typescript: specifier: catalog:default version: 5.8.3 @@ -881,7 +881,7 @@ importers: devDependencies: '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 is-odd: specifier: ^3.0.1 version: 3.0.1 @@ -903,7 +903,7 @@ importers: version: link:../../packages/workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 '@fixture/pages-plugin': specifier: workspace:* version: link:../pages-plugin-example @@ -972,7 +972,7 @@ importers: version: link:../../packages/workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 typescript: specifier: catalog:default version: 5.8.3 @@ -996,7 +996,7 @@ importers: version: link:../../packages/workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 typescript: specifier: catalog:default version: 5.8.3 @@ -1200,19 +1200,19 @@ importers: devDependencies: '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 fixtures/rules-app: devDependencies: '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 fixtures/secrets-store: devDependencies: '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 wrangler: specifier: workspace:* version: link:../../packages/wrangler @@ -1239,7 +1239,7 @@ importers: version: link:../../packages/workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 '@types/is-even': specifier: ^1.0.2 version: 1.0.2 @@ -1266,7 +1266,7 @@ importers: version: link:../../packages/workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 vitest: specifier: catalog:default version: 3.2.3(@types/debug@4.1.12)(@types/node@20.19.9)(@vitest/ui@3.2.3)(jiti@2.6.1)(lightningcss@1.30.2)(msw@2.12.0(@types/node@20.19.9)(typescript@5.9.3))(tsx@4.21.0)(yaml@2.8.1) @@ -1281,7 +1281,7 @@ importers: version: link:../../packages/workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 esbuild: specifier: catalog:default version: 0.27.3 @@ -1308,7 +1308,7 @@ importers: version: link:../../packages/vitest-pool-workers '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 '@microlabs/otel-cf-workers': specifier: 1.0.0-rc.45 version: 1.0.0-rc.45(@opentelemetry/api@1.7.0) @@ -1382,7 +1382,7 @@ importers: version: link:../../packages/workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 '@fixture/shared': specifier: workspace:* version: link:../shared @@ -1443,7 +1443,7 @@ importers: devDependencies: '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 wrangler: specifier: workspace:* version: link:../../packages/wrangler @@ -1458,7 +1458,7 @@ importers: version: link:../../packages/workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 miniflare: specifier: workspace:* version: link:../../packages/miniflare @@ -1512,7 +1512,7 @@ importers: version: link:../../packages/workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 run-script-os: specifier: ^1.1.6 version: 1.1.6 @@ -1539,7 +1539,7 @@ importers: version: link:../../packages/workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 typescript: specifier: catalog:default version: 5.8.3 @@ -1563,7 +1563,7 @@ importers: version: link:../../packages/workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 typescript: specifier: catalog:default version: 5.8.3 @@ -1587,7 +1587,7 @@ importers: version: link:../../packages/workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 typescript: specifier: catalog:default version: 5.8.3 @@ -1611,7 +1611,7 @@ importers: version: link:../../packages/workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 typescript: specifier: catalog:default version: 5.8.3 @@ -1635,7 +1635,7 @@ importers: version: link:../../packages/workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 '@types/jest-image-snapshot': specifier: ^6.4.0 version: 6.4.0 @@ -1671,7 +1671,7 @@ importers: version: link:../../packages/workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 playwright-chromium: specifier: catalog:default version: 1.56.1 @@ -1698,7 +1698,7 @@ importers: version: link:../../packages/workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 typescript: specifier: catalog:default version: 5.8.3 @@ -1719,7 +1719,7 @@ importers: version: link:../../packages/eslint-config-shared '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 typescript: specifier: catalog:default version: 5.8.3 @@ -1819,7 +1819,7 @@ importers: version: link:../workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 '@cloudflare/workers-utils': specifier: workspace:* version: link:../workers-utils @@ -1957,7 +1957,7 @@ importers: version: link:../eslint-config-shared '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 '@octokit/types': specifier: ^13.8.0 version: 13.8.0 @@ -1981,10 +1981,10 @@ importers: version: link:../eslint-config-shared '@cloudflare/vitest-pool-workers': specifier: catalog:default - version: 0.10.15(@cloudflare/workers-types@4.20260305.0)(@vitest/runner@3.2.3)(@vitest/snapshot@3.2.3)(vitest@3.2.3) + version: 0.10.15(@cloudflare/workers-types@4.20260305.1)(@vitest/runner@3.2.3)(@vitest/snapshot@3.2.3)(vitest@3.2.3) '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 '@types/cookie': specifier: ^0.6.0 version: 0.6.0 @@ -2053,7 +2053,7 @@ importers: version: link:../eslint-config-shared '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 eslint: specifier: catalog:default version: 9.39.1(jiti@2.6.1) @@ -2083,10 +2083,10 @@ importers: version: link:../eslint-config-shared '@cloudflare/vitest-pool-workers': specifier: catalog:default - version: 0.10.15(@cloudflare/workers-types@4.20260305.0)(@vitest/runner@3.2.3)(@vitest/snapshot@3.2.3)(vitest@2.1.9) + version: 0.10.15(@cloudflare/workers-types@4.20260305.1)(@vitest/runner@3.2.3)(@vitest/snapshot@3.2.3)(vitest@2.1.9) '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 '@types/mime': specifier: ^3.0.4 version: 3.0.4 @@ -2162,6 +2162,9 @@ importers: '@tanstack/react-router': specifier: ^1.158.0 version: 1.159.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + immer: + specifier: ^11.1.4 + version: 11.1.4 react: specifier: ^19.2.0 version: 19.2.4 @@ -2224,8 +2227,8 @@ importers: specifier: catalog:default version: 7.18.2 workerd: - specifier: 1.20260301.1 - version: 1.20260301.1 + specifier: 1.20260305.1 + version: 1.20260305.1 ws: specifier: catalog:default version: 8.18.0 @@ -2253,7 +2256,7 @@ importers: version: link:../workers-shared '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 '@cloudflare/workers-utils': specifier: workspace:* version: link:../workers-utils @@ -2434,7 +2437,7 @@ importers: version: link:../eslint-config-shared '@cloudflare/vitest-pool-workers': specifier: catalog:default - version: 0.10.15(@cloudflare/workers-types@4.20260305.0)(@vitest/runner@3.2.3)(@vitest/snapshot@3.2.3)(vitest@3.2.3) + version: 0.10.15(@cloudflare/workers-types@4.20260305.1)(@vitest/runner@3.2.3)(@vitest/snapshot@3.2.3)(vitest@3.2.3) '@cloudflare/workers-shared': specifier: workspace:* version: link:../workers-shared @@ -2443,7 +2446,7 @@ importers: version: link:../workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 concurrently: specifier: ^8.2.2 version: 8.2.2 @@ -2480,7 +2483,7 @@ importers: version: link:../eslint-config-shared '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 '@types/cookie': specifier: ^0.6.0 version: 0.6.0 @@ -2520,7 +2523,7 @@ importers: version: link:../workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 '@types/node': specifier: ^20.19.9 version: 20.19.9 @@ -2550,7 +2553,7 @@ importers: version: link:../workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 esbuild: specifier: catalog:default version: 0.27.3 @@ -2639,7 +2642,7 @@ importers: version: link:../workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 '@cloudflare/workers-utils': specifier: workspace:* version: link:../workers-utils @@ -2723,7 +2726,7 @@ importers: version: link:../../../workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 typescript: specifier: catalog:default version: 5.8.3 @@ -2744,7 +2747,7 @@ importers: version: link:../../../workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 typescript: specifier: catalog:default version: 5.8.3 @@ -2765,7 +2768,7 @@ importers: version: link:../../../workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 typescript: specifier: catalog:default version: 5.8.3 @@ -2786,7 +2789,7 @@ importers: version: link:../../../workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 typescript: specifier: catalog:default version: 5.8.3 @@ -2807,7 +2810,7 @@ importers: version: link:../../../workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 typescript: specifier: catalog:default version: 5.8.3 @@ -2828,7 +2831,7 @@ importers: version: link:../../../workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 typescript: specifier: catalog:default version: 5.8.3 @@ -2849,7 +2852,7 @@ importers: version: link:../../../workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 typescript: specifier: catalog:default version: 5.8.3 @@ -2870,7 +2873,7 @@ importers: version: link:../../../workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 typescript: specifier: catalog:default version: 5.8.3 @@ -2891,7 +2894,7 @@ importers: version: link:../../../workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 typescript: specifier: catalog:default version: 5.8.3 @@ -2912,7 +2915,7 @@ importers: version: link:../../../workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 typescript: specifier: catalog:default version: 5.8.3 @@ -2933,7 +2936,7 @@ importers: version: link:../../../workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 typescript: specifier: catalog:default version: 5.8.3 @@ -2954,7 +2957,7 @@ importers: version: link:../../../workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 typescript: specifier: catalog:default version: 5.8.3 @@ -2975,7 +2978,7 @@ importers: version: link:../../../workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 typescript: specifier: catalog:default version: 5.8.3 @@ -2996,7 +2999,7 @@ importers: version: link:../../../workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 typescript: specifier: catalog:default version: 5.8.3 @@ -3017,7 +3020,7 @@ importers: version: link:../../../workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 typescript: specifier: catalog:default version: 5.8.3 @@ -3038,7 +3041,7 @@ importers: version: link:../../../workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 typescript: specifier: catalog:default version: 5.8.3 @@ -3059,7 +3062,7 @@ importers: version: link:../../../workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 '@types/mimetext': specifier: ^2.0.4 version: 2.0.4 @@ -3092,7 +3095,7 @@ importers: version: link:../../../workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 typescript: specifier: catalog:default version: 5.8.3 @@ -3113,7 +3116,7 @@ importers: version: link:../../../workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 typescript: specifier: catalog:default version: 5.8.3 @@ -3134,7 +3137,7 @@ importers: version: link:../../../workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 typescript: specifier: catalog:default version: 5.8.3 @@ -3155,7 +3158,7 @@ importers: version: link:../../../workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 typescript: specifier: catalog:default version: 5.8.3 @@ -3176,7 +3179,7 @@ importers: version: link:../../../workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 typescript: specifier: catalog:default version: 5.8.3 @@ -3197,7 +3200,7 @@ importers: version: link:../../../workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 typescript: specifier: catalog:default version: 5.8.3 @@ -3218,7 +3221,7 @@ importers: version: link:../../../workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 '@playground/main-resolution-package': specifier: file:./package version: file:packages/vite-plugin-cloudflare/playground/main-resolution/package @@ -3242,7 +3245,7 @@ importers: version: link:../../../workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 '@types/express': specifier: ^5.0.1 version: 5.0.1 @@ -3269,7 +3272,7 @@ importers: version: link:../../../workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 '@playground/module-resolution-excludes': specifier: file:./packages/excludes version: file:packages/vite-plugin-cloudflare/playground/module-resolution/packages/excludes @@ -3281,7 +3284,7 @@ importers: version: file:packages/vite-plugin-cloudflare/playground/module-resolution/packages/requires '@remix-run/cloudflare': specifier: 2.12.0 - version: 2.12.0(@cloudflare/workers-types@4.20260305.0)(typescript@5.8.3) + version: 2.12.0(@cloudflare/workers-types@4.20260305.1)(typescript@5.8.3) '@types/react': specifier: ^18.3.11 version: 18.3.18 @@ -3314,7 +3317,7 @@ importers: version: link:../../../workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 typescript: specifier: catalog:default version: 5.8.3 @@ -3335,7 +3338,7 @@ importers: version: link:../../../workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 '@types/debug': specifier: ^4.1.12 version: 4.1.12 @@ -3384,7 +3387,7 @@ importers: version: link:../../../workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 '@types/react': specifier: 19.1.0 version: 19.1.0 @@ -3405,7 +3408,7 @@ importers: dependencies: partyserver: specifier: ^0.0.64 - version: 0.0.64(@cloudflare/workers-types@4.20260305.0) + version: 0.0.64(@cloudflare/workers-types@4.20260305.1) partysocket: specifier: ^1.0.3 version: 1.0.3 @@ -3424,7 +3427,7 @@ importers: version: link:../../../workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 '@tailwindcss/vite': specifier: ^4.0.15 version: 4.0.15(vite@7.1.12(@types/node@20.19.9)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.1)) @@ -3460,7 +3463,7 @@ importers: version: link:../../../workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 typescript: specifier: catalog:default version: 5.8.3 @@ -3481,7 +3484,7 @@ importers: version: link:../../../workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 '@cloudflare/workers-utils': specifier: workspace:* version: link:../../../workers-utils @@ -3521,7 +3524,7 @@ importers: version: link:../../../workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 '@types/react': specifier: 19.1.0 version: 19.1.0 @@ -3551,7 +3554,7 @@ importers: version: link:../../../workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 typescript: specifier: catalog:default version: 5.8.3 @@ -3572,7 +3575,7 @@ importers: version: link:../../../workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 typescript: specifier: catalog:default version: 5.8.3 @@ -3600,7 +3603,7 @@ importers: version: link:../../../workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 '@types/react': specifier: 19.1.0 version: 19.1.0 @@ -3633,7 +3636,7 @@ importers: version: link:../../../workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 typescript: specifier: catalog:default version: 5.8.3 @@ -3654,7 +3657,7 @@ importers: version: link:../../../workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 typescript: specifier: catalog:default version: 5.8.3 @@ -3675,7 +3678,7 @@ importers: version: link:../../../workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 '@vitejs/plugin-basic-ssl': specifier: ^2.0.0 version: 2.0.0(vite@7.1.12(@types/node@20.19.9)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.1)) @@ -3699,7 +3702,7 @@ importers: version: link:../../../workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 typescript: specifier: catalog:default version: 5.8.3 @@ -3720,7 +3723,7 @@ importers: version: link:../../../workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 typescript: specifier: catalog:default version: 5.8.3 @@ -3741,7 +3744,7 @@ importers: version: link:../../../workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 typescript: specifier: catalog:default version: 5.8.3 @@ -3762,7 +3765,7 @@ importers: version: link:../../../workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 typescript: specifier: catalog:default version: 5.8.3 @@ -3799,7 +3802,7 @@ importers: version: link:../workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 '@cloudflare/workers-utils': specifier: workspace:* version: link:../workers-utils @@ -4026,13 +4029,13 @@ importers: version: link:../eslint-config-shared '@cloudflare/vitest-pool-workers': specifier: catalog:default - version: 0.10.15(@cloudflare/workers-types@4.20260305.0)(@vitest/runner@3.2.3)(@vitest/snapshot@3.2.3)(vitest@2.1.9) + version: 0.10.15(@cloudflare/workers-types@4.20260305.1)(@vitest/runner@3.2.3)(@vitest/snapshot@3.2.3)(vitest@2.1.9) '@cloudflare/workers-tsconfig': specifier: workspace:* version: link:../workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 '@sentry/cli': specifier: ^2.37.0 version: 2.41.1(encoding@0.1.13) @@ -4143,13 +4146,13 @@ importers: version: link:../eslint-config-shared '@cloudflare/vitest-pool-workers': specifier: catalog:default - version: 0.10.15(@cloudflare/workers-types@4.20260305.0)(@vitest/runner@3.2.3)(@vitest/snapshot@3.2.3)(vitest@3.2.3) + version: 0.10.15(@cloudflare/workers-types@4.20260305.1)(@vitest/runner@3.2.3)(@vitest/snapshot@3.2.3)(vitest@3.2.3) '@cloudflare/workers-tsconfig': specifier: workspace:* version: link:../workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 '@types/mime': specifier: ^3.0.4 version: 3.0.4 @@ -4190,8 +4193,8 @@ importers: specifier: 2.0.0-rc.24 version: 2.0.0-rc.24 workerd: - specifier: 1.20260301.1 - version: 1.20260301.1 + specifier: 1.20260305.1 + version: 1.20260305.1 optionalDependencies: fsevents: specifier: ~2.3.2 @@ -4226,7 +4229,7 @@ importers: version: link:../workers-tsconfig '@cloudflare/workers-types': specifier: catalog:default - version: 4.20260305.0 + version: 4.20260305.1 '@cloudflare/workers-utils': specifier: workspace:* version: link:../workers-utils @@ -5298,6 +5301,12 @@ packages: cpu: [x64] os: [darwin] + '@cloudflare/workerd-darwin-64@1.20260305.1': + resolution: {integrity: sha512-DujkFIxbPDtaVOzQLtQU92eCHmf4UQA3RAtQqaot65Eae9h3mVqJEW04tKPl/0yedCg66MeFM3En38EMX5414w==} + engines: {node: '>=16'} + cpu: [x64] + os: [darwin] + '@cloudflare/workerd-darwin-arm64@1.20251210.0': resolution: {integrity: sha512-Mg8iYIZQFnbevq/ls9eW/eneWTk/EE13Pej1MwfkY5et0jVpdHnvOLywy/o+QtMJFef1AjsqXGULwAneYyBfHw==} engines: {node: '>=16'} @@ -5310,6 +5319,12 @@ packages: cpu: [arm64] os: [darwin] + '@cloudflare/workerd-darwin-arm64@1.20260305.1': + resolution: {integrity: sha512-X/3ccTe21beOdafyLtEJjpL+79/iXoFpUSG35LANzTyNt1cW6RaE1RJixuj7dejlc/MBSKRGI9kGzb+Luph2Mw==} + engines: {node: '>=16'} + cpu: [arm64] + os: [darwin] + '@cloudflare/workerd-linux-64@1.20251210.0': resolution: {integrity: sha512-kjC2fCZhZ2Gkm1biwk2qByAYpGguK5Gf5ic8owzSCUw0FOUfQxTZUT9Lp3gApxsfTLbbnLBrX/xzWjywH9QR4g==} engines: {node: '>=16'} @@ -5322,6 +5337,12 @@ packages: cpu: [x64] os: [linux] + '@cloudflare/workerd-linux-64@1.20260305.1': + resolution: {integrity: sha512-8MWi+o7fTSEwXC3SDcHBcNWzgqpBGqPRAjmFJYrQfkQIQXHYnH1Kv+uERdO/DpELuzcMaA5pMJv7xFWax89t4Q==} + engines: {node: '>=16'} + cpu: [x64] + os: [linux] + '@cloudflare/workerd-linux-arm64@1.20251210.0': resolution: {integrity: sha512-2IB37nXi7PZVQLa1OCuO7/6pNxqisRSO8DmCQ5x/3sezI5op1vwOxAcb1osAnuVsVN9bbvpw70HJvhKruFJTuA==} engines: {node: '>=16'} @@ -5334,6 +5355,12 @@ packages: cpu: [arm64] os: [linux] + '@cloudflare/workerd-linux-arm64@1.20260305.1': + resolution: {integrity: sha512-893pX7SyyodmRIXllQoI7jujP/KAJDl357ZOCnesbm15Pk3XIIxAK5GcBx7M4drttcaqwkTqko0ZnsAEDPqtcw==} + engines: {node: '>=16'} + cpu: [arm64] + os: [linux] + '@cloudflare/workerd-windows-64@1.20251210.0': resolution: {integrity: sha512-Uaz6/9XE+D6E7pCY4OvkCuJHu7HcSDzeGcCGY1HLhojXhHd7yL52c3yfiyJdS8hPatiAa0nn5qSI/42+aTdDSw==} engines: {node: '>=16'} @@ -5346,6 +5373,12 @@ packages: cpu: [x64] os: [win32] + '@cloudflare/workerd-windows-64@1.20260305.1': + resolution: {integrity: sha512-H/5kjiHnMJKxDdZBccyQLaA7QpjIA+w1qC40sxIamllOclIgjnjjTTlbo13S/1RVGtfWfMgV+PIUSwmBAwDUwQ==} + engines: {node: '>=16'} + cpu: [x64] + os: [win32] + '@cloudflare/workers-editor-shared@0.1.1': resolution: {integrity: sha512-tk7dZ3rj61o8oPL2JIfJbjAldBOJZNHHIWlkfY5X5ftw7QhAIccACz4zW7LFcMyw6HHexmHhIPlcdENqqnp28w==} peerDependencies: @@ -5354,8 +5387,8 @@ packages: react: ^17.0.2 || ^18.2.21 react-dom: ^17.0.2 || ^18.2.21 - '@cloudflare/workers-types@4.20260305.0': - resolution: {integrity: sha512-sCgPFnQ03SVpC2OVW8wysONLZW/A8hlp9Mq2ckG/h1oId4kr9NawA6vUiOmOjCWRn2hIohejBYVQ+Vu20rCdKA==} + '@cloudflare/workers-types@4.20260305.1': + resolution: {integrity: sha512-835BZaIcgjuYIUqgOWJSpwQxFSJ8g/X1OCZFLO7bmirM6TGmVgIGwiGItBgkjUXXCPrYzJEldsJkuFuK7ePuMw==} '@codemirror/autocomplete@6.20.0': resolution: {integrity: sha512-bOwvTOIJcG5FVo5gUUupiwYh8MioPLQ4UcqbcRf7UQ98X90tCa9E1kZ3Z7tqwpZxYyOvh1YTYbmZE9RTfTp5hg==} @@ -11047,6 +11080,9 @@ packages: flatted@3.3.3: resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} + flatted@3.3.4: + resolution: {integrity: sha512-3+mMldrTAPdta5kjX2G2J7iX4zxtnwpdA8Tr2ZSjkyPSanvbZAcy6flmtnXbEybHrDcU9641lxrMfFuUxVz9vA==} + for-each@0.3.5: resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} engines: {node: '>= 0.4'} @@ -11455,6 +11491,9 @@ packages: resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} engines: {node: '>= 4'} + immer@11.1.4: + resolution: {integrity: sha512-XREFCPo6ksxVzP4E0ekD5aMdf8WMwmdNaz6vuvxgI40UaEiu6q3p8X52aU6GdyvLY3XXX/8R7JOTXStz/nBbRw==} + import-fresh@3.3.1: resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} engines: {node: '>=6'} @@ -15232,6 +15271,11 @@ packages: engines: {node: '>=16'} hasBin: true + workerd@1.20260305.1: + resolution: {integrity: sha512-UdoZK3XG89acwdfNBKrE2PFq6JMDLb2C97UR4dz1iGTf7mpIGY5vGeaDXP2+MW/D8zFzK+oJPfr0RSi60boVTQ==} + engines: {node: '>=16'} + hasBin: true + wrangler@4.54.0: resolution: {integrity: sha512-bANFsjDwJLbprYoBK+hUDZsVbUv2SqJd8QvArLIcZk+fPq4h/Ohtj5vkKXD3k0s2bD1DXLk08D+hYmeNH+xC6A==} engines: {node: '>=20.0.0'} @@ -16749,7 +16793,7 @@ snapshots: lodash.memoize: 4.1.2 marked: 0.3.19 - '@cloudflare/vitest-pool-workers@0.10.15(@cloudflare/workers-types@4.20260305.0)(@vitest/runner@3.2.3)(@vitest/snapshot@3.2.3)(vitest@2.1.9)': + '@cloudflare/vitest-pool-workers@0.10.15(@cloudflare/workers-types@4.20260305.1)(@vitest/runner@3.2.3)(@vitest/snapshot@3.2.3)(vitest@2.1.9)': dependencies: '@vitest/runner': 3.2.3 '@vitest/snapshot': 3.2.3 @@ -16759,14 +16803,14 @@ snapshots: miniflare: 4.20251210.0 semver: 7.7.3 vitest: 2.1.9(@types/node@20.19.9)(@vitest/ui@2.1.9)(lightningcss@1.30.2)(msw@2.12.0(@types/node@20.19.9)(typescript@5.9.3)) - wrangler: 4.54.0(@cloudflare/workers-types@4.20260305.0) + wrangler: 4.54.0(@cloudflare/workers-types@4.20260305.1) zod: 3.25.76 transitivePeerDependencies: - '@cloudflare/workers-types' - bufferutil - utf-8-validate - '@cloudflare/vitest-pool-workers@0.10.15(@cloudflare/workers-types@4.20260305.0)(@vitest/runner@3.2.3)(@vitest/snapshot@3.2.3)(vitest@3.2.3)': + '@cloudflare/vitest-pool-workers@0.10.15(@cloudflare/workers-types@4.20260305.1)(@vitest/runner@3.2.3)(@vitest/snapshot@3.2.3)(vitest@3.2.3)': dependencies: '@vitest/runner': 3.2.3 '@vitest/snapshot': 3.2.3 @@ -16776,7 +16820,7 @@ snapshots: miniflare: 4.20251210.0 semver: 7.7.3 vitest: 3.2.3(@types/debug@4.1.12)(@types/node@20.19.9)(@vitest/ui@3.2.3)(jiti@2.6.1)(lightningcss@1.30.2)(msw@2.12.0(@types/node@20.19.9)(typescript@5.9.3))(tsx@4.21.0)(yaml@2.8.1) - wrangler: 4.54.0(@cloudflare/workers-types@4.20260305.0) + wrangler: 4.54.0(@cloudflare/workers-types@4.20260305.1) zod: 3.25.76 transitivePeerDependencies: - '@cloudflare/workers-types' @@ -16789,30 +16833,45 @@ snapshots: '@cloudflare/workerd-darwin-64@1.20260301.1': optional: true + '@cloudflare/workerd-darwin-64@1.20260305.1': + optional: true + '@cloudflare/workerd-darwin-arm64@1.20251210.0': optional: true '@cloudflare/workerd-darwin-arm64@1.20260301.1': optional: true + '@cloudflare/workerd-darwin-arm64@1.20260305.1': + optional: true + '@cloudflare/workerd-linux-64@1.20251210.0': optional: true '@cloudflare/workerd-linux-64@1.20260301.1': optional: true + '@cloudflare/workerd-linux-64@1.20260305.1': + optional: true + '@cloudflare/workerd-linux-arm64@1.20251210.0': optional: true '@cloudflare/workerd-linux-arm64@1.20260301.1': optional: true + '@cloudflare/workerd-linux-arm64@1.20260305.1': + optional: true + '@cloudflare/workerd-windows-64@1.20251210.0': optional: true '@cloudflare/workerd-windows-64@1.20260301.1': optional: true + '@cloudflare/workerd-windows-64@1.20260305.1': + optional: true + '@cloudflare/workers-editor-shared@0.1.1(@cloudflare/style-const@6.1.3(react@19.2.4))(@cloudflare/style-container@7.12.2(@cloudflare/style-const@6.1.3(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: '@cloudflare/style-const': 6.1.3(react@19.2.4) @@ -16821,7 +16880,7 @@ snapshots: react-dom: 19.2.4(react@19.2.4) react-split-pane: 0.1.92(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@cloudflare/workers-types@4.20260305.0': {} + '@cloudflare/workers-types@4.20260305.1': {} '@codemirror/autocomplete@6.20.0': dependencies: @@ -18332,7 +18391,7 @@ snapshots: '@prisma/adapter-d1@7.0.1': dependencies: - '@cloudflare/workers-types': 4.20260305.0 + '@cloudflare/workers-types': 4.20260305.1 '@prisma/driver-adapter-utils': 7.0.1 ky: 1.7.5 @@ -18559,10 +18618,10 @@ snapshots: optionalDependencies: '@types/react': 18.3.3 - '@remix-run/cloudflare@2.12.0(@cloudflare/workers-types@4.20260305.0)(typescript@5.8.3)': + '@remix-run/cloudflare@2.12.0(@cloudflare/workers-types@4.20260305.1)(typescript@5.8.3)': dependencies: '@cloudflare/kv-asset-handler': 0.1.3 - '@cloudflare/workers-types': 4.20260305.0 + '@cloudflare/workers-types': 4.20260305.1 '@remix-run/server-runtime': 2.12.0(typescript@5.8.3) optionalDependencies: typescript: 5.8.3 @@ -20468,7 +20527,7 @@ snapshots: dependencies: '@vitest/utils': 2.1.9 fflate: 0.8.2 - flatted: 3.3.3 + flatted: 3.3.4 pathe: 1.1.2 sirv: 3.0.2 tinyglobby: 0.2.15 @@ -22806,6 +22865,9 @@ snapshots: flatted@3.3.3: {} + flatted@3.3.4: + optional: true + for-each@0.3.5: dependencies: is-callable: 1.2.7 @@ -23237,6 +23299,8 @@ snapshots: ignore@7.0.5: {} + immer@11.1.4: {} + import-fresh@3.3.1: dependencies: parent-module: 1.0.1 @@ -24554,9 +24618,9 @@ snapshots: parseurl@1.3.3: {} - partyserver@0.0.64(@cloudflare/workers-types@4.20260305.0): + partyserver@0.0.64(@cloudflare/workers-types@4.20260305.1): dependencies: - '@cloudflare/workers-types': 4.20260305.0 + '@cloudflare/workers-types': 4.20260305.1 nanoid: 5.1.0 partysocket@1.0.3: @@ -27530,7 +27594,15 @@ snapshots: '@cloudflare/workerd-linux-arm64': 1.20260301.1 '@cloudflare/workerd-windows-64': 1.20260301.1 - wrangler@4.54.0(@cloudflare/workers-types@4.20260305.0): + workerd@1.20260305.1: + optionalDependencies: + '@cloudflare/workerd-darwin-64': 1.20260305.1 + '@cloudflare/workerd-darwin-arm64': 1.20260305.1 + '@cloudflare/workerd-linux-64': 1.20260305.1 + '@cloudflare/workerd-linux-arm64': 1.20260305.1 + '@cloudflare/workerd-windows-64': 1.20260305.1 + + wrangler@4.54.0(@cloudflare/workers-types@4.20260305.1): dependencies: '@cloudflare/kv-asset-handler': 0.4.1 '@cloudflare/unenv-preset': 2.7.13(unenv@2.0.0-rc.24)(workerd@1.20251210.0) @@ -27541,7 +27613,7 @@ snapshots: unenv: 2.0.0-rc.24 workerd: 1.20251210.0 optionalDependencies: - '@cloudflare/workers-types': 4.20260305.0 + '@cloudflare/workers-types': 4.20260305.1 fsevents: 2.3.3 transitivePeerDependencies: - bufferutil diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 7795d5cad087..9238d5a3188b 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -32,8 +32,8 @@ catalog: "ws": "8.18.0" esbuild: "0.27.3" playwright-chromium: "^1.56.1" - "@cloudflare/workers-types": "^4.20260226.1" - workerd: "1.20260301.1" + "@cloudflare/workers-types": "^4.20260305.1" + workerd: "1.20260305.1" eslint: "^9.39.1" jsonc-parser: "^3.2.0" smol-toml: "^1.5.2"