deepspace 0.17.0 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,149 @@
1
1
  # deepspace
2
2
 
3
+ ## 0.18.0
4
+
5
+ ### Minor Changes
6
+
7
+ - **Deploy no longer reads `.dev.vars`. The secret store is the only source.**
8
+
9
+ Deploy used to compare hand-edited `.dev.vars` keys against the store and
10
+ refuse (`secrets_not_uploaded`) or warn when they differed — a guard that
11
+ inferred intent from a local file. It also broke its own escape hatch: the
12
+ refusal pointed at `secrets upload .dev.vars` while that same deploy had
13
+ already written the SDK-managed block into that file, whose keys the upload
14
+ then rejected, with no code and no action to recover from. An agent that hit
15
+ it had no way forward.
16
+
17
+ `.dev.vars` keeps its real job — deploy WRITES it so `deepspace dev` sees the
18
+ same values — and is never read back to decide anything.
19
+
20
+ **Removed:** the `--allow-missing-secrets` flag and the `secrets_not_uploaded`
21
+ refusal code, which only existed to escape that guard.
22
+
23
+ Deploy now distinguishes a missing config from an explicitly created empty
24
+ config. A missing config regenerates the local cache without app secrets and
25
+ refuses before build, Git push, or upload, with an executable
26
+ `secrets configs create` action. An existing empty config is explicit
27
+ delete-all intent. The deploy server independently preserves live bindings
28
+ when an older client omits secret authority, making the rollout safe in both
29
+ directions.
30
+
31
+ Authoritative deletion is part of release finalization, not a best-effort log.
32
+ The server retries Cloudflare reconciliation three times and retains the
33
+ per-app release fence on failure. Replaying the exact deploy retries deletion
34
+ without issuing a second Worker activation; a release is recorded only after
35
+ stale bindings, including `ALLOW_DEBUG_ROUTES`, are gone.
36
+
37
+ If the original CLI process exits after that partial result, a fresh deploy key
38
+ can resume only when the complete Worker, secret, attribution, and source
39
+ lineage hash matches the live operation. The server first proves that exact
40
+ operation is live at Cloudflare; different input stays fenced. Malformed
41
+ successful Cloudflare secret-list envelopes also fail closed.
42
+
43
+ The per-app release transaction is now reserved before route registration,
44
+ binding auto-provisioning, or rate-limit allocation. Losing concurrent deploys
45
+ therefore return without renaming the production app or creating provider
46
+ resources. An incomplete reservation cannot activate; an exact retry may
47
+ atomically take ownership and finish its resolved rollback metadata. Durable
48
+ key aliases keep displaced processes from reclaiming the operation and replay
49
+ the successor after finalization; a safe pre-activation abort removes the
50
+ aliases with the fence. A compare-and-set transition grants exactly one request
51
+ permission to issue the Worker PUT. That winner is bound to a request-scoped
52
+ claim nonce: it can clear its own committed-but-lost claim response before the
53
+ PUT begins, while an uncertain concurrent request cannot clear the winner's
54
+ activation fence.
55
+
56
+ - **`.dev.vars` is now fully generated. Hand edits do not survive.**
57
+
58
+ The file used to be three zones — an SDK section, a hand-edited section
59
+ preserved across runs, and a store cache — which required a divider grammar, a
60
+ dotenv parser to read the file back, and reconciliation between the two
61
+ sources. That made `.dev.vars` a second source of truth, and historically a
62
+ de-facto deploy input (docs/proposals/secrets-source-of-truth.md).
63
+
64
+ Now it is a materialization: rewritten whole on every `dev`, `test`, `deploy`,
65
+ and `secrets pull` run from platform values plus the app's secret store, with
66
+ a header saying so. Nothing reads it back.
67
+
68
+ **If you hand-edited `.dev.vars`, put required values in the store before
69
+ updating** (`deepspace secrets set KEY=value`). The next dev/test/pull run
70
+ overwrites the file. There is no legacy import or compatibility path; beta
71
+ consumers must update their configuration.
72
+
73
+ All Wrangler environments now share the one generated `.dev.vars`. Missing
74
+ configs materialize as empty, so a successful refresh cannot leave stale local
75
+ values behind.
76
+
77
+ Also removed: `secrets upload` no longer strips a generated block (there is no
78
+ block to strip — uploading the generated file is not a flow; use
79
+ `secrets download` for backups).
80
+
81
+ ### Patch Changes
82
+
83
+ - Remove stale lint suppressions from the Messaging and Documents feature
84
+ sources so an app containing every public feature builds without unused-rule
85
+ warnings.
86
+ - Support the maintained Node 22 (22.15+), 24, and 26 release lines. Reject
87
+ end-of-life odd-numbered releases explicitly instead of allowing installs that
88
+ can fail inside their frozen npm dependency resolver.
89
+
90
+ Because npm treats `engines` as a warning by default, `create-deepspace` also
91
+ checks the runtime before prompts, file copies, identity minting, or Git
92
+ initialization. Help and version remain available for diagnosis.
93
+
94
+ - `deepspace pull` no longer traps an agent when local work is simply unpushed.
95
+
96
+ Local-ahead — the ordinary state after `commit` — was classified as divergence.
97
+ `pull` exited 2 with `actionRequired: true` and handed back
98
+ `git merge refs/remotes/space/<branch>`, which answers "Already up to date" and
99
+ changes nothing. An agent honouring the exit-2 contract re-ran `pull` forever;
100
+ only `push` clears the state, and `push` was not the pinned action.
101
+
102
+ It is now `status: "local_ahead"` on a successful (exit 0) pull. Human output
103
+ names `deepspace push`, and JSON carries that same targeted push as its
104
+ executable success action. `deepspace status` has always classified this
105
+ correctly — the two now agree.
106
+
107
+ - Typo'd flags are now refused instead of silently ignored.
108
+
109
+ citty hardcodes its parser to `strict: false`, so an unknown flag was never
110
+ rejected — it was dropped and the command ran with the caller's intent
111
+ discarded. `deepspace releases --limitt 1` swallowed the flag _and_ its value
112
+ and returned every release with exit 0; `--jsonn` printed human prose to stdout
113
+ while the caller waited for JSON. Unknown subcommands and bad flag _values_
114
+ were already rejected; only flag names went unchecked.
115
+
116
+ One check at the shared command boundary now rejects them with
117
+ `code: "unknown_option"` before any side effect, naming the options that verb
118
+ accepts. Aliases, hyphenated names, and `--no-<flag>` are unaffected.
119
+
120
+ - Collaborative apps no longer show stale data as live when the connection dies
121
+ quietly.
122
+
123
+ A peer that stops answering without closing leaves the socket ESTABLISHED — no
124
+ packets are lost, so nothing retransmits, so no close event ever arrives.
125
+ Measured against a peer frozen mid-conversation, an unprobed connection stayed
126
+ open indefinitely. That is a hung Durable Object, a broken relay, or a
127
+ blackholed path; the browser's `offline` event fires for none of them, because
128
+ the machine's own network is fine.
129
+
130
+ Everything downstream already handled this correctly and was simply never
131
+ called: `useRecordContext().status` flips to `'disconnected'`, every live query
132
+ resets to loading while keeping its records on screen, and the socket
133
+ reconnects with backoff. The client now probes a connection once it has gone
134
+ quiet and closes it after 45s of silence, so those run when they should.
135
+
136
+ The probe costs nothing on the server: `BaseRoom` already registers a
137
+ `WebSocketRequestResponsePair('ping','pong')`, so the Cloudflare runtime
138
+ answers it while the Durable Object stays hibernated. An app already receiving
139
+ updates is never probed. Liveness is probe-based: a quiet socket sends a ping
140
+ after 15 seconds and closes only when that outstanding probe receives no
141
+ inbound answer for a further 30 seconds. A backgrounded timer's first resumed
142
+ callback therefore probes instead of falsely disconnecting a healthy socket.
143
+ If suspension occurs after a ping was sent, the first delayed callback also
144
+ discards that pre-suspension judgment and sends a fresh probe before applying
145
+ the normal deadline.
146
+
3
147
  ## 0.17.0
4
148
 
5
149
  ### Minor Changes
@@ -122,7 +266,7 @@ worktree remove` or a failed cleanup deleted.
122
266
 
123
267
  ### Minor Changes
124
268
 
125
- - **`deepspace app migrate` is removed**, replaced by `deepspace app update` (below). It existed for one historical cutover — moving an app from a name-shaped id to a canonical one — and the platform endpoints behind it are unchanged, so an app still on a legacy id migrates with `npx deepspace@0.13.0 app migrate` and then upgrades normally.
269
+ - **`deepspace app migrate` is removed**, replaced by `deepspace app update` (below). It existed for one historical cutover — moving an app from a name-shaped id to a canonical one. The platform migration endpoints were subsequently removed too; an unexpected legacy-id app now requires operator-owned recovery. Do not downgrade to run the old command.
126
270
 
127
271
  A file that no longer exists now answers `404`, not the app's HTML. Deploys configured the asset layer with `not_found_handling: "single-page-application"`, so it answered EVERY unmatched path with `index.html` at 200 — correct for a client route, wrong for a file. A deploy replaces the hashed build chunks, so a tab still holding the previous `index.html` requested one and got HTML where JavaScript belonged: the script tag parsed it, failed, and the page went white with no error in any log, monitor, or network panel. The same answer went to agents probing `/llms.txt` and `/.well-known/mcp`, telling them the app publishes a manifest it does not have.
128
272
 
package/README.md CHANGED
@@ -6,7 +6,8 @@
6
6
 
7
7
  The DeepSpace SDK — build real-time collaborative apps on Cloudflare Workers.
8
8
  Bundles auth, real-time data subscriptions, RBAC, messaging, file storage,
9
- collaborative editing (Yjs), and zero-config deployment behind four imports.
9
+ collaborative editing (Yjs), and zero-config deployment through focused public
10
+ entry points.
10
11
 
11
12
  The fastest way to start is to scaffold a full app rather than wire the SDK up
12
13
  by hand:
@@ -27,15 +28,18 @@ npm install deepspace
27
28
 
28
29
  ## Entry points
29
30
 
30
- The package has four supported import paths:
31
+ The package has seven supported import paths:
31
32
 
32
33
  - **`deepspace`** — the React client SDK (hooks, providers, auth, storage,
33
34
  messaging, theme). Runs in the browser.
35
+ - **`deepspace/schema`** — schema builders and shared schema types.
34
36
  - **`deepspace/worker`** — the Cloudflare Worker runtime (`RecordRoom`, schemas,
35
37
  JWT verification, HMAC auth). Runs in your app's Worker.
36
38
  - **`deepspace/server`** — app-server helpers for actions, billing, and room
37
39
  handlers.
38
40
  - **`deepspace/testing`** — Playwright fixtures for multi-user tests.
41
+ - **`deepspace/documentation`** — documentation compiler and runtime helpers.
42
+ - **`deepspace/documentation/react`** — documentation React components.
39
43
 
40
44
  ## Minimal usage
41
45
 
@@ -89,11 +93,10 @@ npx deepspace dev start # run locally
89
93
  npx deepspace deploy # deploy to *.app.space
90
94
  ```
91
95
 
92
- The [normative CLI hierarchy](../../docs/platform/cli-contract.md#public-command-hierarchy)
93
- keeps durable app lifecycle and version migrations under `deepspace app`,
94
- while checkout-oriented Git, workspace, release, and deploy operations stay
95
- top-level. In particular, app migration is
96
- `deepspace app migrate`; there is no top-level `deepspace migrate` alias.
96
+ The hierarchy shown by `deepspace --help` keeps durable app lifecycle under
97
+ `deepspace app`, while checkout-oriented Git, workspace, release, and deploy
98
+ operations stay top-level. The historical `deepspace app migrate` command was
99
+ removed in 0.15.0; it is not an upgrade or recovery path.
97
100
 
98
101
  Every app has one authoritative Git repository. DeepSpace source is the packaged
99
102
  default: the first normal deploy claims it and publishes automatically.
@@ -114,40 +117,14 @@ DeepSpace verifies GitHub but never writes it. Inspect or transfer authority wit
114
117
  `deepspace app source`, `deepspace app source github`, or
115
118
  `deepspace app source deepspace`. Transfers mirror branches and tags before one
116
119
  atomic authority change; switching back uses the same commands. Commands support
117
- `--json` for agents. See the
118
- [repository guide](https://github.com/deepdotspace/deepspace/blob/main/docs/platform/repo-store-git.md)
119
- for workspaces, releases, and rollback.
120
-
121
- `deepspace app migrate` is the permanent upgrade runner for breaking app
122
- changes. It contains an ordered set of structural, idempotent migrations, so
123
- agents and developers keep using the same command across releases:
124
-
125
- ```bash
126
- npx deepspace app migrate --dry-run
127
- npx deepspace app migrate
128
- ```
129
-
130
- The dry-run lists pending source migrations without changing files. For a
131
- legacy GitHub app whose `DEEPSPACE_APP_ID` is still name-shaped, it also lists
132
- the exact registry rows that will be re-keyed and the physical stores that
133
- remain at the existing resource id. The command applies only transformations
134
- it recognizes safely, pauses for normal commit/push, and finishes with one
135
- deploy. Applied steps live in the checked-in `deepspace.migrations.json`
136
- manifest. Normal deploy bundles record that manifest in the release, so the
137
- next run can determine whether the migration is live without depending on Git
138
- commit lineage. Rerun after each returned action; when nothing is pending it
139
- reports `up_to_date`. This is the same workflow for GitHub and DeepSpace
140
- source; only their normal push behavior differs. `APP_NAME`-based
141
- legacy room and storage addresses are retained; canonical `DEEPSPACE_APP_ID`
142
- is used only for logical identity and platform authentication.
143
-
144
- Keep deploy, release rollback, and undeploy idle from the mutating command until
145
- that returned deploy begins; normal app traffic continues throughout.
146
- Before the registry cutover commits, `--cancel` reverses a prepared migration
147
- after the restored legacy configuration is committed and pushed. After the
148
- cutover, recovery is deliberately forward-only: deploy the canonical app and
149
- rerun `deepspace app migrate` to verify the live release. DeepSpace never
150
- writes the GitHub repository.
120
+ `--json` for agents. Use `deepspace --help`, command-specific `--help`, and the
121
+ [public manual](https://documentation.deep.space) for workspaces, releases, and
122
+ rollback.
123
+
124
+ Use the current command-specific release notes for supported upgrade steps. If
125
+ an app or checkout still carries a name-shaped legacy id, stop and contact the
126
+ DeepSpace operator; do not downgrade the SDK or run migration commands copied
127
+ from historical changelogs and proposals.
151
128
 
152
129
  ## Debugging
153
130