v5.3.2
Generated from commits between v5.3.1 and HEAD
[HOTFIX] fix(editor): license fixes and product metadata (#10062)
-
Fixed default UI components (such as
DefaultToolbarandDefaultQuickActionsContent) crashing when mounted outside theTldrawcomponent. -
Fixed license validation treating native apps served from custom protocols as development environments.
-
Fixed wildcard license host matching so
*.example.commatches only that domain's subdomains. -
Added internal
useMaybeLicenseManager(): the license manager from context, falling back to the nearest editor's, ornull. -
Added internal
Editor.licenseManager, assigned by<TldrawEditor />when it creates the editor. -
Changed internal
useLicenseFeatureFlagto acceptLicenseManager | nulland returnfalsefornull.
v7.7.0
I am pleased to announce the release of officeParser v7.7.0! This release hardens the Markdown ↔ HTML round trip for the kind of rich content a ProseMirror/Tiptap-style editor produces. Nested lists, aligned tables, highlights, and link/image titles now survive a full md → HTML → md cycle. It also reworks the Markdown dialect configuration so every capability is named by the syntax it selects instead of a product flavor or a bare boolean.
The fidelity items are corrections: the only output that moves is content that was previously flattened, dropped, or emitted as invalid markup. The dialect rework is backward-compatible: existing boolean/flavor configs still work (they coerce to the new values), and are now deprecated.
Each mdConfig.dialect capability now names the syntax it selects: admonitions: 'blockquote' | 'fence' | 'fence-attribute', and strikethrough/definitionLists/footnotes/citations/wikilinks/attributeLists as '<marker>' | 'none' (e.g. strikethrough: 'tilde', wikilinks: 'double-bracket'). A shared convention is a single value, and a second syntax can be added later without a breaking change. A new highlight: 'equals' | 'none' capability joins them.
In dialects that define it (Obsidian/extended), a highlighted run emits as ==text== and ==text== parses back to a highlight. Other dialects keep the HTML <mark> fallback.
[text](url "Title") and  now keep their title in both directions. Previously an inline destination swallowed url "Title" as one URL.
A multi-paragraph list item joins onto its single Markdown line with <br> (default on), mirroring cellLineBreaks for table cells.
An HTML <li> that wraps its text in <p> (the shape rich-text editors emit) exported as - a\n\n\n - a1, which reparsed flat. List items are now tight, a conservative parser pass rejoins a blank-line-split child, and generated HTML nests spec-validly (<li>a<ul>…</ul></li> instead of the invalid sibling shape), which also makes generated EPUB XHTML valid.
:--- / :---: / ---: alignment now lives on each cell and is emitted as text-align on <th>/<td> (and read back), so per-column alignment survives md → HTML → md, the editor import path, instead of vanishing on the HTML hop.
Inline code emits <code> (not a font-family: monospace <span>); a single-line code block with a language stays a <pre><code> block; a plain <blockquote> round-trips to > quoted; an HTML <br> reads back as a hard line break rather than collapsing to a space; and an own-line $$…$$ parses as block math instead of leaking stray $.
Boolean dialect toggles (strikethrough: true) and admonition flavor names (admonitions: 'github') still work. They coerce to the new syntax values (true becomes the marker, false becomes 'none'; flavors become 'blockquote'/'fence'/'fence-attribute'), but are deprecated and will be removed in the next major. Prefer the syntax names.
- Fixed a cold-run
npm testflake where a PDF-OCR parity timeout was killed at the 30s cap and misreported as a0.0% similaritycontent mismatch. Timeouts now surface distinctly and the OCR run gets a 120s budget. Test tooling only. (#111)
npm install officeparser@7.7.0
🔗 Full Changelog: View v7.7.0 details 🔗 Documentation & Visualizer: officeparser.harshankur.com
v4.1.10
[!IMPORTANT] Vuetify Needs Your Support! The OpenCollective funds dried up. We are currently unable to compensate our contributors for their continued work on the framework and the ecosystem tools.
If Vuetify is part of your stack, please consider sponsoring the project so we can continue delivering updates and fixes.
Even if you look with optimism into the future (despite the sad economic reality), it is not responsible to keep your largest open source dependency in this poor financial state. Vuetify is on the borrowed time - if anything happens to maintainers primary employment, they are more likely to drop off.
Every contribution helps us keep Vuetify alive and signals to maintainers that their effort is appreciated.
Thank you.
- VDataTable: key cells to prevent slot reuse (#23124) (a9528b5), closes #23123
- VDatePicker: restore the hover preview for range selection (6c1dee2)
- VDialog: avoid error when unmounted while closing (#23054) (8293f4c), closes #23053
- VNumberInput: snap to min/max when using buttons and value is out of range (#23109) (a35ab72), closes #23098
- VOverlay: reliably return focus to activator when eager (c879795)
- VProgressLinear: restore
left/rightanimation in split variant (537a5f7) - VProgressLinear: keep indeterminate bars visible in Firefox (694fcdb), closes #23125
- VTreeviewItem: only attach click handler when interactive (#23118) (a4297d1), closes #23117
v2.8.52
- New
getExportedSize()method onZipDirectoryEntryandFSinstances. It returns the exact size of the zip file the matchingexport*()call would write, without writing it. It takes the same options as theexport*()methods, so the value it returns is the one the export produces. It is meant for theContent-Lengthheader of a streamed download. It throws the newERR_UNDETERMINED_SIZEerror when the size cannot be known before writing, i.e. when an entry is compressed, when an entry has no known size, whensignCentralDirectoryis set, and when thebufferedWriteoption lets the physical layout depend on the order in which the entries are written. Encryption does not prevent the prediction, its overhead is a fixed number of bytes - New
onentryprogressoption in theexport*()methods of the filesystem API. It is called once per written entry with the number of entries written, the total number of entries, and the entry itself. It reports the entries whereasonprogressreports the bytes. It is called after the entry has been written. WhenbufferedWriteis enabled the entries are written concurrently, so it counts the entries written instead of giving the position of the entry in the zip file - New
globalCommentoption in theexport*()methods of the filesystem API. It sets the comment of the zip file. The options of these methods are applied to every entry, so settingcommentthere comments each entry instead of the archive, exactly aslastModDatethere sets the date of each entry. The zip file comment therefore needed a name of its own importZip()now accepts aZipReaderinstance in addition to the data of a zip file. The caller builds the reader, passes it, and keeps it after the import. This is the way to readprependedData,appendedData,comment,digitalSignature,directoryOffsetanddirectoryLength, which are only filled once the entries have been read. The options of the reader are merged with the options of the import, and the options of the import win- New
symlinkproperty on entries. It istruewhen the entry is a symbolic link. The target of the link is the content of the entry, which is read like any other entry, e.g. withgetData(new TextWriter()). The target is not validated, it can be an absolute path or escape the directory of the entry, so it must be checked before being used. Writing a symbolic link is done by setting theunixModeoption to a mode carrying theS_IFLNKtype, e.g.0o120777, with the path of the target as content exportFileSystemHandle()now accepts thereaderOptionsoption. Thepasswordoption must be set there to export the entries of an encrypted zip file, since thepasswordoption of the export encrypts the written entries instead- The
readerOptionsoption of the filesystem export now acceptspassThrough. The entries imported from a zip file are then written as-is, without being decompressed and decrypted, exactly as importing them with this option does. The entries added to the filesystem are compressed as usual - The
signCentralDirectoryoption is now declared in the export options of the filesystem API. It was already forwarded to theZipWriterinstance, it was simply missing from the TypeScript definitions - New
ERR_UNDETERMINED_SIZE,ERR_INVALID_PASS_THROUGHandERR_UNSUPPORTED_ENCRYPTION_PASS_THROUGHerror constants
- The
export*()methods of the filesystem API now report the progress of the whole archive instead of the progress of each entry.onstartandonendare called once, with the total size of the entries and with the number of bytes written. They used to be called once per entry, whileonprogresswas already reporting the archive as a whole, so the three callbacks disagreed with each other.onprogressis unchanged. Use the newonentryprogressoption to be notified for each entry - The export options of the filesystem API now take precedence over the metadata of the entries imported from a zip file. Setting
lastModDate,comment,versionMadeBy,uid,gidor the file attributes in the export options used to have no effect on those entries, althoughunixModeandmsdosAttributesdid reach them, so the same attribute word was writable one way and not the other. The order is now the metadata of the source entry, then the export options, then the description of the entries copied as-is, then the options of the entry. The description of the entries copied as-is stays above the export options because it describes the bytes being copied, not an intent. Alevelor acompressionMethodwinning over it would write headers that do not match the content. An export using the default options is unchanged, so round trips keep their fidelity ZipReader#close()now cancels theReadableStreaminstance passed to the constructor when nothing has been read from it. It used to do nothing at all. The stream of a reader whose entries have been read is left alone, and so is aReaderinstance, which belongs to the caller. The entries stay readable after the call- The
preventCloseoption is now honored only when the caller owns the writable, i.e. when aWritableWriterinstance is passed toexportZip()orexportWritable(). It is ignored by the otherexport*()methods of the filesystem API, whose Writer instance can only return its data once its writable is closed. Setting it there used to prevent the export from ever resolving - Writing an entry with the
passThroughoption and a password now throwsERR_UNSUPPORTED_ENCRYPTION_PASS_THROUGH. The data is copied as-is, so it cannot be encrypted. The password used to be ignored silently and the entry was written unencrypted although its header announced encryption - The
passThroughoption is now ignored for the entries with no content.add("dir/", undefined, { directory: true, passThrough: true })used to throwERR_UNDEFINED_READER, so aZipWriterinstance created withpassThroughset totruecould not write a single directory - Writing an entry with the
unixModeoption now stamps the type of the file in the external file attributes. zip.js used to write a mode with no type, e.g.0o000644where Info-ZIP writes0o100644, sounzip -llisted the entry as?rw-r--r--. A mode already carrying a type is left untouched, and theexternalFileAttributesoption still writes the value verbatim - The
executableproperty of an entry is nowfalsefor symbolic links. The permission bits of a link are always0o777, so the flag was meaningless on every link
- Reading a range of data no longer emits empty chunks.
Reader#createReadable()enqueued an empty chunk at the end of every entry whose size is known, and one extra read was issued for an entry of unknown size. The data was correct, the stream simply contained a chunk of length 0 getBlob()andgetData64URI()now honor the MIME type they are given. A filesystem entry holding aBlobinstance returned it as-is, with the MIME type it was created with, and ignored the requested one- The filesystem API now runs the overlapping entry check when
checkOverlappingEntryOnlyis set in its reader options. The option means "run the check and stop before reading the content" in the core API. The filesystem API needs the content, so it used to drop the option and skip the check altogether. It is now mapped tocheckOverlappingEntry, so the check runs and the content is still read - The reader options that withhold the content of an entry are now ignored by the filesystem API.
checkPasswordOnly,checkOverlappingEntryOnlyandpreventCloseused to be forwarded to the entries read from a zip file, which returned no data - Progress is now reported for the filesystem entries that were not imported from a zip file. Reading such an entry pipes the reader to the writer without going through a codec, so
onprogressnever fired. It is now reported for every entry exportFileSystemHandle()now counts the bytes it writes. It used to report the compressed size of each entry against the uncompressed size of the archive, so the progress stopped around 1% of the total, and it reported nothing at all for the entries that were not imported from a zip fileaddFileSystemHandle()now applies the entry options to the directories it creates. They were applied to the files only- The dates of the Info-ZIP unix extra field are now read as signed timestamps. A date before 1970 was read as a date in 2106
- Writing an entry whose name ends with a slash no longer corrupts the
unixModeoption. The type of the file was combined with the type already present in the mode instead of replacing it, so0o100644became a socket and0o120777became an invalid type. Both were then read back as neither a directory nor a symbolic link - The deprecated
externalFileAttributeandinternalFileAttributeoptions work again. They were removed when they were renamed toexternalFileAttributesandinternalFileAttributes. They are back as deprecated aliases, and an option passed toadd()now takes precedence over the option of theZipWriterinstance whatever the spelling of each addText()now stores the size of the text in bytes instead of its number of UTF-16 code units. OnlygetExportedSize()read that value, so the size was under-reported for any text containing non-ASCII characters. The export itself was correct- The buffer reserved for the expansion of the deflate algorithm is now allocated only for the entries that are really compressed. A stored entry reserved the same margin as a deflated one
- The
export*()methods of the filesystem API now keep a running total instead of summing the progress of every entry on every tick. The cost was quadratic in the number of entries. Passingonprogresson an archive of 10,000 entries added 50% to the duration of the export, and now adds nothing measurable
- The
useCompressionStreamoption now states that the native API is used for compression only whenlevelis undefined or equal to 6.CompressionStreamdoes not support compression levels, so any other value compresses the data with the embedded implementation. It also states that the data produced at a given level can vary between platforms, and thatuseCompressionStreammust be set tofalseto get the same output everywhere - The
uidandgidoptions now state which unix extra field carries them ZipReader#close()and thecreateTempStreamoption now describe what they do. A temporary stream must be able to hold a whole entry, because the local header written before it holds the size and the CRC-32 of the entry. Its readable side is therefore consumed only once its writable side has been closed. A factory returningnew TransformStream()deadlocks, whereas the default buffers everything
- The browser test runner uses Selenium instead of Playwright. It accepts
--exe-path,--url-search,--build,--headfuland--help, and thetest-webkitscript was renamed totest-safari - A workflow runs the test suite on every push, including the native build
- A workflow checks that the markdown documentation is up to date with
index.d.ts - The API documentation is published to the GitHub Pages site on each release
- The web runner accepts a
maxParallelTestsparameter. Chromium 87 loses the wake-up of the backpressure of a stream when 16 tests run in parallel, so its jobs cap the parallelism at 4 - The tests that check the abort reason are skipped on the browsers that ignore the signal of
pipeTo()instead of being reported as failures
- @danny0838 contributed the switch to Selenium, the test workflow and the arguments of the browser runner (#673)
- Claude (Opus 5) contributed to every change listed above
Full Changelog: https://github.com/gildas-lormeau/zip.js/compare/v2.8.51...v2.8.52
💎 Version 6.10.0
A feature release built around one question: what if the arrangement of a chart's marks were something you could hand it?
The unit chart already drew one dot per thing counted, and 6.9.0 opened a seam for supplying the positions yourself. This release ships the thing that seam was for. apexcharts/unit-shapes is a companion kit of 39 shapes a count can take: a heart, a house, a globe, a checkmark, a heartbeat trace, or the figure 1,024 drawn in 1,024 dots. Each one is a function of the marks and the plot rectangle rather than a picture, so the same shape serves 40 dots in a sparkline and 3,000 in a poster.
Alongside it: outer name labels for those shapes, so a crowd of dots reads without a legend, and a fix worth reading even if you never draw a heart, because it swallowed any update that changed only a callback.
A new entry point, tree-shaken per shape. Importing one costs about 4 KB gzipped; importing the catalog is not something you need to do.
import ApexCharts from 'apexcharts'
import { heart } from 'apexcharts/unit-shapes'
new ApexCharts(el, {
chart: { type: 'unit' },
series: [57600, 16800, 4200, 3400],
labels: ['Repeat donors', 'First-time', 'Workplace drives', 'Emergency call-ups'],
plotOptions: {
unit: { layout: 'custom', positions: heart, unitValue: 100 },
},
}).render()
A shape is a plain callable, so positions: heart needs no registration step, and plotOptions.unit.positions already accepted a function: nothing in the chart had to learn about shapes.
The dots are packed, not stamped onto a template. Rows are cut across the outline, each row split into the spans that fall inside it, and the gap between dots is then bisected until the spans hold exactly the number of marks the data asks for. Density follows the shape's own area, which is why one outline covers three orders of magnitude of dot count. A thin limb, fin or tip keeps its single dot rather than dropping out, because that is what stops a shape dissolving as the count falls.
Three kinds, because things in the world are not all areas:
- Silhouettes (29) fill an outline:
heart,house,tree,leaf,flame,droplet,fish,sun,human,group,star,crown,trophy,moneybag,funnel,shield,gear,robot,bulb,flask,car,plane,rocket,battery,pin,mountain,cross,bolt,arrow. - Strokes (7) pack a thickened centreline, for a thing with no interior:
check,wifi,pulse,xmark,percent,question,spiral. A dotted checkmark still reads as a checkmark, which is how a stroke degrades where a thin silhouette feature would simply vanish. - Generated (3) compute their positions from maths and have no outline at all:
globe(latitude rings with a tilt),target(concentric bands),pyramid(tiers).
Every shape carries its metadata: which category it belongs to, how it was made, and minUnits, the count below which it stops being recognisable. Ask for fewer and the chart says so in a console warning naming the shape, rather than rendering mush.
outlined(heart) // trace the outline instead of filling it
heart.with({ order: 'cols' }) // where each series band lands inside the shape
glyphs('1,024') // the number, drawn in that many dots
preview(heart, { series }) // -> an SVG string, no chart and no DOM
outlined() gives all 29 silhouettes a hollow twin for no new artwork, since a stroked closed path is a ring. The fill order is what decides where each category sits: rows bands a shape top to bottom, cols left to right (which is why battery fills like a charge meter), centerOut puts the first series at its heart. preview() renders a shape to standalone SVG, so docs galleries, README images and launch graphics can be generated at build time or on a server from the catalog alone.
Shapes are also registrable by name (ApexCharts.registerUnitLayout), and from a script tag dist/unit-shapes.js exposes the kit as ApexUnitShapes with every shape pre-registered.
On provenance: every outline in the kit was drawn in this repository. No third-party path is admitted, permissively licensed or not, because an outline ships verbatim inside the bundle: a copied path would make its licence notice travel into every consumer's build forever. Brand marks are excluded outright. A test enforces it.
A shape packed with four categories used to need a legend, which asks the reader to match a swatch to a band. Names can now sit in the margin with a leader line to their own dots, the way a pie names its slices.
plotOptions: {
unit: { clusterLabels: { external: { show: true } } },
}
The gutter is reserved on both sides before the dot size is chosen, so the shape is sized for the room it will actually get instead of being scaled down afterwards, and it stays centred. Each label anchors on a real dot of its own band, sides are assigned from how the bands are actually arranged, and crowded labels are spaced apart in one pass before they reach the DOM. The implementation is the one pie and donut already use, extracted rather than rewritten.
Twenty new unit demos, one per shape family, including a gallery that switches between all 39 shapes with the same dots flowing from one arrangement into the next. Palettes use separated hues rather than tints of one colour: at dot size a lightness ramp cannot be read back, and the palest end disappears against the card.
update() skips a redundant render by comparing the incoming options with the previous ones, and that comparison went through JSON.stringify, which drops function values. Two configs differing only in a callback therefore serialised identically and the update was thrown away.
Any function-valued option was affected: a new dataLabels.formatter, a new custom tooltip, a new plotOptions.unit.positions. The first such update always worked, since there was nothing to compare against yet, which is what made it look like a rendering problem rather than an update problem.
Functions are now compared by identity: passing the same function twice still skips, so the optimisation keeps paying, while a different one gets the render it asked for. A caller who builds a fresh closure on every update now gets a render every time, which is the safe direction to err in, since the closure may capture new state.
A data point whose x is a Date object had its milliseconds truncated, so points inside the same second collapsed onto each other. The type definitions also refused a Date there, despite it being the natural thing to pass. Thanks to @aron-intframe (#5277).
- the
unitandunit-shapessub-entry artifacts are built and published, soapexcharts/unitandapexcharts/unit-shapesresolve for bundlers and script tags alike - shape geometry is covered by its own suite: containment against the outline it claims, spacing, the exact-count guarantee at every dot count, provenance, and a cross-check that the catalog, the exports and the type definitions can never disagree
- two authoring tools ship with the repo rather than the package: a contact sheet that renders every shape at a given count, and a winding checker that catches a subpath which would punch a hole where it meant to fill
Full Changelog: https://github.com/apexcharts/apexcharts.js/compare/v6.9.0...v6.10.0
v16.3.1-canary.22
- fix(turbo-persistence): allow 32-bit usize conversion: #97288
- test: restore missing NFT
exports*unit fixtures: #97459 - [ci] Fix backport canary release dispatch: #97383
- turbo-tasks-backend: Enforce that tasks exist when accessing them: #96043
- turbo-tasks-backend: add persistence delete/tombstone plumbing for GC: #95975
- turbo-persistence: add key-value tombstones for MultiValue families: #96929
Huge thanks to @hardfist, @mischnic, @ztanner, and @lukesandberg for helping!
remix v3.0.0-beta.10
-
BREAKING CHANGE: Beta.10 supersedes beta.6 through beta.9 and consolidates their changes into one supported prerelease. Legacy package-aligned
remix/*aliases have been removed in favor of canonical entrypoints that group related APIs together. Update imports when moving from beta.5 to beta.10:- import { requireAuth } from 'remix/auth-middleware' - import { createPostgresDatabase } from 'remix/data-table-postgres' - import { createRouter } from 'remix/fetch-router' + import { requireAuth } from 'remix/middleware/auth' + import { createPostgresDatabase } from 'remix/data-table/postgres' + import { createRouter } from 'remix/router'
The same canonical structure applies to the other entrypoints: middleware lives under
remix/middleware/*, database dialects underremix/data-table/*, storage adapters underremix/file-storage/*andremix/session-storage/*, and route definitions move fromremix/fetch-router/routestoremix/routes. -
BREAKING CHANGE:
createAssetServer()fromremix/assetsnow usesallowFilesanddenyFilesinstead ofallowanddenyfor file path access rules:import { createAssetServer } from 'remix/assets' export const assetServer = createAssetServer({ - allow: ['app/routes.ts', 'app/**/public/**'], - deny: ['app/**/*.test.*'], + allowFiles: ['app/routes.ts', 'app/**/public/**'], + denyFiles: ['app/**/*.test.*'], }) -
BREAKING CHANGE:
remix/cookienow treats customencodeanddecodefunctions as the complete cookie value codec. Custom encoded values are signed and serialized as-is instead of being wrapped in Remix's default base64 encoding. The default codec keeps the existing base64-safe representation. -
BREAKING CHANGE: Route patterns now use delimiter-bounded params. Params stop at raw
/and., but not-, so a pattern such as/:year-:monthmust become one inseparable param such as/:date, or place the captures in separate path segments. Ambiguous adjacent captures are now rejected, and matching work is bounded to prevent pathological patterns (see #11651). -
BREAKING CHANGE: Href helpers from
remix/route-pattern/hrefandremix/routesnow take search parameters in asearchParamsoptions property:- const href = userRoute.href({ id: '123' }, { tab: 'settings' }) + const href = userRoute.href( + { id: '123' }, + { searchParams: { tab: 'settings' } }, + )
The options object also accepts a
baseURLfor generating path-relative same-origin hrefs. Route matching accepts the same option for relative URL strings, andsearchParamsaccepts both typed objects andURLSearchParams. -
BREAKING CHANGE:
remix/middleware/sessionnow makes session cookies HTTP-only whenhttpOnlyis omitted. SethttpOnly: falseexplicitly if client-side JavaScript must read the cookie.Cookie.httpOnlyfromremix/cookienow returnsboolean | undefinedso omitted and explicitly disabled settings can be distinguished. -
BREAKING CHANGE: Run tests with
remix testinstead of the removedremix-testexecutable, and move settings fromremix-test.config.tsor.jsinto thetestproperty ofremix.json:- remix-test --type server --concurrency 1 + remix test --type server --concurrency 1
The programmatic
runRemixTest()API fromremix/test/clinow accepts typed runner options instead of raw command-line arguments. The test runner also adds--onlyfor matching suite or test names,--quietfor omitting skipped tests, and defaultsNODE_ENVtotestwhen it is not already set (see #11623, #11628). -
BREAKING CHANGE: Browser frame resolvers now receive one options object instead of positional
signalandtargetarguments:- async function resolveFrame(src, signal, target) { + async function resolveFrame(src, options) { + const { signal, target } = options ?? {} // ... }
-
Add an
allowPackagesoption tocreateAssetServer()fromremix/assets. This allows a package and its dependencies to be served without listing every file the package may load:import { createAssetServer } from 'remix/assets' export const assetServer = createAssetServer({ allowFiles: ['app/routes.ts', 'app/**/public/**'], allowPackages: ['remix'], })
-
Added a new
remix dbworkflow for inspecting migration status, migrating, seeding, wiping, and resetting the current app database. Configure a built-in SQLite, PostgreSQL, or MySQL database inremix.json; for example:{ "$schema": "https://remix.run/schemas/remix.json", "db": { "adapter": { "type": "sqlite", "filename": "./db/app.sqlite", }, "migrations": { "directory": "./db/migrations", }, "seed": "./db/seed.sql", }, }The same configuration then powers the complete local database lifecycle:
remix db status remix db migrate remix db seed remix db reset --force
Command flags override configured values, database commands work from project subdirectories by finding the nearest
remix.json, and destructivewipeandresetcommands require--force(see #11608, #11639). -
Added an optional JSONC
remix.jsonfile for sharedremix db,remix test, andremix doctorsettings. Relative paths and globs resolve from the configuration file, command-line options take precedence, and the globalremix --config <path>option selects a different file (see #11628, #11638, #11639). -
Added complete
createPostgresDatabase(),createMysqlDatabase(), andcreateSqliteDatabase()factories throughremix/data-table/postgres,remix/data-table/mysql, andremix/data-table/sqlite. These return theDatabaseused for queries and lifecycle operations such asmigrate(),migrationStatus(),reset(),wipe(), andclose()(see #11608, #11639).BREAKING CHANGE: Replace the removed adapter and migration-runner APIs with a concrete database and its lifecycle methods:
- import { createDatabase } from 'remix/data-table' - import { createPostgresDatabaseAdapter } from 'remix/data-table/postgres' + import { createPostgresDatabase } from 'remix/data-table/postgres' - const db = createDatabase( - createPostgresDatabaseAdapter({ connectionString: process.env.DATABASE_URL }), - ) + const db = createPostgresDatabase({ + connectionString: process.env.DATABASE_URL, + }) - await migrationRunner.migrate() + await db.migrate(migrations)
Applications should use a dialect factory; database integration packages can extend
Databasewith a composedDatabaseDriverfromremix/data-table. -
Beta.10 includes an integrated full-stack hot module replacement workflow. Run
npm run hmrin a newly generated project to reload server modules and update compatible UI components in place while preserving their state.New projects include the script and a complete
hmr.tsrunner. The core setup looks like this:{ "scripts": { "hmr": "NODE_ENV=development node hmr.ts" } }// hmr.ts (excerpt) import { run } from 'remix/node-hmr' const hmrRunner = run('server.ts', { nodeArgs: ['--import', 'remix/node-tsx', '--import', 'remix/ui-hmr/node'], browserHmrChannel: { port: 44101 }, })
remix/node-hmr,remix/ui-hmr, andremix/assetscoordinate server and browser updates through the standardimport.meta.hotAPI. Browser-reachable source is scaffolded in colocatedpublic/directories so the server/browser boundary remains explicit. -
Remix UI navigation now progressively enhances same-origin forms into frame navigations. Forms support
rmx-target,rmx-document, andrmx-history="push|replace"; resolvers receive native submission data and may return aResponse, including redirected responses whose final URL becomes the top frame's canonical location. The newrmx-preserve-domattribute protects client-owned subtrees such as custom elements during reloads, andrun()exposesapp.framesfor inspecting the current frame collection. -
run()fromremix/uinow fetches frame HTML by default, so apps no longer need a customresolveFramejust to enable frame reloads and same-origin link and form navigation:let app = run({ loadModule, - resolveFrame: (src, options) => fetch(src, { signal: options?.signal }), })Keep a custom resolver when the app needs custom request headers, body encoding, response handling, or error UI. Add
rmx-documentto a link or form to leave that navigation to the browser (see #11693). -
Allow
resolveClientEntry()inremix/uito return module preload hrefs so client entries can preload their browser module graphs. -
This beta also improves runtime reliability across the stack. UI hydration, document navigation, and frame reloads no longer stall, lose newly rendered siblings, retain stale server-rendered content, or reload the wrong top-frame URL in the fixed edge cases. Styled components adapt to dark color schemes, and server-rendered CSS safely escapes values that could close a
<style>element. Node handlers now receive nativeRequestinstances, response compression varies caches correctly byAccept-Encoding, proxied responses discard stale encoding and framing headers, and multipart parsing rejects overlong boundaries without stalling non-Node runtimes. -
Fixed fresh Remix projects failing type checking when
staticFiles()and other router middleware are used together.remix/middleware/staticcontinues to use@remix-run/static-middleware, now with the same@remix-run/fetch-routerdependency asremix/router, so package managers do not install incompatibleRequestContexttypes. -
Bumped
@remix-run/*dependencies:
ui v0.7.0
-
run()now uses a default browser frame resolver whenresolveFrameis omitted. Apps that supplied a resolver only to fetch frame HTML can remove it:let app = run({ loadModule, - resolveFrame(src, options) { - return fetch(src, { - headers: { Accept: 'text/html' }, - signal: options?.signal, - }) - }, })All
run()calls now enable frame reloads and same-origin link and form navigation through the Navigation API. The default resolver submits the requested method, encoding, and form data, and rejects non-OK responses. Keep a customresolveFramewhen the app needs custom request headers, body encoding, response handling, or error UI. Addrmx-documentto a link or form to leave that navigation to the browser (see #11693).
{ "$schema": "https://remix.run/schemas/remix.json", "test": { "type": ["server"], "concurrency": 1, "quiet": true, }, }