@_davideast/stitch-mcp 0.1.1 → 0.1.2
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 +79 -89
- package/dist/cli.js +130 -3
- package/dist/ui/serve-behaviors/handlers.d.ts +9 -0
- package/dist/ui/serve-behaviors/index.d.ts +7 -0
- package/dist/ui/serve-behaviors/registry.d.ts +10 -0
- package/dist/ui/serve-behaviors/server.d.ts +8 -0
- package/dist/ui/serve-behaviors/types.d.ts +18 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -19,58 +19,14 @@ This single command will:
|
|
|
19
19
|
6. Enable Stitch API
|
|
20
20
|
7. Generate MCP configuration for your client
|
|
21
21
|
|
|
22
|
-
**Example session:**
|
|
23
|
-
```
|
|
24
|
-
Stitch MCP Setup
|
|
25
|
-
|
|
26
|
-
Step 1: Select your MCP client
|
|
27
|
-
✔ Which MCP client are you using? Antigravity
|
|
28
|
-
|
|
29
|
-
Step 2: Setting up Google Cloud CLI
|
|
30
|
-
✔ Google Cloud CLI ready (bundled): v552.0.0
|
|
31
|
-
|
|
32
|
-
Step 3: Setup Authentication
|
|
33
|
-
✔ Check your current setup status? Yes
|
|
34
|
-
|
|
35
|
-
Authenticate with Google Cloud
|
|
36
|
-
|
|
37
|
-
CLOUDSDK_CONFIG="~/.stitch-mcp/config" gcloud auth login
|
|
38
|
-
|
|
39
|
-
(copied to clipboard)
|
|
40
|
-
✔ Press Enter when complete Yes
|
|
41
|
-
✔ Logged in as you@gmail.com
|
|
42
|
-
|
|
43
|
-
Authorize Application Default Credentials
|
|
44
|
-
|
|
45
|
-
CLOUDSDK_CONFIG="~/.stitch-mcp/config" gcloud auth application-default login
|
|
46
|
-
|
|
47
|
-
(copied to clipboard)
|
|
48
|
-
✔ Press Enter when complete Yes
|
|
49
|
-
✔ ADC configured
|
|
50
|
-
|
|
51
|
-
Step 4: Select a Google Cloud project
|
|
52
|
-
✔ Select a project: My Project (my-project-id)
|
|
53
|
-
|
|
54
|
-
Step 5: Configure IAM Permissions
|
|
55
|
-
✔ Required IAM role is already configured.
|
|
56
|
-
|
|
57
|
-
Step 6: Generating MCP Configuration
|
|
58
|
-
✔ Configuration generated
|
|
59
|
-
|
|
60
|
-
Setup Complete! ✔
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
**How it works:** Commands are displayed and automatically copied to your clipboard. Run the command in your terminal, complete the OAuth flow in your browser, then press Enter to continue.
|
|
64
|
-
|
|
65
22
|
**Example output:**
|
|
66
23
|
```json
|
|
67
24
|
{
|
|
68
25
|
"mcpServers": {
|
|
69
26
|
"stitch": {
|
|
70
|
-
"
|
|
71
|
-
"
|
|
72
|
-
|
|
73
|
-
"STITCH_PROJECT_ID": "your-project-id"
|
|
27
|
+
"serverUrl": "https://stitch.googleapis.com/mcp",
|
|
28
|
+
"headers": {
|
|
29
|
+
"X-Goog-Api-Key": "YOUR-API-KEY"
|
|
74
30
|
}
|
|
75
31
|
}
|
|
76
32
|
}
|
|
@@ -79,46 +35,6 @@ Setup Complete! ✔
|
|
|
79
35
|
|
|
80
36
|
Copy this config into your MCP client settings and you're ready to use the Stitch MCP server.
|
|
81
37
|
|
|
82
|
-
## Quick Start (Existing gcloud Users)
|
|
83
|
-
|
|
84
|
-
If you already have `gcloud` configured, skip `init` and use the proxy directly.
|
|
85
|
-
|
|
86
|
-
**Prerequisites:**
|
|
87
|
-
```bash
|
|
88
|
-
# 1. Application Default Credentials
|
|
89
|
-
gcloud auth application-default login
|
|
90
|
-
|
|
91
|
-
# 2. Set project (if not already set)
|
|
92
|
-
gcloud config set project <PROJECT_ID>
|
|
93
|
-
|
|
94
|
-
# 3. Enable Stitch API (requires beta component)
|
|
95
|
-
gcloud components install beta
|
|
96
|
-
gcloud beta services mcp enable stitch.googleapis.com --project=<PROJECT_ID>
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
**MCP Configuration:**
|
|
100
|
-
```json
|
|
101
|
-
{
|
|
102
|
-
"mcpServers": {
|
|
103
|
-
"stitch": {
|
|
104
|
-
"command": "npx",
|
|
105
|
-
"args": ["@_davideast/stitch-mcp", "proxy"],
|
|
106
|
-
"env": {
|
|
107
|
-
"STITCH_USE_SYSTEM_GCLOUD": "1"
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
**Environment Variables:**
|
|
115
|
-
| Variable | Description |
|
|
116
|
-
|----------|-------------|
|
|
117
|
-
| `STITCH_USE_SYSTEM_GCLOUD` | Use system gcloud config instead of isolated config |
|
|
118
|
-
| `STITCH_PROJECT_ID` | Override project ID |
|
|
119
|
-
| `GOOGLE_CLOUD_PROJECT` | Alternative project ID variable |
|
|
120
|
-
| `STITCH_HOST` | Custom Stitch API endpoint |
|
|
121
|
-
|
|
122
38
|
## Verify Your Setup
|
|
123
39
|
|
|
124
40
|
```bash
|
|
@@ -217,7 +133,7 @@ Revokes both user authentication and Application Default Credentials. Useful for
|
|
|
217
133
|
- Clearing authentication for testing
|
|
218
134
|
- Resetting state when troubleshooting
|
|
219
135
|
|
|
220
|
-
#### `view` -
|
|
136
|
+
#### `view` - Interactive Resource Viewer
|
|
221
137
|
|
|
222
138
|
```bash
|
|
223
139
|
npx @_davideast/stitch-mcp view [options]
|
|
@@ -230,7 +146,41 @@ npx @_davideast/stitch-mcp view [options]
|
|
|
230
146
|
- `--project <id>` - Project ID
|
|
231
147
|
- `--screen <id>` - Screen ID
|
|
232
148
|
|
|
233
|
-
Interactively
|
|
149
|
+
Interactively browse Stitch resources in a navigable JSON tree. Supports drilling into nested objects and performing actions on selected nodes.
|
|
150
|
+
|
|
151
|
+
**Keyboard Shortcuts:**
|
|
152
|
+
|
|
153
|
+
| Key | Action |
|
|
154
|
+
|-----|--------|
|
|
155
|
+
| `↑` / `↓` | Navigate up/down |
|
|
156
|
+
| `Enter` | Expand/collapse or drill into nested object |
|
|
157
|
+
| `Backspace` | Go back one level |
|
|
158
|
+
| `c` | Copy selected value to clipboard |
|
|
159
|
+
| `cc` | Extended copy (downloads content for URLs) |
|
|
160
|
+
| `s` | **Preview HTML** - serves `htmlCode` in-memory and opens browser |
|
|
161
|
+
| `o` | Open project in Stitch web app |
|
|
162
|
+
| `q` | Quit viewer |
|
|
163
|
+
|
|
164
|
+
**HTML Preview Feature:**
|
|
165
|
+
|
|
166
|
+
When viewing a screen, select the `htmlCode` node and press `s` to:
|
|
167
|
+
1. Download the HTML code from Stitch
|
|
168
|
+
2. Start a local server (auto-closes after 5 minutes)
|
|
169
|
+
3. Open your browser to preview the rendered HTML
|
|
170
|
+
|
|
171
|
+
```
|
|
172
|
+
Selected Path: screen.htmlCode | 'c' copy, 'cc' extended, 's' preview
|
|
173
|
+
🌐 Preview at http://127.0.0.1:54268 (auto-closes in 5 min)
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
**Example Usage:**
|
|
177
|
+
```bash
|
|
178
|
+
# Browse all projects
|
|
179
|
+
npx @_davideast/stitch-mcp view --projects
|
|
180
|
+
|
|
181
|
+
# View a specific screen
|
|
182
|
+
npx @_davideast/stitch-mcp view --project <project-id> --screen <screen-id>
|
|
183
|
+
```
|
|
234
184
|
|
|
235
185
|
#### `proxy` - MCP Proxy Server
|
|
236
186
|
|
|
@@ -249,6 +199,46 @@ This command is typically configured as the entry point in your MCP client setti
|
|
|
249
199
|
- Error handling
|
|
250
200
|
- Debug logging (when `--debug` is enabled to `/tmp/stitch-proxy-debug.log`)
|
|
251
201
|
|
|
202
|
+
## OAuth setup with gcloud
|
|
203
|
+
|
|
204
|
+
If you already have `gcloud` configured, skip `init` and use the proxy directly.
|
|
205
|
+
|
|
206
|
+
**Prerequisites:**
|
|
207
|
+
```bash
|
|
208
|
+
# 1. Application Default Credentials
|
|
209
|
+
gcloud auth application-default login
|
|
210
|
+
|
|
211
|
+
# 2. Set project (if not already set)
|
|
212
|
+
gcloud config set project <PROJECT_ID>
|
|
213
|
+
|
|
214
|
+
# 3. Enable Stitch API (requires beta component)
|
|
215
|
+
gcloud components install beta
|
|
216
|
+
gcloud beta services mcp enable stitch.googleapis.com --project=<PROJECT_ID>
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
**MCP Configuration:**
|
|
220
|
+
```json
|
|
221
|
+
{
|
|
222
|
+
"mcpServers": {
|
|
223
|
+
"stitch": {
|
|
224
|
+
"command": "npx",
|
|
225
|
+
"args": ["@_davideast/stitch-mcp", "proxy"],
|
|
226
|
+
"env": {
|
|
227
|
+
"STITCH_USE_SYSTEM_GCLOUD": "1"
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
**Environment Variables:**
|
|
235
|
+
| Variable | Description |
|
|
236
|
+
|----------|-------------|
|
|
237
|
+
| `STITCH_USE_SYSTEM_GCLOUD` | Use system gcloud config instead of isolated config |
|
|
238
|
+
| `STITCH_PROJECT_ID` | Override project ID |
|
|
239
|
+
| `GOOGLE_CLOUD_PROJECT` | Alternative project ID variable |
|
|
240
|
+
| `STITCH_HOST` | Custom Stitch API endpoint |
|
|
241
|
+
|
|
252
242
|
### How It Works
|
|
253
243
|
|
|
254
244
|
#### Automatic gcloud Management
|
package/dist/cli.js
CHANGED
|
@@ -72336,6 +72336,106 @@ var init_navigation_behaviors = __esm(() => {
|
|
|
72336
72336
|
];
|
|
72337
72337
|
});
|
|
72338
72338
|
|
|
72339
|
+
// src/ui/serve-behaviors/server.ts
|
|
72340
|
+
import { createServer } from "node:http";
|
|
72341
|
+
import { spawn as spawn4 } from "node:child_process";
|
|
72342
|
+
async function serveHtmlInMemory(html, options) {
|
|
72343
|
+
const timeout = options?.timeout ?? 5 * 60 * 1000;
|
|
72344
|
+
const openBrowser = options?.openBrowser ?? true;
|
|
72345
|
+
return new Promise((resolve, reject) => {
|
|
72346
|
+
const server = createServer((req, res) => {
|
|
72347
|
+
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
72348
|
+
res.end(html);
|
|
72349
|
+
});
|
|
72350
|
+
server.listen(0, "127.0.0.1", () => {
|
|
72351
|
+
const address = server.address();
|
|
72352
|
+
if (!address || typeof address === "string") {
|
|
72353
|
+
reject(new Error("Failed to get server address"));
|
|
72354
|
+
return;
|
|
72355
|
+
}
|
|
72356
|
+
const url2 = `http://127.0.0.1:${address.port}`;
|
|
72357
|
+
const timer = setTimeout(() => server.close(), timeout);
|
|
72358
|
+
const stop = () => {
|
|
72359
|
+
clearTimeout(timer);
|
|
72360
|
+
server.close();
|
|
72361
|
+
};
|
|
72362
|
+
if (openBrowser) {
|
|
72363
|
+
const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "cmd" : "xdg-open";
|
|
72364
|
+
const args = process.platform === "win32" ? ["/c", "start", url2] : [url2];
|
|
72365
|
+
spawn4(cmd, args, { detached: true, stdio: "ignore" }).unref();
|
|
72366
|
+
}
|
|
72367
|
+
resolve({ url: url2, stop });
|
|
72368
|
+
});
|
|
72369
|
+
server.on("error", reject);
|
|
72370
|
+
});
|
|
72371
|
+
}
|
|
72372
|
+
var init_server = () => {};
|
|
72373
|
+
|
|
72374
|
+
// src/ui/serve-behaviors/handlers.ts
|
|
72375
|
+
var deps, htmlCodeServeHandler;
|
|
72376
|
+
var init_handlers2 = __esm(() => {
|
|
72377
|
+
init_server();
|
|
72378
|
+
deps = {
|
|
72379
|
+
serveHtmlInMemory
|
|
72380
|
+
};
|
|
72381
|
+
htmlCodeServeHandler = {
|
|
72382
|
+
async serve(ctx) {
|
|
72383
|
+
try {
|
|
72384
|
+
let url2;
|
|
72385
|
+
if (typeof ctx.value === "string") {
|
|
72386
|
+
url2 = ctx.value;
|
|
72387
|
+
} else if (typeof ctx.value === "object" && ctx.value?.downloadUrl) {
|
|
72388
|
+
url2 = ctx.value.downloadUrl;
|
|
72389
|
+
} else {
|
|
72390
|
+
return { success: false, message: "No download URL found" };
|
|
72391
|
+
}
|
|
72392
|
+
ctx.onProgress?.("\uD83D\uDCE5 Downloading HTML...");
|
|
72393
|
+
const response = await fetch(url2);
|
|
72394
|
+
if (!response.ok) {
|
|
72395
|
+
return { success: false, message: `Download failed: ${response.status} ${response.statusText}` };
|
|
72396
|
+
}
|
|
72397
|
+
const html = await response.text();
|
|
72398
|
+
ctx.onProgress?.("\uD83D\uDE80 Starting local server...");
|
|
72399
|
+
const { url: serveUrl } = await deps.serveHtmlInMemory(html);
|
|
72400
|
+
ctx.onProgress?.("\uD83C\uDF10 Opening browser...");
|
|
72401
|
+
return { success: true, message: `\uD83C\uDF10 Preview at ${serveUrl} (auto-closes in 5 min)`, url: serveUrl };
|
|
72402
|
+
} catch (error2) {
|
|
72403
|
+
return { success: false, message: `Serve failed: ${error2 instanceof Error ? error2.message : String(error2)}` };
|
|
72404
|
+
}
|
|
72405
|
+
}
|
|
72406
|
+
};
|
|
72407
|
+
});
|
|
72408
|
+
|
|
72409
|
+
// src/ui/serve-behaviors/registry.ts
|
|
72410
|
+
function registerServeHandler(matcher, handler2) {
|
|
72411
|
+
registrations2.push({ matcher, handler: handler2 });
|
|
72412
|
+
}
|
|
72413
|
+
function getServeHandler(path10) {
|
|
72414
|
+
for (let i2 = registrations2.length - 1;i2 >= 0; i2--) {
|
|
72415
|
+
const reg = registrations2[i2];
|
|
72416
|
+
if (reg && reg.matcher(path10))
|
|
72417
|
+
return reg.handler;
|
|
72418
|
+
}
|
|
72419
|
+
return null;
|
|
72420
|
+
}
|
|
72421
|
+
function endsWith2(suffix) {
|
|
72422
|
+
return (path10) => path10.endsWith(suffix);
|
|
72423
|
+
}
|
|
72424
|
+
var registrations2;
|
|
72425
|
+
var init_registry2 = __esm(() => {
|
|
72426
|
+
init_handlers2();
|
|
72427
|
+
registrations2 = [];
|
|
72428
|
+
registerServeHandler(endsWith2(".htmlCode"), htmlCodeServeHandler);
|
|
72429
|
+
registerServeHandler(endsWith2(".htmlCode.downloadUrl"), htmlCodeServeHandler);
|
|
72430
|
+
});
|
|
72431
|
+
|
|
72432
|
+
// src/ui/serve-behaviors/index.ts
|
|
72433
|
+
var init_serve_behaviors = __esm(() => {
|
|
72434
|
+
init_server();
|
|
72435
|
+
init_handlers2();
|
|
72436
|
+
init_registry2();
|
|
72437
|
+
});
|
|
72438
|
+
|
|
72339
72439
|
// node_modules/react/cjs/react-jsx-dev-runtime.development.js
|
|
72340
72440
|
var require_react_jsx_dev_runtime_development = __commonJS((exports) => {
|
|
72341
72441
|
var React10 = __toESM(require_react(), 1);
|
|
@@ -72560,7 +72660,7 @@ var require_jsx_dev_runtime = __commonJS((exports, module) => {
|
|
|
72560
72660
|
});
|
|
72561
72661
|
|
|
72562
72662
|
// src/ui/JsonTree.tsx
|
|
72563
|
-
import { spawn as
|
|
72663
|
+
import { spawn as spawn5 } from "child_process";
|
|
72564
72664
|
function getType(value) {
|
|
72565
72665
|
if (value === null)
|
|
72566
72666
|
return "null";
|
|
@@ -72666,6 +72766,32 @@ var import_react26, jsx_dev_runtime, JsonTree = ({ data, rootLabel, onNavigate,
|
|
|
72666
72766
|
}
|
|
72667
72767
|
return;
|
|
72668
72768
|
}
|
|
72769
|
+
if (input === "s") {
|
|
72770
|
+
const node = visibleNodes[selectedIndex];
|
|
72771
|
+
if (!node)
|
|
72772
|
+
return;
|
|
72773
|
+
const handler2 = getServeHandler(node.id);
|
|
72774
|
+
if (!handler2) {
|
|
72775
|
+
if (feedbackTimeout.current)
|
|
72776
|
+
clearTimeout(feedbackTimeout.current);
|
|
72777
|
+
setFeedbackMessage("⚠️ No preview available for this path");
|
|
72778
|
+
feedbackTimeout.current = setTimeout(() => setFeedbackMessage(null), 3000);
|
|
72779
|
+
return;
|
|
72780
|
+
}
|
|
72781
|
+
const onProgress = (message) => {
|
|
72782
|
+
if (feedbackTimeout.current)
|
|
72783
|
+
clearTimeout(feedbackTimeout.current);
|
|
72784
|
+
setFeedbackMessage(message);
|
|
72785
|
+
};
|
|
72786
|
+
const ctx = { key: node.key, value: node.value, path: node.id, onProgress };
|
|
72787
|
+
handler2.serve(ctx).then((result) => {
|
|
72788
|
+
if (feedbackTimeout.current)
|
|
72789
|
+
clearTimeout(feedbackTimeout.current);
|
|
72790
|
+
setFeedbackMessage(result.message);
|
|
72791
|
+
feedbackTimeout.current = setTimeout(() => setFeedbackMessage(null), 1e4);
|
|
72792
|
+
});
|
|
72793
|
+
return;
|
|
72794
|
+
}
|
|
72669
72795
|
if (input === "o") {
|
|
72670
72796
|
const node = visibleNodes[selectedIndex];
|
|
72671
72797
|
if (!node)
|
|
@@ -72700,7 +72826,7 @@ var import_react26, jsx_dev_runtime, JsonTree = ({ data, rootLabel, onNavigate,
|
|
|
72700
72826
|
if (projectId) {
|
|
72701
72827
|
const url2 = `https://stitch.withgoogle.com/projects/${projectId}`;
|
|
72702
72828
|
const openCmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
|
|
72703
|
-
|
|
72829
|
+
spawn5(openCmd, [url2], { stdio: "ignore", detached: true }).unref();
|
|
72704
72830
|
if (feedbackTimeout.current)
|
|
72705
72831
|
clearTimeout(feedbackTimeout.current);
|
|
72706
72832
|
setFeedbackMessage(`\uD83D\uDD17 Opened project in browser`);
|
|
@@ -72855,7 +72981,7 @@ var import_react26, jsx_dev_runtime, JsonTree = ({ data, rootLabel, onNavigate,
|
|
|
72855
72981
|
children: [
|
|
72856
72982
|
"Selected Path: ",
|
|
72857
72983
|
visibleNodes[selectedIndex]?.id || "none",
|
|
72858
|
-
" |
|
|
72984
|
+
" | 'c' copy, 'cc' extended, 's' preview"
|
|
72859
72985
|
]
|
|
72860
72986
|
}, undefined, true, undefined, this),
|
|
72861
72987
|
feedbackMessage && /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
|
|
@@ -72871,6 +72997,7 @@ var init_JsonTree = __esm(async () => {
|
|
|
72871
72997
|
await init_build2();
|
|
72872
72998
|
init_copy_behaviors();
|
|
72873
72999
|
init_navigation_behaviors();
|
|
73000
|
+
init_serve_behaviors();
|
|
72874
73001
|
jsx_dev_runtime = __toESM(require_jsx_dev_runtime(), 1);
|
|
72875
73002
|
});
|
|
72876
73003
|
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Serve handlers - isolated behavior implementations.
|
|
3
|
+
*/
|
|
4
|
+
import type { ServeHandler } from './types.js';
|
|
5
|
+
import { serveHtmlInMemory } from './server.js';
|
|
6
|
+
export declare const deps: {
|
|
7
|
+
serveHtmlInMemory: typeof serveHtmlInMemory;
|
|
8
|
+
};
|
|
9
|
+
export declare const htmlCodeServeHandler: ServeHandler;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Serve behaviors for JSON viewer.
|
|
3
|
+
*/
|
|
4
|
+
export type { ServeHandler, ServeContext, ServeResult, PathMatcher } from './types.js';
|
|
5
|
+
export { serveHtmlInMemory } from './server.js';
|
|
6
|
+
export { htmlCodeServeHandler } from './handlers.js';
|
|
7
|
+
export { registerServeHandler, getServeHandler, endsWith, contains } from './registry.js';
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Registry for path-based serve handler selection.
|
|
3
|
+
*/
|
|
4
|
+
import type { ServeHandler, PathMatcher } from './types.js';
|
|
5
|
+
import { htmlCodeServeHandler } from './handlers.js';
|
|
6
|
+
export declare function registerServeHandler(matcher: PathMatcher, handler: ServeHandler): void;
|
|
7
|
+
export declare function getServeHandler(path: string): ServeHandler | null;
|
|
8
|
+
export declare function endsWith(suffix: string): PathMatcher;
|
|
9
|
+
export declare function contains(segment: string): PathMatcher;
|
|
10
|
+
export { htmlCodeServeHandler };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Serve behavior types for the JSON viewer.
|
|
3
|
+
*/
|
|
4
|
+
export interface ServeContext {
|
|
5
|
+
key: string;
|
|
6
|
+
value: any;
|
|
7
|
+
path: string;
|
|
8
|
+
onProgress?: (message: string) => void;
|
|
9
|
+
}
|
|
10
|
+
export interface ServeResult {
|
|
11
|
+
success: boolean;
|
|
12
|
+
message: string;
|
|
13
|
+
url?: string;
|
|
14
|
+
}
|
|
15
|
+
export interface ServeHandler {
|
|
16
|
+
serve(ctx: ServeContext): Promise<ServeResult>;
|
|
17
|
+
}
|
|
18
|
+
export type PathMatcher = (path: string) => boolean;
|
package/package.json
CHANGED