@nearform/fling 0.0.0-stage → 0.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/LICENSE +21 -0
- package/README.md +218 -2
- package/dist/cli.js +3000 -0
- package/dist/cli.js.map +7 -0
- package/package.json +48 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Nearform
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,219 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @nearform/fling
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Fling a folder of static files at [fling.labs.nearform.com](https://fling.labs.nearform.com) and
|
|
4
|
+
get a stable link back:
|
|
5
|
+
|
|
6
|
+
```
|
|
7
|
+
https://<name>.fling.labs.nearform.com
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
Site names are one global namespace, first come first served. Sites are private to signed-in Nearformers by default. Share links make them viewable by anyone
|
|
11
|
+
who has the link.
|
|
12
|
+
|
|
13
|
+
## Install
|
|
14
|
+
|
|
15
|
+
Node 22 or later.
|
|
16
|
+
|
|
17
|
+
```sh
|
|
18
|
+
npm install -g @nearform/fling # then: fling …
|
|
19
|
+
# or run without installing:
|
|
20
|
+
npx @nearform/fling …
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Log in
|
|
24
|
+
|
|
25
|
+
```sh
|
|
26
|
+
fling login
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
This opens your browser for Nearform Google sign-in and stores an API key in
|
|
30
|
+
`~/.fling/config.json` (mode 0600). `fling whoami` shows who you are, and `fling logout` removes the
|
|
31
|
+
key. For CI, set `FLING_API_KEY` instead.
|
|
32
|
+
|
|
33
|
+
## Deploy
|
|
34
|
+
|
|
35
|
+
```sh
|
|
36
|
+
npm run build
|
|
37
|
+
fling ./dist # name generated from the project, e.g. rocketpod-docs; you confirm it
|
|
38
|
+
fling ./dist --name my-app # → https://my-app.fling.labs.nearform.com
|
|
39
|
+
fling ./dist --name my-app --spa # client-side routing: unknown paths serve index.html
|
|
40
|
+
fling ./dist --public # no sign-in needed to view
|
|
41
|
+
fling ./dist --yes # never prompt (CI): use the generated name as is
|
|
42
|
+
fling # deploys the current folder
|
|
43
|
+
fling "Pitch Deck.html" # a single page, served as index.html → pitch-deck
|
|
44
|
+
fling site.zip # a zip of a site: extracted, a single top folder unwrapped
|
|
45
|
+
fling diagram.svg # any other file, next to a generated page that shows it
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
What you can fling:
|
|
49
|
+
|
|
50
|
+
- **A folder**, as is.
|
|
51
|
+
- **A single `.html`/`.htm` file**, served as the site's `index.html`.
|
|
52
|
+
- **A `.zip`**: extracted (paths that would escape the folder are refused), `__MACOSX/` and dotfiles
|
|
53
|
+
skipped, and a single top-level folder unwrapped.
|
|
54
|
+
- **Any other file** (`.pdf`, `.svg`, `.png`, `.md`…), served next to a small generated `index.html`
|
|
55
|
+
that shows it (images, PDF, video, audio) or links to it.
|
|
56
|
+
|
|
57
|
+
A file's default site name comes from its name, without the extension or a browser's ` (1)`
|
|
58
|
+
duplicate suffix: `Pitch Deck (1).html` → `pitch-deck`. Folders use the naming rules below.
|
|
59
|
+
|
|
60
|
+
**Files by name.** If the path doesn't exist where you are, Fling looks for it by name, newest
|
|
61
|
+
first, in Downloads (`FLING_DOWNLOADS_DIR` if set; on Linux your XDG download folder), Desktop,
|
|
62
|
+
`~/Documents/Claude`, `~/Claude` and Claude Desktop's output folders, and says where it found it:
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
$ fling Pitch-Deck.html
|
|
66
|
+
fling Found in Downloads: /Users/me/Downloads/Pitch-Deck.html
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
- Re-fling to update. Identical content is a no-op, and content you deployed before is restored
|
|
70
|
+
instantly without uploading.
|
|
71
|
+
- Dotfiles, `node_modules` and anything listed in a `.flingignore` (gitignore syntax) are skipped.
|
|
72
|
+
Symlinks pointing outside the folder are never followed.
|
|
73
|
+
- Limits are 25 MB per file, 100 MB per deploy and 5,000 files.
|
|
74
|
+
- Absolute asset paths (`/assets/x.js`) work because each site has its own subdomain.
|
|
75
|
+
|
|
76
|
+
### Site names
|
|
77
|
+
|
|
78
|
+
Names use lowercase letters, digits and single hyphens, up to 50 characters, and are first come,
|
|
79
|
+
first served across everyone. A few (`api`, `www`, `fling`…) are reserved. If a name belongs to
|
|
80
|
+
someone else, Fling suggests free ones with your initials appended (`my-app-cc`, `my-app-cc2`…).
|
|
81
|
+
|
|
82
|
+
Without `--name`, the name is generated from the folder, never from your user name:
|
|
83
|
+
|
|
84
|
+
1. Find the project root: the nearest folder (this one or above) containing `.git`, otherwise
|
|
85
|
+
`package.json`, `pyproject.toml`, `Cargo.toml` or `go.mod`. The search stops at your home folder.
|
|
86
|
+
2. Use the root's folder name plus the folders from the root down, skipping build output
|
|
87
|
+
(`dist`, `build`, `out`, `output`, `public`, `www`, `_site`, `site`, `html`, `static`, `export`,
|
|
88
|
+
`target`), monorepo containers (`apps`, `packages`, `src`, `sites`, `libs`, `projects`,
|
|
89
|
+
`services`), dot-folders (`.vitepress`, `.next`…) and repeats. A `-static`/`-dist`/`-build`/`-out`
|
|
90
|
+
suffix is trimmed (`storybook-static` → `storybook`).
|
|
91
|
+
3. With no project root, use the deepest folder that isn't build output.
|
|
92
|
+
4. Too long? Middle parts are dropped, then it is truncated.
|
|
93
|
+
|
|
94
|
+
| Folder | Name |
|
|
95
|
+
|---|---|
|
|
96
|
+
| `~/work/rocketpod/docs` | `rocketpod-docs` |
|
|
97
|
+
| `~/work/myapp/dist` | `myapp` |
|
|
98
|
+
| `~/work/mono/apps/web/dist` | `mono-web` |
|
|
99
|
+
| `~/work/mono/packages/ui/storybook-static` | `mono-ui-storybook` |
|
|
100
|
+
| `~/Downloads/report/dist` (no project) | `report` |
|
|
101
|
+
|
|
102
|
+
### Prompts
|
|
103
|
+
|
|
104
|
+
In a terminal, Fling checks the generated name and asks before deploying:
|
|
105
|
+
|
|
106
|
+
```
|
|
107
|
+
fling Site name: rocketpod-docs → https://rocketpod-docs.fling.labs.nearform.com/ (new)
|
|
108
|
+
Use "rocketpod-docs"? [Y/n or type another name]
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
The note says `(new)` or `(updates your existing site)`. If the name is taken it lists suggestions
|
|
112
|
+
and offers the first one. Press Enter to accept, type another name to check that one, or `n` to
|
|
113
|
+
abort.
|
|
114
|
+
|
|
115
|
+
If there is no `index.html` at the top it asks:
|
|
116
|
+
|
|
117
|
+
```
|
|
118
|
+
No index.html at the root. [L]ist the HTML pages on a generated index page / [f]ling anyway (the root will 404) / [a]bort
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
**L** (the default, offered when there are `.html` pages) adds a generated `index.html` that links
|
|
122
|
+
every HTML page, titled from each page's `<title>`. It is built in memory and uploaded with the
|
|
123
|
+
site; your folder is never written to. Without HTML pages the choices are fling anyway or abort
|
|
124
|
+
(the default). `--list-html` and `--no-list-html` decide up front.
|
|
125
|
+
|
|
126
|
+
With `--name` there is no name prompt. With `--yes`, or without a terminal (CI, agents), Fling never
|
|
127
|
+
asks: with no `index.html` it generates the listing when there are HTML pages (otherwise it warns),
|
|
128
|
+
and a taken name fails (exit 1) with suggestions rather than picking another name — pass `--name`.
|
|
129
|
+
|
|
130
|
+
## Manage sites
|
|
131
|
+
|
|
132
|
+
| Command | |
|
|
133
|
+
|---|---|
|
|
134
|
+
| `fling ls [--archived]` | your sites |
|
|
135
|
+
| `fling info <name>` / `fling versions <name>` | details and version history |
|
|
136
|
+
| `fling files <name> [versionId]` | the files in the live version (or an earlier one) |
|
|
137
|
+
| `fling rollback <name> <versionId>` | serve an earlier version |
|
|
138
|
+
| `fling share <name> [--refresh] [--revoke]` | public share link: print or create it, rotate it, or remove it |
|
|
139
|
+
| `fling visibility <name> private\|public` | require sign-in, or not |
|
|
140
|
+
| `fling archive <name>` / `fling unarchive <name>` | take offline and keep the files, or bring back |
|
|
141
|
+
| `fling rm <name> [--yes]` | delete permanently |
|
|
142
|
+
|
|
143
|
+
Global options: `--json` prints machine-readable output, and `--server <url>` points at another
|
|
144
|
+
server. Exit codes are `0` ok, `1` error, `2` not logged in and `3` forbidden.
|
|
145
|
+
|
|
146
|
+
Environment: `FLING_API_KEY`, `FLING_URL`, `FLING_CONFIG_DIR`, `FLING_DEBUG`, `FLING_DOWNLOADS_DIR`
|
|
147
|
+
(where files given by name are looked for first), `FLING_NO_WAIT=1` (after a deploy or a new share
|
|
148
|
+
link, don't wait the few seconds it takes to reach every edge).
|
|
149
|
+
|
|
150
|
+
## Claude Code plugin and MCP
|
|
151
|
+
|
|
152
|
+
The Fling plugin gives Claude a `fling` skill plus an MCP server (`fling mcp`), so you can say
|
|
153
|
+
"fling the dist folder and give me a share link":
|
|
154
|
+
|
|
155
|
+
```
|
|
156
|
+
/plugin marketplace add nearform/fling
|
|
157
|
+
/plugin install fling@fling
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Log in once with `fling login` (or `npx @nearform/fling login` if it is not installed). The MCP server reuses that login.
|
|
161
|
+
|
|
162
|
+
The MCP tools:
|
|
163
|
+
|
|
164
|
+
- `fling_deploy`: a folder, `.html`, `.zip` or other file on this computer, by path or just its
|
|
165
|
+
name (looked up like the CLI does).
|
|
166
|
+
- `fling_publish`: files passed inline, for content Claude wrote in the conversation. It has the same
|
|
167
|
+
definition as the remote connector's tool.
|
|
168
|
+
- `fling_find_files`: recent `.html`/`.zip` files and folders with an `index.html` in those folders,
|
|
169
|
+
newest first (last 14 days by default).
|
|
170
|
+
- `fling_login`: opens the browser sign-in. If you haven't finished after about 30 seconds it returns
|
|
171
|
+
and keeps waiting in the background for up to 5 minutes.
|
|
172
|
+
- `fling_check_name`, `fling_list`, `fling_info`, `fling_share`, `fling_set_visibility`,
|
|
173
|
+
`fling_archive`, `fling_rollback`, `fling_delete` (needs `confirm: true`) and `fling_whoami`.
|
|
174
|
+
|
|
175
|
+
The MCP server never prompts:
|
|
176
|
+
|
|
177
|
+
- **Names.** Without a `name`, `fling_deploy` uses the generated name and fails with suggestions if
|
|
178
|
+
it is taken. `fling_check_name` (with a `name`, or a `path` to see its generated name) lets the
|
|
179
|
+
agent confirm a name with you first.
|
|
180
|
+
- **No `index.html`.** If there are HTML pages but no `index.html`, `fling_deploy` and
|
|
181
|
+
`fling_publish` don't deploy. They ask the agent to check with you, then retry with
|
|
182
|
+
`listHtml: true` (generate the listing) or `listHtml: false` (deploy anyway).
|
|
183
|
+
|
|
184
|
+
## Claude Desktop extension
|
|
185
|
+
|
|
186
|
+
For Claude Desktop (including Cowork), install the one-click extension. It runs the same MCP server
|
|
187
|
+
on your computer, so Claude can fling files you downloaded or that Claude Desktop saved, by name,
|
|
188
|
+
without uploading anything from Claude's sandbox.
|
|
189
|
+
|
|
190
|
+
1. Download [fling.mcpb](https://fling.labs.nearform.com/downloads/fling.mcpb).
|
|
191
|
+
2. Double-click it, or drag it into Claude Desktop, or go to **Settings → Extensions → Advanced
|
|
192
|
+
settings → Install Extension…** and pick the file.
|
|
193
|
+
3. Optional settings: **Fling server** (default `https://fling.labs.nearform.com`) and **Downloads
|
|
194
|
+
folder** (default `~/Downloads`).
|
|
195
|
+
4. Ask Claude to "fling Pitch Deck.html from my Downloads". If you're not signed in, Claude calls
|
|
196
|
+
`fling_login` and your browser opens. The extension and the CLI share the login in
|
|
197
|
+
`~/.fling/config.json`.
|
|
198
|
+
|
|
199
|
+
It needs Node.js 20 or later, which Claude Desktop provides, on macOS or Windows.
|
|
200
|
+
|
|
201
|
+
Build it with `pnpm --filter @nearform/fling build:mcpb`. That bundles `src/mcp-entry.ts` and every
|
|
202
|
+
dependency into one file, then validates and packs `mcpb/manifest.json` into `dist/fling.mcpb`.
|
|
203
|
+
CI publishes it at `/downloads/fling.mcpb`.
|
|
204
|
+
|
|
205
|
+
To use the MCP server in another client, run it over stdio:
|
|
206
|
+
|
|
207
|
+
```json
|
|
208
|
+
{ "command": "npx", "args": ["-y", "@nearform/fling@latest", "mcp"] }
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
## Development
|
|
212
|
+
|
|
213
|
+
From the repo root:
|
|
214
|
+
|
|
215
|
+
```sh
|
|
216
|
+
pnpm cli --server http://localhost:3001 login # against `pnpm dev`
|
|
217
|
+
pnpm --filter @nearform/fling test
|
|
218
|
+
pnpm --filter @nearform/fling build # → dist/cli.js
|
|
219
|
+
```
|