@mfeflow/contracts 0.0.0-stage → 0.1.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/LICENSE +21 -0
- package/README.md +14 -2
- package/dist/cost-model.d.ts +48 -0
- package/dist/docs.d.ts +13 -0
- package/dist/entry.d.ts +11 -0
- package/dist/entry.js +38 -0
- package/dist/feature.d.ts +173 -0
- package/dist/html-injection.d.ts +39 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +1417 -0
- package/dist/json-schema.d.ts +9 -0
- package/dist/manifest-assets.d.ts +38 -0
- package/dist/mfe-manifest.d.ts +42 -0
- package/dist/project.d.ts +46 -0
- package/dist/registry.d.ts +49 -0
- package/dist/validate.d.ts +32 -0
- package/package.json +58 -3
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type SchemaName } from './docs.js';
|
|
2
|
+
type Json = Record<string, unknown>;
|
|
3
|
+
/**
|
|
4
|
+
* Editor schemas for the five JSON documents mfeflow reads. They mirror the validators in this package; the
|
|
5
|
+
* validators stay the authority (they also check things a schema cannot, like duplicate routes), so a document
|
|
6
|
+
* can pass here and still fail `mfeflow validate`.
|
|
7
|
+
*/
|
|
8
|
+
export declare const JSON_SCHEMAS: Record<SchemaName, Json>;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/** What the registry needs from a built remote's `mf-manifest.json`. */
|
|
2
|
+
export interface RemoteAssets {
|
|
3
|
+
/** Absolute URL of the remote's entry script. Absent when `manifestOnly` is set. */
|
|
4
|
+
remoteEntry?: string;
|
|
5
|
+
/** Per expose (`./App`), URLs of the JS and CSS files it loads before it renders. Empty when `manifestOnly` is set. */
|
|
6
|
+
exposes: Record<string, string[]>;
|
|
7
|
+
/**
|
|
8
|
+
* Why the files' URLs cannot be known at publish time (`metaData.getPublicPath`
|
|
9
|
+
* computes them in the browser, or a relative `publicPath` resolves against a
|
|
10
|
+
* page URL that was not given). Keep such a remote manifest-only: publish its
|
|
11
|
+
* manifest URL, not a `remoteEntry`.
|
|
12
|
+
*/
|
|
13
|
+
manifestOnly?: string;
|
|
14
|
+
/** How the entry script is loaded (`module` for ESM). Absent when the manifest does not say. */
|
|
15
|
+
type?: string;
|
|
16
|
+
/** The global the entry script defines, when the manifest names one. */
|
|
17
|
+
entryGlobalName?: string;
|
|
18
|
+
}
|
|
19
|
+
export interface AssetsOptions {
|
|
20
|
+
/**
|
|
21
|
+
* The shell page the remote loads into. Module Federation joins a relative or
|
|
22
|
+
* root-relative `publicPath` as `${publicPath}${file}` and the browser
|
|
23
|
+
* resolves that against the page, so it is needed to know those URLs here.
|
|
24
|
+
*/
|
|
25
|
+
pageUrl?: string;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Reads the entry script and each expose's synchronous files out of a Module
|
|
29
|
+
* Federation `mf-manifest.json`, resolved against where it is served from
|
|
30
|
+
* (`manifestUrl`) for an `auto` `publicPath`, and joined to the `publicPath`
|
|
31
|
+
* otherwise (a relative one against `options.pageUrl`). With
|
|
32
|
+
* `metaData.getPublicPath`, or a relative `publicPath` and no `pageUrl`, the
|
|
33
|
+
* URLs cannot be known here: the result has `manifestOnly` set and no
|
|
34
|
+
* `remoteEntry`. Every URL returned is absolute. Run at
|
|
35
|
+
* publish or build time; the browser never parses a manifest. Throws on a
|
|
36
|
+
* manifest without an entry.
|
|
37
|
+
*/
|
|
38
|
+
export declare function assetsFromManifest(manifest: unknown, manifestUrl: string, options?: AssetsOptions): RemoteAssets;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { type Issue } from './validate.js';
|
|
2
|
+
/** `mfe.json`: who owns a micro-frontend and what it promises. */
|
|
3
|
+
export interface MfeManifest {
|
|
4
|
+
$schema?: string;
|
|
5
|
+
/** Module Federation name: lowercase letters, digits, `_`. */
|
|
6
|
+
name: string;
|
|
7
|
+
/** Owning team, e.g. `team-payments`. Alerts route here. */
|
|
8
|
+
owner: string;
|
|
9
|
+
/** Slack channel, email or URL. */
|
|
10
|
+
contact?: string;
|
|
11
|
+
/** Shells this remote runs in. Empty for a shell's own manifest. */
|
|
12
|
+
shells: string[];
|
|
13
|
+
/** Routes the remote claims, e.g. `/cart` or `/checkout/*`. */
|
|
14
|
+
routes: string[];
|
|
15
|
+
/** Exposed modules, e.g. `./App`. */
|
|
16
|
+
exposes: string[];
|
|
17
|
+
events?: {
|
|
18
|
+
publishes: string[];
|
|
19
|
+
consumes: string[];
|
|
20
|
+
};
|
|
21
|
+
analyticsEvents?: string[];
|
|
22
|
+
budgets?: {
|
|
23
|
+
initialJsKb?: number;
|
|
24
|
+
lcpMs?: number;
|
|
25
|
+
};
|
|
26
|
+
/** Platform package ranges, e.g. `{ "react": "^19", "@mfeflow/runtime": "^0.2" }`. */
|
|
27
|
+
platform?: Record<string, string>;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Lowercase words of letters and digits, joined by single underscores. A name never ends
|
|
31
|
+
* in `_` and `_` is never followed by a digit, so `cart_` and `cart`, or `a__b` and `a_b`,
|
|
32
|
+
* cannot become the same component or global name.
|
|
33
|
+
*/
|
|
34
|
+
export declare const MFE_NAME: RegExp;
|
|
35
|
+
export declare const ROUTE: RegExp;
|
|
36
|
+
export declare const EXPOSE: RegExp;
|
|
37
|
+
/** `<domain>.<event>@<major>`, e.g. `cart.item_added@1`. */
|
|
38
|
+
export declare const EVENT_NAME: RegExp;
|
|
39
|
+
/** `<domain>_<object>_<action>`, e.g. `checkout_order_completed`. */
|
|
40
|
+
export declare const ANALYTICS_EVENT: RegExp;
|
|
41
|
+
export declare function validateMfeManifest(value: unknown): Issue[];
|
|
42
|
+
export declare function isMfeManifest(value: unknown): value is MfeManifest;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { type Issue } from './validate.js';
|
|
2
|
+
/** `mfeflow.json`: the CLI's record of a project. */
|
|
3
|
+
export interface MfeflowProject {
|
|
4
|
+
$schema?: string;
|
|
5
|
+
version: 1;
|
|
6
|
+
topology: 'monorepo' | 'polyrepo' | 'hybrid';
|
|
7
|
+
packageManager: 'pnpm' | 'npm';
|
|
8
|
+
/** npm scope for the project's own packages, e.g. `@shopco`. */
|
|
9
|
+
scope: string;
|
|
10
|
+
apps: Record<string, {
|
|
11
|
+
kind: 'shell' | 'remote';
|
|
12
|
+
path: string;
|
|
13
|
+
port?: number;
|
|
14
|
+
}>;
|
|
15
|
+
features: Record<string, {
|
|
16
|
+
version: string;
|
|
17
|
+
options?: Record<string, unknown>;
|
|
18
|
+
}>;
|
|
19
|
+
/** Hashes of copied files, so `upgrade` can tell when a file was edited. */
|
|
20
|
+
files?: Record<string, string>;
|
|
21
|
+
/** Third-party feature registries: `{ "@someone": "https://…/{name}.json" }`. `@mfeflow` is reserved. */
|
|
22
|
+
registries?: Record<string, string>;
|
|
23
|
+
/** Built mfeflow checkout, relative to the project root, that `@mfeflow/*` dependencies link to. Set by `--local` only. */
|
|
24
|
+
local?: string;
|
|
25
|
+
/** Overrides of the cost-model budget `mfeflow budget` and the perf job check. */
|
|
26
|
+
budget?: ProjectBudget;
|
|
27
|
+
}
|
|
28
|
+
export interface ProjectBudget {
|
|
29
|
+
/** JS the shell may add over a one-app build, in KB. Default 32. */
|
|
30
|
+
shellKb?: number;
|
|
31
|
+
/** JS each remote on a route may add, in KB. Default 10. */
|
|
32
|
+
remoteKb?: number;
|
|
33
|
+
/** LCP the shell may add, in ms. Measured by the perf job, not by `mfeflow budget`. Default 300. */
|
|
34
|
+
lcpDeltaMs?: number;
|
|
35
|
+
/** Initial JS of your pages built as one app, in KB. Turns on the shell check in `mfeflow budget`. */
|
|
36
|
+
baselineKb?: number;
|
|
37
|
+
}
|
|
38
|
+
/** The regex form of `isCheckoutPath`, for JSON Schema. */
|
|
39
|
+
export declare const CHECKOUT_PATH: RegExp;
|
|
40
|
+
export declare const FILE_HASH: RegExp;
|
|
41
|
+
export declare const REGISTRY_NAMESPACE: RegExp;
|
|
42
|
+
/** A relative path with forward slashes whose only `..` segments come first, so it may leave the project. */
|
|
43
|
+
export declare function isCheckoutPath(value: string): boolean;
|
|
44
|
+
export declare const SCOPE: RegExp;
|
|
45
|
+
export declare function validateMfeflowProject(value: unknown): Issue[];
|
|
46
|
+
export declare function isMfeflowProject(value: unknown): value is MfeflowProject;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { type Issue } from './validate.js';
|
|
2
|
+
/** `registry/envs/<env>/<name>.json`: what one remote serves in one environment. */
|
|
3
|
+
export interface RegistryEntry {
|
|
4
|
+
version: string;
|
|
5
|
+
manifestUrl: string;
|
|
6
|
+
/** The remote's entry script, read from `mf-manifest.json` at publish time. Production shells register this, not the manifest. */
|
|
7
|
+
remoteEntry?: string;
|
|
8
|
+
/** How `remoteEntry` loads (`module` for ESM). Needed by shells that register it directly. */
|
|
9
|
+
type?: string;
|
|
10
|
+
/** The global `remoteEntry` defines when it differs from the remote's name. */
|
|
11
|
+
entryGlobalName?: string;
|
|
12
|
+
/** Per expose (`./App`), the JS and CSS files it needs before it renders. The edge turns these into preload hints. */
|
|
13
|
+
exposes?: Record<string, string[]>;
|
|
14
|
+
previous?: string;
|
|
15
|
+
owner?: string;
|
|
16
|
+
rollout?: {
|
|
17
|
+
candidate: string;
|
|
18
|
+
stable: string;
|
|
19
|
+
percent: number;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
/** What the shell fetches at boot. */
|
|
23
|
+
export interface RegistryIndex {
|
|
24
|
+
shell?: string;
|
|
25
|
+
env?: string;
|
|
26
|
+
generatedAt?: string;
|
|
27
|
+
remotes: RegistryIndexRemote[];
|
|
28
|
+
}
|
|
29
|
+
export interface RegistryIndexRemote {
|
|
30
|
+
name: string;
|
|
31
|
+
/** `mf-manifest.json` URL. */
|
|
32
|
+
entry: string;
|
|
33
|
+
/** Entry script URL; shells register it in place of `entry` when present. */
|
|
34
|
+
remoteEntry?: string;
|
|
35
|
+
/** How `remoteEntry` loads (`module` for ESM). */
|
|
36
|
+
type?: string;
|
|
37
|
+
/** The global `remoteEntry` defines when it differs from `name`. */
|
|
38
|
+
entryGlobalName?: string;
|
|
39
|
+
/** Per expose, the files to preload. Not inlined into the shell's HTML. */
|
|
40
|
+
exposes?: Record<string, string[]>;
|
|
41
|
+
version?: string;
|
|
42
|
+
routes?: string[];
|
|
43
|
+
owner?: string;
|
|
44
|
+
}
|
|
45
|
+
export declare const VERSION: RegExp;
|
|
46
|
+
export declare function validateRegistryEntry(value: unknown): Issue[];
|
|
47
|
+
export declare function validateRegistryIndex(value: unknown): Issue[];
|
|
48
|
+
export declare function isRegistryEntry(value: unknown): value is RegistryEntry;
|
|
49
|
+
export declare function isRegistryIndex(value: unknown): value is RegistryIndex;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export interface Issue {
|
|
2
|
+
/** Where, e.g. `routes[0]` or `rollout.percent`. Empty for the root. */
|
|
3
|
+
path: string;
|
|
4
|
+
message: string;
|
|
5
|
+
}
|
|
6
|
+
export type Obj = Record<string, unknown>;
|
|
7
|
+
export declare function isObj(value: unknown): value is Obj;
|
|
8
|
+
export declare class Checker {
|
|
9
|
+
readonly issues: Issue[];
|
|
10
|
+
add(path: string, message: string): void;
|
|
11
|
+
/** Reports a missing or wrong-typed string and returns it when valid. */
|
|
12
|
+
string(obj: Obj, key: string, path: string, opts?: {
|
|
13
|
+
required?: boolean;
|
|
14
|
+
pattern?: RegExp;
|
|
15
|
+
hint?: string;
|
|
16
|
+
}): string | undefined;
|
|
17
|
+
stringArray(obj: Obj, key: string, path: string, opts?: {
|
|
18
|
+
required?: boolean;
|
|
19
|
+
pattern?: RegExp;
|
|
20
|
+
hint?: string;
|
|
21
|
+
}): string[];
|
|
22
|
+
number(obj: Obj, key: string, path: string, opts?: {
|
|
23
|
+
required?: boolean;
|
|
24
|
+
min?: number;
|
|
25
|
+
max?: number;
|
|
26
|
+
}): number | undefined;
|
|
27
|
+
object(obj: Obj, key: string, path: string, required?: boolean): Obj | undefined;
|
|
28
|
+
}
|
|
29
|
+
export declare function isUrl(value: string): boolean;
|
|
30
|
+
/** The regex form of `isSafeRelativePath`, for JSON Schema. */
|
|
31
|
+
export declare const SAFE_RELATIVE_PATH: RegExp;
|
|
32
|
+
export declare function isSafeRelativePath(value: string): boolean;
|
package/package.json
CHANGED
|
@@ -1,6 +1,61 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mfeflow/contracts",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Types, validators and JSON Schemas for mfeflow: mfe.json ownership manifests, mfeflow.json project state, and the remote registry (entries and index).",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"micro-frontend",
|
|
7
|
+
"mfe",
|
|
8
|
+
"module-federation",
|
|
9
|
+
"json-schema",
|
|
10
|
+
"manifest",
|
|
11
|
+
"registry",
|
|
12
|
+
"validation",
|
|
13
|
+
"react",
|
|
14
|
+
"rsbuild"
|
|
15
|
+
],
|
|
16
|
+
"homepage": "https://mfeflow.github.io/mfeflow/",
|
|
17
|
+
"bugs": "https://github.com/mfeflow/mfeflow/issues",
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "git+https://github.com/mfeflow/mfeflow.git",
|
|
21
|
+
"directory": "packages/contracts"
|
|
22
|
+
},
|
|
23
|
+
"license": "MIT",
|
|
24
|
+
"author": "Sanjeev Sharma <speedsharma.ai@gmail.com>",
|
|
25
|
+
"type": "module",
|
|
26
|
+
"exports": {
|
|
27
|
+
".": {
|
|
28
|
+
"types": "./dist/index.d.ts",
|
|
29
|
+
"import": "./dist/index.js",
|
|
30
|
+
"default": "./dist/index.js"
|
|
31
|
+
},
|
|
32
|
+
"./entry": {
|
|
33
|
+
"types": "./dist/entry.d.ts",
|
|
34
|
+
"import": "./dist/entry.js",
|
|
35
|
+
"default": "./dist/entry.js"
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
"files": [
|
|
39
|
+
"dist"
|
|
40
|
+
],
|
|
41
|
+
"engines": {
|
|
42
|
+
"node": ">=22.12"
|
|
43
|
+
},
|
|
44
|
+
"publishConfig": {
|
|
45
|
+
"access": "public",
|
|
46
|
+
"provenance": true
|
|
47
|
+
},
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"@rslib/core": "1.0.5",
|
|
50
|
+
"@types/node": "26.6.6",
|
|
51
|
+
"typescript": "7.0.2"
|
|
52
|
+
},
|
|
53
|
+
"sideEffects": false,
|
|
54
|
+
"mfeflow": {
|
|
55
|
+
"bucket": "stateless"
|
|
56
|
+
},
|
|
57
|
+
"scripts": {
|
|
58
|
+
"build": "rslib build",
|
|
59
|
+
"typecheck": "tsc --noEmit"
|
|
60
|
+
}
|
|
6
61
|
}
|