@softarc/native-federation-orchestrator 4.6.1 → 4.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 +2 -2
- package/fesm2022/@softarc/native-federation-orchestrator.mjs +1880 -1281
- package/fesm2022/@softarc/native-federation-orchestrator.mjs.map +4 -4
- package/fesm2022/audit.mjs +1 -1
- package/fesm2022/audit.mjs.map +2 -2
- package/fesm2022/module-federation.mjs +199 -32
- package/fesm2022/module-federation.mjs.map +3 -3
- package/fesm2022/node.mjs +1867 -1257
- package/fesm2022/node.mjs.map +4 -4
- package/fesm2022/options.mjs +7 -3
- package/fesm2022/options.mjs.map +2 -2
- package/fesm2022/registry.mjs +1 -1
- package/fesm2022/registry.mjs.map +2 -2
- package/fesm2022/sdk.mjs +1 -1
- package/fesm2022/sdk.mjs.map +2 -2
- package/init-registry.mjs +1 -1
- package/node-loader/loader.mjs +7 -4
- package/node-loader/loader.mjs.map +2 -2
- package/package.json +9 -1
- package/quickstart.mjs +14 -15
- package/types/lib/core/1.domain/externals/basis.d.ts +2 -15
- package/types/lib/core/1.domain/externals/claims.d.ts +22 -0
- package/types/lib/core/1.domain/externals/compatibility.d.ts +9 -0
- package/types/lib/core/1.domain/externals/external.contract.d.ts +4 -0
- package/types/lib/core/1.domain/externals/rows.d.ts +9 -0
- package/types/lib/core/1.domain/externals/serving.d.ts +52 -0
- package/types/lib/core/1.domain/externals/specifier.d.ts +13 -0
- package/types/lib/core/1.domain/externals/version.contract.d.ts +2 -0
- package/types/lib/core/1.domain/pooling/builds.d.ts +20 -0
- package/types/lib/core/1.domain/pooling/election.d.ts +40 -0
- package/types/lib/core/1.domain/pooling/gate.d.ts +62 -0
- package/types/lib/core/1.domain/pooling/membership.d.ts +17 -0
- package/types/lib/core/1.domain/pooling/plan.d.ts +9 -0
- package/types/lib/core/1.domain/pooling/pool-state.d.ts +4 -0
- package/types/lib/core/1.domain/pooling/records.d.ts +16 -0
- package/types/lib/core/1.domain/pooling/rules.d.ts +6 -0
- package/types/lib/core/1.domain/remote-entry/load-actions.contract.d.ts +4 -0
- package/types/lib/core/1.domain/remote-entry/remote-entry.contract.d.ts +0 -2
- package/types/lib/core/2.app/config/index.d.ts +2 -1
- package/types/lib/core/2.app/config/mode.contract.d.ts +8 -5
- package/types/lib/core/2.app/config/orchestrator-global.contract.d.ts +15 -0
- package/types/lib/core/2.app/config/storage.contract.d.ts +19 -2
- package/types/lib/core/2.app/driver-ports/init/drivers.contract.d.ts +4 -2
- package/types/lib/core/2.app/driver-ports/init/for-committing-changes.port.d.ts +1 -0
- package/types/lib/core/2.app/driver-ports/init/for-deciding-serving-builds.port.d.ts +1 -0
- package/types/lib/core/2.app/driver-ports/init/for-determining-shared-externals.port.d.ts +1 -8
- package/types/lib/core/2.app/driver-ports/init/for-pooling-dynamic-externals.port.d.ts +2 -1
- package/types/lib/core/2.app/driver-ports/init/for-pooling-shared-externals.port.d.ts +1 -3
- package/types/lib/core/2.app/driver-ports/init/for-rolling-back-changes.port.d.ts +1 -0
- package/types/lib/core/2.app/driver-ports/init/for-updating-cache.d.ts +3 -2
- package/types/lib/core/2.app/driver-ports/init/index.d.ts +2 -0
- package/types/lib/core/2.app/driving-ports/for-remote-info-storage.port.d.ts +1 -0
- package/types/lib/core/2.app/driving-ports/for-scoped-externals-storage.port.d.ts +1 -0
- package/types/lib/core/2.app/driving-ports/for-shared-chunks-storage.port.d.ts +1 -0
- package/types/lib/core/2.app/driving-ports/for-shared-externals-storage.port.d.ts +5 -1
- package/types/lib/core/2.app/steps/apply-winner.d.ts +6 -13
- package/types/lib/core/2.app/steps/decide-serving-builds.d.ts +5 -0
- package/types/lib/core/2.app/steps/pooling/pool-shared-externals.d.ts +0 -29
- package/types/lib/core/2.app/steps/rollback-changes.d.ts +5 -0
- package/types/lib/core/2.app/steps/store-remote-entry.d.ts +2 -2
- package/types/lib/core/3.adapters/storage/cache-state.d.ts +5 -0
- package/types/lib/core/3.adapters/storage/chunk.repository.d.ts +1 -1
- package/types/lib/core/3.adapters/storage/remote-info.repository.d.ts +1 -1
- package/types/lib/core/3.adapters/storage/scoped-externals.repository.d.ts +1 -1
- package/types/lib/core/3.adapters/storage/shared-externals.repository.d.ts +1 -1
- package/types/lib/core/4.config/orchestrator-version.d.ts +1 -0
- package/types/lib/core/4.config/storage/publish-storage-info.d.ts +9 -0
- package/types/lib/core/4.config/storage/storage.config.d.ts +1 -1
- package/types/lib/core/5.di/federation-result.factory.d.ts +1 -1
- package/types/lib/sdk.index.d.ts +4 -0
- package/types/lib/utils/compare-strings.d.ts +2 -0
- package/types/lib/utils/deep-readonly.d.ts +3 -0
- package/types/lib/core/2.app/driver-ports/init/for-marking-pools-for-reelection.port.d.ts +0 -6
- package/types/lib/core/2.app/steps/pooling/anchoring.d.ts +0 -69
- package/types/lib/core/2.app/steps/pooling/mark-pools-for-reelection.d.ts +0 -5
- package/types/lib/core/2.app/steps/pooling/pool-graph.d.ts +0 -30
- package/types/lib/core/2.app/steps/pooling/pool-views.d.ts +0 -63
- package/types/lib/core/2.app/steps/pooling/pool.types.d.ts +0 -35
- package/types/lib/core/2.app/steps/pooling/pool.util.d.ts +0 -18
- package/types/lib/testing/handlers/log.handler.d.ts +0 -3
- package/types/lib/testing/pooling/no-tear.d.ts +0 -37
package/fesm2022/options.mjs
CHANGED
|
@@ -26,7 +26,7 @@ var noopLogger = {
|
|
|
26
26
|
// src/lib/core/native-federation.error.ts
|
|
27
27
|
var NFError = class extends Error {
|
|
28
28
|
constructor(message, cause) {
|
|
29
|
-
super(message, cause);
|
|
29
|
+
super(message, cause ? { cause } : void 0);
|
|
30
30
|
this.name = "NFError";
|
|
31
31
|
}
|
|
32
32
|
};
|
|
@@ -67,6 +67,8 @@ var globalThisStorageEntry = (namespace) => (key, initialValue) => {
|
|
|
67
67
|
};
|
|
68
68
|
return entry;
|
|
69
69
|
};
|
|
70
|
+
globalThisStorageEntry.type = "globalThis";
|
|
71
|
+
Object.freeze(globalThisStorageEntry);
|
|
70
72
|
|
|
71
73
|
// src/lib/core/4.config/storage/local.storage.ts
|
|
72
74
|
var localStorageEntry = (namespace) => (key, initialValue) => {
|
|
@@ -87,6 +89,8 @@ var localStorageEntry = (namespace) => (key, initialValue) => {
|
|
|
87
89
|
};
|
|
88
90
|
return entry;
|
|
89
91
|
};
|
|
92
|
+
localStorageEntry.type = "localStorage";
|
|
93
|
+
Object.freeze(localStorageEntry);
|
|
90
94
|
|
|
91
95
|
// src/lib/core/4.config/storage/session.storage.ts
|
|
92
96
|
var sessionStorageEntry = (namespace) => (key, initialValue) => {
|
|
@@ -107,6 +111,8 @@ var sessionStorageEntry = (namespace) => (key, initialValue) => {
|
|
|
107
111
|
};
|
|
108
112
|
return entry;
|
|
109
113
|
};
|
|
114
|
+
sessionStorageEntry.type = "sessionStorage";
|
|
115
|
+
Object.freeze(sessionStorageEntry);
|
|
110
116
|
|
|
111
117
|
// src/lib/core/4.config/import-map/trusted-types.ts
|
|
112
118
|
var IMPORT_MAP_KEYS = /* @__PURE__ */ new Set(["imports", "scopes", "integrity"]);
|
|
@@ -215,7 +221,6 @@ var useDefaultImportMap = (trustedTypesPolicyName = "nfo") => ({
|
|
|
215
221
|
var defaultProfile = {
|
|
216
222
|
latestSharedExternal: false,
|
|
217
223
|
skipInvalidExternalVersions: false,
|
|
218
|
-
scopeUncoveredEntrypoints: false,
|
|
219
224
|
overrideCachedRemotes: "init-only",
|
|
220
225
|
overrideCachedRemotesIfURLMatches: false
|
|
221
226
|
};
|
|
@@ -224,7 +229,6 @@ var defaultProfile = {
|
|
|
224
229
|
var cachingProfile = {
|
|
225
230
|
latestSharedExternal: false,
|
|
226
231
|
skipInvalidExternalVersions: false,
|
|
227
|
-
scopeUncoveredEntrypoints: false,
|
|
228
232
|
overrideCachedRemotes: "never",
|
|
229
233
|
overrideCachedRemotesIfURLMatches: false
|
|
230
234
|
};
|
package/fesm2022/options.mjs.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/lib/core/2.app/config/log.contract.ts", "../../src/lib/core/4.config/logging/console.logger.ts", "../../src/lib/core/4.config/logging/noop.logger.ts", "../../src/lib/core/native-federation.error.ts", "../../src/lib/utils/clone-entry.ts", "../../src/lib/core/4.config/storage/global-this.storage.ts", "../../src/lib/core/4.config/storage/local.storage.ts", "../../src/lib/core/4.config/storage/session.storage.ts", "../../src/lib/core/4.config/import-map/trusted-types.ts", "../../src/lib/core/4.config/import-map/replace-in-dom.ts", "../../src/lib/core/4.config/import-map/use-import-shim.ts", "../../src/lib/core/4.config/import-map/use-default.ts", "../../src/lib/core/4.config/mode/default.profile.ts", "../../src/lib/core/4.config/mode/caching.profile.ts"],
|
|
4
|
-
"sourcesContent": ["export const LogLevel = {\n debug: 0,\n warn: 1,\n error: 2,\n};\n\nexport type LogType = keyof typeof LogLevel;\n\nexport type Logger = {\n error: (step: number, msg: string, details?: unknown) => void;\n warn: (step: number, msg: string, details?: unknown) => void;\n debug: (step: number, msg: string, details?: unknown) => void;\n};\n\nexport type LogHandler = Logger & {\n level: LogType;\n};\n\nexport type LoggingConfig = {\n log: LogHandler;\n sse: boolean;\n};\n\nexport type LoggingOptions = {\n logger?: Logger;\n logLevel?: LogType;\n sse?: boolean;\n};\n", "import type { Logger } from 'lib/core/2.app/config/log.contract';\n\nconst consoleLogger: Logger = {\n /* eslint no-console: \"off\", curly: \"error\" */\n debug: (step: number, msg: string, err) =>\n !!err ? console.log(`[DEBUG][${step}]: ${msg}`, err) : console.log(`[DEBUG][${step}]: ${msg}`),\n error: (step: number, msg: string, err) =>\n !!err ? console.error(`[NF][${step}]: ${msg}`, err) : console.error(`[NF][${step}]: ${msg}`),\n warn: (step: number, msg: string, err) =>\n !!err ? console.warn(`[NF][${step}]: ${msg}`, err) : console.warn(`[NF][${step}]: ${msg}`),\n};\n\nexport { consoleLogger };\n", "import type { Logger } from 'lib/core/2.app/config/log.contract';\n\nconst noopLogger: Logger = {\n debug: () => {},\n error: () => {},\n warn: () => {},\n};\n\nexport { noopLogger };\n", "class NFError extends Error {\n constructor(message: string, cause?: Error) {\n super(message, cause);\n this.name = 'NFError';\n }\n}\n\nexport { NFError };\n", "import type { StorageEntryKey } from 'lib/core/2.app/config/storage.contract';\nimport { NFError } from 'lib/core/native-federation.error';\n\ntype CloneEntry = <T>(name: StorageEntryKey, raw: T) => T;\n\nconst cloneEntry: CloneEntry = <T>(name: StorageEntryKey, raw: T) => {\n try {\n if (typeof structuredClone === 'function') {\n return structuredClone(raw);\n }\n } catch {\n /* structured clone is unavailable */\n }\n try {\n return JSON.parse(JSON.stringify(raw));\n } catch {\n /* object is not stringifyable */\n }\n throw new NFError(`Could not clone entry '${String(name)}'`);\n};\n\nexport { CloneEntry, cloneEntry };\n", "import { cloneEntry } from 'lib/utils/clone-entry';\nimport {\n type StorageEntryCreator,\n type StorageEntry,\n} from 'lib/core/2.app/config/storage.contract';\n\nconst globalThisStorageEntry: StorageEntryCreator =\n (namespace: string) =>\n <TValue>(key: string, initialValue: TValue) => {\n if (!(globalThis as unknown as { [namespace]: unknown })[namespace]) {\n (globalThis as unknown as { [namespace]: unknown })[namespace] = {};\n }\n\n const storage = (globalThis as unknown as { [namespace]: { [P in typeof key]: TValue } })[\n namespace\n ]!;\n\n const entry: StorageEntry<TValue> = {\n get(): TValue {\n return cloneEntry(key, key in storage ? storage[key] : initialValue)!;\n },\n set(value: TValue): StorageEntry<TValue> {\n storage[key] = cloneEntry(key, value);\n return entry;\n },\n clear(): StorageEntry<TValue> {\n storage[key] = cloneEntry(key, initialValue);\n return this;\n },\n };\n\n return entry;\n };\n\nexport { globalThisStorageEntry };\n", "import type { StorageEntryCreator, StorageEntry } from 'lib/core/2.app/config/storage.contract';\nimport { cloneEntry } from 'lib/utils/clone-entry';\n\nconst localStorageEntry: StorageEntryCreator =\n (namespace: string) =>\n <TValue>(key: string, initialValue: TValue) => {\n const entry: StorageEntry<TValue> = {\n get() {\n const fromCache = localStorage.getItem(`${namespace}.${String(key)}`);\n if (!fromCache) return cloneEntry(key, initialValue);\n return JSON.parse(fromCache);\n },\n set(value: TValue): StorageEntry<TValue> {\n localStorage.setItem(`${namespace}.${String(key)}`, JSON.stringify(value));\n return entry;\n },\n clear(): StorageEntry<TValue> {\n localStorage.setItem(`${namespace}.${String(key)}`, JSON.stringify(initialValue));\n return this;\n },\n };\n return entry;\n };\n\nexport { localStorageEntry };\n", "import type { StorageEntryCreator, StorageEntry } from 'lib/core/2.app/config/storage.contract';\nimport { cloneEntry } from 'lib/utils/clone-entry';\n\nconst sessionStorageEntry: StorageEntryCreator =\n (namespace: string) =>\n <TValue>(key: string, initialValue: TValue) => {\n const entry: StorageEntry<TValue> = {\n get() {\n const fromCache = sessionStorage.getItem(`${namespace}.${String(key)}`);\n if (!fromCache) return cloneEntry(key, initialValue);\n return JSON.parse(fromCache);\n },\n set(value: TValue): StorageEntry<TValue> {\n sessionStorage.setItem(`${namespace}.${String(key)}`, JSON.stringify(value));\n return entry;\n },\n clear(): StorageEntry<TValue> {\n sessionStorage.setItem(`${namespace}.${String(key)}`, JSON.stringify(initialValue));\n return this;\n },\n };\n return entry;\n };\n\nexport { sessionStorageEntry };\n", "type TTCreateScript = (input: string) => string;\ntype TTCreateScriptURL = (input: string) => string;\n\ntype TTPolicyRules = {\n createScript?: TTCreateScript;\n createScriptURL?: TTCreateScriptURL;\n};\n\ntype TrustedValue = { toString(): string };\n\ntype TTPolicy = {\n createScript: (input: string) => TrustedValue;\n createScriptURL: (input: string) => TrustedValue;\n};\n\ntype TTFactory = {\n createPolicy: (name: string, rules: TTPolicyRules) => TTPolicy;\n};\n\nexport type NFTrustedTypesPolicy = {\n // `script.text` is a TrustedScript sink, so this must stay the genuine object.\n createScript: (input: string) => TrustedValue;\n createScriptURL: (input: string) => string;\n};\n\nconst IMPORT_MAP_KEYS = new Set(['imports', 'scopes', 'integrity']);\n\nconst validateImportMapJSON = (input: string): string => {\n let parsed: unknown;\n try {\n parsed = JSON.parse(input);\n } catch {\n throw new TypeError('[nf-orchestrator] trusted-types: import map is not valid JSON');\n }\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {\n throw new TypeError('[nf-orchestrator] trusted-types: import map must be a plain object');\n }\n for (const key of Object.keys(parsed as Record<string, unknown>)) {\n if (!IMPORT_MAP_KEYS.has(key)) {\n throw new TypeError(`[nf-orchestrator] trusted-types: unexpected key \"${key}\" in import map`);\n }\n }\n return input;\n};\n\nconst validateScriptURL = (input: string): string => {\n const base = typeof location !== 'undefined' ? location.href : 'http://localhost/';\n let url: URL;\n try {\n url = new URL(input, base);\n } catch {\n throw new TypeError(`[nf-orchestrator] trusted-types: invalid script URL \"${input}\"`);\n }\n if (url.protocol !== 'https:' && url.protocol !== 'http:') {\n throw new TypeError(\n `[nf-orchestrator] trusted-types: disallowed protocol \"${url.protocol}\" for script URL`\n );\n }\n return input;\n};\n\nconst passThroughPolicy: NFTrustedTypesPolicy = {\n createScript: input => input,\n createScriptURL: input => input,\n};\n\nlet cachedPolicy: NFTrustedTypesPolicy | null = null;\n\nexport const getTrustedTypesPolicy = (\n name: string | false = 'nfo'\n): NFTrustedTypesPolicy => {\n if (name === false) return passThroughPolicy;\n if (cachedPolicy) return cachedPolicy;\n\n const factory = (globalThis as { trustedTypes?: TTFactory }).trustedTypes;\n if (!factory) {\n cachedPolicy = passThroughPolicy;\n return cachedPolicy;\n }\n\n const native = factory.createPolicy(name, {\n createScript: validateImportMapJSON,\n createScriptURL: validateScriptURL,\n });\n\n cachedPolicy = {\n createScript: input => native.createScript(input),\n createScriptURL: input => String(native.createScriptURL(input)),\n };\n return cachedPolicy;\n};\n\nexport const __resetTrustedTypesPolicyForTests = (): void => {\n cachedPolicy = null;\n};\n", "import type { ImportMap } from 'lib/core/1.domain';\nimport type { SetImportMap } from 'lib/core/2.app/config/import-map.contract';\nimport { getTrustedTypesPolicy } from './trusted-types';\n\nexport const replaceInDOM =\n (mapType: string, trustedTypesPolicyName: string | false = 'nfo'): SetImportMap =>\n (importMap: ImportMap, opts = {}) => {\n if (opts?.override) {\n document.head\n .querySelectorAll(`script[type=\"${mapType}\"]`)\n .forEach(importMap => importMap.remove());\n }\n\n const policy = getTrustedTypesPolicy(trustedTypesPolicyName);\n document.head.appendChild(\n Object.assign(document.createElement('script'), {\n type: mapType,\n text: policy.createScript(JSON.stringify(importMap)),\n })\n );\n return Promise.resolve(importMap);\n };\n", "import type { ImportMapConfig } from 'lib/core/2.app/config/import-map.contract';\nimport { replaceInDOM } from './replace-in-dom';\nimport { getTrustedTypesPolicy } from './trusted-types';\n\ndeclare function importShim<T>(url: string): T;\n\nconst useShimImportMap = (\n cfg: { shimMode: boolean } = { shimMode: false },\n trustedTypesPolicyName: string | false = 'nfo'\n): ImportMapConfig => ({\n loadModuleFn: url => {\n const trusted = getTrustedTypesPolicy(trustedTypesPolicyName).createScriptURL(url);\n return importShim(trusted);\n },\n setImportMapFn: replaceInDOM(\n cfg.shimMode ? 'importmap-shim' : 'importmap',\n trustedTypesPolicyName\n ),\n reloadBrowserFn: () => {\n window.location.reload();\n },\n});\n\nexport { useShimImportMap };\n", "import type { ImportMapConfig } from 'lib/core/2.app/config/import-map.contract';\nimport { replaceInDOM } from './replace-in-dom';\nimport { getTrustedTypesPolicy } from './trusted-types';\n\nconst useDefaultImportMap = (trustedTypesPolicyName: string | false = 'nfo'): ImportMapConfig => ({\n loadModuleFn: url => {\n const trusted = getTrustedTypesPolicy(trustedTypesPolicyName).createScriptURL(url);\n return import(/* @vite-ignore */ trusted);\n },\n setImportMapFn: replaceInDOM('importmap', trustedTypesPolicyName),\n reloadBrowserFn: () => {\n window.location.reload();\n },\n});\n\nexport { useDefaultImportMap };\n", "import type { ModeProfileConfig } from 'lib/core/2.app/config/mode.contract';\n\nexport const defaultProfile: ModeProfileConfig = {\n latestSharedExternal: false,\n skipInvalidExternalVersions: false,\n scopeUncoveredEntrypoints: false,\n overrideCachedRemotes: 'init-only',\n overrideCachedRemotesIfURLMatches: false,\n};\n", "import type { ModeProfileConfig } from 'lib/core/2.app/config/mode.contract';\n\nexport const cachingProfile: ModeProfileConfig = {\n latestSharedExternal: false,\n skipInvalidExternalVersions: false,\n scopeUncoveredEntrypoints: false,\n overrideCachedRemotes: 'never',\n overrideCachedRemotesIfURLMatches: false,\n};\n"],
|
|
5
|
-
"mappings": ";AAAO,IAAM,WAAW;AAAA,EACtB,OAAO;AAAA,EACP,MAAM;AAAA,EACN,OAAO;AACT;;;ACFA,IAAM,gBAAwB;AAAA;AAAA,EAE5B,OAAO,CAAC,MAAc,KAAa,QACjC,CAAC,CAAC,MAAM,QAAQ,IAAI,WAAW,IAAI,MAAM,GAAG,IAAI,GAAG,IAAI,QAAQ,IAAI,WAAW,IAAI,MAAM,GAAG,EAAE;AAAA,EAC/F,OAAO,CAAC,MAAc,KAAa,QACjC,CAAC,CAAC,MAAM,QAAQ,MAAM,QAAQ,IAAI,MAAM,GAAG,IAAI,GAAG,IAAI,QAAQ,MAAM,QAAQ,IAAI,MAAM,GAAG,EAAE;AAAA,EAC7F,MAAM,CAAC,MAAc,KAAa,QAChC,CAAC,CAAC,MAAM,QAAQ,KAAK,QAAQ,IAAI,MAAM,GAAG,IAAI,GAAG,IAAI,QAAQ,KAAK,QAAQ,IAAI,MAAM,GAAG,EAAE;AAC7F;;;ACRA,IAAM,aAAqB;AAAA,EACzB,OAAO,MAAM;AAAA,EAAC;AAAA,EACd,OAAO,MAAM;AAAA,EAAC;AAAA,EACd,MAAM,MAAM;AAAA,EAAC;AACf;;;ACNA,IAAM,UAAN,cAAsB,MAAM;AAAA,EAC1B,YAAY,SAAiB,OAAe;AAC1C,UAAM,SAAS,
|
|
4
|
+
"sourcesContent": ["export const LogLevel = {\n debug: 0,\n warn: 1,\n error: 2,\n};\n\nexport type LogType = keyof typeof LogLevel;\n\nexport type Logger = {\n error: (step: number, msg: string, details?: unknown) => void;\n warn: (step: number, msg: string, details?: unknown) => void;\n debug: (step: number, msg: string, details?: unknown) => void;\n};\n\nexport type LogHandler = Logger & {\n level: LogType;\n};\n\nexport type LoggingConfig = {\n log: LogHandler;\n sse: boolean;\n};\n\nexport type LoggingOptions = {\n logger?: Logger;\n logLevel?: LogType;\n sse?: boolean;\n};\n", "import type { Logger } from 'lib/core/2.app/config/log.contract';\n\nconst consoleLogger: Logger = {\n /* eslint no-console: \"off\", curly: \"error\" */\n debug: (step: number, msg: string, err) =>\n !!err ? console.log(`[DEBUG][${step}]: ${msg}`, err) : console.log(`[DEBUG][${step}]: ${msg}`),\n error: (step: number, msg: string, err) =>\n !!err ? console.error(`[NF][${step}]: ${msg}`, err) : console.error(`[NF][${step}]: ${msg}`),\n warn: (step: number, msg: string, err) =>\n !!err ? console.warn(`[NF][${step}]: ${msg}`, err) : console.warn(`[NF][${step}]: ${msg}`),\n};\n\nexport { consoleLogger };\n", "import type { Logger } from 'lib/core/2.app/config/log.contract';\n\nconst noopLogger: Logger = {\n debug: () => {},\n error: () => {},\n warn: () => {},\n};\n\nexport { noopLogger };\n", "class NFError extends Error {\n constructor(message: string, cause?: Error) {\n super(message, cause ? { cause } : undefined);\n this.name = 'NFError';\n }\n}\n\nexport { NFError };\n", "import type { StorageEntryKey } from 'lib/core/2.app/config/storage.contract';\nimport { NFError } from 'lib/core/native-federation.error';\n\ntype CloneEntry = <T>(name: StorageEntryKey, raw: T) => T;\n\nconst cloneEntry: CloneEntry = <T>(name: StorageEntryKey, raw: T) => {\n try {\n if (typeof structuredClone === 'function') {\n return structuredClone(raw);\n }\n } catch {\n /* structured clone is unavailable */\n }\n try {\n return JSON.parse(JSON.stringify(raw));\n } catch {\n /* object is not stringifyable */\n }\n throw new NFError(`Could not clone entry '${String(name)}'`);\n};\n\nexport { CloneEntry, cloneEntry };\n", "import { cloneEntry } from 'lib/utils/clone-entry';\nimport {\n type StorageEntryCreator,\n type StorageEntry,\n} from 'lib/core/2.app/config/storage.contract';\n\nconst globalThisStorageEntry: StorageEntryCreator =\n (namespace: string) =>\n <TValue>(key: string, initialValue: TValue) => {\n if (!(globalThis as unknown as { [namespace]: unknown })[namespace]) {\n (globalThis as unknown as { [namespace]: unknown })[namespace] = {};\n }\n\n const storage = (globalThis as unknown as { [namespace]: { [P in typeof key]: TValue } })[\n namespace\n ]!;\n\n const entry: StorageEntry<TValue> = {\n get(): TValue {\n return cloneEntry(key, key in storage ? storage[key] : initialValue)!;\n },\n set(value: TValue): StorageEntry<TValue> {\n storage[key] = cloneEntry(key, value);\n return entry;\n },\n clear(): StorageEntry<TValue> {\n storage[key] = cloneEntry(key, initialValue);\n return this;\n },\n };\n\n return entry;\n };\n\nglobalThisStorageEntry.type = 'globalThis';\nObject.freeze(globalThisStorageEntry);\n\nexport { globalThisStorageEntry };\n", "import type { StorageEntryCreator, StorageEntry } from 'lib/core/2.app/config/storage.contract';\nimport { cloneEntry } from 'lib/utils/clone-entry';\n\nconst localStorageEntry: StorageEntryCreator =\n (namespace: string) =>\n <TValue>(key: string, initialValue: TValue) => {\n const entry: StorageEntry<TValue> = {\n get() {\n const fromCache = localStorage.getItem(`${namespace}.${String(key)}`);\n if (!fromCache) return cloneEntry(key, initialValue);\n return JSON.parse(fromCache);\n },\n set(value: TValue): StorageEntry<TValue> {\n localStorage.setItem(`${namespace}.${String(key)}`, JSON.stringify(value));\n return entry;\n },\n clear(): StorageEntry<TValue> {\n localStorage.setItem(`${namespace}.${String(key)}`, JSON.stringify(initialValue));\n return this;\n },\n };\n return entry;\n };\n\nlocalStorageEntry.type = 'localStorage';\nObject.freeze(localStorageEntry);\n\nexport { localStorageEntry };\n", "import type { StorageEntryCreator, StorageEntry } from 'lib/core/2.app/config/storage.contract';\nimport { cloneEntry } from 'lib/utils/clone-entry';\n\nconst sessionStorageEntry: StorageEntryCreator =\n (namespace: string) =>\n <TValue>(key: string, initialValue: TValue) => {\n const entry: StorageEntry<TValue> = {\n get() {\n const fromCache = sessionStorage.getItem(`${namespace}.${String(key)}`);\n if (!fromCache) return cloneEntry(key, initialValue);\n return JSON.parse(fromCache);\n },\n set(value: TValue): StorageEntry<TValue> {\n sessionStorage.setItem(`${namespace}.${String(key)}`, JSON.stringify(value));\n return entry;\n },\n clear(): StorageEntry<TValue> {\n sessionStorage.setItem(`${namespace}.${String(key)}`, JSON.stringify(initialValue));\n return this;\n },\n };\n return entry;\n };\n\nsessionStorageEntry.type = 'sessionStorage';\nObject.freeze(sessionStorageEntry);\n\nexport { sessionStorageEntry };\n", "type TTCreateScript = (input: string) => string;\ntype TTCreateScriptURL = (input: string) => string;\n\ntype TTPolicyRules = {\n createScript?: TTCreateScript;\n createScriptURL?: TTCreateScriptURL;\n};\n\ntype TrustedValue = { toString(): string };\n\ntype TTPolicy = {\n createScript: (input: string) => TrustedValue;\n createScriptURL: (input: string) => TrustedValue;\n};\n\ntype TTFactory = {\n createPolicy: (name: string, rules: TTPolicyRules) => TTPolicy;\n};\n\nexport type NFTrustedTypesPolicy = {\n // `script.text` is a TrustedScript sink, so this must stay the genuine object.\n createScript: (input: string) => TrustedValue;\n createScriptURL: (input: string) => string;\n};\n\nconst IMPORT_MAP_KEYS = new Set(['imports', 'scopes', 'integrity']);\n\nconst validateImportMapJSON = (input: string): string => {\n let parsed: unknown;\n try {\n parsed = JSON.parse(input);\n } catch {\n throw new TypeError('[nf-orchestrator] trusted-types: import map is not valid JSON');\n }\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {\n throw new TypeError('[nf-orchestrator] trusted-types: import map must be a plain object');\n }\n for (const key of Object.keys(parsed as Record<string, unknown>)) {\n if (!IMPORT_MAP_KEYS.has(key)) {\n throw new TypeError(`[nf-orchestrator] trusted-types: unexpected key \"${key}\" in import map`);\n }\n }\n return input;\n};\n\nconst validateScriptURL = (input: string): string => {\n const base = typeof location !== 'undefined' ? location.href : 'http://localhost/';\n let url: URL;\n try {\n url = new URL(input, base);\n } catch {\n throw new TypeError(`[nf-orchestrator] trusted-types: invalid script URL \"${input}\"`);\n }\n if (url.protocol !== 'https:' && url.protocol !== 'http:') {\n throw new TypeError(\n `[nf-orchestrator] trusted-types: disallowed protocol \"${url.protocol}\" for script URL`\n );\n }\n return input;\n};\n\nconst passThroughPolicy: NFTrustedTypesPolicy = {\n createScript: input => input,\n createScriptURL: input => input,\n};\n\nlet cachedPolicy: NFTrustedTypesPolicy | null = null;\n\nexport const getTrustedTypesPolicy = (\n name: string | false = 'nfo'\n): NFTrustedTypesPolicy => {\n if (name === false) return passThroughPolicy;\n if (cachedPolicy) return cachedPolicy;\n\n const factory = (globalThis as { trustedTypes?: TTFactory }).trustedTypes;\n if (!factory) {\n cachedPolicy = passThroughPolicy;\n return cachedPolicy;\n }\n\n const native = factory.createPolicy(name, {\n createScript: validateImportMapJSON,\n createScriptURL: validateScriptURL,\n });\n\n cachedPolicy = {\n createScript: input => native.createScript(input),\n createScriptURL: input => String(native.createScriptURL(input)),\n };\n return cachedPolicy;\n};\n\nexport const __resetTrustedTypesPolicyForTests = (): void => {\n cachedPolicy = null;\n};\n", "import type { ImportMap } from 'lib/core/1.domain';\nimport type { SetImportMap } from 'lib/core/2.app/config/import-map.contract';\nimport { getTrustedTypesPolicy } from './trusted-types';\n\nexport const replaceInDOM =\n (mapType: string, trustedTypesPolicyName: string | false = 'nfo'): SetImportMap =>\n (importMap: ImportMap, opts = {}) => {\n if (opts?.override) {\n document.head\n .querySelectorAll(`script[type=\"${mapType}\"]`)\n .forEach(importMap => importMap.remove());\n }\n\n const policy = getTrustedTypesPolicy(trustedTypesPolicyName);\n document.head.appendChild(\n Object.assign(document.createElement('script'), {\n type: mapType,\n text: policy.createScript(JSON.stringify(importMap)),\n })\n );\n return Promise.resolve(importMap);\n };\n", "import type { ImportMapConfig } from 'lib/core/2.app/config/import-map.contract';\nimport { replaceInDOM } from './replace-in-dom';\nimport { getTrustedTypesPolicy } from './trusted-types';\n\ndeclare function importShim<T>(url: string): T;\n\nconst useShimImportMap = (\n cfg: { shimMode: boolean } = { shimMode: false },\n trustedTypesPolicyName: string | false = 'nfo'\n): ImportMapConfig => ({\n loadModuleFn: url => {\n const trusted = getTrustedTypesPolicy(trustedTypesPolicyName).createScriptURL(url);\n return importShim(trusted);\n },\n setImportMapFn: replaceInDOM(\n cfg.shimMode ? 'importmap-shim' : 'importmap',\n trustedTypesPolicyName\n ),\n reloadBrowserFn: () => {\n window.location.reload();\n },\n});\n\nexport { useShimImportMap };\n", "import type { ImportMapConfig } from 'lib/core/2.app/config/import-map.contract';\nimport { replaceInDOM } from './replace-in-dom';\nimport { getTrustedTypesPolicy } from './trusted-types';\n\nconst useDefaultImportMap = (trustedTypesPolicyName: string | false = 'nfo'): ImportMapConfig => ({\n loadModuleFn: url => {\n const trusted = getTrustedTypesPolicy(trustedTypesPolicyName).createScriptURL(url);\n return import(/* @vite-ignore */ trusted);\n },\n setImportMapFn: replaceInDOM('importmap', trustedTypesPolicyName),\n reloadBrowserFn: () => {\n window.location.reload();\n },\n});\n\nexport { useDefaultImportMap };\n", "import type { ModeProfileConfig } from 'lib/core/2.app/config/mode.contract';\n\nexport const defaultProfile: ModeProfileConfig = {\n latestSharedExternal: false,\n skipInvalidExternalVersions: false,\n overrideCachedRemotes: 'init-only',\n overrideCachedRemotesIfURLMatches: false,\n};\n", "import type { ModeProfileConfig } from 'lib/core/2.app/config/mode.contract';\n\nexport const cachingProfile: ModeProfileConfig = {\n latestSharedExternal: false,\n skipInvalidExternalVersions: false,\n overrideCachedRemotes: 'never',\n overrideCachedRemotesIfURLMatches: false,\n};\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["importMap"]
|
|
7
7
|
}
|
package/fesm2022/registry.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/lib/core/native-federation.error.ts", "../../src/lib/utils/clone-entry.ts", "../../src/lib/registry/setup-registry.ts"],
|
|
4
|
-
"sourcesContent": ["class NFError extends Error {\n constructor(message: string, cause?: Error) {\n super(message, cause);\n this.name = 'NFError';\n }\n}\n\nexport { NFError };\n", "import type { StorageEntryKey } from 'lib/core/2.app/config/storage.contract';\nimport { NFError } from 'lib/core/native-federation.error';\n\ntype CloneEntry = <T>(name: StorageEntryKey, raw: T) => T;\n\nconst cloneEntry: CloneEntry = <T>(name: StorageEntryKey, raw: T) => {\n try {\n if (typeof structuredClone === 'function') {\n return structuredClone(raw);\n }\n } catch {\n /* structured clone is unavailable */\n }\n try {\n return JSON.parse(JSON.stringify(raw));\n } catch {\n /* object is not stringifyable */\n }\n throw new NFError(`Could not clone entry '${String(name)}'`);\n};\n\nexport { CloneEntry, cloneEntry };\n", "import type {\n NFEventConsumer,\n NFEventData,\n NFEventProvider,\n NFEventUnsubscribe,\n} from './event.contract';\nimport type { ForManagingEvents } from './for-managing-events.port';\nimport type { NFEventRegistryConfig, NFEventRegistryOptions } from './registry.contract';\nimport { cloneEntry } from 'lib/utils/clone-entry';\n\nexport function createRegistry(opts: NFEventRegistryOptions): ForManagingEvents {\n const cfg: NFEventRegistryConfig = {\n maxStreams: opts.maxStreams,\n maxEvents: opts.maxEvents ?? 1,\n removePercentage: opts.removePercentage,\n };\n\n // resources\n const resources = new Map<string, unknown>();\n const pending = new Map<string, Set<NFEventConsumer<any>>>();\n\n // events\n const events = new Map<string, NFEventData[]>();\n const listeners = new Map<string, Set<NFEventConsumer<NFEventData<any>>>>();\n const recentlyUsedStreams = new Set<string>();\n\n // Clamp to (maxEvents - 1) so at least one event always survives the trim.\n // Without this, maxEvents=1 (or any config where REMOVE_EVENTS == maxEvents)\n // would compute slice(-0), which returns the whole array and never trims.\n const REMOVE_EVENTS = Math.min(\n cfg.maxEvents - 1,\n cfg.removePercentage ? Math.ceil(cfg.maxEvents * cfg.removePercentage) : 1\n );\n\n /**\n * Mark `type` as the most-recently-used stream. When `maxStreams` is set and\n * the LRU set grows past that bound, the oldest stream (and its history) is\n * dropped. No-op when `maxStreams` is undefined \u2014 streams are then unbounded.\n */\n const touchStream = (type: string): void => {\n if (!cfg.maxStreams) return;\n recentlyUsedStreams.delete(type);\n recentlyUsedStreams.add(type);\n\n if (recentlyUsedStreams.size > cfg.maxStreams) {\n const oldest = recentlyUsedStreams.values().next().value;\n if (oldest) {\n recentlyUsedStreams.delete(oldest);\n events.delete(oldest);\n }\n }\n };\n\n /**\n * Append an event to `type`'s history, trim the history if it exceeds\n * `maxEvents`, and synchronously notify all current listeners. Trimming is\n * batched: when the history overflows, it is sliced down to\n * `(maxEvents - REMOVE_EVENTS)` items so subsequent emits don't slice on\n * every call.\n */\n const appendAndNotify = <T>(type: string, event: NFEventData<T>): void => {\n let history = events.get(type) ?? [];\n history.push(event);\n\n if (history.length > cfg.maxEvents) {\n history = history.slice(-(cfg.maxEvents - REMOVE_EVENTS));\n }\n\n events.set(type, history);\n\n const typeListeners = listeners.get(type);\n if (typeListeners && typeListeners.size > 0) {\n typeListeners.forEach(listener => listener(event));\n }\n };\n\n /**\n * RESOURCE: Register a resource by name. If the resource is a provider function, it is\n * invoked to obtain the actual resource. All callbacks waiting for this\n * resource via `onReady` are invoked once the resource is registered.\n */\n const register = async <T>(type: string, resource: T | NFEventProvider<T>): Promise<void> => {\n const value =\n typeof resource === 'function' ? await (resource as NFEventProvider<T>)() : resource;\n\n resources.set(type, value);\n\n const callbacks = pending.get(type);\n if (callbacks) {\n pending.delete(type);\n callbacks.forEach(cb => cb(value));\n }\n };\n\n /**\n * RESOURCE: Subscribe to the readiness of a resource. If the resource is already\n * registered, the callback is invoked immediately. Otherwise, the callback\n * is invoked once the resource is registered.\n */\n const onReady = <T>(type: string, callback: NFEventConsumer<T>): NFEventUnsubscribe => {\n const existing = resources.get(type);\n if (existing !== undefined) {\n callback(existing as T);\n return () => {};\n }\n\n let callbacks = pending.get(type);\n if (!callbacks) {\n callbacks = new Set();\n pending.set(type, callbacks);\n }\n callbacks.add(callback);\n\n return () => {\n callbacks!.delete(callback);\n if (callbacks!.size === 0) {\n pending.delete(type);\n }\n };\n };\n\n /**\n * EVENT: Subscribe to events of a specific type. The callback is invoked for\n * all future events of that type, and \u2014 when `opts.replay > 0` \u2014 for the\n * most recent `opts.replay` events already in history. Replay deliveries are\n * scheduled via `queueMicrotask`, so the unsubscribe handle is returned\n * synchronously and the callback fires after the current task completes.\n *\n * @param type Stream identifier.\n * @param callback Listener invoked with each event (replay + future).\n * @param opts.replay Number of buffered events to replay on subscribe, taken\n * from the tail of history (most recent first, delivered\n * in chronological order). Defaults to `1`, matching the\n * BehaviorSubject pattern: a fresh subscriber receives\n * the latest state. Pass `0` to suppress replay; pass a\n * larger value (capped by `maxEvents`) to receive more\n * history.\n * @returns Function that unsubscribes the listener.\n */\n const on = <T>(\n type: string,\n callback: NFEventConsumer<NFEventData<T>>,\n opts: { replay?: number } = {}\n ): NFEventUnsubscribe => {\n const replay = opts.replay ?? 1;\n const history = events.get(type);\n\n let typeListeners = listeners.get(type);\n if (!typeListeners) {\n typeListeners = new Set();\n listeners.set(type, typeListeners);\n }\n typeListeners.add(callback);\n\n if (history && history.length > 0 && replay > 0) {\n queueMicrotask(() => {\n const start = Math.max(0, history.length - replay);\n for (let i = start; i < history.length; i++) {\n callback(cloneEntry('event channel ' + type, history[i]!));\n }\n });\n }\n\n return () => {\n typeListeners!.delete(callback);\n if (typeListeners!.size === 0) {\n listeners.delete(type);\n }\n };\n };\n\n /**\n * EVENT: Publish a new event on `type`. The event is appended to the stream's\n * history and delivered synchronously to every current listener. When\n * `maxEvents` is exceeded the history is batch-trimmed; when `maxStreams` is\n * set, emitting to a new type may evict the least-recently-used stream.\n */\n const emit = <T>(type: string, data: T): void => {\n touchStream(type);\n appendAndNotify(type, { data, timestamp: Date.now() });\n };\n\n /**\n * EVENT: Publish a new event on `type` derived from the previous value, in\n * the style of a state reducer. `updateFn` receives a structured clone of\n * the last event's data (or `undefined` if the stream is empty), and its\n * return value becomes the next event. The clone protects historical events\n * from accidental mutation inside `updateFn`.\n *\n * Use this instead of `emit` when the new state depends on the old one \u2014 it\n * collapses the read-modify-write into a single, race-free call. Requires\n * `data` to be structured-clone-able when the stream is non-empty.\n *\n * @param type Stream identifier.\n * @param updateFn Reducer: `(current | undefined) => next`. Called with a\n * cloned snapshot of the last value (or `undefined` on\n * first emit).\n */\n const update = <T>(type: string, updateFn: (current: T | undefined) => T): void => {\n touchStream(type);\n\n const history = events.get(type) ?? [];\n const lastEvent = history[history.length - 1];\n const current =\n lastEvent === undefined ? undefined : cloneEntry('event channel ' + type, lastEvent.data);\n\n appendAndNotify(type, {\n data: updateFn(current),\n timestamp: Date.now(),\n });\n };\n\n const clear = (type?: string): void => {\n if (type) {\n // Clear event-related data\n events.delete(type);\n listeners.delete(type);\n\n // Clear resource-related data\n resources.delete(type);\n pending.delete(type);\n\n recentlyUsedStreams.delete(type);\n } else {\n // Clear all data\n events.clear();\n listeners.clear();\n pending.clear();\n resources.clear();\n recentlyUsedStreams.clear();\n }\n };\n\n return () => ({\n register,\n onReady,\n emit,\n update,\n on,\n clear,\n });\n}\n"],
|
|
5
|
-
"mappings": ";AAAA,IAAM,UAAN,cAAsB,MAAM;AAAA,EAC1B,YAAY,SAAiB,OAAe;AAC1C,UAAM,SAAS,
|
|
4
|
+
"sourcesContent": ["class NFError extends Error {\n constructor(message: string, cause?: Error) {\n super(message, cause ? { cause } : undefined);\n this.name = 'NFError';\n }\n}\n\nexport { NFError };\n", "import type { StorageEntryKey } from 'lib/core/2.app/config/storage.contract';\nimport { NFError } from 'lib/core/native-federation.error';\n\ntype CloneEntry = <T>(name: StorageEntryKey, raw: T) => T;\n\nconst cloneEntry: CloneEntry = <T>(name: StorageEntryKey, raw: T) => {\n try {\n if (typeof structuredClone === 'function') {\n return structuredClone(raw);\n }\n } catch {\n /* structured clone is unavailable */\n }\n try {\n return JSON.parse(JSON.stringify(raw));\n } catch {\n /* object is not stringifyable */\n }\n throw new NFError(`Could not clone entry '${String(name)}'`);\n};\n\nexport { CloneEntry, cloneEntry };\n", "import type {\n NFEventConsumer,\n NFEventData,\n NFEventProvider,\n NFEventUnsubscribe,\n} from './event.contract';\nimport type { ForManagingEvents } from './for-managing-events.port';\nimport type { NFEventRegistryConfig, NFEventRegistryOptions } from './registry.contract';\nimport { cloneEntry } from 'lib/utils/clone-entry';\n\nexport function createRegistry(opts: NFEventRegistryOptions): ForManagingEvents {\n const cfg: NFEventRegistryConfig = {\n maxStreams: opts.maxStreams,\n maxEvents: opts.maxEvents ?? 1,\n removePercentage: opts.removePercentage,\n };\n\n // resources\n const resources = new Map<string, unknown>();\n const pending = new Map<string, Set<NFEventConsumer<any>>>();\n\n // events\n const events = new Map<string, NFEventData[]>();\n const listeners = new Map<string, Set<NFEventConsumer<NFEventData<any>>>>();\n const recentlyUsedStreams = new Set<string>();\n\n // Clamp to (maxEvents - 1) so at least one event always survives the trim.\n // Without this, maxEvents=1 (or any config where REMOVE_EVENTS == maxEvents)\n // would compute slice(-0), which returns the whole array and never trims.\n const REMOVE_EVENTS = Math.min(\n cfg.maxEvents - 1,\n cfg.removePercentage ? Math.ceil(cfg.maxEvents * cfg.removePercentage) : 1\n );\n\n /**\n * Mark `type` as the most-recently-used stream. When `maxStreams` is set and\n * the LRU set grows past that bound, the oldest stream (and its history) is\n * dropped. No-op when `maxStreams` is undefined \u2014 streams are then unbounded.\n */\n const touchStream = (type: string): void => {\n if (!cfg.maxStreams) return;\n recentlyUsedStreams.delete(type);\n recentlyUsedStreams.add(type);\n\n if (recentlyUsedStreams.size > cfg.maxStreams) {\n const oldest = recentlyUsedStreams.values().next().value;\n if (oldest) {\n recentlyUsedStreams.delete(oldest);\n events.delete(oldest);\n }\n }\n };\n\n /**\n * Append an event to `type`'s history, trim the history if it exceeds\n * `maxEvents`, and synchronously notify all current listeners. Trimming is\n * batched: when the history overflows, it is sliced down to\n * `(maxEvents - REMOVE_EVENTS)` items so subsequent emits don't slice on\n * every call.\n */\n const appendAndNotify = <T>(type: string, event: NFEventData<T>): void => {\n let history = events.get(type) ?? [];\n history.push(event);\n\n if (history.length > cfg.maxEvents) {\n history = history.slice(-(cfg.maxEvents - REMOVE_EVENTS));\n }\n\n events.set(type, history);\n\n const typeListeners = listeners.get(type);\n if (typeListeners && typeListeners.size > 0) {\n typeListeners.forEach(listener => listener(event));\n }\n };\n\n /**\n * RESOURCE: Register a resource by name. If the resource is a provider function, it is\n * invoked to obtain the actual resource. All callbacks waiting for this\n * resource via `onReady` are invoked once the resource is registered.\n */\n const register = async <T>(type: string, resource: T | NFEventProvider<T>): Promise<void> => {\n const value =\n typeof resource === 'function' ? await (resource as NFEventProvider<T>)() : resource;\n\n resources.set(type, value);\n\n const callbacks = pending.get(type);\n if (callbacks) {\n pending.delete(type);\n callbacks.forEach(cb => cb(value));\n }\n };\n\n /**\n * RESOURCE: Subscribe to the readiness of a resource. If the resource is already\n * registered, the callback is invoked immediately. Otherwise, the callback\n * is invoked once the resource is registered.\n */\n const onReady = <T>(type: string, callback: NFEventConsumer<T>): NFEventUnsubscribe => {\n const existing = resources.get(type);\n if (existing !== undefined) {\n callback(existing as T);\n return () => {};\n }\n\n let callbacks = pending.get(type);\n if (!callbacks) {\n callbacks = new Set();\n pending.set(type, callbacks);\n }\n callbacks.add(callback);\n\n return () => {\n callbacks!.delete(callback);\n if (callbacks!.size === 0) {\n pending.delete(type);\n }\n };\n };\n\n /**\n * EVENT: Subscribe to events of a specific type. The callback is invoked for\n * all future events of that type, and \u2014 when `opts.replay > 0` \u2014 for the\n * most recent `opts.replay` events already in history. Replay deliveries are\n * scheduled via `queueMicrotask`, so the unsubscribe handle is returned\n * synchronously and the callback fires after the current task completes.\n *\n * @param type Stream identifier.\n * @param callback Listener invoked with each event (replay + future).\n * @param opts.replay Number of buffered events to replay on subscribe, taken\n * from the tail of history (most recent first, delivered\n * in chronological order). Defaults to `1`, matching the\n * BehaviorSubject pattern: a fresh subscriber receives\n * the latest state. Pass `0` to suppress replay; pass a\n * larger value (capped by `maxEvents`) to receive more\n * history.\n * @returns Function that unsubscribes the listener.\n */\n const on = <T>(\n type: string,\n callback: NFEventConsumer<NFEventData<T>>,\n opts: { replay?: number } = {}\n ): NFEventUnsubscribe => {\n const replay = opts.replay ?? 1;\n const history = events.get(type);\n\n let typeListeners = listeners.get(type);\n if (!typeListeners) {\n typeListeners = new Set();\n listeners.set(type, typeListeners);\n }\n typeListeners.add(callback);\n\n if (history && history.length > 0 && replay > 0) {\n queueMicrotask(() => {\n const start = Math.max(0, history.length - replay);\n for (let i = start; i < history.length; i++) {\n callback(cloneEntry('event channel ' + type, history[i]!));\n }\n });\n }\n\n return () => {\n typeListeners!.delete(callback);\n if (typeListeners!.size === 0) {\n listeners.delete(type);\n }\n };\n };\n\n /**\n * EVENT: Publish a new event on `type`. The event is appended to the stream's\n * history and delivered synchronously to every current listener. When\n * `maxEvents` is exceeded the history is batch-trimmed; when `maxStreams` is\n * set, emitting to a new type may evict the least-recently-used stream.\n */\n const emit = <T>(type: string, data: T): void => {\n touchStream(type);\n appendAndNotify(type, { data, timestamp: Date.now() });\n };\n\n /**\n * EVENT: Publish a new event on `type` derived from the previous value, in\n * the style of a state reducer. `updateFn` receives a structured clone of\n * the last event's data (or `undefined` if the stream is empty), and its\n * return value becomes the next event. The clone protects historical events\n * from accidental mutation inside `updateFn`.\n *\n * Use this instead of `emit` when the new state depends on the old one \u2014 it\n * collapses the read-modify-write into a single, race-free call. Requires\n * `data` to be structured-clone-able when the stream is non-empty.\n *\n * @param type Stream identifier.\n * @param updateFn Reducer: `(current | undefined) => next`. Called with a\n * cloned snapshot of the last value (or `undefined` on\n * first emit).\n */\n const update = <T>(type: string, updateFn: (current: T | undefined) => T): void => {\n touchStream(type);\n\n const history = events.get(type) ?? [];\n const lastEvent = history[history.length - 1];\n const current =\n lastEvent === undefined ? undefined : cloneEntry('event channel ' + type, lastEvent.data);\n\n appendAndNotify(type, {\n data: updateFn(current),\n timestamp: Date.now(),\n });\n };\n\n const clear = (type?: string): void => {\n if (type) {\n // Clear event-related data\n events.delete(type);\n listeners.delete(type);\n\n // Clear resource-related data\n resources.delete(type);\n pending.delete(type);\n\n recentlyUsedStreams.delete(type);\n } else {\n // Clear all data\n events.clear();\n listeners.clear();\n pending.clear();\n resources.clear();\n recentlyUsedStreams.clear();\n }\n };\n\n return () => ({\n register,\n onReady,\n emit,\n update,\n on,\n clear,\n });\n}\n"],
|
|
5
|
+
"mappings": ";AAAA,IAAM,UAAN,cAAsB,MAAM;AAAA,EAC1B,YAAY,SAAiB,OAAe;AAC1C,UAAM,SAAS,QAAQ,EAAE,MAAM,IAAI,MAAS;AAC5C,SAAK,OAAO;AAAA,EACd;AACF;;;ACAA,IAAM,aAAyB,CAAI,MAAuB,QAAW;AACnE,MAAI;AACF,QAAI,OAAO,oBAAoB,YAAY;AACzC,aAAO,gBAAgB,GAAG;AAAA,IAC5B;AAAA,EACF,QAAQ;AAAA,EAER;AACA,MAAI;AACF,WAAO,KAAK,MAAM,KAAK,UAAU,GAAG,CAAC;AAAA,EACvC,QAAQ;AAAA,EAER;AACA,QAAM,IAAI,QAAQ,0BAA0B,OAAO,IAAI,CAAC,GAAG;AAC7D;;;ACTO,SAAS,eAAe,MAAiD;AAC9E,QAAM,MAA6B;AAAA,IACjC,YAAY,KAAK;AAAA,IACjB,WAAW,KAAK,aAAa;AAAA,IAC7B,kBAAkB,KAAK;AAAA,EACzB;AAGA,QAAM,YAAY,oBAAI,IAAqB;AAC3C,QAAM,UAAU,oBAAI,IAAuC;AAG3D,QAAM,SAAS,oBAAI,IAA2B;AAC9C,QAAM,YAAY,oBAAI,IAAoD;AAC1E,QAAM,sBAAsB,oBAAI,IAAY;AAK5C,QAAM,gBAAgB,KAAK;AAAA,IACzB,IAAI,YAAY;AAAA,IAChB,IAAI,mBAAmB,KAAK,KAAK,IAAI,YAAY,IAAI,gBAAgB,IAAI;AAAA,EAC3E;AAOA,QAAM,cAAc,CAAC,SAAuB;AAC1C,QAAI,CAAC,IAAI,WAAY;AACrB,wBAAoB,OAAO,IAAI;AAC/B,wBAAoB,IAAI,IAAI;AAE5B,QAAI,oBAAoB,OAAO,IAAI,YAAY;AAC7C,YAAM,SAAS,oBAAoB,OAAO,EAAE,KAAK,EAAE;AACnD,UAAI,QAAQ;AACV,4BAAoB,OAAO,MAAM;AACjC,eAAO,OAAO,MAAM;AAAA,MACtB;AAAA,IACF;AAAA,EACF;AASA,QAAM,kBAAkB,CAAI,MAAc,UAAgC;AACxE,QAAI,UAAU,OAAO,IAAI,IAAI,KAAK,CAAC;AACnC,YAAQ,KAAK,KAAK;AAElB,QAAI,QAAQ,SAAS,IAAI,WAAW;AAClC,gBAAU,QAAQ,MAAM,EAAE,IAAI,YAAY,cAAc;AAAA,IAC1D;AAEA,WAAO,IAAI,MAAM,OAAO;AAExB,UAAM,gBAAgB,UAAU,IAAI,IAAI;AACxC,QAAI,iBAAiB,cAAc,OAAO,GAAG;AAC3C,oBAAc,QAAQ,cAAY,SAAS,KAAK,CAAC;AAAA,IACnD;AAAA,EACF;AAOA,QAAM,WAAW,OAAU,MAAc,aAAoD;AAC3F,UAAM,QACJ,OAAO,aAAa,aAAa,MAAO,SAAgC,IAAI;AAE9E,cAAU,IAAI,MAAM,KAAK;AAEzB,UAAM,YAAY,QAAQ,IAAI,IAAI;AAClC,QAAI,WAAW;AACb,cAAQ,OAAO,IAAI;AACnB,gBAAU,QAAQ,QAAM,GAAG,KAAK,CAAC;AAAA,IACnC;AAAA,EACF;AAOA,QAAM,UAAU,CAAI,MAAc,aAAqD;AACrF,UAAM,WAAW,UAAU,IAAI,IAAI;AACnC,QAAI,aAAa,QAAW;AAC1B,eAAS,QAAa;AACtB,aAAO,MAAM;AAAA,MAAC;AAAA,IAChB;AAEA,QAAI,YAAY,QAAQ,IAAI,IAAI;AAChC,QAAI,CAAC,WAAW;AACd,kBAAY,oBAAI,IAAI;AACpB,cAAQ,IAAI,MAAM,SAAS;AAAA,IAC7B;AACA,cAAU,IAAI,QAAQ;AAEtB,WAAO,MAAM;AACX,gBAAW,OAAO,QAAQ;AAC1B,UAAI,UAAW,SAAS,GAAG;AACzB,gBAAQ,OAAO,IAAI;AAAA,MACrB;AAAA,IACF;AAAA,EACF;AAoBA,QAAM,KAAK,CACT,MACA,UACAA,QAA4B,CAAC,MACN;AACvB,UAAM,SAASA,MAAK,UAAU;AAC9B,UAAM,UAAU,OAAO,IAAI,IAAI;AAE/B,QAAI,gBAAgB,UAAU,IAAI,IAAI;AACtC,QAAI,CAAC,eAAe;AAClB,sBAAgB,oBAAI,IAAI;AACxB,gBAAU,IAAI,MAAM,aAAa;AAAA,IACnC;AACA,kBAAc,IAAI,QAAQ;AAE1B,QAAI,WAAW,QAAQ,SAAS,KAAK,SAAS,GAAG;AAC/C,qBAAe,MAAM;AACnB,cAAM,QAAQ,KAAK,IAAI,GAAG,QAAQ,SAAS,MAAM;AACjD,iBAAS,IAAI,OAAO,IAAI,QAAQ,QAAQ,KAAK;AAC3C,mBAAS,WAAW,mBAAmB,MAAM,QAAQ,CAAC,CAAE,CAAC;AAAA,QAC3D;AAAA,MACF,CAAC;AAAA,IACH;AAEA,WAAO,MAAM;AACX,oBAAe,OAAO,QAAQ;AAC9B,UAAI,cAAe,SAAS,GAAG;AAC7B,kBAAU,OAAO,IAAI;AAAA,MACvB;AAAA,IACF;AAAA,EACF;AAQA,QAAM,OAAO,CAAI,MAAc,SAAkB;AAC/C,gBAAY,IAAI;AAChB,oBAAgB,MAAM,EAAE,MAAM,WAAW,KAAK,IAAI,EAAE,CAAC;AAAA,EACvD;AAkBA,QAAM,SAAS,CAAI,MAAc,aAAkD;AACjF,gBAAY,IAAI;AAEhB,UAAM,UAAU,OAAO,IAAI,IAAI,KAAK,CAAC;AACrC,UAAM,YAAY,QAAQ,QAAQ,SAAS,CAAC;AAC5C,UAAM,UACJ,cAAc,SAAY,SAAY,WAAW,mBAAmB,MAAM,UAAU,IAAI;AAE1F,oBAAgB,MAAM;AAAA,MACpB,MAAM,SAAS,OAAO;AAAA,MACtB,WAAW,KAAK,IAAI;AAAA,IACtB,CAAC;AAAA,EACH;AAEA,QAAM,QAAQ,CAAC,SAAwB;AACrC,QAAI,MAAM;AAER,aAAO,OAAO,IAAI;AAClB,gBAAU,OAAO,IAAI;AAGrB,gBAAU,OAAO,IAAI;AACrB,cAAQ,OAAO,IAAI;AAEnB,0BAAoB,OAAO,IAAI;AAAA,IACjC,OAAO;AAEL,aAAO,MAAM;AACb,gBAAU,MAAM;AAChB,cAAQ,MAAM;AACd,gBAAU,MAAM;AAChB,0BAAoB,MAAM;AAAA,IAC5B;AAAA,EACF;AAEA,SAAO,OAAO;AAAA,IACZ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;",
|
|
6
6
|
"names": ["opts"]
|
|
7
7
|
}
|
package/fesm2022/sdk.mjs
CHANGED
package/fesm2022/sdk.mjs.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/lib/core/1.domain/externals/external.contract.ts", "../../src/lib/utils/optional.ts", "../../src/lib/utils/path.ts", "../../src/lib/core/native-federation.error.ts", "../../src/lib/utils/clone-entry.ts"],
|
|
4
|
-
"sourcesContent": ["import type { SharedVersion, ScopedVersion } from './version.contract';\n\nexport type ExternalName = string;\n\nexport type ScopedExternals = Record<string, ScopedExternal>;\n\nexport const GLOBAL_SCOPE = '__GLOBAL__';\n\nexport const STRICT_SCOPE = 'strict';\n\nexport type SharedExternal = {\n dirty: boolean;\n versions: SharedVersion[];\n};\n\nexport type shareScope = Record<string, SharedExternal>;\n\nexport type SharedExternals = Record<string, shareScope> & { [GLOBAL_SCOPE]: shareScope };\n\nexport type ScopedExternal = Record<string, ScopedVersion>;\n", "export class Optional<T> {\n private constructor(private item?: T) {}\n\n public static of<T>(item?: T): Optional<T> {\n return new Optional(item);\n }\n public static empty<U>(): Optional<U> {\n return Optional.of<U>(undefined);\n }\n\n public isPresent() {\n return typeof this.item !== 'undefined' && this.item !== null;\n }\n public set<U>(other: U) {\n return Optional.of(other);\n }\n\n public ifPresent(callback: (_: T) => void): void {\n if (this.isPresent()) callback(this.item as T);\n }\n\n public map<U>(callback: (_: NonNullable<T>) => U | Optional<U>): Optional<U> {\n if (!this.isPresent()) return Optional.empty();\n\n const result = callback(this.item as NonNullable<T>);\n return result instanceof Optional ? result : Optional.of(result);\n }\n\n public orElse(other: Required<T>): NonNullable<T> {\n return this.isPresent() ? (this.item as NonNullable<T>) : (other as NonNullable<T>);\n }\n\n public orThrow(error: Error | string | (() => Error)): NonNullable<T> {\n if (this.isPresent()) return this.item as NonNullable<T>;\n if (typeof error === 'function') throw error();\n throw typeof error === 'string' ? new Error(error) : error;\n }\n\n public get(): T | undefined {\n return this.item;\n }\n}\n", "function join(pathA: string, pathB: string): string {\n pathA = pathA.endsWith('/') ? pathA.slice(0, -1) : pathA;\n pathB = pathB.startsWith('/') ? pathB.slice(1) : pathB;\n return `${pathA}/${pathB}`;\n}\n\nfunction getScope(path: string) {\n if (!path) return '';\n\n const parts = path.split('/');\n\n if (parts[parts.length - 1] === '' || parts[parts.length - 1]!.includes('.')) {\n parts.pop();\n }\n if (parts.length < 1) return '';\n\n return `${parts.join('/')}/`;\n}\n\nexport { join, getScope };\n", "class NFError extends Error {\n constructor(message: string, cause?: Error) {\n super(message, cause);\n this.name = 'NFError';\n }\n}\n\nexport { NFError };\n", "import type { StorageEntryKey } from 'lib/core/2.app/config/storage.contract';\nimport { NFError } from 'lib/core/native-federation.error';\n\ntype CloneEntry = <T>(name: StorageEntryKey, raw: T) => T;\n\nconst cloneEntry: CloneEntry = <T>(name: StorageEntryKey, raw: T) => {\n try {\n if (typeof structuredClone === 'function') {\n return structuredClone(raw);\n }\n } catch {\n /* structured clone is unavailable */\n }\n try {\n return JSON.parse(JSON.stringify(raw));\n } catch {\n /* object is not stringifyable */\n }\n throw new NFError(`Could not clone entry '${String(name)}'`);\n};\n\nexport { CloneEntry, cloneEntry };\n"],
|
|
5
|
-
"mappings": ";;;;;;;
|
|
4
|
+
"sourcesContent": ["import type { RemoteName } from '../remote/remote-info.contract';\nimport type { SharedVersion, ScopedVersion } from './version.contract';\n\nexport type ExternalName = string;\n\nexport type ScopedExternals = Record<string, ScopedExternal>;\n\nexport const GLOBAL_SCOPE = '__GLOBAL__';\n\nexport const STRICT_SCOPE = 'strict';\n\nexport type SharedExternal = {\n dirty: boolean;\n // The pool this external resolves in, as pooling last computed it; absent when it is in none.\n poolName?: string;\n // The build its pool's last election made global; a tied re-election keeps it.\n poolWinner?: RemoteName;\n // The build every specifier of this external's package is served from in this scope; the same on each of them.\n // A remote, not a tag: a host serves every tag it ships.\n servingBuild?: RemoteName;\n versions: SharedVersion[];\n};\n\nexport type shareScope = Record<string, SharedExternal>;\n\nexport type SharedExternals = Record<string, shareScope> & { [GLOBAL_SCOPE]: shareScope };\n\nexport type ScopedExternal = Record<string, ScopedVersion>;\n", "export class Optional<T> {\n private constructor(private item?: T) {}\n\n public static of<T>(item?: T): Optional<T> {\n return new Optional(item);\n }\n public static empty<U>(): Optional<U> {\n return Optional.of<U>(undefined);\n }\n\n public isPresent() {\n return typeof this.item !== 'undefined' && this.item !== null;\n }\n public set<U>(other: U) {\n return Optional.of(other);\n }\n\n public ifPresent(callback: (_: T) => void): void {\n if (this.isPresent()) callback(this.item as T);\n }\n\n public map<U>(callback: (_: NonNullable<T>) => U | Optional<U>): Optional<U> {\n if (!this.isPresent()) return Optional.empty();\n\n const result = callback(this.item as NonNullable<T>);\n return result instanceof Optional ? result : Optional.of(result);\n }\n\n public orElse(other: Required<T>): NonNullable<T> {\n return this.isPresent() ? (this.item as NonNullable<T>) : (other as NonNullable<T>);\n }\n\n public orThrow(error: Error | string | (() => Error)): NonNullable<T> {\n if (this.isPresent()) return this.item as NonNullable<T>;\n if (typeof error === 'function') throw error();\n throw typeof error === 'string' ? new Error(error) : error;\n }\n\n public get(): T | undefined {\n return this.item;\n }\n}\n", "function join(pathA: string, pathB: string): string {\n pathA = pathA.endsWith('/') ? pathA.slice(0, -1) : pathA;\n pathB = pathB.startsWith('/') ? pathB.slice(1) : pathB;\n return `${pathA}/${pathB}`;\n}\n\nfunction getScope(path: string) {\n if (!path) return '';\n\n const parts = path.split('/');\n\n if (parts[parts.length - 1] === '' || parts[parts.length - 1]!.includes('.')) {\n parts.pop();\n }\n if (parts.length < 1) return '';\n\n return `${parts.join('/')}/`;\n}\n\nexport { join, getScope };\n", "class NFError extends Error {\n constructor(message: string, cause?: Error) {\n super(message, cause ? { cause } : undefined);\n this.name = 'NFError';\n }\n}\n\nexport { NFError };\n", "import type { StorageEntryKey } from 'lib/core/2.app/config/storage.contract';\nimport { NFError } from 'lib/core/native-federation.error';\n\ntype CloneEntry = <T>(name: StorageEntryKey, raw: T) => T;\n\nconst cloneEntry: CloneEntry = <T>(name: StorageEntryKey, raw: T) => {\n try {\n if (typeof structuredClone === 'function') {\n return structuredClone(raw);\n }\n } catch {\n /* structured clone is unavailable */\n }\n try {\n return JSON.parse(JSON.stringify(raw));\n } catch {\n /* object is not stringifyable */\n }\n throw new NFError(`Could not clone entry '${String(name)}'`);\n};\n\nexport { CloneEntry, cloneEntry };\n"],
|
|
5
|
+
"mappings": ";;;;;;;AAOO,IAAM,eAAe;AAErB,IAAM,eAAe;;;ACTrB,IAAM,WAAN,MAAM,UAAY;AAAA,EACf,YAAoB,MAAU;AAAV;AAAA,EAAW;AAAA,EAAX;AAAA,EAE5B,OAAc,GAAM,MAAuB;AACzC,WAAO,IAAI,UAAS,IAAI;AAAA,EAC1B;AAAA,EACA,OAAc,QAAwB;AACpC,WAAO,UAAS,GAAM,MAAS;AAAA,EACjC;AAAA,EAEO,YAAY;AACjB,WAAO,OAAO,KAAK,SAAS,eAAe,KAAK,SAAS;AAAA,EAC3D;AAAA,EACO,IAAO,OAAU;AACtB,WAAO,UAAS,GAAG,KAAK;AAAA,EAC1B;AAAA,EAEO,UAAU,UAAgC;AAC/C,QAAI,KAAK,UAAU,EAAG,UAAS,KAAK,IAAS;AAAA,EAC/C;AAAA,EAEO,IAAO,UAA+D;AAC3E,QAAI,CAAC,KAAK,UAAU,EAAG,QAAO,UAAS,MAAM;AAE7C,UAAM,SAAS,SAAS,KAAK,IAAsB;AACnD,WAAO,kBAAkB,YAAW,SAAS,UAAS,GAAG,MAAM;AAAA,EACjE;AAAA,EAEO,OAAO,OAAoC;AAChD,WAAO,KAAK,UAAU,IAAK,KAAK,OAA2B;AAAA,EAC7D;AAAA,EAEO,QAAQ,OAAuD;AACpE,QAAI,KAAK,UAAU,EAAG,QAAO,KAAK;AAClC,QAAI,OAAO,UAAU,WAAY,OAAM,MAAM;AAC7C,UAAM,OAAO,UAAU,WAAW,IAAI,MAAM,KAAK,IAAI;AAAA,EACvD;AAAA,EAEO,MAAqB;AAC1B,WAAO,KAAK;AAAA,EACd;AACF;;;ACzCA;AAAA;AAAA;AAAA;AAAA;AAAA,SAAS,KAAK,OAAe,OAAuB;AAClD,UAAQ,MAAM,SAAS,GAAG,IAAI,MAAM,MAAM,GAAG,EAAE,IAAI;AACnD,UAAQ,MAAM,WAAW,GAAG,IAAI,MAAM,MAAM,CAAC,IAAI;AACjD,SAAO,GAAG,KAAK,IAAI,KAAK;AAC1B;AAEA,SAAS,SAAS,MAAc;AAC9B,MAAI,CAAC,KAAM,QAAO;AAElB,QAAM,QAAQ,KAAK,MAAM,GAAG;AAE5B,MAAI,MAAM,MAAM,SAAS,CAAC,MAAM,MAAM,MAAM,MAAM,SAAS,CAAC,EAAG,SAAS,GAAG,GAAG;AAC5E,UAAM,IAAI;AAAA,EACZ;AACA,MAAI,MAAM,SAAS,EAAG,QAAO;AAE7B,SAAO,GAAG,MAAM,KAAK,GAAG,CAAC;AAC3B;;;ACjBA,IAAM,UAAN,cAAsB,MAAM;AAAA,EAC1B,YAAY,SAAiB,OAAe;AAC1C,UAAM,SAAS,QAAQ,EAAE,MAAM,IAAI,MAAS;AAC5C,SAAK,OAAO;AAAA,EACd;AACF;;;ACAA,IAAM,aAAyB,CAAI,MAAuB,QAAW;AACnE,MAAI;AACF,QAAI,OAAO,oBAAoB,YAAY;AACzC,aAAO,gBAAgB,GAAG;AAAA,IAC5B;AAAA,EACF,QAAQ;AAAA,EAER;AACA,MAAI;AACF,WAAO,KAAK,MAAM,KAAK,UAAU,GAAG,CAAC;AAAA,EACvC,QAAQ;AAAA,EAER;AACA,QAAM,IAAI,QAAQ,0BAA0B,OAAO,IAAI,CAAC,GAAG;AAC7D;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/init-registry.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var l=class extends Error{constructor(s,
|
|
1
|
+
var l=class extends Error{constructor(s,a){super(s,a?{cause:a}:void 0),this.name="NFError"}};var u=(o,s)=>{try{if(typeof structuredClone=="function")return structuredClone(s)}catch{}try{return JSON.parse(JSON.stringify(s))}catch{}throw new l(`Could not clone entry '${String(o)}'`)};function y(o){let s={maxStreams:o.maxStreams,maxEvents:o.maxEvents??1,removePercentage:o.removePercentage},a=new Map,c=new Map,m=new Map,d=new Map,g=new Set,F=Math.min(s.maxEvents-1,s.removePercentage?Math.ceil(s.maxEvents*s.removePercentage):1),f=e=>{if(s.maxStreams&&(g.delete(e),g.add(e),g.size>s.maxStreams)){let t=g.values().next().value;t&&(g.delete(t),m.delete(t))}},N=(e,t)=>{let r=m.get(e)??[];r.push(t),r.length>s.maxEvents&&(r=r.slice(-(s.maxEvents-F))),m.set(e,r);let n=d.get(e);n&&n.size>0&&n.forEach(i=>i(t))},p=async(e,t)=>{let r=typeof t=="function"?await t():t;a.set(e,r);let n=c.get(e);n&&(c.delete(e),n.forEach(i=>i(r)))},S=(e,t)=>{let r=a.get(e);if(r!==void 0)return t(r),()=>{};let n=c.get(e);return n||(n=new Set,c.set(e,n)),n.add(t),()=>{n.delete(t),n.size===0&&c.delete(e)}},T=(e,t,r={})=>{let n=r.replay??1,i=m.get(e),v=d.get(e);return v||(v=new Set,d.set(e,v)),v.add(t),i&&i.length>0&&n>0&&queueMicrotask(()=>{let R=Math.max(0,i.length-n);for(let E=R;E<i.length;E++)t(u("event channel "+e,i[E]))}),()=>{v.delete(t),v.size===0&&d.delete(e)}},x=(e,t)=>{f(e),N(e,{data:t,timestamp:Date.now()})},h=(e,t)=>{f(e);let r=m.get(e)??[],n=r[r.length-1],i=n===void 0?void 0:u("event channel "+e,n.data);N(e,{data:t(i),timestamp:Date.now()})},w=e=>{e?(m.delete(e),d.delete(e),a.delete(e),c.delete(e),g.delete(e)):(m.clear(),d.clear(),c.clear(),a.clear(),g.clear())};return()=>({register:p,onReady:S,emit:x,update:h,on:T,clear:w})}(function(){let o=document.currentScript,s={maxStreams:o?.dataset?.maxStreams?Number(o.dataset.maxStreams):void 0,maxEvents:o?.dataset?.maxEvents?Number(o.dataset.maxEvents):void 0,removePercentage:o?.dataset?.removePercentage?Number(o.dataset.removePercentage)/100:void 0},a=y(s);window.__NF_REGISTRY__=Object.freeze(a())})();
|
package/node-loader/loader.mjs
CHANGED
|
@@ -11,6 +11,7 @@ var baseURL = (() => {
|
|
|
11
11
|
var activeMap = EMPTY_MAP;
|
|
12
12
|
var hostInstanceKeys = /* @__PURE__ */ Object.create(null);
|
|
13
13
|
var lastRemoteBaseURL;
|
|
14
|
+
var federatedURLs = /* @__PURE__ */ new Set();
|
|
14
15
|
function initialize(data = {}) {
|
|
15
16
|
if (data.initialImportMap) {
|
|
16
17
|
activeMap = normalize(data.initialImportMap);
|
|
@@ -34,11 +35,13 @@ async function resolve(specifier, context, nextResolve) {
|
|
|
34
35
|
}
|
|
35
36
|
const effectiveParent = context.parentURL || lastRemoteBaseURL;
|
|
36
37
|
let mapped = resolveSpecifier(activeMap, specifier, effectiveParent);
|
|
38
|
+
let federated = mapped !== null;
|
|
37
39
|
if (!mapped) {
|
|
38
40
|
const isRelative = specifier.startsWith("/") || specifier.startsWith("./") || specifier.startsWith("../");
|
|
39
41
|
try {
|
|
40
42
|
if (isRelative && effectiveParent) {
|
|
41
43
|
mapped = new URL(specifier, effectiveParent).href;
|
|
44
|
+
federated = federatedURLs.has(effectiveParent);
|
|
42
45
|
} else if (/^https?:\/\//.test(specifier)) {
|
|
43
46
|
mapped = specifier;
|
|
44
47
|
}
|
|
@@ -48,7 +51,10 @@ async function resolve(specifier, context, nextResolve) {
|
|
|
48
51
|
if (mapped && (mapped.startsWith("http://") || mapped.startsWith("https://"))) {
|
|
49
52
|
return { url: mapped, format: "module", shortCircuit: true };
|
|
50
53
|
}
|
|
51
|
-
|
|
54
|
+
const result = await nextResolve(mapped ?? specifier, context);
|
|
55
|
+
if (!federated) return result;
|
|
56
|
+
federatedURLs.add(result.url);
|
|
57
|
+
return { ...result, format: "module" };
|
|
52
58
|
}
|
|
53
59
|
async function load(url, context, nextLoad) {
|
|
54
60
|
if (url.startsWith(HOST_PREFIX)) {
|
|
@@ -68,9 +74,6 @@ async function load(url, context, nextLoad) {
|
|
|
68
74
|
const source = await res.text();
|
|
69
75
|
return { shortCircuit: true, format: "module", source, responseURL: url };
|
|
70
76
|
}
|
|
71
|
-
if (!url.startsWith("node:")) {
|
|
72
|
-
context.format = "module";
|
|
73
|
-
}
|
|
74
77
|
return nextLoad(url, context);
|
|
75
78
|
}
|
|
76
79
|
function synthHostModule(specifier, keys) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/scripts/node-loader.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Node.js module customization hooks for native-federation.\n *\n * Registered via `module.register(<this file>, import.meta.url, { data: { port }, transferList: [port] })`\n * from the orchestrator. The main thread posts the resolved import map over the\n * MessagePort whenever it changes; this loader rewrites `import` specifiers\n * accordingly and fetches http(s) modules into the loader as source text.\n */\n\nimport type { MessagePort } from 'node:worker_threads';\n\ntype Imports = Record<string, string>;\ntype Scopes = Record<string, Imports>;\ntype ImportMap = { imports: Imports; scopes?: Scopes };\n\n/** Per-specifier list of export names to re-export from the host's published instances. */\ntype HostInstanceKeys = Record<string, string[]>;\n\ntype InitData = {\n port?: MessagePort;\n initialImportMap?: ImportMap;\n};\n\ntype IncomingMessage =\n | { type: 'set-import-map'; map: ImportMap }\n | { type: 'set-host-instances'; keys?: HostInstanceKeys };\n\nconst EMPTY_MAP: ImportMap = Object.freeze({ imports: {}, scopes: {} });\n\n/** Synthetic URL scheme for specifiers bridged to the host's instances. */\nconst HOST_PREFIX = 'nf-host:';\n/** Global key on the main thread holding `{ [specifier]: namespaceObject }`. */\nconst HOST_INSTANCES_GLOBAL = '__NF_HOST_INSTANCES__';\n\nconst baseURL = (() => {\n const cwd = process.cwd();\n const url = new URL('file://');\n url.pathname = cwd.endsWith('/') ? cwd : cwd + '/';\n return url.href.endsWith('/') ? url.href : url.href + '/';\n})();\n\nlet activeMap: ImportMap = EMPTY_MAP;\nlet hostInstanceKeys: HostInstanceKeys = Object.create(null);\n// Fallback parent when context.parentURL arrives empty (seen under module.register()'s worker-thread hook).\nlet lastRemoteBaseURL: string | undefined;\n\nexport function initialize(data: InitData = {}): void {\n if (data.initialImportMap) {\n activeMap = normalize(data.initialImportMap);\n }\n if (data.port) {\n data.port.on('message', (msg: IncomingMessage) => {\n if (msg && msg.type === 'set-import-map') {\n activeMap = normalize(msg.map);\n data.port!.postMessage({ type: 'import-map-applied' });\n } else if (msg && msg.type === 'set-host-instances') {\n hostInstanceKeys = msg.keys ?? Object.create(null);\n data.port!.postMessage({ type: 'host-instances-applied' });\n }\n });\n data.port.unref?.();\n }\n}\n\ntype ResolveContext = { parentURL?: string };\ntype ResolveResult = { url: string; format?: string | null; shortCircuit?: boolean };\ntype NextResolve = (specifier: string, context?: ResolveContext) => Promise<ResolveResult>;\n\nexport async function resolve(\n specifier: string,\n context: ResolveContext,\n nextResolve: NextResolve\n): Promise<ResolveResult> {\n // Bridged specifiers win over the import map: route them to a synthetic\n // module that re-exports from the host's published instances.\n if (Object.prototype.hasOwnProperty.call(hostInstanceKeys, specifier)) {\n return { url: HOST_PREFIX + encodeURIComponent(specifier), shortCircuit: true };\n }\n // context.parentURL can be an empty string (not just missing) here; treat it as absent.\n const effectiveParent = context.parentURL || lastRemoteBaseURL;\n let mapped = resolveSpecifier(activeMap, specifier, effectiveParent);\n\n // Not every relative/absolute specifier has an import-map entry (e.g. a sibling chunk); resolve those directly.\n if (!mapped) {\n const isRelative =\n specifier.startsWith('/') || specifier.startsWith('./') || specifier.startsWith('../');\n try {\n if (isRelative && effectiveParent) {\n mapped = new URL(specifier, effectiveParent).href;\n } else if (/^https?:\\/\\//.test(specifier)) {\n mapped = specifier;\n }\n } catch {\n // fall through to nextResolve, which will surface the original error\n }\n }\n\n // nextResolve() can't handle absolute http(s) URLs (throws ERR_INVALID_URL); short-circuit like load() does.\n if (mapped && (mapped.startsWith('http://') || mapped.startsWith('https://'))) {\n return { url: mapped, format: 'module', shortCircuit: true };\n }\n\n
|
|
5
|
-
"mappings": ";AA2BA,IAAM,YAAuB,OAAO,OAAO,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC;AAGtE,IAAM,cAAc;AAEpB,IAAM,wBAAwB;AAE9B,IAAM,WAAW,MAAM;AACrB,QAAM,MAAM,QAAQ,IAAI;AACxB,QAAM,MAAM,IAAI,IAAI,SAAS;AAC7B,MAAI,WAAW,IAAI,SAAS,GAAG,IAAI,MAAM,MAAM;AAC/C,SAAO,IAAI,KAAK,SAAS,GAAG,IAAI,IAAI,OAAO,IAAI,OAAO;AACxD,GAAG;AAEH,IAAI,YAAuB;AAC3B,IAAI,mBAAqC,uBAAO,OAAO,IAAI;AAE3D,IAAI;
|
|
4
|
+
"sourcesContent": ["/**\n * Node.js module customization hooks for native-federation.\n *\n * Registered via `module.register(<this file>, import.meta.url, { data: { port }, transferList: [port] })`\n * from the orchestrator. The main thread posts the resolved import map over the\n * MessagePort whenever it changes; this loader rewrites `import` specifiers\n * accordingly and fetches http(s) modules into the loader as source text.\n */\n\nimport type { MessagePort } from 'node:worker_threads';\n\ntype Imports = Record<string, string>;\ntype Scopes = Record<string, Imports>;\ntype ImportMap = { imports: Imports; scopes?: Scopes };\n\n/** Per-specifier list of export names to re-export from the host's published instances. */\ntype HostInstanceKeys = Record<string, string[]>;\n\ntype InitData = {\n port?: MessagePort;\n initialImportMap?: ImportMap;\n};\n\ntype IncomingMessage =\n | { type: 'set-import-map'; map: ImportMap }\n | { type: 'set-host-instances'; keys?: HostInstanceKeys };\n\nconst EMPTY_MAP: ImportMap = Object.freeze({ imports: {}, scopes: {} });\n\n/** Synthetic URL scheme for specifiers bridged to the host's instances. */\nconst HOST_PREFIX = 'nf-host:';\n/** Global key on the main thread holding `{ [specifier]: namespaceObject }`. */\nconst HOST_INSTANCES_GLOBAL = '__NF_HOST_INSTANCES__';\n\nconst baseURL = (() => {\n const cwd = process.cwd();\n const url = new URL('file://');\n url.pathname = cwd.endsWith('/') ? cwd : cwd + '/';\n return url.href.endsWith('/') ? url.href : url.href + '/';\n})();\n\nlet activeMap: ImportMap = EMPTY_MAP;\nlet hostInstanceKeys: HostInstanceKeys = Object.create(null);\n// Fallback parent when context.parentURL arrives empty (seen under module.register()'s worker-thread hook).\nlet lastRemoteBaseURL: string | undefined;\n// Federated file:// modules (import-map targets and their relative chunks). Only these are forced to\n// ESM; everything else keeps Node's own format detection, since npm packages may resolve to CJS (#79).\nconst federatedURLs = new Set<string>();\n\nexport function initialize(data: InitData = {}): void {\n if (data.initialImportMap) {\n activeMap = normalize(data.initialImportMap);\n }\n if (data.port) {\n data.port.on('message', (msg: IncomingMessage) => {\n if (msg && msg.type === 'set-import-map') {\n activeMap = normalize(msg.map);\n data.port!.postMessage({ type: 'import-map-applied' });\n } else if (msg && msg.type === 'set-host-instances') {\n hostInstanceKeys = msg.keys ?? Object.create(null);\n data.port!.postMessage({ type: 'host-instances-applied' });\n }\n });\n data.port.unref?.();\n }\n}\n\ntype ResolveContext = { parentURL?: string };\ntype ResolveResult = { url: string; format?: string | null; shortCircuit?: boolean };\ntype NextResolve = (specifier: string, context?: ResolveContext) => Promise<ResolveResult>;\n\nexport async function resolve(\n specifier: string,\n context: ResolveContext,\n nextResolve: NextResolve\n): Promise<ResolveResult> {\n // Bridged specifiers win over the import map: route them to a synthetic\n // module that re-exports from the host's published instances.\n if (Object.prototype.hasOwnProperty.call(hostInstanceKeys, specifier)) {\n return { url: HOST_PREFIX + encodeURIComponent(specifier), shortCircuit: true };\n }\n // context.parentURL can be an empty string (not just missing) here; treat it as absent.\n const effectiveParent = context.parentURL || lastRemoteBaseURL;\n let mapped = resolveSpecifier(activeMap, specifier, effectiveParent);\n let federated = mapped !== null;\n\n // Not every relative/absolute specifier has an import-map entry (e.g. a sibling chunk); resolve those directly.\n if (!mapped) {\n const isRelative =\n specifier.startsWith('/') || specifier.startsWith('./') || specifier.startsWith('../');\n try {\n if (isRelative && effectiveParent) {\n mapped = new URL(specifier, effectiveParent).href;\n federated = federatedURLs.has(effectiveParent);\n } else if (/^https?:\\/\\//.test(specifier)) {\n mapped = specifier;\n }\n } catch {\n // fall through to nextResolve, which will surface the original error\n }\n }\n\n // nextResolve() can't handle absolute http(s) URLs (throws ERR_INVALID_URL); short-circuit like load() does.\n if (mapped && (mapped.startsWith('http://') || mapped.startsWith('https://'))) {\n return { url: mapped, format: 'module', shortCircuit: true };\n }\n\n const result = await nextResolve(mapped ?? specifier, context);\n if (!federated) return result;\n federatedURLs.add(result.url);\n return { ...result, format: 'module' };\n}\n\ntype LoadContext = { format?: string | null };\ntype LoadResult = {\n format: string;\n source?: string | ArrayBuffer | Uint8Array;\n shortCircuit?: boolean;\n responseURL?: string;\n};\ntype NextLoad = (url: string, context?: LoadContext) => Promise<LoadResult>;\n\nexport async function load(\n url: string,\n context: LoadContext,\n nextLoad: NextLoad\n): Promise<LoadResult> {\n if (url.startsWith(HOST_PREFIX)) {\n const specifier = decodeURIComponent(url.slice(HOST_PREFIX.length));\n return {\n shortCircuit: true,\n format: 'module',\n source: synthHostModule(specifier, hostInstanceKeys[specifier]),\n };\n }\n if (url.startsWith('http://') || url.startsWith('https://')) {\n lastRemoteBaseURL = url;\n const res = await fetch(url);\n if (!res.ok) {\n throw new Error(`Failed to fetch module from ${url}: ${res.status} ${res.statusText}`);\n }\n const source = await res.text();\n return { shortCircuit: true, format: 'module', source, responseURL: url };\n }\n return nextLoad(url, context);\n}\n\n// --- host-instance bridge --------------------------------------------------\n// Synthesizes an in-memory ESM module whose exports forward to the namespace\n// the host published on `globalThis[HOST_INSTANCES_GLOBAL]`. The export-key\n// list is computed on the main thread (where the namespace lives) and shipped\n// over the port, so the loader realm never has to enumerate a namespace it\n// can't see. The `globalThis[...]` reads below run at module-eval time on the\n// main thread, where the instances actually exist.\n\nfunction synthHostModule(specifier: string, keys: string[] | undefined): string {\n const ID = /^[\\p{ID_Start}$_][\\p{ID_Continue}$]*$/u;\n const ref = `globalThis[${JSON.stringify(HOST_INSTANCES_GLOBAL)}][${JSON.stringify(specifier)}]`;\n const lines = [\n `const __ns = ${ref};`,\n `if (!__ns) throw new Error(${JSON.stringify(\n `[native-federation] host instance '${specifier}' not published`\n )});`,\n ];\n let hasDefault = false;\n for (const k of keys ?? []) {\n if (k === 'default') {\n hasDefault = true;\n continue;\n }\n // Defensive: only emit syntactically valid export identifiers. Angular's\n // \u0275\u2026 names pass \\p{ID_Start}; anything else is skipped.\n if (ID.test(k)) lines.push(`export const ${k} = __ns[${JSON.stringify(k)}];`);\n }\n if (hasDefault) lines.push(`export default __ns[\"default\"];`);\n return lines.join('\\n') + '\\n';\n}\n\n// --- WICG import-map resolve algorithm ------------------------------------\n// https://wicg.github.io/import-maps/#new-resolve-algorithm\n\nfunction resolveSpecifier(map: ImportMap, specifier: string, parentURL?: string): string | null {\n const currentBaseURL = parentURL ? parentURL.slice(0, parentURL.lastIndexOf('/') + 1) : baseURL;\n const normalizedSpecifier = parseURLLikeSpecifier(specifier, currentBaseURL) ?? specifier;\n\n if (map.scopes) {\n for (const scopePrefix in map.scopes) {\n if (\n scopePrefix === currentBaseURL ||\n (scopePrefix.endsWith('/') && currentBaseURL.startsWith(scopePrefix))\n ) {\n const match = resolveImportsMatch(normalizedSpecifier, map.scopes[scopePrefix]!);\n if (match) return match;\n }\n }\n }\n\n return resolveImportsMatch(normalizedSpecifier, map.imports);\n}\n\nfunction resolveImportsMatch(normalizedSpecifier: string, specifierMap: Imports): string | null {\n for (const specifierKey in specifierMap) {\n const resolutionResult = specifierMap[specifierKey];\n if (resolutionResult === undefined) continue;\n\n if (specifierKey === normalizedSpecifier) return resolutionResult;\n\n if (specifierKey.endsWith('/') && normalizedSpecifier.startsWith(specifierKey)) {\n const afterPrefix = normalizedSpecifier.slice(specifierKey.length);\n try {\n return new URL(afterPrefix, resolutionResult).href;\n } catch {\n throw new TypeError(\n `import-map resolution of '${specifierKey}' failed due to URL parse failure`\n );\n }\n }\n }\n return null;\n}\n\nfunction parseURLLikeSpecifier(specifier: string, base: string): string | null {\n const useBase =\n specifier.startsWith('/') || specifier.startsWith('./') || specifier.startsWith('../');\n try {\n return new URL(specifier, useBase ? base : undefined).href;\n } catch {\n return null;\n }\n}\n\nfunction normalize(parsed: ImportMap): ImportMap {\n return {\n imports: parsed.imports ?? {},\n scopes: parsed.scopes ?? {},\n };\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "4.
|
|
2
|
+
"version": "4.8.0",
|
|
3
3
|
"name": "@softarc/native-federation-orchestrator",
|
|
4
4
|
"author": "Aukevanoost",
|
|
5
5
|
"keywords": [
|
|
@@ -19,6 +19,14 @@
|
|
|
19
19
|
"dependencies": {
|
|
20
20
|
"semver": "^7.7.1"
|
|
21
21
|
},
|
|
22
|
+
"peerDependencies": {
|
|
23
|
+
"@softarc/native-federation": "^4.8.0"
|
|
24
|
+
},
|
|
25
|
+
"peerDependenciesMeta": {
|
|
26
|
+
"@softarc/native-federation": {
|
|
27
|
+
"optional": true
|
|
28
|
+
}
|
|
29
|
+
},
|
|
22
30
|
"exports": {
|
|
23
31
|
"./package.json": {
|
|
24
32
|
"default": "./package.json"
|