feat(compile): persist Web Storage/KV in a per-app data directory (#34618)
In a `deno compile`-d binary, origin-bound storage did not work. The
default `Deno.openKv()` (called without an explicit path) silently fell
back to an in-memory database, so data never survived across runs, and
both `localStorage` and the Web `caches` API threw `NotSupported`.
The root cause was in the standalone runtime (`cli/rt/run.rs`), which
built the worker factory with `StorageKeyResolver::empty()` and
`origin_data_folder_path: None`. With no storage key the worker resolves
both `origin_storage_dir` and `cache_storage_dir` to `None`; KV then
opens
an in-memory connection and the storage globals are disabled.
Rather than route this through `DENO_DIR` the way `deno run` does, this
treats a compiled binary as a standalone application. Persistent storage
now lives under the platform's app data directory (`%LOCALAPPDATA%`,
`~/Library/Application Support`, `$XDG_DATA_HOME`), reusing the same
`get_data_local_dir()` resolution already used for self-extracting
binaries, keyed by an app name. This keeps a shipped binary from writing
user data into a Deno tooling cache that may not even exist on the
target
machine.
The app name is the single source of storage identity. It is baked in at
compile time from a new `--app-name` flag, falling back to the output
file
name when the flag is omitted, so it is stable across runs and even if
the
produced binary is later renamed. Recompiling with a different
`--output`/`--app-name` starts a fresh store. Because the name (not the
main-module URL) drives the directory, two binaries compiled with the
same
`--app-name` share a store while differently named apps stay isolated,
and
the previous footgun where two binaries that merely shared an executable
file name would collide is gone. A single fixed storage key is used per
app, so each app gets one store rather than per-origin namespacing;
`--location` is no longer involved in storage. When the data directory
cannot be resolved the storage key is left empty and the previous
in-memory fallback is preserved, which also avoids unwrapping a missing
data folder path in the worker.
The app name is carried in the compile `Metadata` so the standalone
runtime can read it back; `--app-version` (#29038) is a natural next
member of this same app-identity metadata.
Spec tests under `tests/specs/compile` compile a script and exercise it
across cold processes: `kv_default_storage_path` proves a default
`Deno.openKv()` survives between runs, `local_storage_default_path` does
the same for `localStorage`, `web_cache_storage` proves `caches` is
available, and `app_name_storage` proves two binaries sharing an
`--app-name` share a store while a differently named app does not. Each
test redirects the platform app data directory into its temp dir to stay
hermetic.
Fixes #24318