@fluid-app/fluid-cli-member-site 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/README.md CHANGED
@@ -1,3 +1,457 @@
1
- # Temporary Holding Version
1
+ # @fluid-app/fluid-cli-member-site
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Fluid CLI plugin for member sites. Adds `fluid member-site`, which works with
4
+ the member site API and the company member sites API: it lists, creates, pulls,
5
+ pushes, publishes, lints and previews sites.
6
+
7
+ This is not `fluid mysite`, which is an unrelated command, and not `fluid theme`.
8
+
9
+ ## Installation
10
+
11
+ ```bash
12
+ npm install -g @fluid-app/fluid-cli @fluid-app/fluid-cli-member-site
13
+ ```
14
+
15
+ Requires `@fluid-app/fluid-cli` as the core CLI.
16
+
17
+ ## Which login builds which site
18
+
19
+ The credential follows the owner of the site:
20
+
21
+ | Site owner | API | Login |
22
+ | ---------- | ------------------------------------ | --------------------------------------- |
23
+ | Member | `/api/member/v2026-10/sites` | The member's own login |
24
+ | Company | `/api/company/v2026-10/member-sites` | A signed-in admin who may change themes |
25
+
26
+ The plugin keeps no credential of its own. It uses the login, profiles and
27
+ `.fluidrc` of the core CLI, so `FLUID_TOKEN`, a project's `.fluidrc` profile and
28
+ the active profile apply as they do for every other command. The API base
29
+ follows the login: `FLUID_API_BASE` if set, else the base the stored profile was
30
+ made for (a `.fluidrc` profile, else the active one). There is no default base,
31
+ so a token from `FLUID_TOKEN`, or a profile with no recorded base, needs
32
+ `FLUID_API_BASE`. With neither, the command stops with "No API base for this
33
+ login: run `fluid login` or set FLUID_API_BASE" before it makes any request.
34
+
35
+ The core CLI stores a token and does not record whose it is, so the plugin
36
+ cannot tell a member's token from an admin's before it sends a request. Say
37
+ which it is with `--as member` or `--as admin`, and a site of the other owner
38
+ kind is refused before any request, with the login it needs. Without `--as`,
39
+ the server decides, and a refusal names the login the site needs.
40
+
41
+ A member who is also an admin of the same company is refused by the member API
42
+ and builds company sites only.
43
+
44
+ `fluid login` signs in admins and reps only. A member signs in to this command
45
+ with the member's own token, set in `FLUID_TOKEN`.
46
+
47
+ ## Commands
48
+
49
+ ### `fluid member-site list`
50
+
51
+ With a member login, lists the member's own sites. With an admin login, lists
52
+ every site in the company with its owner and status. A member's site is shown
53
+ read-only: its owner builds it.
54
+
55
+ ```bash
56
+ fluid member-site list
57
+ fluid member-site list --as member
58
+ ```
59
+
60
+ Without `--as`, the company API is tried first and the member API when the
61
+ company API refuses the login.
62
+
63
+ ### `fluid member-site create <handle>`
64
+
65
+ Creates a site as a draft. The handle is lowercase letters, digits and single
66
+ hyphens, at most 40 characters. The name defaults to the handle in words.
67
+
68
+ ```bash
69
+ fluid member-site create rileys-shop --name "Riley's Shop" # a member's site
70
+ fluid member-site create fall-launch --company --as admin # a company site
71
+ ```
72
+
73
+ `--company` creates a company-owned site and needs an admin login.
74
+
75
+ ### `fluid member-site pull <site> [dir]`
76
+
77
+ Pulls a site into a local folder. `<site>` is the site's handle or id, and
78
+ `dir` defaults to the handle. Every text file is written at its API path, the
79
+ pages are written to `config/pages.json`, and a binding file records where the
80
+ folder came from.
81
+
82
+ ```bash
83
+ fluid member-site pull rileys-shop --as member # a member's site
84
+ fluid member-site pull fall-launch ./site --as admin # a company site
85
+ ```
86
+
87
+ ```text
88
+ rileys-shop/
89
+ layouts/site.liquid sections/hero.liquid snippets/card.liquid
90
+ pages/index.liquid pages/about.liquid
91
+ assets/site.css assets/site.js
92
+ config/settings.json config/menus.json config/pages.json
93
+ config/access.json (only when the site declares what it uses)
94
+ .member-site.json
95
+ ```
96
+
97
+ - The folder is the API: a path here is the path the file API uses. The home
98
+ page is `pages/index.liquid`.
99
+ - `config/access.json` is the site's declaration of the viewer data it uses and
100
+ the actions it takes as the viewer: `{ "uses": ["member.email", "orders: read"] }`.
101
+ A member site has it once it has a draft declaration, and a company site never
102
+ does. It is a draft until the site is published.
103
+ - `config/pages.json` holds the site's default `layout` and, for each page, its
104
+ `slug`, `title`, `position`, `published`, `layout` and `menu` (the menu's
105
+ slug). It holds no page content, which is in `pages/<slug>.liquid`. A page
106
+ whose content is a template the site does not own has a row there and no
107
+ file.
108
+ - `.member-site.json` is the binding file. It records the site's `site_id`,
109
+ `handle` and `owner_kind`, the `api_base` it was pulled from, the settings
110
+ `lock_version`, the site's default `layout`, each page's `id`, `lock_version`
111
+ and row by slug (the row lets a push tell which fields you changed), and for every
112
+ file the `lock_version`, `updated_at` and the `version` the file list
113
+ reports (a binding from a pull before the API reported one has none), plus a
114
+ SHA-256 of the content written. It is local state and is never pushed.
115
+ - A site holds text assets only (css, js, json, txt, html). The file list holds
116
+ no other file, and a listed asset that is not text is skipped and named in
117
+ the summary. Use images and fonts from the media library by URL.
118
+ - A pull reads every file before it writes any, so a failed read leaves the
119
+ folder as it was. A file already identical on disk is left alone, so a second
120
+ pull of an unchanged site changes nothing.
121
+ - A folder that is not empty and is not bound to this site is refused, and so
122
+ is a pull that would overwrite a file edited since the last pull. `--force`
123
+ writes anyway. Files that are not on the server are never removed, with one
124
+ exception: when the site no longer has `config/access.json` and the local copy
125
+ is unchanged since the last pull or push, the pull deletes it, so the next push
126
+ does not bring back a declaration another writer removed. An edited copy is
127
+ kept unless `--force` is passed.
128
+ - A pull does not write through a symbolic link. A file or folder of the site
129
+ that is, or is inside, a link is refused, with or without `--force`, before
130
+ any file is written. Each file is written to a new file that replaces the old
131
+ one.
132
+ - A member's site cannot be pulled with an admin login, because the company
133
+ routes refuse a member's site. With `--as admin`, or in a folder bound to a
134
+ member's site, that stops before any file or page request, and names the login
135
+ the site needs.
136
+
137
+ ### `fluid member-site push [dir]`
138
+
139
+ Pushes the changes in a pulled folder to its site. Run it in the folder, or pass
140
+ the folder. The folder's binding names the site and its owner kind, so a member's
141
+ site goes through the member API and a company site through the company API, and
142
+ a login of the other kind is refused before any request.
143
+
144
+ ```bash
145
+ fluid member-site push --dry-run # print the plan, send nothing
146
+ fluid member-site push --as member
147
+ fluid member-site push --publish # push, then publish once
148
+ ```
149
+
150
+ A push compares the folder with the binding and sends only what changed. A pull
151
+ followed by a push with no edit sends nothing.
152
+
153
+ Every write and delete carries the version the binding recorded for it, and the
154
+ server refuses it with 409 if the file or page changed since. A push never
155
+ overwrites or deletes a copy that moved on the server. A path the binding never
156
+ saw is created with `must_not_exist`, so a file another writer created after the
157
+ pull is not replaced.
158
+
159
+ What it sends, in this order:
160
+
161
+ 1. `config/settings.json`, with the settings `lock_version` the binding recorded.
162
+ It goes first because every page write moves that version, so a settings write
163
+ that came after one would answer 409 to the push's own work.
164
+ 2. Each changed or new layout, section, snippet and asset, and `config/access.json`
165
+ (`PUT files/:path`), in path order, so the declaration goes ahead of the
166
+ layouts. A changed file carries its recorded `version`; a new one carries
167
+ `must_not_exist`. On a company site the push leaves `config/access.json`
168
+ alone and says so, as the server refuses the path.
169
+ 3. Each new page (`POST pages`) with its file's content, then each changed page
170
+ (`PATCH pages/:id`) with the changed row fields and the changed content, each
171
+ with the page's `lock_version`.
172
+ 4. `config/menus.json`, when it changed, with its recorded `version`. It replaces
173
+ every menu of the site. A menus write moves the site's version and the version
174
+ of every page assigned to a menu it drops, so the push reads the pages again
175
+ before the next step.
176
+ 5. Each page's menu assignment (`PATCH pages/:id` with `menu`), with the page's
177
+ re-read version. A page body never carries `menu`, so it is never sent before
178
+ its menu exists.
179
+ 6. Each removed page (`DELETE pages/:id?lock_version=`), then each removed
180
+ layout, section, snippet, asset and `config/access.json` (`DELETE files/:path?version=`;
181
+ removing the declaration clears its draft). Removals go
182
+ last, so a write that fails never leaves a menu pointing at a page that is
183
+ gone.
184
+
185
+ After each response the binding takes the versions it returned and is saved, so
186
+ a push that stops can be run again after a pull. A removed page or file leaves the
187
+ binding when the server removes it. After the last write the push reads the
188
+ settings once more to record their version, and keeps it only when the settings
189
+ are still the ones in the folder. A second push straight after the first sends
190
+ nothing and does not conflict with it. A push without `--publish` never
191
+ publishes. A publish by someone else moves the version of every page, layout,
192
+ section and snippet it publishes, so the push stops at the first of those it
193
+ writes: pull again first.
194
+
195
+ A page is removed by taking its row out of `config/pages.json` and its file out of
196
+ the folder. A page renamed in `config/pages.json` is a new page and a removal: the
197
+ new page is created first and the old one is deleted after it. `config/settings.json`
198
+ and `config/menus.json` cannot be removed. If either file is missing, the push says
199
+ so and leaves the server's copy.
200
+
201
+ What it lists and does not send: a change to the site's default `layout` in
202
+ `config/pages.json`, which is a change to the site row.
203
+
204
+ What takes effect without a publish. Before the first write, the push lists the
205
+ files and rows that are live as soon as they are written: assets (changed, new or
206
+ removed), any removed file, `config/menus.json`, and page rows (a new page, a
207
+ changed row field, a menu assignment, a removed page). Changes to layouts,
208
+ sections, snippets, page content and the settings are saved as drafts, but
209
+ removing a layout, section or snippet deletes it and its published copy at once,
210
+ so the site stops rendering it without a publish. A push that changes none of
211
+ these lists none.
212
+
213
+ Without `--publish`, a push never calls the publish route.
214
+
215
+ Everything that can be refused is refused before the first request, and every
216
+ refusal is listed at once:
217
+
218
+ - a file that is not a text asset: an asset must be css, js, json, txt or html,
219
+ valid UTF-8 and not empty. Use images and fonts from the media library by URL;
220
+ - a path outside `layouts`, `sections`, `snippets`, `pages`, `assets` and
221
+ `config`, a path in a subfolder, a symbolic link, and a name outside lowercase
222
+ letters, digits, hyphens and underscores (a page's name is lowercase letters
223
+ and digits separated by single hyphens). Names that start with a dot are ignored;
224
+ - a page file with no row in `config/pages.json`, and a new page row with no
225
+ file; a file for a page whose template the site does not own;
226
+ - a page row removed while its file is still in the folder, and a page file
227
+ removed while its row is still in `config/pages.json`: a page goes with its
228
+ file, so remove both or neither;
229
+ - a changed, new-to-the-binding or removed file, or changed menus, whose version
230
+ the binding does not hold (a binding from before the API reported versions).
231
+ Pull the site again first;
232
+ - a `config/pages.json` that is not valid, a slug `index` (the home page is
233
+ `/`), a menu that `config/menus.json` does not define, settings that are not a
234
+ JSON object, and menus that are not JSON or not shaped as the API takes them
235
+ (an object with a `menus` array, and the required keys and types of each menu
236
+ and item; whether a linked page exists is left to the server);
237
+ - new pages that do not fit in the site's 50-page limit. Removals are sent after
238
+ the new pages are created, so a renamed page's old page still counts. Push the
239
+ removals on their own first. This needs the site's current page count, so
240
+ `--dry-run`, which sends no request, does not check it and says so;
241
+ - a menu link whose `url` the server's URL parser refuses: anything but a
242
+ well-formed `http` or `https` address with a host, as written. A space or
243
+ non-ASCII character in the address, or a space around it, is refused rather
244
+ than corrected.
245
+
246
+ A `--dry-run` prints the plan, removals included, and sends no request. With
247
+ `--publish` it also says that a publish would follow.
248
+
249
+ The first stale version stops the push. It names the file or page, tells you to
250
+ pull, lists what was already written, and sends nothing after it. A path that was
251
+ to be created and now exists on the server is reported as created by another
252
+ writer, and a removal the server refused is reported as not deleted. The push is
253
+ not atomic: the API has no batch write, so what was written stays written. A stale
254
+ settings version also follows any page another writer changed, because the
255
+ settings version is the site's.
256
+
257
+ With `--publish`, the push calls the publish route once, after the last write
258
+ succeeded, and prints what `publish` prints (below). It is never called after a
259
+ write failed or a change was refused, and a push with nothing to send still
260
+ publishes. If the publish itself is refused, the pushed changes stay saved as
261
+ drafts and the command says the site was not published.
262
+
263
+ ### `fluid member-site publish [dir]`
264
+
265
+ Publishes the site of a pulled folder: the drafts of its layouts, sections,
266
+ snippets, pages and settings become the live site. Run it in the folder, or pass
267
+ the folder. A member's site is published through the member API
268
+ (`POST sites/:id/publish`) with the member's login, and a company site through
269
+ the company API (`POST member-sites/:id/publish`) with an admin's login, chosen
270
+ by the binding as for `push`.
271
+
272
+ ```bash
273
+ fluid member-site publish
274
+ fluid member-site publish ./rileys-shop --as member
275
+ ```
276
+
277
+ It makes one publish request and sends no file, so a local edit that was not
278
+ pushed is not published. It prints the site's `status` and its new
279
+ `content_version`.
280
+
281
+ - A site that an admin took down cannot be published again. The command prints
282
+ the API's message, exits non-zero and does not retry.
283
+ - A 409 is reported as a conflict: the site was changed while it was being
284
+ published, so it was not published. Run the command again.
285
+ - A publish moves the version of every layout, section, snippet and page file it
286
+ publishes, of every page, and of the settings. After it succeeds the command
287
+ records a new version in the binding only when it can prove the publish
288
+ published what the folder holds, so the next push does not conflict with the
289
+ publish but still finds a change another writer made. A layout, section,
290
+ snippet or page file takes the server's version when it is the one computed
291
+ from the file's content in the folder. A page takes its `lock_version` when
292
+ that moved by exactly one. The settings take the site's `lock_version` when
293
+ the publish response shows the settings the folder holds and the version moved
294
+ by what one publish moves it. Anything else keeps its old version, the command
295
+ names it, and the next push stops on it and asks for a pull. A file edited in
296
+ the folder and not pushed is not proven either, and keeps its old version, so
297
+ push it before publishing. Assets and menus are not changed by a publish, and
298
+ keep their versions. If the versions cannot be read after the publish, the site
299
+ is still published, and the command says to pull before the next push.
300
+
301
+ ### `fluid member-site lint [dir]`
302
+
303
+ Checks a site folder on disk and makes no request. It needs no login and no
304
+ binding file, so it works on a folder that was never pulled. Run it in the
305
+ folder, or pass the folder.
306
+
307
+ ```bash
308
+ fluid member-site lint
309
+ fluid member-site lint ./rileys-shop
310
+ ```
311
+
312
+ A clean folder prints nothing and exits 0. Any error exits 1, and each finding
313
+ names its file. Warnings are printed and do not fail the command.
314
+
315
+ - Liquid in layouts, sections, snippets and pages is checked the way
316
+ `fluid theme lint` checks it, and its messages are the theme linter's: the
317
+ `{% schema %}` block and the pairing of block tags such as `{% if %}` and
318
+ `{% endif %}`. The theme linter's cart-code, missing-section and
319
+ routed-template checks are theme rules and are not run.
320
+ - The file rules a push enforces, with the same messages: a path outside
321
+ `layouts`, `sections`, `snippets`, `pages`, `assets` and `config`, a name
322
+ outside the allowed characters, a subfolder, a symbolic link, and an asset that
323
+ is binary, not css, js, json, txt or html, or empty. Every file is judged, also
324
+ one a pull wrote.
325
+ - `config/pages.json` must be valid, and lists at most 50 pages. The count is the
326
+ rows in the file, so a page with no file counts.
327
+ - `config/menus.json` must have the shape the API takes, and each menu link
328
+ (`page`) must name a page that `config/pages.json` lists. A folder with no
329
+ `config/pages.json` lists no pages.
330
+ - `config/access.json` must be what the file API accepts, and each problem is an
331
+ error: not valid JSON, a key other than `uses` or a repeated key, an entry that
332
+ is not a string or is listed twice, an unknown field, family or mode,
333
+ `session: read`, more than 64 entries, or more than 4 KiB.
334
+ - Warnings for a site's use of viewer data. A Liquid file that reads
335
+ `member.<field>` is warned whatever the declaration holds, because member data is leaving
336
+ member-site Liquid: read it in a script with
337
+ `fluid.fetch("/api/member/v2026-10/me")`, which needs `profile: read`.
338
+ - When `config/access.json` is valid, each `fluid.fetch(` call (also
339
+ `window.fluid.fetch(`) in a layout, section, snippet, page or `.js` asset is
340
+ checked against `src/lint/path-scopes.json`, a copy of the SDK's route table
341
+ that a test holds equal to the SDK's. The lint takes the path from a string
342
+ literal, or from a template literal whose `${...}` parts are whole path
343
+ segments (`` `/api/member/v2026-10/orders/${id}` ``), and the method from a
344
+ `method: "POST"` string literal in an object-literal second argument (`GET`
345
+ when there is none). It moves the path as `fluid.fetch` does: a Member API
346
+ path (`/api/member/v2026-10/...`) stays, and any other `/api/` path moves under
347
+ `/api/member-storefront/`. It ignores the query string. Then:
348
+ - a scope the declaration holds, or `session: read`, gives no finding;
349
+ - a scope the declaration lacks is warned, naming the scope;
350
+ - a route no site can reach is warned, with the reason;
351
+ - a call the lint cannot check is warned too, never skipped: a path or method
352
+ that is a variable or is computed, an interpolation that is not a whole
353
+ segment, a path outside `/api/`, or a path and method no route matches. Such
354
+ a call is refused at run time if its scope is not declared.
355
+
356
+ A folder with no `config/access.json` is not checked for calls, because a site
357
+ with no declaration is not limited.
358
+
359
+ ### `fluid member-site dev [dir]`
360
+
361
+ Shows a site's draft while you edit it. It saves each change you make in a
362
+ pulled folder as a draft and serves the draft on a local port, rendered by the
363
+ server with the same renderer members get, not by a local one. Run it in the
364
+ folder, or pass the folder.
365
+
366
+ ```bash
367
+ fluid member-site dev
368
+ fluid member-site dev ./rileys-shop --as member --port 9600
369
+ fluid member-site dev --allow-production
370
+ ```
371
+
372
+ - **It does not write production unless you say so.** A session saves the
373
+ folder when it starts and again on every change, and assets, removals, menus
374
+ and page rows are live as soon as they are written. So `dev` stops, before it
375
+ makes any request, when the login's API base is production, with a message that
376
+ names the base and the flag, and writes nothing. Pass `--allow-production` to
377
+ save to production anyway. A base that is not production keeps syncing without
378
+ it: a local one (`localhost`, a loopback address (any of `127.0.0.0/8`, or `::1`), `*.localhost`), a stage one
379
+ (`*.stage.fluid.app`) and a name under `.test`. Any other base, a custom or
380
+ unknown host included, is taken for production. `fluid theme dev` is
381
+ never pointed at a live theme either: it works on a development theme unless
382
+ `--theme` names another one, and this site has no development copy to use in
383
+ its place, so the choice is a flag.
384
+ - **It saves drafts and never publishes.** A save is `push` without
385
+ `--publish`: the same plan, the same refusals, the same version on every
386
+ write, and the same stop at a stale version (pull, then run `dev` again). It
387
+ never calls the publish route. What takes effect without a publish is listed
388
+ before each save, as for `push`: assets, removals, menus and page rows are live
389
+ as soon as they are written. Run `fluid member-site publish` when the draft is
390
+ ready.
391
+ - **It starts only when it can show a draft.** First it reads the site, then it
392
+ asks the server for the draft preview route. A server without it stops the
393
+ command with "Draft preview is not available on this server yet" before
394
+ anything is saved. It never shows the published page in its place. Then what
395
+ the folder holds is saved, so the page shows the folder, and a refused or stale
396
+ save stops the command. The folder is watched before it is read for that first
397
+ save, so an edit made while it runs is saved before the preview is served,
398
+ and none is missed.
399
+ - **After that**, each change is saved after a short pause, and the command
400
+ keeps serving when a save is refused, so you can fix the file. Reload the
401
+ preview to see a save. There is no live reload yet.
402
+ - **The preview** is `http://127.0.0.1:<port>` (`--port`, default 9500; `--port 0`
403
+ takes a free one). `/` is the home page and `/<slug>` another page, read
404
+ through `GET .../sites/:id/preview/pages(/:slug)` of the member API, or
405
+ `GET .../member-sites/:id/preview/pages(/:slug)` of the company API for a
406
+ company site. A text asset is at `/files/assets/<file>` (served to the
407
+ preview's own origin and the address bar only: see below), read through
408
+ `.../preview/files/*path`. A page links its assets at the published frame
409
+ address and its pages at the site's shell address, and neither opens a draft,
410
+ so the preview rewrites both to its own paths.
411
+ - **The credential stays in the CLI.** The server listens on `127.0.0.1` only.
412
+ The bearer is added to the request to the API by this process, and is never in
413
+ a URL, a page or a header sent to the browser. Nothing the browser sends
414
+ (cookies, its own `Authorization`) goes to the API. A request is refused
415
+ unless its `Host` is the local address, its `Origin` is the preview's own, and
416
+ it is not a cross-site request that a page could read. A preview is served
417
+ with the sandbox policy the frame has, `Cache-Control: private, no-store` and
418
+ `Referrer-Policy: no-referrer`. The sandbox gives the page an opaque origin
419
+ (`Origin: null`), and so does every other sandboxed page, so the origin
420
+ cannot say whose request it is. The preview gives each session a random token
421
+ and links its assets at `/files/assets/<token>/<file>`. Only `GET` of such a
422
+ path, as a script or a stylesheet, is let read with CORS (a module script
423
+ needs it), and only then is `Access-Control-Allow-Origin: null` sent. A
424
+ request from an opaque origin for any other path is refused. An asset path
425
+ without the token (`/files/assets/<file>`, or the published frame address) is
426
+ served only when `Sec-Fetch-Site` is `same-origin` or `none`, so a page of
427
+ another site that loads it as a stylesheet or script without CORS gets
428
+ nothing and cannot read what the CLI's login can. The preview rewrites the
429
+ frame addresses in a stylesheet or script to the path with the token. The token is not the
430
+ credential and authorizes nothing at the API.
431
+ - With `--as`, the login is checked as for `push`: a member's site needs a
432
+ member login, a company site an admin's.
433
+
434
+ ## Errors
435
+
436
+ | API answer | What the command says |
437
+ | ---------- | ------------------------------------------------------------------------------------------------- |
438
+ | 404 | Member sites are not enabled for this company or the site is not yours |
439
+ | 401 | The login was not accepted, and which login the site needs |
440
+ | 403 | The API's message, and which login the site needs |
441
+ | 409 | The site (or the named file or page) changed on the server; on a publish, a conflict to run again |
442
+ | 422 | The API's message and each field error |
443
+ | other | The API's message and the request id |
444
+
445
+ A 404 answers the same for a company without member sites, a missing site and
446
+ another owner's site, so the command names the first and the last. It is never
447
+ retried. A read that fails with 502, 503 or 504 is retried twice. A write is
448
+ never retried.
449
+
450
+ ## Development
451
+
452
+ ```bash
453
+ pnpm --filter @fluid-app/fluid-cli-member-site test
454
+ pnpm --filter @fluid-app/fluid-cli-member-site typecheck
455
+ pnpm --filter @fluid-app/fluid-cli-member-site lint
456
+ pnpm --filter @fluid-app/fluid-cli-member-site build
457
+ ```
@@ -0,0 +1,7 @@
1
+ import { FluidPlugin } from "@fluid-app/fluid-cli";
2
+
3
+ //#region src/index.d.ts
4
+ declare const plugin: FluidPlugin;
5
+ //#endregion
6
+ export { plugin as default };
7
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/index.ts"],"mappings":";;;cAGM,MAAA,EAAQ,WAAA"}