@nearform/fling 0.6.0 → 0.8.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/README.md CHANGED
@@ -12,7 +12,8 @@ link.
12
12
 
13
13
  > **Upgrading from 0.2?** The CLI no longer has a built-in server. If you were logged in with 0.2
14
14
  > it carries on with the server you logged in to. Otherwise (or on a new machine) run
15
- > `fling login <url>` once with your Fling's address. See [CHANGELOG.md](CHANGELOG.md).
15
+ > `fling login <url>` once with your Fling's address. See the
16
+ > [changelog](https://github.com/nearform/fling/blob/main/CHANGELOG.md).
16
17
 
17
18
  ## Install
18
19
 
@@ -33,7 +34,8 @@ fling setup https://fling.example.com # your Fling's address; later runs can l
33
34
  This does everything a new machine needs:
34
35
 
35
36
  1. **Signs you in.** The CLI reads the server's `/.well-known/fling` (its name, where its sites
36
- live, how people sign in) and remembers it. Your browser opens for sign-in and an API key is
37
+ live, how people sign in) and remembers it. Your browser opens for sign-in (on a Fling with two
38
+ sign-in providers, its login page, to choose one) and an API key is
37
39
  stored in `~/.fling/config.json` (mode 0600). This is skipped if you're already signed in.
38
40
  The server becomes your current one; logins to other Flings are kept.
39
41
  2. **Adds Fling to Claude Code.** If `claude` is on your PATH, setup installs the Fling plugin
@@ -73,7 +75,9 @@ npm run build
73
75
  fling deploy ./dist # name generated from the project, e.g. rocketpod-docs; you confirm it
74
76
  fling deploy ./dist --name my-app # → https://my-app.<your sites domain>
75
77
  fling deploy ./dist --name my-app --spa # client-side routing: unknown paths serve index.html
76
- fling deploy ./dist --public # no sign-in needed to view
78
+ fling deploy ./dist --access members # a new site everyone signed in can open
79
+ fling deploy ./dist --access people --add bob@example.com # only you and Bob
80
+ fling deploy ./dist --access public # no sign-in needed to view
77
81
  fling deploy ./dist --yes # never prompt (CI): use the generated name as is
78
82
  fling deploy # deploys the current folder
79
83
  fling deploy "Pitch Deck.html" # a single page, served as index.html → pitch-deck
@@ -101,6 +105,23 @@ does; see below).
101
105
 
102
106
  - Re-fling to update. Identical content is a no-op, and content you deployed before is restored
103
107
  instantly without uploading.
108
+ - **Publish one folder of a site** with `--path` (and `--name`): `fling deploy ./report --name
109
+ changelog --path 30-10-26` serves the report at `https://changelog.<sites domain>/30-10-26/` and
110
+ keeps every other file of the site. Only the folder's files are uploaded; the server copies the
111
+ rest into the new version (at most 1,000 files, else `too_large`: deploy the whole site). If
112
+ someone else publishes the site in between, the deploy runs once more on top of theirs. `fling
113
+ versions` shows where each one went (PATH), and rolling back removes it. On a Fling without path
114
+ publishing (`pathPublish`) the CLI refuses rather than replace the whole site.
115
+ - **Change a site you can open** with `fling pull <name> [dir]`: it downloads the current version
116
+ into `dir` (default `./<name>`) with a site link, `.fling-site.json`, naming the server, the site
117
+ and the version pulled. `fling deploy <dir>` then publishes to that site on that version and
118
+ uploads only what changed (`3 changed, 1 removed`). If someone published the site since you
119
+ pulled, it stops (`base_changed`) rather than overwrite their work: pull again into another
120
+ folder and redo your change, or `fling deploy <dir> --force` to replace what they published.
121
+ `--path <folder>` pulls one folder of the site; `--version-id <id>` another version (owners and
122
+ publishers). Anyone signed in who can open the site may pull it; only its owners and publishers
123
+ may deploy. A folder that isn't empty needs `--force`. On a Fling without the `pull` capability
124
+ the CLI says so.
104
125
  - **Fling never publishes dotfiles, gitignored files, secret files (keys, certs, credentials) or
105
126
  files that contain secrets; it stops and tells you which file and line.** There is no flag to
106
127
  override this, and the server enforces it too.
@@ -180,43 +201,92 @@ and a taken name fails (exit 1) with suggestions rather than picking another nam
180
201
  |---|---|
181
202
  | `fling ls [--archived] [--sort updated\|created\|name]` | your sites, last updated first (`created`: newest first; `name`: A–Z) |
182
203
  | `fling ls --shared [--sort …]` | the restricted sites others have shared with you: owner, and how (your address or a group) |
183
- | `fling info <name>` / `fling versions <name>` | details and version history |
204
+ | `fling info <name>` / `fling versions <name>` | details and version history, with who published each version and, for a path publish, the folder (PATH) |
205
+ | `fling pull <name> [dir] [--path <folder>] [--version-id <id>] [--force]` | download a site's files to change them; `fling deploy <dir>` publishes on the version pulled |
184
206
  | `fling files <name> [versionId]` | the files in the live version (or an earlier one) |
185
207
  | `fling rollback <name> <versionId>` | serve an earlier version |
186
208
  | `fling share <name> [--refresh] [--revoke]` | public share link: print or create it, rotate it, or remove it |
187
- | `fling visibility <name> private\|public` | require sign-in, or not |
188
- | `fling access <name> [--add <emails>] [--remove <emails>] [--group <slugs>] [--remove-group <slugs>] [--clear]` | who can open a private site: everyone signed in, or only listed people and groups |
209
+ | `fling visibility <name> private\|public` | require sign-in, or not (private again: the access it had) |
210
+ | `fling access <name> [--only-me \| --members \| --public] [--add <emails>] [--remove <emails>] [--group <slugs>] [--remove-group <slugs>] [--clear]` | who can open a site: only you, listed people and groups, everyone signed in, or anyone |
211
+ | `fling owners <name> [--add <emails>] [--remove <emails>] [--set <emails>] [--group <slugs>] [--remove-group <slugs>]` | who owns a site, or change it |
212
+ | `fling publishers <name> [--add …] [--remove …] [--set …] [--group …] [--remove-group …]` | who publishes a site without owning it, or change it |
189
213
  | `fling archive <name>` / `fling unarchive <name>` | take offline and keep the files, or bring back |
190
214
  | `fling rm <name> [--yes]` | delete permanently |
191
215
 
192
- ### Who can open a private site
216
+ An admin of the instance can read anyone's site with these commands (`fling info`, `fling files`,
217
+ the comments). Changing someone else's site needs the admin's browser session: open it from All
218
+ sites in the web app.
193
219
 
194
- A private site opens to everyone signed in to your Fling. `fling access` limits it to listed people
195
- (its audience); you, the owner, can always open it:
220
+ ### Who can open a site
221
+
222
+ Each site has an access level: **only you**, **teams** (groups), **specific people**, **everyone
223
+ signed in** to your Fling, or **public**. A new site gets the one you give with `deploy --access
224
+ only_me|members|groups|people|public` (with `--add <emails>` and `--group <slugs>` for people and
225
+ teams); without it, your Fling's default, which is only you unless it is set up otherwise, and the
226
+ deploy says who can open it. A re-deploy never changes it. `fling ls` shows each site's level in
227
+ its ACCESS column and `fling info` on its Access line.
228
+
229
+ `fling access` shows and changes it. `--only-me`, `--members` and `--public` set the level; the
230
+ audience options limit the site to listed people and groups (its audience); you, the owner, can
231
+ always open it:
196
232
 
197
233
  ```sh
198
234
  fling access my-app # who can open it now
235
+ fling access my-app --only-me # nobody else
236
+ fling access my-app --members # everyone signed in
199
237
  fling access my-app --add bob@example.com,cat@example.com
200
238
  fling access my-app --remove bob@example.com
201
239
  fling access my-app --group design # everyone in the design group too
202
240
  fling access my-app --remove-group design
203
- fling access my-app --clear # everyone signed in again
241
+ fling access my-app --clear # empty the audience: everyone signed in
242
+ fling access my-app --public # anyone, no sign-in
204
243
  ```
205
244
 
206
245
  Addresses are comma-separated or given after `--add` one by one, and each must be one that can sign
207
- in to the Fling. Someone who hasn't signed in yet is marked `(hasn't signed in yet)`; they can open
208
- the site once they do. The audience only applies while the site is private: on a public site it is
246
+ in to the Fling. Where the Fling invites people from outside (its `invites` capability), an outside
247
+ address is invited as a **guest**: a reviewer who signs in with a link emailed to them and sees only
248
+ what is shared with them, marked `(guest)`. You can invite a few new outside addresses a day; past
249
+ that, nothing changes and the CLI says so (`too_many_invites`). The same goes for `fling groups
250
+ create` and `fling groups add`. Someone who hasn't signed in yet is marked `(hasn't signed in yet)`;
251
+ they can open the site once they do. The audience only applies while the site is private: on a public site it is
209
252
  kept for later and `fling access` says so. A share link still opens a restricted site to anyone who
210
253
  has it, and `fling access` warns while one exists. Removing someone shuts them out within 5
211
- minutes. `--json` prints the site with its `audience` (`{ emails: [{ email, known }], groups:
254
+ minutes. `--json` prints the site with its `audience` (`{ emails: [{ email, known, guest? }], groups:
212
255
  [{ slug, name, size }] }`) and `warnings`; `fling info` shows the same line, and `fling ls --json`
213
- gives each site's `restricted`, `audienceSize` and `audienceGroups` (how many of those are groups).
256
+ gives each site's `access`, `restricted`, `audienceSize` and `audienceGroups` (how many of those
257
+ are groups). A share link opens a site only you can see as well: it is your choice to hand it out.
214
258
 
215
259
  `fling ls --shared` lists the other side: the restricted sites whose audience names you, or a group
216
260
  you are in, with their owner and how they reached you. With `--json`, each is `{ name, url,
217
261
  reviewUrl?, owner, via: { direct, groups }, createdAt, updatedAt }`. Your own sites, and private
218
262
  sites open to everyone signed in, aren't listed.
219
263
 
264
+ ### Owners and publishers
265
+
266
+ A site's **owners** are equal: each can publish it, roll it back, change who can open it and its
267
+ settings, its owners and publishers, archive and delete it. Its **publishers** can publish and roll
268
+ back, and nothing else. Both are people and groups, and only people who can sign in to your Fling
269
+ as members (never guests) can hold either:
270
+
271
+ ```sh
272
+ fling owners my-app # who owns and publishes it, and your role
273
+ fling owners my-app --add cat@example.com # Cat owns it too
274
+ fling owners my-app --remove you@example.com # hand it over (someone else must own it)
275
+ fling publishers my-app --add bob@example.com --group design
276
+ fling publishers my-app --remove-group design
277
+ fling publishers my-app --set bob@example.com # exactly these addresses (groups stay)
278
+ ```
279
+
280
+ A site always keeps at least one person as an owner, so `--remove` of the last one is refused
281
+ (`last_owner`); a group alone never counts. Someone in both lists is an owner. Naming a group
282
+ trusts whoever manages it: anyone they add owns or publishes the site too. People you add are told
283
+ by email where your Fling sends it. `fling ls` shows your ROLE on each site (owner, publisher, or
284
+ admin for an admin's view), and `fling info` its Owners, Publishers and You. As a publisher,
285
+ `fling deploy` publishes new content, but can't change the site's access or settings (`--access`,
286
+ `--public`, `--spa` that differ: `owner_only`) or bring an archived site back. With `--json`, the
287
+ commands print `{ name, role, owners, publishers }`, each list `{ emails: [{ email, known, guest?
288
+ }], groups: [{ slug, name, size }] }`.
289
+
220
290
  ### Groups
221
291
 
222
292
  A group is a named list of people, such as a team, that anyone signed in can use in a site's
@@ -257,6 +327,55 @@ feedback (`reviewUrl` in `--json`); reviewers sign in to use it.
257
327
  | `fling resolve <name> <id> [--reopen]` | resolve a thread, or reopen it |
258
328
  | `fling uncomment <name> <id> [--yes]` | delete a comment (a thread with its replies): your own, or any on your site |
259
329
 
330
+ ## Forms
331
+
332
+ A form collects structured feedback on a site's review page: a label per page, rubric scores, an
333
+ A/B preference, a flagged passage's severity. It is a JSON Schema the review page renders, and
334
+ reviewers' answers (responses) come back as data you can export, instead of codes typed into
335
+ comments. On a Fling with forms (the `forms` capability, on with comments), put a
336
+ `fling.forms.json` at the top of the folder you deploy:
337
+
338
+ ```sh
339
+ fling forms init ./dist --template labels --title Labels # a starter: labels, rubric, compare, issue or survey
340
+ fling forms check ./dist # as a deploy will: errors, and the pages each form applies to
341
+ fling deploy ./dist # sends it as the site's forms (never served as a file)
342
+ fling responses my-app # who answered which page, and how far each form has got
343
+ fling responses my-app --format csv -o labels.csv # the export: json, jsonl or csv
344
+ ```
345
+
346
+ - `fling deploy` checks the file against the folder's pages and stops on errors. After the deploy
347
+ it lists each form and the pages it applies to (`forms` in `--json`). Without the file, it ends
348
+ with one line on adding a form (`formsHint` in `--json`; `--quiet` leaves it out).
349
+ - Without the file, deploying a whole site removes its forms. A `--path` deploy keeps them, and so
350
+ does a pulled folder, unless it was pulled with a `fling.forms.json` you have since deleted.
351
+ - `fling pull` writes the site's `fling.forms.json` back into the folder.
352
+ - On a form with `"visibility": "own"`, reviewers see only their own answers; the site's owners see
353
+ everyone's.
354
+
355
+ | Command | |
356
+ |---|---|
357
+ | `fling forms <name> [--path <page>]` | the live forms: a line per form, then the config as JSON (`> fling.forms.json` saves it) |
358
+ | `fling forms init [dir] [--template <name>] [--title <title>] [--force]` | write a starter `fling.forms.json` |
359
+ | `fling forms check [path]` | check a folder's `fling.forms.json` (or a file) against the folder's pages |
360
+ | `fling responses <name> [--form <id>] [--path <page>] [--format json\|jsonl\|csv] [-o file]` | the responses as a table with progress, or the export |
361
+
362
+ ## Notifications
363
+
364
+ A Fling with email tells you when a site is shared with you (directly or through a group), when
365
+ you are added to a group, and when someone comments on your site or replies in your thread. You
366
+ choose what you hear about, per event and channel; the same settings are on the web app's
367
+ **Settings → Notifications** page, and every email has a link to stop that kind of email.
368
+
369
+ | Command | |
370
+ |---|---|
371
+ | `fling notifications` | a table of events × channels: on or off, `*` where you chose it rather than the default |
372
+ | `fling notifications set <event> <channel> on\|off\|default` | change one event on one channel (`default`: back to the Fling's default), e.g. `fling notifications set comment.created email off` |
373
+ | `fling notifications mute` / `unmute` | stop everything, or start again (your choices are kept) |
374
+ | `fling notifications sent` | what was sent to you in the last 30 days: when, the subject and its events |
375
+
376
+ On a Fling without notifications they say so. `--json` prints the settings as the API returns them
377
+ (`{ channels, events, muted, cells, overrides }`) or `{ sent: [...] }`.
378
+
260
379
  Global options: `--json` prints machine-readable output, and `--server <url>` points one command at
261
380
  another server (a remembered one brings its key; see [Several Flings](#several-flings)). Exit codes are `0` ok, `1` error, `2` not logged in and `3` forbidden.
262
381
 
@@ -303,9 +422,16 @@ accepts).
303
422
  The MCP tools:
304
423
 
305
424
  - `fling_deploy`: a folder, `.html`, `.zip` or other file on this computer, by path or just its
306
- name (looked up like the CLI does).
425
+ name (looked up like the CLI does). `sitePath` (with `name`) publishes it into that folder of the
426
+ site and keeps the rest, like `--path`. A folder pulled with `fling pull` or `fling_pull` deploys
427
+ on the version pulled, like the CLI; `force: true` publishes over whatever is live.
428
+ - `fling_pull`: downloads a site into a folder on this computer (default
429
+ `~/Documents/Claude/fling/<name>`) to change it and deploy it again with `fling_deploy`.
430
+ - `fling_read_files`: a site's files inline, a page at a time, for reading without a download.
307
431
  - `fling_publish`: files passed inline, for content Claude wrote in the conversation. It has the same
308
- definition as the remote connector's tool.
432
+ definition as the remote connector's tool; `path` publishes them into that folder of the site;
433
+ `base` (a version from `fling_read_files`) sends only the files that changed, and `remove` names
434
+ files to delete.
309
435
  - `fling_find_files`: recent `.html`/`.zip` files and folders with an `index.html` in those folders,
310
436
  newest first (last 14 days by default).
311
437
  - `fling_login`: opens the browser sign-in. If you haven't finished after about 30 seconds it returns
@@ -315,11 +441,16 @@ The MCP tools:
315
441
  current), read when called. `{use: <server>}` makes one current, the same as `fling use`.
316
442
  - `fling_check_name`, `fling_list`, `fling_info`, `fling_files`, `fling_share`,
317
443
  `fling_set_visibility`, `fling_archive`, `fling_rollback`, `fling_delete` (needs
318
- `confirm: true`), `fling_whoami`, the comment tools when a Fling has comments, and
444
+ `confirm: true`), `fling_whoami`, the comment tools when a Fling has comments, the forms tools when it has forms
445
+ (`fling_forms`, `fling_forms_template`, `fling_forms_check`, `fling_responses_list`, and
446
+ `fling_response_submit`, which answers a form as you, only when you ask), and
319
447
  `fling_set_audience` (`add`, `remove`, `set` or `clear` the people who can open a private site,
320
448
  and `addGroups`, `removeGroups`, `setGroups` for groups) when it can limit sites to listed
321
- people, and the group tools (`fling_groups`, `fling_group_show`, `fling_group_create`,
322
- `fling_group_members`, `fling_group_rename`, `fling_group_delete`) when it has groups.
449
+ people, `fling_set_owners` and `fling_set_publishers` (the same changes, to a site's owners or
450
+ publishers) where it has site roles, and the group tools (`fling_groups`, `fling_group_show`, `fling_group_create`,
451
+ `fling_group_members`, `fling_group_rename`, `fling_group_delete`) when it has groups, and
452
+ `fling_notifications` and `fling_notifications_set` (`muted`, and `cells` of
453
+ `{ event, channel, value: on|off|default }`) when it has notifications.
323
454
 
324
455
  Results that give URLs (deploys, publishes, comments) end with the Fling they went to.
325
456