@appshell/runtime 1.0.0-alpha.15
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 +54 -0
- package/dist/main.js +1 -0
- package/dist/types/errors.d.ts +26 -0
- package/dist/types/errors.d.ts.map +1 -0
- package/dist/types/index.d.ts +4 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/store.d.ts +26 -0
- package/dist/types/store.d.ts.map +1 -0
- package/dist/types/types.d.ts +10 -0
- package/dist/types/types.d.ts.map +1 -0
- package/package.json +33 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023 Navaris Technologies, LLC
|
|
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
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# @appshell/runtime
|
|
2
|
+
|
|
3
|
+
The store that delivers a package's runtime configuration (`vars`) to it.
|
|
4
|
+
|
|
5
|
+
This is a **shared singleton**. There is exactly one instance per page, held in the
|
|
6
|
+
module federation share scope, and both the host and every package must declare it as
|
|
7
|
+
such. It replaced `window.__appshell_vars__<scope>`.
|
|
8
|
+
|
|
9
|
+
Most packages should not import this directly — use
|
|
10
|
+
[`@appshell/vars`](../vars/README.md), which supplies the scope for you.
|
|
11
|
+
|
|
12
|
+
## Contract
|
|
13
|
+
|
|
14
|
+
```ts
|
|
15
|
+
setVars(scope, vars); // the host, immediately before loading a remote
|
|
16
|
+
readVars(scope); // a package, reading its own configuration
|
|
17
|
+
hasVars(scope); // branch instead of catch
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
`@appshell/loader` calls `setVars` before it loads a remote, so a package's vars are in
|
|
21
|
+
place before its modules evaluate — including a read at module-eval time.
|
|
22
|
+
|
|
23
|
+
The first write for a scope wins and is frozen. Re-delivering the identical vars is a
|
|
24
|
+
no-op, because the same remote can be mounted more than once; replacing them throws
|
|
25
|
+
`VarsConflictError`.
|
|
26
|
+
|
|
27
|
+
`readVars` throws `MissingVarsError` rather than returning an empty object. A package
|
|
28
|
+
that silently renders with no configuration is the failure this replaced.
|
|
29
|
+
|
|
30
|
+
## What this does and does not fix
|
|
31
|
+
|
|
32
|
+
Against the global it replaced, it fixes: unbounded, never-cleaned-up keys; silent
|
|
33
|
+
cross-package overwrite; the load-order coupling between host and remote; and being
|
|
34
|
+
untyped and undiscoverable.
|
|
35
|
+
|
|
36
|
+
It **does not make a scope's vars private.** Any code on the page can call
|
|
37
|
+
`readVars('SomeOtherScope')`, and a package that loads early can squat on a scope that
|
|
38
|
+
has not been delivered yet. Nothing short of a separate realm — an iframe, a worker —
|
|
39
|
+
would change that, and none of this is a security boundary. Do not put a secret in
|
|
40
|
+
`vars`; the registry serves them to the browser in the composition either way.
|
|
41
|
+
|
|
42
|
+
## Setup
|
|
43
|
+
|
|
44
|
+
Both sides declare it, or each ends up with its own empty store:
|
|
45
|
+
|
|
46
|
+
```js
|
|
47
|
+
new ModuleFederationPlugin({
|
|
48
|
+
shared: {
|
|
49
|
+
'@appshell/runtime': { singleton: true },
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
`AppshellPlugin` fails the build when a package omits it.
|
package/dist/main.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
!function(e,r){if("object"==typeof exports&&"object"==typeof module)module.exports=r();else if("function"==typeof define&&define.amd)define([],r);else{var t=r();for(var s in t)("object"==typeof exports?exports:e)[s]=t[s]}}(self,(()=>(()=>{"use strict";var e={d:(r,t)=>{for(var s in t)e.o(t,s)&&!e.o(r,s)&&Object.defineProperty(r,s,{enumerable:!0,get:t[s]})},o:(e,r)=>Object.prototype.hasOwnProperty.call(e,r),r:e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})}},r={};e.r(r),e.d(r,{MissingVarsError:()=>t,VarsConflictError:()=>s,hasVars:()=>i,readVars:()=>n,resetVars:()=>c,setVars:()=>a});class t extends Error{constructor(e,r){super(`No vars were delivered for '${e}'. ${r.length?`Vars are present for ${r.map((e=>`'${e}'`)).join(", ")} — check that '${e}' matches the module federation name the registry knows this package by.`:"Nothing has delivered vars on this page — check that the host and this package both declare '@appshell/runtime' as a shared singleton."}`),this.name="MissingVarsError",this.scope=e}}class s extends Error{constructor(e){super(`Vars for '${e}' were already delivered and cannot be replaced. A scope receives its vars once per page load.`),this.name="VarsConflictError",this.scope=e}}const o=new Map,a=(e,r)=>{const t=o.get(e);var a,n;if(t){if(a=t,n=r,![...new Set([...Object.keys(a),...Object.keys(n)])].every((e=>a[e]===n[e])))throw new s(e)}else o.set(e,Object.freeze({...r}))},n=e=>{const r=o.get(e);if(!r)throw new t(e,[...o.keys()]);return r},i=e=>o.has(e),c=()=>{o.clear()};return r})()));
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A package asked for vars that were never delivered.
|
|
3
|
+
*
|
|
4
|
+
* Almost always one of three things: the package was loaded outside `remoteLoader`
|
|
5
|
+
* (a test, a storybook, a direct import), the host and the package resolved separate
|
|
6
|
+
* copies of `@appshell/runtime` because one of them failed to declare it as a
|
|
7
|
+
* singleton, or the scope compiled into the package is not the scope the registry
|
|
8
|
+
* knows it by.
|
|
9
|
+
*/
|
|
10
|
+
export declare class MissingVarsError extends Error {
|
|
11
|
+
readonly scope: string;
|
|
12
|
+
constructor(scope: string, known: string[]);
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Something tried to replace vars that were already delivered for a scope.
|
|
16
|
+
*
|
|
17
|
+
* The first write wins and is final. Within one page load a scope has exactly one
|
|
18
|
+
* vars object — both resolvers read it from the same `composition.vars[scope]` — so a
|
|
19
|
+
* differing second write is a bug or a package reaching for a scope that is not its own,
|
|
20
|
+
* and neither should be applied quietly.
|
|
21
|
+
*/
|
|
22
|
+
export declare class VarsConflictError extends Error {
|
|
23
|
+
readonly scope: string;
|
|
24
|
+
constructor(scope: string);
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/errors.ts"],"names":[],"mappings":"AACA;;;;;;;;GAQG;AACH,qBAAa,gBAAiB,SAAQ,KAAK;IACzC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;gBAEX,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE;CAc3C;AAED;;;;;;;GAOG;AACH,qBAAa,iBAAkB,SAAQ,KAAK;IAC1C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;gBAEX,KAAK,EAAE,MAAM;CAS1B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAC/D,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAChE,YAAY,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { Vars } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Delivers a scope's vars. Called by `@appshell/loader` immediately before the remote
|
|
4
|
+
* is loaded, so they are in place before the package's modules evaluate.
|
|
5
|
+
*
|
|
6
|
+
* The first write for a scope wins and is frozen. Re-delivering the identical vars is a
|
|
7
|
+
* no-op — the same remote can be mounted more than once — but replacing them throws.
|
|
8
|
+
* That is what keeps one package from overwriting another's: by the time any package
|
|
9
|
+
* evaluates, the host has already written for it.
|
|
10
|
+
*
|
|
11
|
+
* It does not make a scope's vars *private*. Any code on the page can still read another
|
|
12
|
+
* scope by name, and nothing short of a separate realm would change that.
|
|
13
|
+
*/
|
|
14
|
+
export declare const setVars: (scope: string, vars: Vars) => void;
|
|
15
|
+
/**
|
|
16
|
+
* Reads a scope's vars, throwing rather than handing back an empty object — a package
|
|
17
|
+
* that silently renders with no configuration is the failure this replaced.
|
|
18
|
+
*
|
|
19
|
+
* Prefer `getVars()` from `@appshell/vars`, which supplies the scope for you.
|
|
20
|
+
*/
|
|
21
|
+
export declare const readVars: <TVars extends Vars = Vars>(scope: string) => TVars;
|
|
22
|
+
/** Whether a scope has been delivered, for callers that want to branch instead of catch. */
|
|
23
|
+
export declare const hasVars: (scope: string) => boolean;
|
|
24
|
+
/** Test seam. Not part of the contract a package should build on. */
|
|
25
|
+
export declare const resetVars: () => void;
|
|
26
|
+
//# sourceMappingURL=store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/store.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAepC;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,OAAO,UAAW,MAAM,QAAQ,IAAI,KAAG,IAYnD,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,QAAQ,GAAI,KAAK,SAAS,IAAI,gBAAgB,MAAM,KAAG,KAQnE,CAAC;AAEF,4FAA4F;AAC5F,eAAO,MAAM,OAAO,UAAW,MAAM,KAAG,OAA+B,CAAC;AAExE,qEAAqE;AACrE,eAAO,MAAM,SAAS,QAAO,IAE5B,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A package's runtime configuration, already merged by the registry — a package's
|
|
3
|
+
* declared vars, then the application's `overrides.vars`.
|
|
4
|
+
*
|
|
5
|
+
* Structurally identical to `AppshellComposition['vars'][scope]` in `@appshell/config`,
|
|
6
|
+
* but declared here rather than imported. This package is a shared singleton loaded
|
|
7
|
+
* into every micro-frontend on the page, so it carries no dependencies at all.
|
|
8
|
+
*/
|
|
9
|
+
export type Vars = Record<string, string | number | undefined>;
|
|
10
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,MAAM,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@appshell/runtime",
|
|
3
|
+
"version": "1.0.0-alpha.15",
|
|
4
|
+
"description": "The shared singleton that delivers a package's runtime configuration to it",
|
|
5
|
+
"main": "dist/main.js",
|
|
6
|
+
"types": "dist/types/index.d.ts",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/appshellhq/appshell.git"
|
|
10
|
+
},
|
|
11
|
+
"author": "Robert Hamilton <rh@navaris.com>",
|
|
12
|
+
"publishConfig": {
|
|
13
|
+
"access": "public",
|
|
14
|
+
"registry": "https://registry.npmjs.org/"
|
|
15
|
+
},
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "webpack --mode production && npm run build:types",
|
|
18
|
+
"build:types": "tsc --emitDeclarationOnly",
|
|
19
|
+
"clean": "rm -rf dist",
|
|
20
|
+
"prebuild": "npm run clean",
|
|
21
|
+
"start": "webpack --watch --mode development && npm run build:types",
|
|
22
|
+
"stats": "webpack --json > stats.json"
|
|
23
|
+
},
|
|
24
|
+
"files": [
|
|
25
|
+
"dist"
|
|
26
|
+
],
|
|
27
|
+
"keywords": [
|
|
28
|
+
"module federation",
|
|
29
|
+
"micro-frontends",
|
|
30
|
+
"appshell"
|
|
31
|
+
],
|
|
32
|
+
"license": "MIT"
|
|
33
|
+
}
|