mfeflow 0.3.0 → 0.5.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
@@ -13,20 +13,27 @@ pnpm dev # shell on :4300, remotes on :4311,
13
13
 
14
14
  ## Commands
15
15
 
16
- | Command | Does |
17
- | ------------------------------------- | ------------------------------------------------------------------------------------ |
18
- | `mfeflow init [dir]` | New project: a shell, remotes (default `catalog`, `cart`), pnpm workspace, Turborepo |
19
- | `mfeflow add remote <name>` | New remote with its registry entries and a route in every shell |
20
- | `mfeflow add shell <name>` | New shell that routes to every existing remote |
21
- | `mfeflow add <feature...>` | Add features, or `@namespace/feature` from a registry in `mfeflow.json` |
22
- | `mfeflow add env-key <KEY>` | Add a typed env key: `--scope server` (env.ts) or `runtime`, with `--schema <expr>` |
23
- | `mfeflow features [search]` | List the features you can add |
24
- | `mfeflow dev` | Run the shell and every remote, one prefixed log each; follows `add remote` |
25
- | `mfeflow doctor` | Singletons, compatibility, config health, drift; `--fix` repairs the safe ones |
26
- | `mfeflow validate` | `mfeflow.json`, every `mfe.json` and every registry entry against their schemas |
27
- | `mfeflow check-compat` | Each remote's shared ranges against the shells it runs in |
28
- | `mfeflow budget` | Built first-load JS of the shell and each remote against the cost-model budget |
29
- | `mfeflow --version`, `mfeflow --help` | Version, and help with examples (`mfeflow <command> --help` for one command) |
16
+ | Command | Does |
17
+ | ------------------------------------- | ------------------------------------------------------------------------------------- |
18
+ | `mfeflow init [dir]` | New project: a shell, remotes (default `catalog`, `cart`), pnpm workspace, Turborepo |
19
+ | `mfeflow add remote <name>` | New remote with its registry entries and a route in every shell |
20
+ | `mfeflow add shell <name>` | New shell that routes to every existing remote |
21
+ | `mfeflow add <feature...>` | Add features, or `@namespace/feature` from a registry you added with `registry add` |
22
+ | `mfeflow add env-key <KEY>` | Add a typed env key: `--scope server` (env.ts) or `runtime`, with `--schema <expr>` |
23
+ | `mfeflow features [search]` | List and search the features you can add, from mfeflow and every configured registry |
24
+ | `mfeflow registry add @ns <url>` | Add a third-party feature registry (`https`, or `http` on loopback) to `mfeflow.json` |
25
+ | `mfeflow registry list`, `remove @ns` | List the registries, or remove one |
26
+ | `mfeflow registry build <dir>` | Check a folder of features and write `index.json` and the files to host |
27
+ | `mfeflow dev` | Run the shell and every remote, one prefixed log each; follows `add remote` |
28
+ | `mfeflow doctor` | Singletons, compatibility, config health, drift; `--fix` repairs the safe ones |
29
+ | `mfeflow validate` | `mfeflow.json`, every `mfe.json` and every registry entry against their schemas |
30
+ | `mfeflow check-compat` | Each remote's shared ranges against the shells it runs in |
31
+ | `mfeflow budget` | Built first-load JS of the shell and each remote against the cost-model budget |
32
+ | `mfeflow deploy <remote> --env <env>` | Upload a remote's build to a static registry host and point the env's index at it |
33
+ | `mfeflow promote <remote>` | Copy the version one env serves to another env: `--from staging --to prod` |
34
+ | `mfeflow rollback <remote>` | Point an env back at the previous version, or `--to <version>`, without a rebuild |
35
+ | `mfeflow status` | What each env serves, the version before it, and drift from `registry/envs` |
36
+ | `mfeflow --version`, `mfeflow --help` | Version, and help with examples (`mfeflow <command> --help` for one command) |
30
37
 
31
38
  Features that ship with it: `core` and `tsconfig` (always), `lint-oxlint`, `url-factory`, `env-t3` and `testing`
32
39
  (default), `ci-github` and `git-hooks` (opt-in). `init` takes `--scope`, `--remotes a,b`, `--features a,b` and
@@ -102,8 +109,8 @@ MFEFLOW_E108 The target folder is not empty: /work/app already has notes.txt
102
109
  | 3 | project or config problem: `MFEFLOW_E1xx` |
103
110
  | 4 | feature problem: `MFEFLOW_E2xx` |
104
111
  | 5 | build or runtime problem: `MFEFLOW_E3xx` |
105
- | 6 | registry problem: `MFEFLOW_E4xx` |
106
- | 7 | upgrade problem: `MFEFLOW_E5xx` |
112
+ | 6 | feature registry problem: `MFEFLOW_E4xx` |
113
+ | 7 | deploy problem: `MFEFLOW_E5xx` |
107
114
  | 130 | cancelled at a prompt (nothing was written), or Ctrl+C in `mfeflow dev` |
108
115
 
109
116
  ## Try it from a checkout
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "analytics-gtm",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Google Tag Manager with Consent Mode v2 behind @mfeflow/analytics: consent defaults before gtm.js, a consent banner hook, page views on route changes, and a typed tracker per remote. The container id comes from the runtime config.",
5
5
  "requires": ["core", "tsconfig"],
6
6
  "files": [
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ci-github",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "GitHub Actions workflow for pull requests: lint, typecheck, test, build, doctor, validate, check-compat, budget, runtime-config check and the Playwright smoke test. Opt-in.",
5
5
  "requires": ["core"],
6
6
  "files": [
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "env-t3",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Typed env with t3-env: env.ts per app fails the build on a missing variable, runtime-config schema checked before deploy, no validator or env value in the browser bundle.",
5
5
  "requires": ["core", "tsconfig"],
6
6
  "prompts": [
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lint-oxlint",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "oxlint with type-aware rules on TypeScript 7 (@mfeflow/oxlint-config), and Prettier.",
5
5
  "requires": ["core", "tsconfig"],
6
6
  "files": [
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "testing",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Vitest, Testing Library, jsdom and MSW in every app with @mfeflow/testing, and a Playwright smoke test that opens the shell and checks each remote renders.",
5
5
  "requires": ["core", "tsconfig"],
6
6
  "files": [
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tsconfig",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Strict TypeScript 7 presets from @mfeflow/tsconfig, and a typecheck script.",
5
5
  "requires": ["core"],
6
6
  "files": [
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "url-factory",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Typed endpoint definitions and URL building (@mfeflow/url-factory), src/api/endpoints.ts in every app.",
5
5
  "requires": ["core"],
6
6
  "files": [
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "core",
3
- "version": "0.1.0",
3
+ "version": "0.3.0",
4
4
  "description": "The shell, the remotes, the registry and the workspace around them.",
5
5
  "files": [
6
6
  {
@@ -96,6 +96,12 @@
96
96
  "from": "files/shell/src/bootstrap.tsx.eta",
97
97
  "template": true
98
98
  },
99
+ {
100
+ "to": "src/assert.ts",
101
+ "target": "shell",
102
+ "from": "files/shell/src/assert.ts.eta",
103
+ "template": true
104
+ },
99
105
  {
100
106
  "to": "src/App.tsx",
101
107
  "target": "shell",
@@ -45,6 +45,21 @@ Each is a root script for the `mfeflow` CLI in your devDependencies (`pnpm mfefl
45
45
  against the 10 KB a remote may add; set `budget.baselineKb` in `mfeflow.json` (your pages built as one app) to check
46
46
  the shell against baseline + 32 KB too.
47
47
 
48
+ ## Deploy it
49
+
50
+ ```sh
51
+ pnpm build
52
+ pnpm mfeflow deploy catalog --env staging --host file:./site --base-url https://cdn.example.com
53
+ pnpm mfeflow promote catalog --from staging --to prod --host file:./site
54
+ pnpm mfeflow rollback catalog --env prod --host file:./site
55
+ pnpm mfeflow status --host file:./site
56
+ ```
57
+
58
+ `deploy` uploads a remote's `dist` and points an environment at it, `rollback` points it back without a rebuild, and
59
+ `status` shows what is served. Put `host` and `baseUrl` under `registry` in `mfeflow.json` to drop the flags, or use
60
+ `s3://<bucket>` with the `MFEFLOW_S3_*` and `AWS_*` variables. There are no root scripts for these, because the package manager has a deploy command of its own, so
61
+ run them through `pnpm mfeflow`.
62
+
48
63
  ## Before you deploy
49
64
 
50
65
  `registry/envs/staging` and `registry/envs/prod` point at `example.com`. Replace the hosts
@@ -0,0 +1,37 @@
1
+ /* oxlint-disable eslint/no-underscore-dangle -- __MFEFLOW_SINGLETONS__ is the name the rsbuild preset defines */
2
+ import { checkSingletons, reportRemoteError } from '@mfeflow/runtime';
3
+
4
+ // The shell's rsbuild preset defines the packages it shares; an older preset does not, so fall back.
5
+ declare const __MFEFLOW_SINGLETONS__: readonly string[] | undefined;
6
+ const SINGLETONS =
7
+ typeof __MFEFLOW_SINGLETONS__ === 'undefined' ? ['react', 'react-dom'] : __MFEFLOW_SINGLETONS__;
8
+
9
+ // Remotes register their shared packages as they load, so the check repeats for a while.
10
+ const CHECK_EVERY_MS = 3000;
11
+ const STOP_AFTER_MS = 60_000;
12
+
13
+ declare global {
14
+ var mfeflowCheckSingletons: (() => ReturnType<typeof checkSingletons>) | undefined;
15
+ }
16
+
17
+ const reported = new Set<string>();
18
+
19
+ function check(): ReturnType<typeof checkSingletons> {
20
+ const result = checkSingletons(SINGLETONS);
21
+ // `missing` is not a problem: a shared package nothing has loaded yet is not in the share scope.
22
+ for (const name of result.duplicated) {
23
+ const problem = `${name} is loaded in more than one version`;
24
+ if (reported.has(problem)) continue;
25
+ reported.add(problem);
26
+ reportRemoteError('<%= it.app.name %>', 'singletons', new Error(problem));
27
+ }
28
+ return result;
29
+ }
30
+
31
+ // Loaded only in development: it reads every loaded remote's share scope.
32
+ globalThis.mfeflowCheckSingletons = check;
33
+ check();
34
+ const timer = setInterval(check, CHECK_EVERY_MS);
35
+ setTimeout(() => {
36
+ clearInterval(timer);
37
+ }, STOP_AFTER_MS);
@@ -3,6 +3,7 @@ import {
3
3
  applyDevOverrides,
4
4
  loadRegistryIndex,
5
5
  registerRemotesFromIndex,
6
+ registrySources,
6
7
  reportRemoteError,
7
8
  } from '@mfeflow/runtime';
8
9
  import { App } from './App';
@@ -12,13 +13,22 @@ const DEV = process.env.NODE_ENV !== 'production';
12
13
  export async function main(): Promise<void> {
13
14
  try {
14
15
  // Dev only: ?mfe-override=cart@http://localhost:4312/mf-manifest.json points a remote at your build.
15
- const index = applyDevOverrides(await loadRegistryIndex(), { enabled: DEV });
16
+ // runtime-config.json can set registryUrls (primary, then fallback) and registryOrigins for a CDN-hosted registry;
17
+ // it never holds up boot for more than 1.5 s, and is not fetched at all when the index is inlined.
18
+ const { urls, allowedOrigins: cdnOrigins } = await registrySources();
19
+ const index = applyDevOverrides(await loadRegistryIndex(urls, { allowedOrigins: cdnOrigins }), {
20
+ enabled: DEV,
21
+ });
16
22
  // In dev the registry points at the remotes' dev servers; elsewhere remotes share the shell's origin.
17
23
  const devOrigins = DEV ? index.remotes.map((remote) => new URL(remote.entry).origin) : [];
18
- registerRemotesFromIndex(index, { allowedOrigins: [location.origin, ...devOrigins] });
24
+ registerRemotesFromIndex(index, {
25
+ allowedOrigins: [location.origin, ...cdnOrigins, ...devOrigins],
26
+ });
19
27
  } catch (error) {
20
28
  reportRemoteError('<%= it.app.name %>', 'registry', error);
21
29
  }
22
30
  const el = document.getElementById('root');
23
31
  if (el) createRoot(el).render(<App />);
32
+ // Development only, so production builds carry nothing for it.
33
+ if (DEV) void import('./assert');
24
34
  }
package/dist/catalog.d.ts CHANGED
@@ -19,6 +19,10 @@ export interface FeatureSource {
19
19
  fetch?: FetchLike | undefined;
20
20
  /** The version to ask a registry for, when its URL template can pin one. */
21
21
  version?: string | undefined;
22
+ /** Namespaces the user trusts, so their registries may be on loopback or private addresses. */
23
+ trusted?: ReadonlySet<string> | undefined;
24
+ /** Compare the registry index's version with the feature.json's. */
25
+ checkIndex?: boolean | undefined;
22
26
  }
23
27
  /** A first-party feature by name, or `@namespace/name` from a configured registry. */
24
28
  export declare function loadAny(name: string, source: FeatureSource): Promise<LoadedFeature>;
@@ -1,9 +1,6 @@
1
+ import { comparable } from '@mfeflow/registry/static';
1
2
  import { type Check, type Finding } from '../findings.js';
2
- /**
3
- * The comparable version behind an installed version or a declared range. Undefined for a spec
4
- * that names no version (`link:`, `workspace:*`, `catalog:`, `latest`): it is only known after install.
5
- */
6
- export declare function comparable(version: string): string | undefined;
3
+ export { comparable };
7
4
  /** The warning for specs that cannot be compared before install. */
8
5
  export declare function unresolved(check: string, code: 'E301' | 'E302', name: string, specs: readonly string[]): Finding;
9
6
  export declare const singletonVersions: Check;
@@ -78,6 +78,10 @@ export declare const ADD_ARGS: {
78
78
  readonly description: 'add env-key: root, every shell or every remote, instead of --app';
79
79
  readonly valueHint: 'root|shell|remotes';
80
80
  };
81
+ readonly 'accept-changed-content': {
82
+ readonly type: 'boolean';
83
+ readonly description: 'Take a registry feature whose content differs from the hash recorded in mfeflow.json';
84
+ };
81
85
  };
82
86
  /** First-party features in the order `init` applies them, then the rest as typed: a feature may edit another's files. */
83
87
  export declare function inCatalogueOrder(names: readonly string[]): string[];
@@ -0,0 +1,227 @@
1
+ import type { DeployResult } from '../output.js';
2
+ import type { Runtime } from '../runtime.js';
3
+ export declare const DEPLOY_ARGS: {
4
+ readonly yes: {
5
+ readonly type: 'boolean';
6
+ readonly alias: 'y';
7
+ readonly description: 'Take the defaults and never prompt';
8
+ };
9
+ readonly preset: {
10
+ readonly type: 'string';
11
+ readonly description: 'Replay options from a JSON file or an https URL';
12
+ readonly valueHint: 'file|url';
13
+ };
14
+ readonly json: {
15
+ readonly type: 'boolean';
16
+ readonly description: 'Print one JSON document on stdout, nothing else';
17
+ };
18
+ readonly 'dry-run': {
19
+ readonly type: 'boolean';
20
+ readonly description: 'Print the summary and diff, write nothing';
21
+ };
22
+ readonly cwd: {
23
+ readonly type: 'string';
24
+ readonly description: 'Run as if started in this folder';
25
+ readonly valueHint: 'dir';
26
+ };
27
+ readonly install: {
28
+ readonly type: 'boolean';
29
+ readonly default: true;
30
+ readonly description: 'Run the package manager after writing (--no-install to skip)';
31
+ };
32
+ readonly verbose: {
33
+ readonly type: 'boolean';
34
+ readonly description: 'Show package manager output and stack traces';
35
+ };
36
+ readonly local: {
37
+ readonly type: 'string';
38
+ readonly description: 'Link @mfeflow/* from a built mfeflow checkout (env MFEFLOW_LOCAL)';
39
+ readonly valueHint: 'path';
40
+ };
41
+ readonly help: {
42
+ readonly type: 'boolean';
43
+ readonly alias: 'h';
44
+ readonly description: 'Show this help';
45
+ };
46
+ readonly host: {
47
+ readonly type: 'string';
48
+ readonly description: 'Where the registry lives: file:<dir> or s3://<bucket>[/prefix] (default registry.host)';
49
+ readonly valueHint: 'spec';
50
+ };
51
+ readonly 'base-url': {
52
+ readonly type: 'string';
53
+ readonly description: "Where the host's files are served from (default registry.baseUrl)";
54
+ readonly valueHint: 'url';
55
+ };
56
+ readonly 'shell-manifest': {
57
+ readonly type: 'string';
58
+ readonly description: "The shell's deployed mf-manifest.json (default envs/<env>/shell/ on the host)";
59
+ readonly valueHint: 'file';
60
+ };
61
+ readonly env: {
62
+ readonly type: 'string';
63
+ readonly description: 'Environment to deploy to';
64
+ readonly valueHint: 'env';
65
+ };
66
+ readonly version: {
67
+ readonly type: 'string';
68
+ readonly description: "Version to publish (default: the remote's package.json version)";
69
+ readonly valueHint: 'v';
70
+ };
71
+ readonly dist: {
72
+ readonly type: 'string';
73
+ readonly description: 'Build output folder inside the remote (default dist)';
74
+ readonly valueHint: 'dir';
75
+ };
76
+ readonly publish: {
77
+ readonly type: 'boolean';
78
+ readonly default: true;
79
+ readonly description: 'Move the index to the new version (--no-publish uploads the files and stops)';
80
+ };
81
+ };
82
+ export declare const PROMOTE_ARGS: {
83
+ readonly yes: {
84
+ readonly type: 'boolean';
85
+ readonly alias: 'y';
86
+ readonly description: 'Take the defaults and never prompt';
87
+ };
88
+ readonly preset: {
89
+ readonly type: 'string';
90
+ readonly description: 'Replay options from a JSON file or an https URL';
91
+ readonly valueHint: 'file|url';
92
+ };
93
+ readonly json: {
94
+ readonly type: 'boolean';
95
+ readonly description: 'Print one JSON document on stdout, nothing else';
96
+ };
97
+ readonly 'dry-run': {
98
+ readonly type: 'boolean';
99
+ readonly description: 'Print the summary and diff, write nothing';
100
+ };
101
+ readonly cwd: {
102
+ readonly type: 'string';
103
+ readonly description: 'Run as if started in this folder';
104
+ readonly valueHint: 'dir';
105
+ };
106
+ readonly install: {
107
+ readonly type: 'boolean';
108
+ readonly default: true;
109
+ readonly description: 'Run the package manager after writing (--no-install to skip)';
110
+ };
111
+ readonly verbose: {
112
+ readonly type: 'boolean';
113
+ readonly description: 'Show package manager output and stack traces';
114
+ };
115
+ readonly local: {
116
+ readonly type: 'string';
117
+ readonly description: 'Link @mfeflow/* from a built mfeflow checkout (env MFEFLOW_LOCAL)';
118
+ readonly valueHint: 'path';
119
+ };
120
+ readonly help: {
121
+ readonly type: 'boolean';
122
+ readonly alias: 'h';
123
+ readonly description: 'Show this help';
124
+ };
125
+ readonly host: {
126
+ readonly type: 'string';
127
+ readonly description: 'Where the registry lives: file:<dir> or s3://<bucket>[/prefix] (default registry.host)';
128
+ readonly valueHint: 'spec';
129
+ };
130
+ readonly 'base-url': {
131
+ readonly type: 'string';
132
+ readonly description: "Where the host's files are served from (default registry.baseUrl)";
133
+ readonly valueHint: 'url';
134
+ };
135
+ readonly 'shell-manifest': {
136
+ readonly type: 'string';
137
+ readonly description: "The shell's deployed mf-manifest.json (default envs/<env>/shell/ on the host)";
138
+ readonly valueHint: 'file';
139
+ };
140
+ readonly from: {
141
+ readonly type: 'string';
142
+ readonly description: 'Environment to copy the version from';
143
+ readonly valueHint: 'env';
144
+ };
145
+ readonly to: {
146
+ readonly type: 'string';
147
+ readonly description: 'Environment to point at it';
148
+ readonly valueHint: 'env';
149
+ };
150
+ };
151
+ export declare const ROLLBACK_ARGS: {
152
+ readonly yes: {
153
+ readonly type: 'boolean';
154
+ readonly alias: 'y';
155
+ readonly description: 'Take the defaults and never prompt';
156
+ };
157
+ readonly preset: {
158
+ readonly type: 'string';
159
+ readonly description: 'Replay options from a JSON file or an https URL';
160
+ readonly valueHint: 'file|url';
161
+ };
162
+ readonly json: {
163
+ readonly type: 'boolean';
164
+ readonly description: 'Print one JSON document on stdout, nothing else';
165
+ };
166
+ readonly 'dry-run': {
167
+ readonly type: 'boolean';
168
+ readonly description: 'Print the summary and diff, write nothing';
169
+ };
170
+ readonly cwd: {
171
+ readonly type: 'string';
172
+ readonly description: 'Run as if started in this folder';
173
+ readonly valueHint: 'dir';
174
+ };
175
+ readonly install: {
176
+ readonly type: 'boolean';
177
+ readonly default: true;
178
+ readonly description: 'Run the package manager after writing (--no-install to skip)';
179
+ };
180
+ readonly verbose: {
181
+ readonly type: 'boolean';
182
+ readonly description: 'Show package manager output and stack traces';
183
+ };
184
+ readonly local: {
185
+ readonly type: 'string';
186
+ readonly description: 'Link @mfeflow/* from a built mfeflow checkout (env MFEFLOW_LOCAL)';
187
+ readonly valueHint: 'path';
188
+ };
189
+ readonly help: {
190
+ readonly type: 'boolean';
191
+ readonly alias: 'h';
192
+ readonly description: 'Show this help';
193
+ };
194
+ readonly host: {
195
+ readonly type: 'string';
196
+ readonly description: 'Where the registry lives: file:<dir> or s3://<bucket>[/prefix] (default registry.host)';
197
+ readonly valueHint: 'spec';
198
+ };
199
+ readonly 'base-url': {
200
+ readonly type: 'string';
201
+ readonly description: "Where the host's files are served from (default registry.baseUrl)";
202
+ readonly valueHint: 'url';
203
+ };
204
+ readonly 'shell-manifest': {
205
+ readonly type: 'string';
206
+ readonly description: "The shell's deployed mf-manifest.json (default envs/<env>/shell/ on the host)";
207
+ readonly valueHint: 'file';
208
+ };
209
+ readonly env: {
210
+ readonly type: 'string';
211
+ readonly description: 'Environment to roll back';
212
+ readonly valueHint: 'env';
213
+ };
214
+ readonly to: {
215
+ readonly type: 'string';
216
+ readonly description: 'Version to go back to (default: the previous one)';
217
+ readonly valueHint: 'v';
218
+ };
219
+ readonly force: {
220
+ readonly type: 'boolean';
221
+ readonly description: 'Roll back even if the schema, route or compatibility checks fail (the files must still exist)';
222
+ };
223
+ };
224
+ export declare function formatDeploy(result: DeployResult): string;
225
+ export declare function runDeploy(rt: Runtime, args: Record<string, unknown>, raw: readonly string[]): Promise<DeployResult>;
226
+ export declare function runPromote(rt: Runtime, args: Record<string, unknown>, raw: readonly string[]): Promise<DeployResult>;
227
+ export declare function runRollback(rt: Runtime, args: Record<string, unknown>, raw: readonly string[]): Promise<DeployResult>;
@@ -46,8 +46,8 @@ export declare const FEATURES_ARGS: {
46
46
  readonly search: {
47
47
  readonly type: 'positional';
48
48
  readonly required: false;
49
- readonly description: 'Only features whose name or description contains this';
49
+ readonly description: 'Only features whose name, description or keywords contain this';
50
50
  };
51
51
  };
52
- export declare function matches(feature: FeatureInfo, search: string): boolean;
52
+ export declare function matches(feature: FeatureInfo, search: string, keywords?: string[]): boolean;
53
53
  export declare function runFeatures(rt: Runtime, args: Record<string, unknown>, raw: readonly string[]): Promise<FeaturesResult>;
@@ -0,0 +1,52 @@
1
+ import type { RegistryResult } from '../output.js';
2
+ import type { Runtime } from '../runtime.js';
3
+ export declare const REGISTRY_ARGS: {
4
+ readonly yes: {
5
+ readonly type: 'boolean';
6
+ readonly alias: 'y';
7
+ readonly description: 'Take the defaults and never prompt';
8
+ };
9
+ readonly preset: {
10
+ readonly type: 'string';
11
+ readonly description: 'Replay options from a JSON file or an https URL';
12
+ readonly valueHint: 'file|url';
13
+ };
14
+ readonly json: {
15
+ readonly type: 'boolean';
16
+ readonly description: 'Print one JSON document on stdout, nothing else';
17
+ };
18
+ readonly 'dry-run': {
19
+ readonly type: 'boolean';
20
+ readonly description: 'Print the summary and diff, write nothing';
21
+ };
22
+ readonly cwd: {
23
+ readonly type: 'string';
24
+ readonly description: 'Run as if started in this folder';
25
+ readonly valueHint: 'dir';
26
+ };
27
+ readonly install: {
28
+ readonly type: 'boolean';
29
+ readonly default: true;
30
+ readonly description: 'Run the package manager after writing (--no-install to skip)';
31
+ };
32
+ readonly verbose: {
33
+ readonly type: 'boolean';
34
+ readonly description: 'Show package manager output and stack traces';
35
+ };
36
+ readonly local: {
37
+ readonly type: 'string';
38
+ readonly description: 'Link @mfeflow/* from a built mfeflow checkout (env MFEFLOW_LOCAL)';
39
+ readonly valueHint: 'path';
40
+ };
41
+ readonly help: {
42
+ readonly type: 'boolean';
43
+ readonly alias: 'h';
44
+ readonly description: 'Show this help';
45
+ };
46
+ readonly out: {
47
+ readonly type: 'string';
48
+ readonly description: 'registry build: the folder to write (default: <dir>/dist)';
49
+ readonly valueHint: 'dir';
50
+ };
51
+ };
52
+ export declare function runRegistry(rt: Runtime, args: Record<string, unknown>, raw: readonly string[]): Promise<RegistryResult>;
@@ -0,0 +1,58 @@
1
+ import type { StatusResult } from '../output.js';
2
+ import type { Runtime } from '../runtime.js';
3
+ export declare const STATUS_ARGS: {
4
+ readonly yes: {
5
+ readonly type: 'boolean';
6
+ readonly alias: 'y';
7
+ readonly description: 'Take the defaults and never prompt';
8
+ };
9
+ readonly preset: {
10
+ readonly type: 'string';
11
+ readonly description: 'Replay options from a JSON file or an https URL';
12
+ readonly valueHint: 'file|url';
13
+ };
14
+ readonly json: {
15
+ readonly type: 'boolean';
16
+ readonly description: 'Print one JSON document on stdout, nothing else';
17
+ };
18
+ readonly 'dry-run': {
19
+ readonly type: 'boolean';
20
+ readonly description: 'Print the summary and diff, write nothing';
21
+ };
22
+ readonly cwd: {
23
+ readonly type: 'string';
24
+ readonly description: 'Run as if started in this folder';
25
+ readonly valueHint: 'dir';
26
+ };
27
+ readonly install: {
28
+ readonly type: 'boolean';
29
+ readonly default: true;
30
+ readonly description: 'Run the package manager after writing (--no-install to skip)';
31
+ };
32
+ readonly verbose: {
33
+ readonly type: 'boolean';
34
+ readonly description: 'Show package manager output and stack traces';
35
+ };
36
+ readonly local: {
37
+ readonly type: 'string';
38
+ readonly description: 'Link @mfeflow/* from a built mfeflow checkout (env MFEFLOW_LOCAL)';
39
+ readonly valueHint: 'path';
40
+ };
41
+ readonly help: {
42
+ readonly type: 'boolean';
43
+ readonly alias: 'h';
44
+ readonly description: 'Show this help';
45
+ };
46
+ readonly env: {
47
+ readonly type: 'string';
48
+ readonly description: 'Only this environment (default: every env on the host, and every folder in registry/envs but dev)';
49
+ readonly valueHint: 'env';
50
+ };
51
+ readonly host: {
52
+ readonly type: 'string';
53
+ readonly description: 'Where the registry lives: file:<dir> or s3://<bucket>[/prefix] (default registry.host)';
54
+ readonly valueHint: 'spec';
55
+ };
56
+ };
57
+ export declare function formatStatus(result: StatusResult): string;
58
+ export declare function runStatus(rt: Runtime, args: Record<string, unknown>, raw: readonly string[]): Promise<StatusResult>;