nestjs-web-repl 2.1.0 → 2.1.1
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/README.md +32 -94
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -26,6 +26,10 @@ running server.
|
|
|
26
26
|
npm install nestjs-web-repl
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
+
> **Upgrading from 1.x?** The `forRoot`/`forRootAsync` API is deprecated. v2 uses
|
|
30
|
+
> `register`/`registerAsync` — see [Quick start](#quick-start) and
|
|
31
|
+
> [Securing it](#securing-it).
|
|
32
|
+
|
|
29
33
|
## Quick start
|
|
30
34
|
|
|
31
35
|
```ts
|
|
@@ -157,6 +161,22 @@ WebReplModule.registerAsync({
|
|
|
157
161
|
});
|
|
158
162
|
```
|
|
159
163
|
|
|
164
|
+
### How the browser UI authenticates
|
|
165
|
+
|
|
166
|
+
Your guard runs in front of all three routes — the UI page, the SSE stream, and
|
|
167
|
+
the command POST. The bundled UI sends only what a browser attaches
|
|
168
|
+
automatically on a **same-origin** request: **cookies**. It sets no
|
|
169
|
+
`Authorization` header, and the SSE stream uses `EventSource`, which cannot send
|
|
170
|
+
custom headers at all. So protect these routes with **cookie/session** auth (or a
|
|
171
|
+
network-level control such as an IP allowlist, mTLS, or a VPN). A
|
|
172
|
+
bearer-token / `Authorization`-header guard rejects the UI — it still works for
|
|
173
|
+
direct `curl` clients, where you set the header yourself, but the browser cannot.
|
|
174
|
+
|
|
175
|
+
The UI is served from the same origin it calls, so a logged-in session cookie
|
|
176
|
+
rides along on the page load, the SSE connection, and every command. One caveat:
|
|
177
|
+
the UI sends no CSRF token, so authenticate off the session itself rather than
|
|
178
|
+
requiring a CSRF token on these routes.
|
|
179
|
+
|
|
160
180
|
## Adapter / multi-instance
|
|
161
181
|
|
|
162
182
|
If you run more than one instance of your app (multiple processes, pods,
|
|
@@ -188,10 +208,10 @@ solves this with an **ownership + fan-out** protocol:
|
|
|
188
208
|
never preempted this way. Takeover loses that channel's in-memory
|
|
189
209
|
variables (the dead owner's session is gone) but restores availability
|
|
190
210
|
instead of leaving the channel wedged fleet-wide (see
|
|
191
|
-
[Limitations](#limitations
|
|
211
|
+
[Limitations](#limitations)).
|
|
192
212
|
- Because ownership is decided by whichever instance's `onCmd` handler runs
|
|
193
213
|
first, two instances racing to claim the same brand-new channel at the
|
|
194
|
-
same instant resolve **last-claim-wins** (see [Limitations](#limitations
|
|
214
|
+
same instant resolve **last-claim-wins** (see [Limitations](#limitations)).
|
|
195
215
|
|
|
196
216
|
By default this coordination happens via `InMemoryWebReplAdapter`, which only
|
|
197
217
|
works within a single process (fine for local dev / single-instance
|
|
@@ -299,27 +319,6 @@ and `WEB_REPL_OPTIONS` (the DI token for the resolved options, useful when
|
|
|
299
319
|
injecting them into a sibling-registered controller subclass), plus the types
|
|
300
320
|
`WebReplAdapter`, `WebReplModuleOptions`, `WebReplModuleExtras`,
|
|
301
321
|
`WebReplAdapterConfig`, `WebReplEvent`, `SseEventType`.
|
|
302
|
-
|
|
303
|
-
## Migrating from 1.x → 2.0
|
|
304
|
-
|
|
305
|
-
- `WebReplModule.forRoot(...)` → `WebReplModule.register(...)`.
|
|
306
|
-
- `WebReplModule.forRootAsync(...)` → `WebReplModule.registerAsync(...)`.
|
|
307
|
-
- `adapter` is no longer an option resolved by `useFactory`; it's a static
|
|
308
|
-
"extra" passed alongside the options (or alongside `useFactory`/`inject` for
|
|
309
|
-
the async form), and now also accepts `{ useClass, imports? }` or
|
|
310
|
-
`{ useFactory, inject?, imports? }` in addition to a ready instance — see
|
|
311
|
-
[Adapter / multi-instance](#adapter--multi-instance).
|
|
312
|
-
- `registerController: false` is gone. To run your own guarded controller
|
|
313
|
-
instead of the default, subclass `WebReplController`, add `@UseGuards(...)`,
|
|
314
|
-
and pass it as the `controller` extra to `register`/`registerAsync` — see
|
|
315
|
-
[Securing it](#securing-it). Unlike the old `registerController` flag, this
|
|
316
|
-
works identically for both the sync and async form.
|
|
317
|
-
- A disabled module (`enabled: false`) now still registers the
|
|
318
|
-
controller/service, but every route 404s and the module never subscribes to
|
|
319
|
-
the adapter — it no longer silently registers nothing. If you were relying
|
|
320
|
-
on a disabled module contributing zero routes/providers to the Nest module
|
|
321
|
-
graph, that is no longer the case.
|
|
322
|
-
|
|
323
322
|
## AI skill
|
|
324
323
|
|
|
325
324
|
This package ships a [Claude Code](https://claude.com/claude-code) skill that
|
|
@@ -335,7 +334,7 @@ agent picks it up on its next session. The command never clobbers a modified
|
|
|
335
334
|
skill file silently — if you have edited it, re-run with `--force` to refresh it
|
|
336
335
|
after upgrading the package.
|
|
337
336
|
|
|
338
|
-
## Limitations
|
|
337
|
+
## Limitations
|
|
339
338
|
|
|
340
339
|
- **Monaco loads from a CDN** (`cdn.jsdelivr.net`) inside the `/ui` page — the
|
|
341
340
|
*browser* needs internet access to load the editor; the server side has no
|
|
@@ -383,11 +382,10 @@ We tell you this because the honest thing to do is let you judge the code on
|
|
|
383
382
|
its merits rather than guess at its origins. If you are skeptical of AI-written
|
|
384
383
|
code, here is what to actually look at:
|
|
385
384
|
|
|
386
|
-
- **The tests.**
|
|
387
|
-
that proves cross-instance command routing and output fan-out, and an
|
|
385
|
+
- **The tests.** A thorough automated suite, including a two-instance end-to-end
|
|
386
|
+
test that proves cross-instance command routing and output fan-out, and an
|
|
388
387
|
execution-proof test that resolves a real provider through the live REPL
|
|
389
|
-
context. `npm test`, `npm run build`, and
|
|
390
|
-
--noEmit` are all green.
|
|
388
|
+
context. `npm test`, `npm run build`, and the typecheck all run green in CI.
|
|
391
389
|
- **The commit history.** The real TDD trail is preserved — failing test,
|
|
392
390
|
implementation, fixes — including several rounds where review caught genuine
|
|
393
391
|
defects (the trickiest: `node:repl` completion detection on modern Node, and
|
|
@@ -399,72 +397,6 @@ code, here is what to actually look at:
|
|
|
399
397
|
|
|
400
398
|
AI assistance does not exempt the code from scrutiny — it raises the bar for
|
|
401
399
|
it. Issues and fixes are welcome from anyone who finds something we missed.
|
|
402
|
-
|
|
403
|
-
## AI usage & training
|
|
404
|
-
|
|
405
|
-
The source here is published so people and their tools can **use** it — read
|
|
406
|
-
it, run it, debug against it, integrate it. It is not offered as training data.
|
|
407
|
-
[`robots.txt`](./robots.txt) and [`ai.txt`](./ai.txt) record a request that AI
|
|
408
|
-
model *training* crawlers (GPTBot, ClaudeBot, CCBot, Google-Extended, and
|
|
409
|
-
others) not ingest this repository. Those files are advisory — they express
|
|
410
|
-
intent and do not, and cannot, technically enforce anything, nor do they bind
|
|
411
|
-
GitHub's own hosting. Using an AI coding assistant to help you *work with* this
|
|
412
|
-
library is entirely fine and expected.
|
|
413
|
-
|
|
414
|
-
## Releasing
|
|
415
|
-
|
|
416
|
-
Releases are **fully automated**. Merging a PR to `main` with releasable
|
|
417
|
-
[Conventional Commits](https://www.conventionalcommits.org/) triggers
|
|
418
|
-
`.github/workflows/release.yml`, which runs the full test suite and then
|
|
419
|
-
[semantic-release](https://semantic-release.gitbook.io/):
|
|
420
|
-
|
|
421
|
-
| Commit type | Version bump |
|
|
422
|
-
| ---------------------- | ----------------- |
|
|
423
|
-
| `fix:` | patch (x.y.**z**) |
|
|
424
|
-
| `feat:` | minor (x.**y**.0) |
|
|
425
|
-
| `feat!:` / `BREAKING CHANGE:` in body | major (**x**.0.0) |
|
|
426
|
-
| `docs:` `chore:` `test:` `ci:` `refactor:` | no release |
|
|
427
|
-
|
|
428
|
-
It computes the next version, updates `CHANGELOG.md`, publishes to npm
|
|
429
|
-
(**tokenless via OIDC trusted publishing, with provenance attached
|
|
430
|
-
automatically**), tags the commit, cuts a GitHub Release, and commits the
|
|
431
|
-
version/changelog bump back to `main` as `chore(release): x.y.z [skip ci]`.
|
|
432
|
-
Do not bump `version` in `package.json` by hand.
|
|
433
|
-
|
|
434
|
-
### One-time bootstrap (maintainer, once)
|
|
435
|
-
|
|
436
|
-
npm's OIDC trusted publishing cannot perform a package's *first* publish, so a
|
|
437
|
-
maintainer does this once:
|
|
438
|
-
|
|
439
|
-
1. **Create the package on npm with a placeholder:**
|
|
440
|
-
```bash
|
|
441
|
-
npm login
|
|
442
|
-
npm version 0.0.0 --no-git-tag-version # temp, do not commit
|
|
443
|
-
npm publish --access public
|
|
444
|
-
git checkout -- package.json # restore working version
|
|
445
|
-
```
|
|
446
|
-
Do **not** create a git tag for `0.0.0`; with no tags semantic-release's
|
|
447
|
-
first automated release is `1.0.0`.
|
|
448
|
-
2. **Register the Trusted Publisher** at
|
|
449
|
-
`https://www.npmjs.com/package/nestjs-web-repl/access` → *Trusted Publishers*
|
|
450
|
-
→ GitHub Actions: owner `p-dim-popov`, repository `nestjs-web-repl`, workflow
|
|
451
|
-
`release.yml` (leave environment blank). After this, no token is needed.
|
|
452
|
-
3. (Optional, after `1.0.0` ships) `npm deprecate nestjs-web-repl@0.0.0 "placeholder"`.
|
|
453
|
-
|
|
454
|
-
### Verifying the first real release
|
|
455
|
-
|
|
456
|
-
After the bootstrap, the next merge to `main` containing a `feat:`/`fix:` commit
|
|
457
|
-
should produce `1.0.0`. Confirm:
|
|
458
|
-
|
|
459
|
-
- `npm view nestjs-web-repl version` → `1.0.0`
|
|
460
|
-
- the npm package page shows a provenance / "Published via GitHub Actions" badge
|
|
461
|
-
- a `v1.0.0` git tag and a matching GitHub Release with generated notes exist
|
|
462
|
-
- `CHANGELOG.md` and a `chore(release): 1.0.0` commit are on `main`
|
|
463
|
-
- the `release.yml` run is green
|
|
464
|
-
|
|
465
|
-
If the publish step fails with an auth error, the Trusted Publisher registration
|
|
466
|
-
(step 2) is missing or its repo/workflow fields don't match exactly.
|
|
467
|
-
|
|
468
400
|
## Contributing
|
|
469
401
|
|
|
470
402
|
Contributions are welcome — see [`CONTRIBUTING.md`](./CONTRIBUTING.md). AI-
|
|
@@ -472,6 +404,12 @@ assisted PRs are fine; we just ask you to disclose the assistance and to
|
|
|
472
404
|
understand what you submit. Agents working in this repo should start with
|
|
473
405
|
[`AGENTS.md`](./AGENTS.md).
|
|
474
406
|
|
|
407
|
+
PRs merge as a single squash commit whose message is the **PR title and
|
|
408
|
+
description**, and that commit drives an automated release. Write the PR title as
|
|
409
|
+
a [Conventional Commit](https://www.conventionalcommits.org/) (`feat:`, `fix:`,
|
|
410
|
+
`docs:`, …) so the version bump is correct; put any `BREAKING CHANGE:` note in the
|
|
411
|
+
description.
|
|
412
|
+
|
|
475
413
|
## License
|
|
476
414
|
|
|
477
415
|
[MIT](./LICENSE) © Petar Popov
|