@vurb/core 3.6.10 → 3.7.3
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 +195 -25
- package/dist/cli/args.d.ts +2 -1
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +5 -0
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/commands/create.d.ts.map +1 -1
- package/dist/cli/commands/create.js +46 -7
- package/dist/cli/commands/create.js.map +1 -1
- package/dist/cli/commands/deploy.d.ts.map +1 -1
- package/dist/cli/commands/deploy.js +101 -11
- package/dist/cli/commands/deploy.js.map +1 -1
- package/dist/cli/constants.d.ts +1 -0
- package/dist/cli/constants.d.ts.map +1 -1
- package/dist/cli/constants.js +2 -0
- package/dist/cli/constants.js.map +1 -1
- package/dist/cli/scaffold.d.ts.map +1 -1
- package/dist/cli/scaffold.js +69 -1
- package/dist/cli/scaffold.js.map +1 -1
- package/dist/cli/templates/cloudflare.d.ts +30 -0
- package/dist/cli/templates/cloudflare.d.ts.map +1 -0
- package/dist/cli/templates/cloudflare.js +344 -0
- package/dist/cli/templates/cloudflare.js.map +1 -0
- package/dist/cli/templates/constants.d.ts +2 -0
- package/dist/cli/templates/constants.d.ts.map +1 -1
- package/dist/cli/templates/constants.js +2 -0
- package/dist/cli/templates/constants.js.map +1 -1
- package/dist/cli/templates/index.d.ts +2 -0
- package/dist/cli/templates/index.d.ts.map +1 -1
- package/dist/cli/templates/index.js +4 -0
- package/dist/cli/templates/index.js.map +1 -1
- package/dist/cli/templates/vercel.d.ts +30 -0
- package/dist/cli/templates/vercel.d.ts.map +1 -0
- package/dist/cli/templates/vercel.js +311 -0
- package/dist/cli/templates/vercel.js.map +1 -0
- package/dist/cli/types.d.ts +4 -0
- package/dist/cli/types.d.ts.map +1 -1
- package/dist/core/builder/GroupedToolBuilder.d.ts +13 -0
- package/dist/core/builder/GroupedToolBuilder.d.ts.map +1 -1
- package/dist/core/builder/GroupedToolBuilder.js +24 -0
- package/dist/core/builder/GroupedToolBuilder.js.map +1 -1
- package/dist/core/registry/ToolRegistry.d.ts.map +1 -1
- package/dist/core/registry/ToolRegistry.js +13 -1
- package/dist/core/registry/ToolRegistry.js.map +1 -1
- package/dist/server/startServer.d.ts +32 -0
- package/dist/server/startServer.d.ts.map +1 -1
- package/dist/server/startServer.js +34 -1
- package/dist/server/startServer.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -20,6 +20,50 @@ Type-safe tools, structured AI perception, and built-in security. Deploy once
|
|
|
20
20
|
|
|
21
21
|
---
|
|
22
22
|
|
|
23
|
+
## Table of Contents
|
|
24
|
+
|
|
25
|
+
- [Zero Learning Curve — Ship a SKILL.md, Not a Tutorial](#zero-learning-curve--ship-a-skillmd-not-a-tutorial)
|
|
26
|
+
- [Get Started in 5 Seconds](#get-started-in-5-seconds)
|
|
27
|
+
- [Deploy Targets](#deploy-targets)
|
|
28
|
+
- [Why Vurb.ts Exists](#why-vurb-ts-exists)
|
|
29
|
+
- [The MVA Solution](#the-mva-solution)
|
|
30
|
+
- [Before vs. After](#before-vs-after)
|
|
31
|
+
- [Architecture](#architecture)
|
|
32
|
+
- [Egress Firewall — Schema as Security Boundary](#egress-firewall--schema-as-security-boundary)
|
|
33
|
+
- [DLP Compliance Engine — PII Redaction](#dlp-compliance-engine--pii-redaction)
|
|
34
|
+
- [8 Anti-Hallucination Mechanisms](#8-anti-hallucination-mechanisms)
|
|
35
|
+
- [FSM State Gate — Temporal Anti-Hallucination](#fsm-state-gate--temporal-anti-hallucination)
|
|
36
|
+
- [Zero-Trust Sandbox — Computation Delegation](#zero-trust-sandbox--computation-delegation)
|
|
37
|
+
- [State Sync — Temporal Awareness for Agents](#state-sync--temporal-awareness-for-agents)
|
|
38
|
+
- [Prompt Engine — Server-Side Templates](#prompt-engine--server-side-templates)
|
|
39
|
+
- [Agent Skills — Progressive Instruction Distribution](#agent-skills--progressive-instruction-distribution)
|
|
40
|
+
- [Fluent API — Semantic Verbs & Chainable Builders](#fluent-api--semantic-verbs--chainable-builders)
|
|
41
|
+
- [Middleware — Pre-Compiled, Zero-Allocation](#middleware--pre-compiled-zero-allocation)
|
|
42
|
+
- [Fluent Router — Grouped Tooling](#fluent-router--grouped-tooling)
|
|
43
|
+
- [tRPC-Style Client — Compile-Time Route Validation](#trpc-style-client--compile-time-route-validation)
|
|
44
|
+
- [Self-Healing Errors](#self-healing-errors)
|
|
45
|
+
- [Capability Governance — Cryptographic Surface Integrity](#capability-governance--cryptographic-surface-integrity)
|
|
46
|
+
- [Code Generators](#code-generators)
|
|
47
|
+
- [OpenAPI → MCP in One Command](#openapi--mcp-in-one-command)
|
|
48
|
+
- [Prisma → MCP with Field-Level Security](#prisma--mcp-with-field-level-security)
|
|
49
|
+
- [n8n Workflows → MCP Tools](#n8n-workflows--mcp-tools)
|
|
50
|
+
- [Inspector — Real-Time Dashboard](#inspector--real-time-dashboard)
|
|
51
|
+
- [Testing — Full Pipeline in RAM](#testing--full-pipeline-in-ram)
|
|
52
|
+
- [Deploy Anywhere](#deploy-anywhere)
|
|
53
|
+
- [Vinkius Edge](#vinkius-edge)
|
|
54
|
+
- [Vercel Functions](#vercel-functions)
|
|
55
|
+
- [Cloudflare Workers](#cloudflare-workers)
|
|
56
|
+
- [Ecosystem](#ecosystem)
|
|
57
|
+
- [Adapters](#adapters)
|
|
58
|
+
- [Generators & Connectors](#generators--connectors)
|
|
59
|
+
- [Security & Auth](#security--auth)
|
|
60
|
+
- [Developer Experience](#developer-experience)
|
|
61
|
+
- [Documentation](#documentation)
|
|
62
|
+
- [Contributing](#contributing)
|
|
63
|
+
- [License](#license)
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
23
67
|
## Zero Learning Curve — Ship a SKILL.md, Not a Tutorial
|
|
24
68
|
|
|
25
69
|
Every framework you've adopted followed the same loop: read the docs, study the conventions, hit an edge case, search GitHub issues, re-read the docs. Weeks before your first production PR. Your AI coding agent does the same — it hallucinates Express patterns into your Hono project because it has no formal contract to work from.
|
|
@@ -80,7 +124,7 @@ That's it. A production-ready MCP server with file-based routing, Presenters, mi
|
|
|
80
124
|
|
|
81
125
|
```
|
|
82
126
|
Project name? › my-server
|
|
83
|
-
Transport? ›
|
|
127
|
+
Transport? › http
|
|
84
128
|
Vector? › vanilla
|
|
85
129
|
|
|
86
130
|
● Scaffolding project — 14 files (6ms)
|
|
@@ -98,9 +142,32 @@ Choose a vector to scaffold exactly the project you need:
|
|
|
98
142
|
| `openapi` | OpenAPI 3.x / Swagger 2.0 → full MVA tool generation |
|
|
99
143
|
| `oauth` | RFC 8628 Device Flow authentication |
|
|
100
144
|
|
|
145
|
+
### Deploy Targets
|
|
146
|
+
|
|
147
|
+
Choose where your server runs with `--target`:
|
|
148
|
+
|
|
149
|
+
| Target | Runtime | Deploy with |
|
|
150
|
+
|---|---|---|
|
|
151
|
+
| `node` (default) | Node.js — Streamable HTTP | [`vurb deploy`](#vinkius-edge) |
|
|
152
|
+
| `vercel` | Next.js App Router — Vercel Functions | [`vercel deploy`](#vercel-functions) |
|
|
153
|
+
| `cloudflare` | Cloudflare Workers — V8 isolates | [`wrangler deploy`](#cloudflare-workers) |
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
# Node.js (default) — Streamable HTTP, deploy to Vinkius Edge
|
|
157
|
+
vurb create my-server --yes
|
|
158
|
+
|
|
159
|
+
# Vercel Functions — Next.js App Router + @vurb/vercel adapter
|
|
160
|
+
vurb create my-server --target vercel --yes
|
|
161
|
+
|
|
162
|
+
# Cloudflare Workers — wrangler + @vurb/cloudflare adapter
|
|
163
|
+
vurb create my-server --target cloudflare --yes
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Each target scaffolds the correct project structure, adapter imports, config files (`next.config.ts`, `wrangler.toml`), and deploy instructions. Same Fluent API, same Presenters, same middleware — only the transport layer changes.
|
|
167
|
+
|
|
101
168
|
```bash
|
|
102
169
|
# Database-driven server with Presenter egress firewall
|
|
103
|
-
vurb create my-api --vector prisma --transport
|
|
170
|
+
vurb create my-api --vector prisma --transport http --yes
|
|
104
171
|
|
|
105
172
|
# Bridge your n8n workflows to any MCP client
|
|
106
173
|
vurb create ops-bridge --vector n8n --yes
|
|
@@ -651,59 +718,162 @@ Assert every MVA layer: `result.data` (egress firewall), `result.systemRules` (J
|
|
|
651
718
|
|
|
652
719
|
## Deploy Anywhere
|
|
653
720
|
|
|
654
|
-
|
|
721
|
+
Same tools, same Presenters, same middleware — **zero code changes between platforms**:
|
|
722
|
+
|
|
723
|
+
```bash
|
|
724
|
+
# Vinkius Edge — zero-config managed deployment
|
|
725
|
+
vurb deploy
|
|
726
|
+
|
|
727
|
+
# Vercel Functions — Next.js App Router
|
|
728
|
+
cd my-server && vercel deploy
|
|
729
|
+
|
|
730
|
+
# Cloudflare Workers — V8 isolates, 300+ locations
|
|
731
|
+
cd my-server && wrangler deploy
|
|
732
|
+
```
|
|
733
|
+
|
|
734
|
+
Write once, deploy to any edge. Your business logic, schemas, PII redaction, FSM gates, and HATEOAS suggestions are identical across all three targets — only the transport layer changes.
|
|
735
|
+
|
|
736
|
+
### Vinkius Edge
|
|
737
|
+
|
|
738
|
+
**Zero-config managed deployment.** One command. No Dockerfile, no infra config, no CI pipeline. `vurb deploy` bundles your entire server into a **Fat Bundle** — a fully self-contained IIFE (esbuild, platform `browser`, target `es2022`, tree-shaking + minification) — compresses it with gzip, computes a SHA-256 integrity hash, and uploads to Vinkius Edge.
|
|
739
|
+
|
|
740
|
+
```bash
|
|
741
|
+
vurb deploy
|
|
742
|
+
```
|
|
743
|
+
|
|
744
|
+
```
|
|
745
|
+
● Bundle 172.3KB → 48.1KB gzip, 72% smaller
|
|
746
|
+
● Introspect 4 tools, 2 prompts, manifest signed
|
|
747
|
+
● Upload Deploying to Edge
|
|
748
|
+
|
|
749
|
+
Vinkius Edge · my-server is ready in just 2.1s
|
|
750
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
751
|
+
|
|
752
|
+
MCP Server Stateful
|
|
753
|
+
https://mcp.vinkius.com/s/my-server
|
|
754
|
+
|
|
755
|
+
TOOLS 4 tools ready
|
|
756
|
+
|
|
757
|
+
● billing.get_invoice Get an invoice by ID
|
|
758
|
+
● billing.pay Process payment
|
|
759
|
+
● users.list List all users
|
|
760
|
+
● system.health Health check
|
|
761
|
+
|
|
762
|
+
↻ 48.1KB gzip · ✓ manifest signed · SHA-256: f6e5d4...
|
|
763
|
+
```
|
|
764
|
+
|
|
765
|
+
**What happens under the hood:**
|
|
766
|
+
|
|
767
|
+
1. **Edge Stub Plugin** — a custom esbuild plugin intercepts every Node.js built-in import (`fs`, `path`, `crypto`, `node:fs/promises`, etc.) and redirects them to `edge-stub.ts`. Two tiers: **Structural stubs** (`EventEmitter`, `Readable`, `Writable`, `Server`, `Socket`) satisfy the AST so the MCP SDK compiles — never called at runtime. **Crash stubs** (`readFileSync`, `exec`, `spawn`, `createHash`) fail-fast with `[Vinkius Edge] "<api>" is blocked in the Serverless Sandbox.`
|
|
768
|
+
|
|
769
|
+
2. **Bundle Sanitizer** — static analysis transforms dangerous patterns without changing JS semantics: `eval(` → `(0,eval)(`, `new Function(` → `new(0,Function)(`, `__proto__` → `["__proto__"]`, prototype pollution vectors neutralized.
|
|
770
|
+
|
|
771
|
+
3. **Introspection** — sets `VURB_INTROSPECT=1`, imports your entrypoint, runs `compileContracts()` + `generateLockfile()` to produce a **cryptographic capability manifest**. Tool names, descriptions, and behavioral fingerprints are extracted. The lockfile ships with the bundle for runtime attestation.
|
|
772
|
+
|
|
773
|
+
4. **Upload** — base64-encoded gzip payload with SHA-256 hash, 60s timeout, server ID validation (`^[a-zA-Z0-9_-]+$` — path traversal blocked). Status-specific error handling: 401 (token revoked), 403 (wrong server), 404 (server not found), 422 (invalid payload).
|
|
774
|
+
|
|
775
|
+
**Warnings:** The CLI detects and warns about edge-incompatible patterns before bundling — `autoDiscover()` (requires `fs.readdir`), `SandboxEngine` (requires `child_process`), `Inspector` (requires Node.js IPC), `fast-redact` (uses `Function` constructor).
|
|
655
776
|
|
|
656
777
|
### Vercel Functions
|
|
657
778
|
|
|
779
|
+
**Next.js App Router + `@vurb/vercel` adapter.** Deploy to Vercel with one command:
|
|
780
|
+
|
|
781
|
+
```bash
|
|
782
|
+
vercel deploy
|
|
783
|
+
```
|
|
784
|
+
|
|
785
|
+
Same MVA structure — `models/`, `presenters/`, `tools/`, `registry.ts` — under `src/mcp/`. The only Vercel-specific file is the route handler:
|
|
786
|
+
|
|
658
787
|
```typescript
|
|
788
|
+
// app/api/mcp/route.ts
|
|
659
789
|
import { vercelAdapter } from '@vurb/vercel';
|
|
790
|
+
import { registry, contextFactory } from '@/mcp/vurb';
|
|
791
|
+
|
|
660
792
|
export const POST = vercelAdapter({ registry, contextFactory });
|
|
661
|
-
export const runtime = 'edge'; // global edge distribution
|
|
662
793
|
```
|
|
663
794
|
|
|
795
|
+
**How the adapter works:**
|
|
796
|
+
|
|
797
|
+
- **Cold start (once):** `ToolRegistry` compiles at module top-level scope — Zod reflection, Presenter compilation, schema generation. Zero CPU on warm requests.
|
|
798
|
+
- **Warm request (per invocation):** Ephemeral `McpServer` + `WebStandardStreamableHTTPServerTransport` per request. Stateless JSON-RPC only (`enableJsonResponse: true`) — no SSE, no sessions, no streaming. Pure request/response.
|
|
799
|
+
- **Context factory** receives the raw `Request` object — extract headers, auth tokens, tenant ID. Errors return JSON-RPC `-32603`.
|
|
800
|
+
- **Cleanup:** `await server.close()` in `finally` block — no resource leaks.
|
|
801
|
+
- **Method enforcement:** Non-POST returns JSON-RPC `-32600` with `405 Allow: POST`.
|
|
802
|
+
|
|
803
|
+
Works with both **Edge Runtime** (V8 isolate, global distribution) and **Node.js Runtime** (full Node.js API access). Add `export const runtime = 'edge'` for Edge. Explicit imports in the registry — no `autoDiscover()` (Vercel needs static analysis for tree-shaking).
|
|
804
|
+
|
|
664
805
|
### Cloudflare Workers
|
|
665
806
|
|
|
807
|
+
**Workers + `@vurb/cloudflare` adapter.** Deploy to Cloudflare's 300+ edge locations with one command:
|
|
808
|
+
|
|
809
|
+
```bash
|
|
810
|
+
wrangler deploy
|
|
811
|
+
```
|
|
812
|
+
|
|
813
|
+
Same MVA structure — `models/`, `presenters/`, `tools/`, `registry.ts` — under `src/`. The only Cloudflare-specific file is the worker entry:
|
|
814
|
+
|
|
666
815
|
```typescript
|
|
816
|
+
// src/worker.ts
|
|
667
817
|
import { cloudflareWorkersAdapter } from '@vurb/cloudflare';
|
|
818
|
+
import { registry, contextFactory } from './mcp/vurb.js';
|
|
819
|
+
|
|
668
820
|
export default cloudflareWorkersAdapter({ registry, contextFactory });
|
|
669
|
-
//
|
|
821
|
+
// Returns { fetch(request, env, ctx) } — Workers ES Modules interface
|
|
670
822
|
```
|
|
671
823
|
|
|
824
|
+
**How the adapter works:**
|
|
825
|
+
|
|
826
|
+
- **Same cold-start/warm-request split** as Vercel — registry compiled once, ephemeral server per request, stateless JSON-RPC via `WebStandardStreamableHTTPServerTransport`.
|
|
827
|
+
- **`env` injection:** Cloudflare bindings (D1, KV, R2, secrets) are injected per-request through the Worker `fetch(request, env, ctx)` signature. The `contextFactory` receives all three — full access to edge-native storage:
|
|
828
|
+
|
|
829
|
+
```typescript
|
|
830
|
+
contextFactory: (req, env, ctx) => ({
|
|
831
|
+
db: env.DB, // D1 — edge-native SQL
|
|
832
|
+
cache: env.CACHE, // KV — sub-ms reads
|
|
833
|
+
storage: env.BUCKET, // R2 — S3-compatible object storage
|
|
834
|
+
waitUntil: ctx.waitUntil.bind(ctx),
|
|
835
|
+
})
|
|
836
|
+
```
|
|
837
|
+
|
|
838
|
+
- **Non-blocking cleanup:** Server shutdown is deferred via `ctx.waitUntil(server.close())` — does not delay the response to the client. Both success and error paths use `waitUntil`.
|
|
839
|
+
- **Zero polyfills** — Cloudflare Workers natively support the WinterCG APIs (`Request`, `Response`, `ReadableStream`, `crypto`) that `@vurb/cloudflare` requires. No `@cloudflare/workers-types` runtime dependency — the adapter defines `ExecutionContext` inline.
|
|
840
|
+
- **Wrangler config:** `compatibility_date: '2024-12-01'`, `compatibility_flags: ['nodejs_compat']`. Commented D1/KV/R2 binding examples ready to uncomment.
|
|
841
|
+
|
|
672
842
|
---
|
|
673
843
|
|
|
674
844
|
## Ecosystem
|
|
675
845
|
|
|
676
846
|
### Adapters
|
|
677
847
|
|
|
678
|
-
| Package | Target |
|
|
679
|
-
|
|
680
|
-
| [`@vurb/vercel`](https://vurb.vinkius.com/vercel-adapter) | Vercel Functions (Edge / Node.js) |
|
|
681
|
-
| [`@vurb/cloudflare`](https://vurb.vinkius.com/cloudflare-adapter) | Cloudflare Workers — zero polyfills |
|
|
848
|
+
| Package | Name | Target |
|
|
849
|
+
|---|---|---|
|
|
850
|
+
| [`@vurb/vercel`](https://vurb.vinkius.com/vercel-adapter) | Vercel Adapter | Vercel Functions (Edge / Node.js) |
|
|
851
|
+
| [`@vurb/cloudflare`](https://vurb.vinkius.com/cloudflare-adapter) | Cloudflare Adapter | Cloudflare Workers — zero polyfills |
|
|
682
852
|
|
|
683
853
|
### Generators & Connectors
|
|
684
854
|
|
|
685
|
-
| Package | Purpose |
|
|
686
|
-
|
|
687
|
-
| [`@vurb/openapi-gen`](https://vurb.vinkius.com/openapi-gen) | Generate typed tools from OpenAPI 3.x / Swagger 2.0 specs |
|
|
688
|
-
| [`@vurb/prisma-gen`](https://vurb.vinkius.com/prisma-gen) | Generate CRUD tools with field-level security from Prisma |
|
|
689
|
-
| [`@vurb/n8n`](https://vurb.vinkius.com/n8n-connector) | Auto-discover n8n workflows as MCP tools |
|
|
690
|
-
| [`@vurb/aws`](https://vurb.vinkius.com/aws-connector) | Auto-discover AWS Lambda & Step Functions |
|
|
691
|
-
| [`@vurb/skills`](https://vurb.vinkius.com/skills) | Progressive instruction distribution for agents |
|
|
855
|
+
| Package | Name | Purpose |
|
|
856
|
+
|---|---|---|
|
|
857
|
+
| [`@vurb/openapi-gen`](https://vurb.vinkius.com/openapi-gen) | OpenAPI Generator | Generate typed tools from OpenAPI 3.x / Swagger 2.0 specs |
|
|
858
|
+
| [`@vurb/prisma-gen`](https://vurb.vinkius.com/prisma-gen) | Prisma Generator | Generate CRUD tools with field-level security from Prisma |
|
|
859
|
+
| [`@vurb/n8n`](https://vurb.vinkius.com/n8n-connector) | n8n Connector | Auto-discover n8n workflows as MCP tools |
|
|
860
|
+
| [`@vurb/aws`](https://vurb.vinkius.com/aws-connector) | AWS Connector | Auto-discover AWS Lambda & Step Functions |
|
|
861
|
+
| [`@vurb/skills`](https://vurb.vinkius.com/skills) | Agent Skills | Progressive instruction distribution for agents |
|
|
692
862
|
|
|
693
863
|
### Security & Auth
|
|
694
864
|
|
|
695
|
-
| Package | Purpose |
|
|
696
|
-
|
|
697
|
-
| [`@vurb/oauth`](https://vurb.vinkius.com/oauth) | RFC 8628 Device Flow authentication |
|
|
698
|
-
| [`@vurb/jwt`](https://vurb.vinkius.com/jwt) | JWT verification — HS256/RS256/ES256 + JWKS |
|
|
699
|
-
| [`@vurb/api-key`](https://vurb.vinkius.com/api-key) | API key validation with timing-safe comparison |
|
|
865
|
+
| Package | Name | Purpose |
|
|
866
|
+
|---|---|---|
|
|
867
|
+
| [`@vurb/oauth`](https://vurb.vinkius.com/oauth) | OAuth Provider | RFC 8628 Device Flow authentication |
|
|
868
|
+
| [`@vurb/jwt`](https://vurb.vinkius.com/jwt) | JWT Verifier | JWT verification — HS256/RS256/ES256 + JWKS |
|
|
869
|
+
| [`@vurb/api-key`](https://vurb.vinkius.com/api-key) | API Key Guard | API key validation with timing-safe comparison |
|
|
700
870
|
|
|
701
871
|
### Developer Experience
|
|
702
872
|
|
|
703
|
-
| Package | Purpose |
|
|
704
|
-
|
|
705
|
-
| [`@vurb/testing`](https://vurb.vinkius.com/testing) | In-memory pipeline testing with MVA layer assertions |
|
|
706
|
-
| [`@vurb/inspector`](https://vurb.vinkius.com/inspector) | Real-time terminal dashboard via Shadow Socket |
|
|
873
|
+
| Package | Name | Purpose |
|
|
874
|
+
|---|---|---|
|
|
875
|
+
| [`@vurb/testing`](https://vurb.vinkius.com/testing) | Testing Kit | In-memory pipeline testing with MVA layer assertions |
|
|
876
|
+
| [`@vurb/inspector`](https://vurb.vinkius.com/inspector) | Inspector | Real-time terminal dashboard via Shadow Socket |
|
|
707
877
|
|
|
708
878
|
---
|
|
709
879
|
|
package/dist/cli/args.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* CLI argument parser.
|
|
3
3
|
* @module
|
|
4
4
|
*/
|
|
5
|
-
import type { IngestionVector, TransportLayer } from './types.js';
|
|
5
|
+
import type { DeployTarget, IngestionVector, TransportLayer } from './types.js';
|
|
6
6
|
/** @internal exported for testing */
|
|
7
7
|
export interface CliArgs {
|
|
8
8
|
command: string;
|
|
@@ -14,6 +14,7 @@ export interface CliArgs {
|
|
|
14
14
|
projectName: string | undefined;
|
|
15
15
|
transport: TransportLayer | undefined;
|
|
16
16
|
vector: IngestionVector | undefined;
|
|
17
|
+
target: DeployTarget | undefined;
|
|
17
18
|
testing: boolean | undefined;
|
|
18
19
|
yes: boolean;
|
|
19
20
|
dir: string | undefined;
|
package/dist/cli/args.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"args.d.ts","sourceRoot":"","sources":["../../src/cli/args.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"args.d.ts","sourceRoot":"","sources":["../../src/cli/args.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAehF,qCAAqC;AACrC,MAAM,WAAW,OAAO;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,OAAO,CAAC;IAEd,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,SAAS,EAAE,cAAc,GAAG,SAAS,CAAC;IACtC,MAAM,EAAE,eAAe,GAAG,SAAS,CAAC;IACpC,MAAM,EAAE,YAAY,GAAG,SAAS,CAAC;IACjC,OAAO,EAAE,OAAO,GAAG,SAAS,CAAC;IAC7B,GAAG,EAAE,OAAO,CAAC;IAEb,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC;IAExB,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,aAAa,EAAE,OAAO,CAAC;IAEvB,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,UAAU,EAAE,OAAO,CAAC;CACvB;AAID,qCAAqC;AACrC,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CA0HjD"}
|
package/dist/cli/args.js
CHANGED
|
@@ -21,6 +21,7 @@ export function parseArgs(argv) {
|
|
|
21
21
|
projectName: undefined,
|
|
22
22
|
transport: undefined,
|
|
23
23
|
vector: undefined,
|
|
24
|
+
target: undefined,
|
|
24
25
|
testing: undefined,
|
|
25
26
|
yes: false,
|
|
26
27
|
dir: undefined,
|
|
@@ -78,6 +79,10 @@ export function parseArgs(argv) {
|
|
|
78
79
|
result.vector = consumeValue(args, i, arg);
|
|
79
80
|
i++;
|
|
80
81
|
break;
|
|
82
|
+
case '--target':
|
|
83
|
+
result.target = consumeValue(args, i, arg);
|
|
84
|
+
i++;
|
|
85
|
+
break;
|
|
81
86
|
case '--testing':
|
|
82
87
|
result.testing = true;
|
|
83
88
|
break;
|
package/dist/cli/args.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"args.js","sourceRoot":"","sources":["../../src/cli/args.ts"],"names":[],"mappings":"AAMA,oEAAoE;AAEpE,qFAAqF;AACrF,SAAS,YAAY,CAAC,IAAc,EAAE,CAAS,EAAE,IAAY;IACzD,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IACzB,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QAC7C,MAAM,IAAI,KAAK,CAAC,qBAAqB,IAAI,EAAE,CAAC,CAAC;IACjD,CAAC;IACD,OAAO,IAAI,CAAC;AAChB,CAAC;
|
|
1
|
+
{"version":3,"file":"args.js","sourceRoot":"","sources":["../../src/cli/args.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/create.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAKvD,OAAO,KAAK,EAAE,aAAa,
|
|
1
|
+
{"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/create.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAKvD,OAAO,KAAK,EAAE,aAAa,EAAiD,MAAM,aAAa,CAAC;AA8BhG;;;GAGG;AACH,wBAAsB,aAAa,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CA0DhF;AAID,qCAAqC;AACrC,wBAAsB,aAAa,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CA+D7F"}
|
|
@@ -7,7 +7,7 @@ import { existsSync } from 'node:fs';
|
|
|
7
7
|
import { execSync } from 'node:child_process';
|
|
8
8
|
import { createInterface } from 'node:readline';
|
|
9
9
|
import { ProgressTracker } from '../progress.js';
|
|
10
|
-
import { ansi, VALID_TRANSPORTS, VALID_VECTORS } from '../constants.js';
|
|
10
|
+
import { ansi, VALID_TRANSPORTS, VALID_VECTORS, VALID_TARGETS } from '../constants.js';
|
|
11
11
|
import { ask } from '../utils.js';
|
|
12
12
|
import { scaffold } from '../scaffold.js';
|
|
13
13
|
// ─── Validation ──────────────────────────────────────────────────
|
|
@@ -29,6 +29,15 @@ function validateVector(raw) {
|
|
|
29
29
|
process.stderr.write(` ${ansi.red('⚠')} Unknown vector "${raw}" — using ${ansi.bold('vanilla')}. Valid: ${VALID_VECTORS.join(', ')}\n`);
|
|
30
30
|
return 'vanilla';
|
|
31
31
|
}
|
|
32
|
+
/** @internal */
|
|
33
|
+
function validateTarget(raw) {
|
|
34
|
+
if (!raw)
|
|
35
|
+
return 'node';
|
|
36
|
+
if (VALID_TARGETS.includes(raw))
|
|
37
|
+
return raw;
|
|
38
|
+
process.stderr.write(` ${ansi.red('⚠')} Unknown target "${raw}" — using ${ansi.bold('node')}. Valid: ${VALID_TARGETS.join(', ')}\n`);
|
|
39
|
+
return 'node';
|
|
40
|
+
}
|
|
32
41
|
// ─── Config Collection ───────────────────────────────────────────
|
|
33
42
|
/**
|
|
34
43
|
* Collect project config — either from flags or interactive prompts.
|
|
@@ -44,11 +53,13 @@ export async function collectConfig(args) {
|
|
|
44
53
|
}
|
|
45
54
|
const transport = validateTransport(args.transport);
|
|
46
55
|
const vector = validateVector(args.vector);
|
|
56
|
+
const target = validateTarget(args.target);
|
|
47
57
|
return {
|
|
48
58
|
name,
|
|
49
59
|
transport,
|
|
50
60
|
vector,
|
|
51
61
|
testing: args.testing ?? true,
|
|
62
|
+
target,
|
|
52
63
|
};
|
|
53
64
|
}
|
|
54
65
|
// ── Interactive wizard
|
|
@@ -60,14 +71,23 @@ export async function collectConfig(args) {
|
|
|
60
71
|
process.stderr.write(` ${ansi.red('✗')} Invalid name: must start with a letter/number, end with a letter/number, and contain only lowercase letters, numbers, and hyphens.\n`);
|
|
61
72
|
return null;
|
|
62
73
|
}
|
|
63
|
-
const
|
|
64
|
-
const
|
|
74
|
+
const targetRaw = args.target ?? await ask(rl, 'Target? [node, vercel, cloudflare]', 'node');
|
|
75
|
+
const target = validateTarget(targetRaw);
|
|
76
|
+
// For vercel/cloudflare, transport is always HTTP (stateless JSON-RPC)
|
|
77
|
+
let transport;
|
|
78
|
+
if (target === 'vercel' || target === 'cloudflare') {
|
|
79
|
+
transport = 'sse';
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
const transportRaw = args.transport ?? await ask(rl, 'Transport? [stdio, sse]', 'stdio');
|
|
83
|
+
transport = validateTransport(transportRaw);
|
|
84
|
+
}
|
|
65
85
|
const vectorRaw = args.vector ?? await ask(rl, 'Vector? [vanilla, prisma, n8n, openapi, oauth]', 'vanilla');
|
|
66
86
|
const vector = validateVector(vectorRaw);
|
|
67
87
|
const testingRaw = args.testing ?? (await ask(rl, 'Include testing?', 'yes')).toLowerCase();
|
|
68
88
|
const testing = typeof testingRaw === 'boolean' ? testingRaw : testingRaw !== 'no';
|
|
69
89
|
process.stderr.write('\n');
|
|
70
|
-
return { name, transport, vector, testing };
|
|
90
|
+
return { name, transport, vector, testing, target };
|
|
71
91
|
}
|
|
72
92
|
finally {
|
|
73
93
|
rl.close();
|
|
@@ -102,7 +122,13 @@ export async function commandCreate(args, reporter) {
|
|
|
102
122
|
progress.fail('install', 'Installing dependencies', 'run npm install manually');
|
|
103
123
|
}
|
|
104
124
|
const steps = [`cd ${config.name}`];
|
|
105
|
-
if (config.
|
|
125
|
+
if (config.target === 'vercel') {
|
|
126
|
+
steps.push('npm run dev', '# MCP endpoint: POST http://localhost:3000/api/mcp', 'npx vercel deploy');
|
|
127
|
+
}
|
|
128
|
+
else if (config.target === 'cloudflare') {
|
|
129
|
+
steps.push('npm run dev', '# MCP endpoint: POST http://localhost:8787/', 'npm run deploy');
|
|
130
|
+
}
|
|
131
|
+
else if (config.transport === 'sse') {
|
|
106
132
|
steps.push('vurb dev', '# then connect Cursor or Claude to http://localhost:3001/mcp');
|
|
107
133
|
}
|
|
108
134
|
else {
|
|
@@ -110,12 +136,25 @@ export async function commandCreate(args, reporter) {
|
|
|
110
136
|
}
|
|
111
137
|
if (config.testing)
|
|
112
138
|
steps.push('npm test');
|
|
113
|
-
|
|
139
|
+
const targetLabel = config.target === 'vercel'
|
|
140
|
+
? ' (Vercel)'
|
|
141
|
+
: config.target === 'cloudflare'
|
|
142
|
+
? ' (Cloudflare)'
|
|
143
|
+
: '';
|
|
144
|
+
process.stderr.write(`\n ${ansi.green('✓')} ${ansi.bold(config.name)}${targetLabel} is ready!\n\n`);
|
|
114
145
|
process.stderr.write(` ${ansi.dim('Next steps:')}\n`);
|
|
115
146
|
for (const step of steps) {
|
|
116
147
|
process.stderr.write(` ${ansi.cyan('$')} ${step}\n`);
|
|
117
148
|
}
|
|
118
|
-
|
|
149
|
+
if (config.target === 'vercel') {
|
|
150
|
+
process.stderr.write(`\n ${ansi.dim('Deploy:')} npx vercel deploy\n`);
|
|
151
|
+
}
|
|
152
|
+
else if (config.target === 'cloudflare') {
|
|
153
|
+
process.stderr.write(`\n ${ansi.dim('Deploy:')} npx wrangler deploy\n`);
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
process.stderr.write(`\n ${ansi.dim('Cursor:')} .cursor/mcp.json is pre-configured — open in Cursor and go.\n`);
|
|
157
|
+
}
|
|
119
158
|
process.stderr.write(` ${ansi.dim('Docs:')} ${ansi.cyan('https://vurb.vinkius.com/')}\n\n`);
|
|
120
159
|
}
|
|
121
160
|
//# sourceMappingURL=create.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create.js","sourceRoot":"","sources":["../../../src/cli/commands/create.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAGhD,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,IAAI,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"create.js","sourceRoot":"","sources":["../../../src/cli/commands/create.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/deploy.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AA8F1C,wBAAsB,aAAa,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/deploy.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AA8F1C,wBAAsB,aAAa,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAkZhE"}
|
|
@@ -267,6 +267,72 @@ export async function commandDeploy(args) {
|
|
|
267
267
|
? Math.round((1 - compressed.length / rawSizeBytes) * 100)
|
|
268
268
|
: 0;
|
|
269
269
|
progress.done('compress', `Compressing (${rawKB}KB -> ${compressedKB}KB gzip, ${ratio}% smaller)`);
|
|
270
|
+
// ── Step 5b: introspect tools via real registry ──
|
|
271
|
+
// Import the entrypoint with VURB_INTROSPECT=1 so startServer() returns
|
|
272
|
+
// immediately without starting a transport. Then compile contracts and
|
|
273
|
+
// generate the lockfile manifest — the deploy's cryptographic signature.
|
|
274
|
+
progress.start('introspect', 'Introspecting tools');
|
|
275
|
+
let manifest = null;
|
|
276
|
+
let toolNames = [];
|
|
277
|
+
try {
|
|
278
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
279
|
+
const g = globalThis;
|
|
280
|
+
// Set up promise — startServer will resolve it in introspect mode
|
|
281
|
+
let resolveIntrospect;
|
|
282
|
+
const introspectReady = new Promise(resolve => {
|
|
283
|
+
resolveIntrospect = resolve;
|
|
284
|
+
});
|
|
285
|
+
g.__vurb_introspect_resolve = resolveIntrospect;
|
|
286
|
+
process.env['VURB_INTROSPECT'] = '1';
|
|
287
|
+
// Write the already-compiled esbuild bundle to a temp file and import
|
|
288
|
+
// it directly. This is pure JS — no tsx loader, no TypeScript compilation,
|
|
289
|
+
// no module resolution overhead. Near-instant evaluation.
|
|
290
|
+
const { tmpdir } = await import('node:os');
|
|
291
|
+
const { join } = await import('node:path');
|
|
292
|
+
const { writeFileSync, unlinkSync } = await import('node:fs');
|
|
293
|
+
const { pathToFileURL } = await import('node:url');
|
|
294
|
+
const tmpBundle = join(tmpdir(), `vurb-introspect-${Date.now()}.mjs`);
|
|
295
|
+
writeFileSync(tmpBundle, rawCode, 'utf-8');
|
|
296
|
+
try {
|
|
297
|
+
await import(pathToFileURL(tmpBundle).href);
|
|
298
|
+
}
|
|
299
|
+
finally {
|
|
300
|
+
try {
|
|
301
|
+
unlinkSync(tmpBundle);
|
|
302
|
+
}
|
|
303
|
+
catch { /* ignore cleanup errors */ }
|
|
304
|
+
}
|
|
305
|
+
// Wait for startServer to fire (it resolves via globalThis)
|
|
306
|
+
const result = await Promise.race([
|
|
307
|
+
introspectReady,
|
|
308
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error('startServer() was not called within 5s')), 5_000)),
|
|
309
|
+
]);
|
|
310
|
+
// Clean up
|
|
311
|
+
delete process.env['VURB_INTROSPECT'];
|
|
312
|
+
delete g.__vurb_introspect_resolve;
|
|
313
|
+
delete g.__vurb_introspect_result;
|
|
314
|
+
// Compile contracts and generate lockfile using existing introspection
|
|
315
|
+
const { compileContracts } = await import('../../introspection/ToolContract.js');
|
|
316
|
+
const { generateLockfile } = await import('../../introspection/CapabilityLockfile.js');
|
|
317
|
+
const { VURB_VERSION } = await import('../constants.js');
|
|
318
|
+
const builders = [...result.registry.getBuilders()];
|
|
319
|
+
const contracts = await compileContracts(builders);
|
|
320
|
+
const lockfile = await generateLockfile(result.serverName, contracts, VURB_VERSION);
|
|
321
|
+
manifest = lockfile;
|
|
322
|
+
// Extract tool names + descriptions for CLI display
|
|
323
|
+
const lockTools = lockfile.capabilities.tools;
|
|
324
|
+
toolNames = Object.entries(lockTools).map(([name, tool]) => ({
|
|
325
|
+
name,
|
|
326
|
+
description: tool.surface.description ?? '',
|
|
327
|
+
}));
|
|
328
|
+
progress.done('introspect', 'Introspecting tools', `${toolNames.length} tool${toolNames.length !== 1 ? 's' : ''}`);
|
|
329
|
+
}
|
|
330
|
+
catch (err) {
|
|
331
|
+
// Introspection failure is non-fatal — deploy proceeds without manifest
|
|
332
|
+
delete process.env['VURB_INTROSPECT'];
|
|
333
|
+
progress.done('introspect', 'Introspecting tools', 'skipped');
|
|
334
|
+
process.stderr.write(` ${ansi.dim(`⚠ Could not introspect: ${err instanceof Error ? err.message : String(err)}`)}\n`);
|
|
335
|
+
}
|
|
270
336
|
// ── Step 6: upload ──
|
|
271
337
|
progress.start('upload', 'Deploying to Edge');
|
|
272
338
|
// Validate serverId to prevent path-traversal attacks
|
|
@@ -289,6 +355,9 @@ export async function commandDeploy(args) {
|
|
|
289
355
|
bundle: payload,
|
|
290
356
|
hash,
|
|
291
357
|
raw_size: rawSizeBytes,
|
|
358
|
+
...(manifest ? { manifest } : {}),
|
|
359
|
+
// Also send simplified tool list for backward compat
|
|
360
|
+
tools: toolNames,
|
|
292
361
|
}),
|
|
293
362
|
signal: AbortSignal.timeout(60_000),
|
|
294
363
|
});
|
|
@@ -341,20 +410,41 @@ export async function commandDeploy(args) {
|
|
|
341
410
|
process.exit(1);
|
|
342
411
|
}
|
|
343
412
|
progress.done('upload', 'Deploying to Edge');
|
|
344
|
-
// ── Step 7:
|
|
413
|
+
// ── Step 7: Premium Output ──
|
|
345
414
|
const elapsed = ((Date.now() - deployStart) / 1000).toFixed(1);
|
|
346
|
-
process.stderr.write(
|
|
415
|
+
const w = process.stderr.write.bind(process.stderr);
|
|
416
|
+
const magenta = (s) => `\x1b[35m${s}\x1b[0m`;
|
|
417
|
+
const bgGreen = (s) => `\x1b[42m\x1b[30m${s}\x1b[0m`;
|
|
418
|
+
const bgCyan = (s) => `\x1b[46m\x1b[30m${s}\x1b[0m`;
|
|
419
|
+
const white = (s) => `\x1b[97m${s}\x1b[0m`;
|
|
420
|
+
w('\n');
|
|
421
|
+
w(` ${magenta('Vinkius Edge')} ${ansi.dim('·')} ${ansi.bold(data.server_name)} ${ansi.dim('is ready in just')} ${ansi.green(elapsed + 's')}\n`);
|
|
422
|
+
w(` ${ansi.dim('━'.repeat(56))}\n`);
|
|
423
|
+
w('\n');
|
|
424
|
+
// URL (the star of the show)
|
|
425
|
+
w(` ${ansi.dim('MCP Server Stateful')}\n`);
|
|
426
|
+
w(` ${ansi.cyan(data.url)}\n`);
|
|
427
|
+
w('\n');
|
|
428
|
+
// Tools discovered
|
|
429
|
+
if (toolNames.length > 0) {
|
|
430
|
+
w(` ${bgCyan(' TOOLS ')} ${ansi.bold(String(toolNames.length))} ${ansi.dim(toolNames.length === 1 ? 'tool ready' : 'tools ready')}\n`);
|
|
431
|
+
w('\n');
|
|
432
|
+
for (const tool of toolNames) {
|
|
433
|
+
const desc = tool.description
|
|
434
|
+
? ` ${ansi.dim(tool.description.length > 50 ? tool.description.slice(0, 50) + '…' : tool.description)}`
|
|
435
|
+
: '';
|
|
436
|
+
w(` ${ansi.green('●')} ${white(tool.name)}${desc}\n`);
|
|
437
|
+
}
|
|
438
|
+
w('\n');
|
|
439
|
+
}
|
|
440
|
+
// Bundle stats
|
|
441
|
+
w(` ${ansi.dim(`${rawKB}KB → ${compressedKB}KB gzip (${ratio}% smaller)`)}\n`);
|
|
347
442
|
if (data.status === 'restored') {
|
|
348
|
-
|
|
443
|
+
w(` ${ansi.dim('↻ instant deploy — bundle unchanged')}\n`);
|
|
349
444
|
}
|
|
350
|
-
|
|
351
|
-
|
|
445
|
+
if (manifest) {
|
|
446
|
+
w(` ${ansi.dim('✓ manifest signed')}\n`);
|
|
352
447
|
}
|
|
353
|
-
|
|
354
|
-
process.stderr.write(` ${ansi.dim('entry:')} ${entrypoint}\n`);
|
|
355
|
-
process.stderr.write(` ${ansi.dim('size:')} ${rawKB}KB -> ${compressedKB}KB gzip (${ratio}% smaller)\n`);
|
|
356
|
-
process.stderr.write(` ${ansi.dim('url:')} ${ansi.cyan(data.url)}\n`);
|
|
357
|
-
process.stderr.write(` ${ansi.dim('time:')} ${elapsed}s\n`);
|
|
358
|
-
process.stderr.write(`\n ${ansi.dim('Vurb')} ${ansi.dim('->')} ${ansi.cyan('Vinkius Edge')}\n\n`);
|
|
448
|
+
w('\n');
|
|
359
449
|
}
|
|
360
450
|
//# sourceMappingURL=deploy.js.map
|