@earendil-works/chord 1.1.0 → 1.2.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/CHANGELOG.md +20 -0
- package/README.md +77 -194
- package/dist/cell.d.ts +101 -0
- package/dist/cell.d.ts.map +1 -0
- package/dist/cell.js +316 -0
- package/dist/cell.js.map +1 -0
- package/dist/cluster.d.ts +26 -0
- package/dist/cluster.d.ts.map +1 -0
- package/dist/cluster.js +214 -0
- package/dist/cluster.js.map +1 -0
- package/dist/connection.d.ts +157 -0
- package/dist/connection.d.ts.map +1 -0
- package/dist/connection.js +757 -0
- package/dist/connection.js.map +1 -0
- package/dist/context/index.d.ts +12 -1
- package/dist/context/index.d.ts.map +1 -1
- package/dist/context/index.js.map +1 -1
- package/dist/contract.d.ts +133 -0
- package/dist/contract.d.ts.map +1 -0
- package/dist/contract.js +157 -0
- package/dist/contract.js.map +1 -0
- package/dist/declare.d.ts +70 -0
- package/dist/declare.d.ts.map +1 -0
- package/dist/declare.js +22 -0
- package/dist/declare.js.map +1 -0
- package/dist/delta/apply-immutable-trusted.js.map +1 -1
- package/dist/delta/diff.d.ts +1 -1
- package/dist/delta/diff.d.ts.map +1 -1
- package/dist/delta/diff.js.map +1 -1
- package/dist/delta/index.d.ts +2 -2
- package/dist/delta/index.d.ts.map +1 -1
- package/dist/delta/index.js +41 -0
- package/dist/delta/index.js.map +1 -1
- package/dist/delta/revision-validator.d.ts +1 -1
- package/dist/delta/revision-validator.d.ts.map +1 -1
- package/dist/delta/revision-validator.js.map +1 -1
- package/dist/delta/tracker.d.ts +1 -1
- package/dist/delta/tracker.d.ts.map +1 -1
- package/dist/delta/tracker.js +40 -4
- package/dist/delta/tracker.js.map +1 -1
- package/dist/errors.d.ts +27 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +44 -0
- package/dist/errors.js.map +1 -0
- package/dist/host.d.ts +254 -0
- package/dist/host.d.ts.map +1 -0
- package/dist/host.js +795 -0
- package/dist/host.js.map +1 -0
- package/dist/index.d.ts +17 -10
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -8
- package/dist/index.js.map +1 -1
- package/dist/json.d.ts +9 -1
- package/dist/json.d.ts.map +1 -1
- package/dist/json.js.map +1 -1
- package/dist/link.d.ts +72 -0
- package/dist/link.d.ts.map +1 -0
- package/dist/link.js +169 -0
- package/dist/link.js.map +1 -0
- package/dist/loader.d.ts +4 -0
- package/dist/loader.d.ts.map +1 -0
- package/dist/loader.js +68 -0
- package/dist/loader.js.map +1 -0
- package/dist/manager.d.ts +115 -0
- package/dist/manager.d.ts.map +1 -0
- package/dist/manager.js +319 -0
- package/dist/manager.js.map +1 -0
- package/dist/node.d.ts +3 -4
- package/dist/node.d.ts.map +1 -1
- package/dist/node.js +3 -2
- package/dist/node.js.map +1 -1
- package/dist/publish.d.ts +5 -0
- package/dist/publish.d.ts.map +1 -0
- package/dist/publish.js +40 -0
- package/dist/publish.js.map +1 -0
- package/dist/record.d.ts +320 -0
- package/dist/record.d.ts.map +1 -0
- package/dist/record.js +1292 -0
- package/dist/record.js.map +1 -0
- package/dist/registry.d.ts +25 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +6 -0
- package/dist/registry.js.map +1 -0
- package/dist/reload.d.ts +118 -0
- package/dist/reload.d.ts.map +1 -0
- package/dist/reload.js +589 -0
- package/dist/reload.js.map +1 -0
- package/dist/remote.d.ts +70 -0
- package/dist/remote.d.ts.map +1 -0
- package/dist/remote.js +308 -0
- package/dist/remote.js.map +1 -0
- package/dist/schema.d.ts +21 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +228 -0
- package/dist/schema.js.map +1 -0
- package/dist/state.d.ts +92 -0
- package/dist/state.d.ts.map +1 -0
- package/dist/{services/state.js → state.js} +28 -138
- package/dist/state.js.map +1 -0
- package/dist/types.d.ts +62 -262
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/websocket.d.ts +16 -0
- package/dist/websocket.d.ts.map +1 -0
- package/dist/websocket.js +15 -0
- package/dist/websocket.js.map +1 -0
- package/dist/wire.d.ts +135 -0
- package/dist/wire.d.ts.map +1 -0
- package/dist/wire.js +112 -0
- package/dist/wire.js.map +1 -0
- package/docs/guide.md +750 -0
- package/docs/spec.md +261 -0
- package/docs/tutorial.md +909 -0
- package/package.json +9 -10
- package/src/delta/README.md +5 -3
- package/dist/api.d.ts +0 -20
- package/dist/api.d.ts.map +0 -1
- package/dist/api.js +0 -77
- package/dist/api.js.map +0 -1
- package/dist/bundler.d.ts +0 -6
- package/dist/bundler.d.ts.map +0 -1
- package/dist/bundler.js +0 -3
- package/dist/bundler.js.map +0 -1
- package/dist/facets/host.d.ts +0 -12
- package/dist/facets/host.d.ts.map +0 -1
- package/dist/facets/host.js +0 -763
- package/dist/facets/host.js.map +0 -1
- package/dist/facets/loader.d.ts +0 -3
- package/dist/facets/loader.d.ts.map +0 -1
- package/dist/facets/loader.js +0 -5
- package/dist/facets/loader.js.map +0 -1
- package/dist/node/bundle-loader.d.ts +0 -30
- package/dist/node/bundle-loader.d.ts.map +0 -1
- package/dist/node/bundle-loader.js +0 -377
- package/dist/node/bundle-loader.js.map +0 -1
- package/dist/node/bundle.d.ts +0 -26
- package/dist/node/bundle.d.ts.map +0 -1
- package/dist/node/bundle.js +0 -183
- package/dist/node/bundle.js.map +0 -1
- package/dist/node/manifest.d.ts +0 -36
- package/dist/node/manifest.d.ts.map +0 -1
- package/dist/node/manifest.js +0 -6
- package/dist/node/manifest.js.map +0 -1
- package/dist/node/package.d.ts +0 -15
- package/dist/node/package.d.ts.map +0 -1
- package/dist/node/package.js +0 -199
- package/dist/node/package.js.map +0 -1
- package/dist/services/consumer.d.ts +0 -11
- package/dist/services/consumer.d.ts.map +0 -1
- package/dist/services/consumer.js +0 -585
- package/dist/services/consumer.js.map +0 -1
- package/dist/services/errors.d.ts +0 -8
- package/dist/services/errors.d.ts.map +0 -1
- package/dist/services/errors.js +0 -22
- package/dist/services/errors.js.map +0 -1
- package/dist/services/handle.d.ts +0 -15
- package/dist/services/handle.d.ts.map +0 -1
- package/dist/services/handle.js +0 -101
- package/dist/services/handle.js.map +0 -1
- package/dist/services/instances.d.ts +0 -26
- package/dist/services/instances.d.ts.map +0 -1
- package/dist/services/instances.js +0 -140
- package/dist/services/instances.js.map +0 -1
- package/dist/services/loopback.d.ts +0 -5
- package/dist/services/loopback.d.ts.map +0 -1
- package/dist/services/loopback.js +0 -15
- package/dist/services/loopback.js.map +0 -1
- package/dist/services/provider.d.ts +0 -37
- package/dist/services/provider.d.ts.map +0 -1
- package/dist/services/provider.js +0 -521
- package/dist/services/provider.js.map +0 -1
- package/dist/services/state-codec.d.ts +0 -15
- package/dist/services/state-codec.d.ts.map +0 -1
- package/dist/services/state-codec.js +0 -133
- package/dist/services/state-codec.js.map +0 -1
- package/dist/services/state-internals.d.ts +0 -13
- package/dist/services/state-internals.d.ts.map +0 -1
- package/dist/services/state-internals.js +0 -10
- package/dist/services/state-internals.js.map +0 -1
- package/dist/services/state.d.ts +0 -28
- package/dist/services/state.d.ts.map +0 -1
- package/dist/services/state.js.map +0 -1
- package/dist/services/wire.d.ts +0 -63
- package/dist/services/wire.d.ts.map +0 -1
- package/dist/services/wire.js +0 -186
- package/dist/services/wire.js.map +0 -1
package/dist/node/package.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"package.js","sourceRoot":"","sources":["../../src/node/package.ts"],"names":[],"mappings":"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","sourcesContent":["import { readFile, realpath, stat } from \"node:fs/promises\";\nimport { basename, dirname, isAbsolute, join, relative, resolve, sep } from \"node:path\";\nimport { type BundleFacetsResult, bundleFacets } from \"./bundle.ts\";\n\nexport interface BundleFacetPackageOptions {\n\t/** Plugin package directory or its package.json path. */\n\treadonly packagePath: string;\n\treadonly outdir: string;\n\t/** Application conventions applied when the corresponding source file exists. */\n\treadonly defaultFacets?: Readonly<Record<string, string>>;\n}\n\nexport interface BundleFacetPackageResult extends BundleFacetsResult {\n\treadonly packageDirectory: string;\n\treadonly packageJsonPath: string;\n}\n\ninterface FacetPackageMetadata {\n\treadonly packageDirectory: string;\n\treadonly packageJsonPath: string;\n\treadonly name: string;\n\treadonly version: string;\n\treadonly peerDependencies: readonly string[];\n\treadonly configuredFacets: Readonly<Record<string, string | false>>;\n\treadonly external: readonly string[];\n\treadonly sourceMap: boolean;\n}\n\n/** Build a plugin package using package.json metadata and application-provided facet conventions. */\nexport async function bundleFacetPackage(options: BundleFacetPackageOptions): Promise<BundleFacetPackageResult> {\n\tconst metadata = await readFacetPackageMetadata(options.packagePath);\n\tconst entries = await resolveFacetEntries(metadata, options.defaultFacets ?? {});\n\tconst external = [...metadata.peerDependencies, ...metadata.external].flatMap((specifier) => [\n\t\tspecifier,\n\t\t`${specifier}/*`,\n\t]);\n\tconst result = await bundleFacets({\n\t\tplugin: { id: metadata.name, version: metadata.version },\n\t\tentries,\n\t\toutdir: options.outdir,\n\t\tworkingDirectory: metadata.packageDirectory,\n\t\texternal,\n\t\tsourceMap: metadata.sourceMap,\n\t});\n\treturn Object.freeze({\n\t\t...result,\n\t\tpackageDirectory: metadata.packageDirectory,\n\t\tpackageJsonPath: metadata.packageJsonPath,\n\t});\n}\n\nasync function readFacetPackageMetadata(packagePath: string): Promise<FacetPackageMetadata> {\n\tif (packagePath.length === 0) throw new TypeError(\"Facet package path must not be empty\");\n\tconst candidate = resolve(packagePath);\n\tlet packageDirectory: string;\n\tlet packageJsonPath: string;\n\tlet candidateStats: Awaited<ReturnType<typeof stat>>;\n\ttry {\n\t\tcandidateStats = await stat(candidate);\n\t} catch (error) {\n\t\tthrow new Error(`Could not access facet package ${candidate}`, { cause: error });\n\t}\n\tif (candidateStats.isDirectory()) {\n\t\tpackageDirectory = await realpath(candidate);\n\t\tpackageJsonPath = join(packageDirectory, \"package.json\");\n\t} else if (candidateStats.isFile() && basename(candidate) === \"package.json\") {\n\t\tpackageJsonPath = await realpath(candidate);\n\t\tpackageDirectory = dirname(packageJsonPath);\n\t} else {\n\t\tthrow new Error(`Facet package path must name a directory or package.json: ${candidate}`);\n\t}\n\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(await readFile(packageJsonPath, \"utf8\"));\n\t} catch (error) {\n\t\tthrow new Error(`Could not read facet package metadata ${packageJsonPath}`, { cause: error });\n\t}\n\tif (!isRecord(parsed)) throw new Error(`Facet package metadata must be an object: ${packageJsonPath}`);\n\tif (typeof parsed.name !== \"string\" || parsed.name.length === 0) {\n\t\tthrow new Error(`Facet package must have a non-empty name: ${packageJsonPath}`);\n\t}\n\tif (typeof parsed.version !== \"string\" || parsed.version.length === 0) {\n\t\tthrow new Error(`Facet package must have a non-empty version: ${packageJsonPath}`);\n\t}\n\tconst peerDependencies = parsePeerDependencies(parsed.peerDependencies, packageJsonPath);\n\tconst chord = parseChordConfiguration(parsed.chord, packageJsonPath);\n\treturn {\n\t\tpackageDirectory,\n\t\tpackageJsonPath,\n\t\tname: parsed.name,\n\t\tversion: parsed.version,\n\t\tpeerDependencies,\n\t\tconfiguredFacets: chord.facets,\n\t\texternal: chord.external,\n\t\tsourceMap: chord.sourceMap,\n\t};\n}\n\nfunction parsePeerDependencies(value: unknown, packageJsonPath: string): readonly string[] {\n\tif (value === undefined) return [];\n\tif (\n\t\t!isRecord(value) ||\n\t\tObject.entries(value).some(([name, version]) => name.length === 0 || typeof version !== \"string\")\n\t) {\n\t\tthrow new Error(`Facet package has invalid peerDependencies: ${packageJsonPath}`);\n\t}\n\treturn Object.freeze(Object.keys(value).sort());\n}\n\nfunction parseChordConfiguration(\n\tvalue: unknown,\n\tpackageJsonPath: string,\n): {\n\treadonly facets: Readonly<Record<string, string | false>>;\n\treadonly external: readonly string[];\n\treadonly sourceMap: boolean;\n} {\n\tif (value === undefined) return { facets: Object.freeze({}), external: Object.freeze([]), sourceMap: true };\n\tif (!isRecord(value)) throw new Error(`Facet package chord configuration must be an object: ${packageJsonPath}`);\n\tif (Object.keys(value).some((key) => key !== \"facets\" && key !== \"external\" && key !== \"sourceMap\")) {\n\t\tthrow new Error(`Facet package chord configuration has an unknown field: ${packageJsonPath}`);\n\t}\n\tconst facets: Record<string, string | false> = {};\n\tif (value.facets !== undefined) {\n\t\tif (!isRecord(value.facets)) {\n\t\t\tthrow new Error(`Facet package chord.facets must be an object: ${packageJsonPath}`);\n\t\t}\n\t\tfor (const [name, source] of Object.entries(value.facets)) {\n\t\t\tif (name.length === 0 || (typeof source !== \"string\" && source !== false) || source === \"\") {\n\t\t\t\tthrow new Error(`Facet package has an invalid chord.facets entry: ${packageJsonPath}`);\n\t\t\t}\n\t\t\tfacets[name] = source;\n\t\t}\n\t}\n\tlet external: readonly string[] = [];\n\tif (value.external !== undefined) {\n\t\tif (\n\t\t\t!Array.isArray(value.external) ||\n\t\t\tvalue.external.some((specifier) => typeof specifier !== \"string\" || specifier.length === 0)\n\t\t) {\n\t\t\tthrow new Error(`Facet package chord.external must contain non-empty strings: ${packageJsonPath}`);\n\t\t}\n\t\texternal = Object.freeze([...new Set(value.external as readonly string[])].sort());\n\t}\n\tif (value.sourceMap !== undefined && typeof value.sourceMap !== \"boolean\") {\n\t\tthrow new Error(`Facet package chord.sourceMap must be a boolean: ${packageJsonPath}`);\n\t}\n\treturn {\n\t\tfacets: Object.freeze(facets),\n\t\texternal,\n\t\tsourceMap: value.sourceMap ?? true,\n\t};\n}\n\nasync function resolveFacetEntries(\n\tmetadata: FacetPackageMetadata,\n\tdefaultFacets: Readonly<Record<string, string>>,\n): Promise<Readonly<Record<string, string>>> {\n\tconst entries: Record<string, string> = {};\n\tfor (const [name, source] of Object.entries(defaultFacets)) {\n\t\tvalidateFacetMapping(name, source, \"default\");\n\t\tconst path = resolvePackageEntry(metadata.packageDirectory, source, name);\n\t\ttry {\n\t\t\tconst entryStats = await stat(path);\n\t\t\tif (!entryStats.isFile()) throw new Error(`Default facet entry ${name} is not a file: ${path}`);\n\t\t\tconst canonicalPath = await realpath(path);\n\t\t\tvalidateCanonicalPackageEntry(metadata.packageDirectory, canonicalPath, name);\n\t\t\tentries[name] = canonicalPath;\n\t\t} catch (error) {\n\t\t\tif (isMissingPath(error)) continue;\n\t\t\tthrow error;\n\t\t}\n\t}\n\tfor (const [name, source] of Object.entries(metadata.configuredFacets)) {\n\t\tif (source === false) {\n\t\t\tdelete entries[name];\n\t\t\tcontinue;\n\t\t}\n\t\tvalidateFacetMapping(name, source, \"configured\");\n\t\tconst path = resolvePackageEntry(metadata.packageDirectory, source, name);\n\t\tlet entryStats: Awaited<ReturnType<typeof stat>>;\n\t\ttry {\n\t\t\tentryStats = await stat(path);\n\t\t} catch (error) {\n\t\t\tthrow new Error(`Could not access configured facet entry ${name}: ${path}`, { cause: error });\n\t\t}\n\t\tif (!entryStats.isFile()) throw new Error(`Configured facet entry ${name} is not a file: ${path}`);\n\t\tconst canonicalPath = await realpath(path);\n\t\tvalidateCanonicalPackageEntry(metadata.packageDirectory, canonicalPath, name);\n\t\tentries[name] = canonicalPath;\n\t}\n\tif (Object.keys(entries).length === 0) {\n\t\tthrow new Error(`Facet package ${metadata.name} has no configured or conventional facet entries`);\n\t}\n\treturn Object.freeze(entries);\n}\n\nfunction validateFacetMapping(name: string, source: string, kind: string): void {\n\tif (name.length === 0) throw new Error(`Facet package ${kind} entry name must not be empty`);\n\tif (source.length === 0) throw new Error(`Facet package ${kind} entry ${name} must have a source path`);\n}\n\nfunction resolvePackageEntry(packageDirectory: string, source: string, name: string): string {\n\tif (isAbsolute(source)) throw new Error(`Facet package entry ${name} must be relative to the package directory`);\n\tconst path = resolve(packageDirectory, source);\n\tconst relativePath = relative(packageDirectory, path);\n\tif (\n\t\trelativePath.length === 0 ||\n\t\trelativePath === \"..\" ||\n\t\trelativePath.startsWith(`..${sep}`) ||\n\t\tisAbsolute(relativePath)\n\t) {\n\t\tthrow new Error(`Facet package entry ${name} escapes the package directory`);\n\t}\n\treturn path;\n}\n\nfunction validateCanonicalPackageEntry(packageDirectory: string, path: string, name: string): void {\n\tconst relativePath = relative(packageDirectory, path);\n\tif (relativePath === \"..\" || relativePath.startsWith(`..${sep}`) || isAbsolute(relativePath)) {\n\t\tthrow new Error(`Facet package entry ${name} resolves outside the package directory`);\n\t}\n}\n\nfunction isMissingPath(error: unknown): boolean {\n\treturn isRecord(error) && error.code === \"ENOENT\";\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n"]}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import type { Context, RemoteServiceBinding, RemoteServiceBindingOptions, Service } from "../types.ts";
|
|
2
|
-
export declare class RemoteServiceBindingImpl implements RemoteServiceBinding {
|
|
3
|
-
#private;
|
|
4
|
-
constructor(options: RemoteServiceBindingOptions);
|
|
5
|
-
use<T>(service: Service<T>): T;
|
|
6
|
-
observe<T>(service: Service<T>, handler: (service: T, context: Context) => void | Promise<void>): () => void;
|
|
7
|
-
ready(context: Context): Promise<void>;
|
|
8
|
-
rebind(bound: boolean, context: Context): Promise<void>;
|
|
9
|
-
dispose(context: Context): Promise<void>;
|
|
10
|
-
}
|
|
11
|
-
//# sourceMappingURL=consumer.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"consumer.d.ts","sourceRoot":"","sources":["../../src/services/consumer.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACX,OAAO,EAEP,oBAAoB,EACpB,2BAA2B,EAG3B,OAAO,EAOP,MAAM,aAAa,CAAC;AA2arB,qBAAa,wBAAyB,YAAW,oBAAoB;;IAapE,YAAY,OAAO,EAAE,2BAA2B,EAQ/C;IAED,GAAG,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CA2B7B;IAED,OAAO,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,MAAM,IAAI,CAsB3G;IAEK,KAAK,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAkB3C;IAEK,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CA8B5D;IAEK,OAAO,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAoB7C;CAkED"}
|
|
@@ -1,585 +0,0 @@
|
|
|
1
|
-
import { awaitWithContext, BACKGROUND_CONTEXT } from "../context/index.js";
|
|
2
|
-
import { RemoteServiceError } from "./errors.js";
|
|
3
|
-
import { ServiceSlot } from "./handle.js";
|
|
4
|
-
import { InstanceDirectory } from "./instances.js";
|
|
5
|
-
import { ReplicatedStateReplica, serviceDeliveryContext } from "./state.js";
|
|
6
|
-
class MemberSlot {
|
|
7
|
-
#serviceId;
|
|
8
|
-
#member;
|
|
9
|
-
#invoke;
|
|
10
|
-
#state;
|
|
11
|
-
#isActive;
|
|
12
|
-
#assertAccess;
|
|
13
|
-
value;
|
|
14
|
-
#kind;
|
|
15
|
-
#expectedKind;
|
|
16
|
-
constructor(serviceId, member, invoke, isActive, assertAccess, reportError) {
|
|
17
|
-
this.#serviceId = serviceId;
|
|
18
|
-
this.#member = member;
|
|
19
|
-
this.#invoke = invoke;
|
|
20
|
-
this.#isActive = isActive;
|
|
21
|
-
this.#assertAccess = assertAccess;
|
|
22
|
-
this.#state = new ReplicatedStateReplica(reportError);
|
|
23
|
-
const callable = () => { };
|
|
24
|
-
this.value = new Proxy(callable, {
|
|
25
|
-
apply: (_target, _thisArg, args) => this.#call(args),
|
|
26
|
-
get: (_target, property) => {
|
|
27
|
-
if (property === "value") {
|
|
28
|
-
this.#assertAccess();
|
|
29
|
-
this.#expect("state");
|
|
30
|
-
return this.#state.value;
|
|
31
|
-
}
|
|
32
|
-
if (property === "subscribe")
|
|
33
|
-
return this.#subscribe.bind(this);
|
|
34
|
-
if (property === Symbol.toStringTag)
|
|
35
|
-
return "RemoteServiceMember";
|
|
36
|
-
if (property === "then")
|
|
37
|
-
return undefined;
|
|
38
|
-
return undefined;
|
|
39
|
-
},
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
setDescription(kind) {
|
|
43
|
-
if (this.#kind !== undefined && this.#kind !== kind) {
|
|
44
|
-
throw new Error(`Remote service member ${this.#serviceId}.${this.#member} changed kind`);
|
|
45
|
-
}
|
|
46
|
-
this.#kind = kind;
|
|
47
|
-
if (this.#expectedKind !== undefined && this.#expectedKind !== kind) {
|
|
48
|
-
throw new RemoteServiceError("service_member_mismatch", `Remote service member ${this.#serviceId}.${this.#member} is ${kind}, not ${this.#expectedKind}`);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
hydrate(sequence, ops, context) {
|
|
52
|
-
this.setDescription("state");
|
|
53
|
-
this.#state.hydrate(sequence, ops, context);
|
|
54
|
-
}
|
|
55
|
-
update(sequence, ops, context) {
|
|
56
|
-
this.setDescription("state");
|
|
57
|
-
this.#state.update(sequence, ops, context);
|
|
58
|
-
}
|
|
59
|
-
clear() {
|
|
60
|
-
this.#state.clear();
|
|
61
|
-
}
|
|
62
|
-
#subscribe(listener) {
|
|
63
|
-
this.#assertAccess();
|
|
64
|
-
if (typeof listener !== "function") {
|
|
65
|
-
throw new TypeError("Replicated state subscription listener must be a function");
|
|
66
|
-
}
|
|
67
|
-
this.#expect("state");
|
|
68
|
-
return this.#state.subscribe(listener);
|
|
69
|
-
}
|
|
70
|
-
#expect(kind) {
|
|
71
|
-
if (this.#expectedKind !== undefined && this.#expectedKind !== kind) {
|
|
72
|
-
throw new RemoteServiceError("service_member_mismatch", `Remote service member ${this.#serviceId}.${this.#member} was used as two different kinds`);
|
|
73
|
-
}
|
|
74
|
-
this.#expectedKind = kind;
|
|
75
|
-
if (this.#kind !== undefined && this.#kind !== kind) {
|
|
76
|
-
throw new RemoteServiceError("service_member_mismatch", `Remote service member ${this.#serviceId}.${this.#member} is ${this.#kind}, not ${kind}`);
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
#call(args) {
|
|
80
|
-
this.#assertAccess();
|
|
81
|
-
this.#expect("method");
|
|
82
|
-
if (!this.#isActive()) {
|
|
83
|
-
return Promise.reject(new RemoteServiceError("service_stale_instance", `Remote service ${this.#serviceId} binding is closed`));
|
|
84
|
-
}
|
|
85
|
-
const context = args.at(-1);
|
|
86
|
-
if (!isContext(context)) {
|
|
87
|
-
return Promise.reject(new RemoteServiceError("service_invalid_value", `Remote service method ${this.#serviceId}.${this.#member} requires a trailing Context`));
|
|
88
|
-
}
|
|
89
|
-
const businessArgs = args.slice(0, -1);
|
|
90
|
-
return this.#invoke(businessArgs, context);
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
class ServiceFacade {
|
|
94
|
-
#serviceId;
|
|
95
|
-
#address;
|
|
96
|
-
#transport;
|
|
97
|
-
#reportError;
|
|
98
|
-
#slots = new Map();
|
|
99
|
-
#descriptions = new Map();
|
|
100
|
-
#isActive;
|
|
101
|
-
#assertAccess;
|
|
102
|
-
proxy;
|
|
103
|
-
constructor(serviceId, address, transport, isActive, assertAccess, reportError) {
|
|
104
|
-
this.#serviceId = serviceId;
|
|
105
|
-
this.#address = address;
|
|
106
|
-
this.#transport = transport;
|
|
107
|
-
this.#isActive = isActive;
|
|
108
|
-
this.#assertAccess = assertAccess;
|
|
109
|
-
this.#reportError = reportError;
|
|
110
|
-
this.proxy = new Proxy(Object.create(null), {
|
|
111
|
-
get: (_target, property) => {
|
|
112
|
-
if (typeof property !== "string")
|
|
113
|
-
return undefined;
|
|
114
|
-
return this.#slot(property).value;
|
|
115
|
-
},
|
|
116
|
-
});
|
|
117
|
-
}
|
|
118
|
-
install(snapshot, context) {
|
|
119
|
-
if (!sameAddress(snapshot.instance, this.#address))
|
|
120
|
-
throw new Error("Remote service snapshot has the wrong address");
|
|
121
|
-
const members = validateMembers(snapshot.members);
|
|
122
|
-
for (const name of this.#slots.keys()) {
|
|
123
|
-
if (!members.has(name)) {
|
|
124
|
-
throw new RemoteServiceError("service_member_not_found", `Unknown remote service member ${this.#serviceId}.${name}`);
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
this.#descriptions.clear();
|
|
128
|
-
for (const [name, member] of members)
|
|
129
|
-
this.#descriptions.set(name, member.kind);
|
|
130
|
-
for (const member of members.values()) {
|
|
131
|
-
const slot = this.#slots.get(member.name);
|
|
132
|
-
if (member.kind === "state") {
|
|
133
|
-
(slot ?? this.#slot(member.name)).hydrate(member.sequence, member.ops, context);
|
|
134
|
-
}
|
|
135
|
-
else {
|
|
136
|
-
slot?.setDescription(member.kind);
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
update(member, sequence, ops, context) {
|
|
141
|
-
if (this.#descriptions.get(member) !== "state") {
|
|
142
|
-
throw new Error(`Remote service update targets non-state member ${this.#serviceId}.${member}`);
|
|
143
|
-
}
|
|
144
|
-
this.#slot(member).update(sequence, ops, context);
|
|
145
|
-
}
|
|
146
|
-
clear() {
|
|
147
|
-
for (const slot of this.#slots.values())
|
|
148
|
-
slot.clear();
|
|
149
|
-
}
|
|
150
|
-
#slot(member) {
|
|
151
|
-
let slot = this.#slots.get(member);
|
|
152
|
-
if (slot !== undefined)
|
|
153
|
-
return slot;
|
|
154
|
-
slot = new MemberSlot(this.#serviceId, member, (args, context) => this.#transport.invoke({
|
|
155
|
-
serviceId: this.#serviceId,
|
|
156
|
-
...(this.#address === undefined ? {} : { instance: this.#address }),
|
|
157
|
-
member,
|
|
158
|
-
args,
|
|
159
|
-
}, context), this.#isActive, this.#assertAccess, this.#reportError);
|
|
160
|
-
const kind = this.#descriptions.get(member);
|
|
161
|
-
if (kind !== undefined)
|
|
162
|
-
slot.setDescription(kind);
|
|
163
|
-
this.#slots.set(member, slot);
|
|
164
|
-
return slot;
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
class KeyedBinding {
|
|
168
|
-
#service;
|
|
169
|
-
#transport;
|
|
170
|
-
#reportError;
|
|
171
|
-
#assertAccess;
|
|
172
|
-
#onEmpty;
|
|
173
|
-
#instances;
|
|
174
|
-
#subscription;
|
|
175
|
-
#starting;
|
|
176
|
-
#closed = false;
|
|
177
|
-
#bound;
|
|
178
|
-
#revision = 0;
|
|
179
|
-
constructor(service, transport, reportError, assertAccess, onEmpty, bound) {
|
|
180
|
-
this.#service = service;
|
|
181
|
-
this.#transport = transport;
|
|
182
|
-
this.#reportError = reportError;
|
|
183
|
-
this.#assertAccess = assertAccess;
|
|
184
|
-
this.#onEmpty = onEmpty;
|
|
185
|
-
this.#bound = bound;
|
|
186
|
-
this.#instances = new InstanceDirectory({ ready: false, onError: reportError });
|
|
187
|
-
}
|
|
188
|
-
observe(handler) {
|
|
189
|
-
if (this.#closed)
|
|
190
|
-
throw new Error("Remote keyed service binding is closed");
|
|
191
|
-
let stopped = false;
|
|
192
|
-
const stop = this.#instances.observe((service, context) => {
|
|
193
|
-
const slot = new ServiceSlot(this.#service.id, true);
|
|
194
|
-
void slot.bind(service);
|
|
195
|
-
return handler(slot.view(() => {
|
|
196
|
-
this.#assertAccess();
|
|
197
|
-
if (stopped || context.abortSignal?.aborted) {
|
|
198
|
-
throw new RemoteServiceError("service_stale_instance", `Remote service ${this.#service.id} observation is closed`);
|
|
199
|
-
}
|
|
200
|
-
}), context);
|
|
201
|
-
});
|
|
202
|
-
if (this.#bound && this.#starting === undefined) {
|
|
203
|
-
const revision = this.#revision;
|
|
204
|
-
const starting = this.#start(revision);
|
|
205
|
-
this.#starting = starting;
|
|
206
|
-
void starting.catch((error) => {
|
|
207
|
-
if (!this.#closed && this.#revision === revision && this.#bound)
|
|
208
|
-
this.#reportError(toError(error));
|
|
209
|
-
});
|
|
210
|
-
}
|
|
211
|
-
return () => {
|
|
212
|
-
if (stopped)
|
|
213
|
-
return;
|
|
214
|
-
stopped = true;
|
|
215
|
-
stop();
|
|
216
|
-
if (this.#instances.observerCount === 0)
|
|
217
|
-
this.#onEmpty();
|
|
218
|
-
};
|
|
219
|
-
}
|
|
220
|
-
async rebind(bound, context) {
|
|
221
|
-
if (this.#closed)
|
|
222
|
-
return;
|
|
223
|
-
this.#bound = bound;
|
|
224
|
-
const revision = ++this.#revision;
|
|
225
|
-
await this.#reset(context, false);
|
|
226
|
-
if (this.#closed || this.#revision !== revision || this.#bound !== bound)
|
|
227
|
-
return;
|
|
228
|
-
if (bound && this.#instances.observerCount > 0) {
|
|
229
|
-
const starting = this.#start(revision);
|
|
230
|
-
this.#starting = starting;
|
|
231
|
-
await starting;
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
ready() {
|
|
235
|
-
return this.#starting ?? Promise.resolve();
|
|
236
|
-
}
|
|
237
|
-
async close(context) {
|
|
238
|
-
if (this.#closed)
|
|
239
|
-
return;
|
|
240
|
-
this.#closed = true;
|
|
241
|
-
this.#revision += 1;
|
|
242
|
-
await this.#reset(context, true);
|
|
243
|
-
this.#instances.dispose();
|
|
244
|
-
}
|
|
245
|
-
async #reset(context, waitForStarting) {
|
|
246
|
-
this.#instances.reset();
|
|
247
|
-
const starting = this.#starting;
|
|
248
|
-
this.#starting = undefined;
|
|
249
|
-
const subscription = this.#subscription;
|
|
250
|
-
this.#subscription = undefined;
|
|
251
|
-
await Promise.all([
|
|
252
|
-
waitForStarting ? starting?.catch(() => { }) : undefined,
|
|
253
|
-
subscription === undefined ? undefined : subscription.close(context),
|
|
254
|
-
]);
|
|
255
|
-
}
|
|
256
|
-
async #start(revision) {
|
|
257
|
-
const subscription = await this.#transport.subscribe(this.#service.id, "keyed", (update, context) => {
|
|
258
|
-
if (this.#revision === revision)
|
|
259
|
-
this.#update(update, context);
|
|
260
|
-
}, BACKGROUND_CONTEXT);
|
|
261
|
-
if (this.#closed || !this.#bound || this.#revision !== revision) {
|
|
262
|
-
await subscription.close(BACKGROUND_CONTEXT);
|
|
263
|
-
return;
|
|
264
|
-
}
|
|
265
|
-
this.#subscription = subscription;
|
|
266
|
-
if (subscription.snapshot.mode !== "keyed" || subscription.snapshot.serviceId !== this.#service.id) {
|
|
267
|
-
throw new Error(`Remote service ${this.#service.id} returned the wrong keyed snapshot`);
|
|
268
|
-
}
|
|
269
|
-
for (const snapshot of subscription.snapshot.instances)
|
|
270
|
-
this.#spawn(snapshot, serviceDeliveryContext());
|
|
271
|
-
subscription.activate();
|
|
272
|
-
this.#instances.ready();
|
|
273
|
-
}
|
|
274
|
-
#update(update, context) {
|
|
275
|
-
if (this.#closed)
|
|
276
|
-
return;
|
|
277
|
-
try {
|
|
278
|
-
switch (update.type) {
|
|
279
|
-
case "reset": {
|
|
280
|
-
validateResetSnapshot(update.snapshot, this.#service.id, "keyed");
|
|
281
|
-
const snapshots = new Map(update.snapshot.instances.map((snapshot) => [snapshot.instance.key, snapshot]));
|
|
282
|
-
for (const instance of [...this.#instances.values()]) {
|
|
283
|
-
if (snapshots.get(instance.key)?.instance?.generation !== instance.generation) {
|
|
284
|
-
this.#instances.remove(instance);
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
for (const snapshot of snapshots.values()) {
|
|
288
|
-
const instance = this.#instances.get(snapshot.instance.key);
|
|
289
|
-
if (instance === undefined)
|
|
290
|
-
this.#spawn(snapshot, context);
|
|
291
|
-
else
|
|
292
|
-
instance.facade.install(snapshot, context);
|
|
293
|
-
}
|
|
294
|
-
break;
|
|
295
|
-
}
|
|
296
|
-
case "unavailable":
|
|
297
|
-
case "replaced":
|
|
298
|
-
throw new Error("Keyed service received a singleton lifecycle update");
|
|
299
|
-
case "spawned":
|
|
300
|
-
this.#spawn(update.instance, context);
|
|
301
|
-
break;
|
|
302
|
-
case "closed": {
|
|
303
|
-
const instance = this.#instances.get(update.instance.key);
|
|
304
|
-
if (instance?.generation === update.instance.generation)
|
|
305
|
-
this.#instances.remove(instance);
|
|
306
|
-
break;
|
|
307
|
-
}
|
|
308
|
-
case "state": {
|
|
309
|
-
if (update.instance === undefined)
|
|
310
|
-
throw new Error("Keyed state update has no instance address");
|
|
311
|
-
const instance = this.#instances.get(update.instance.key);
|
|
312
|
-
if (instance?.generation !== update.instance.generation)
|
|
313
|
-
return;
|
|
314
|
-
instance.facade.update(update.member, update.sequence, update.ops, context);
|
|
315
|
-
break;
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
catch (error) {
|
|
320
|
-
this.#reportError(toError(error));
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
#spawn(snapshot, context) {
|
|
324
|
-
const address = snapshot.instance;
|
|
325
|
-
if (address === undefined)
|
|
326
|
-
throw new Error("Keyed service instance snapshot has no address");
|
|
327
|
-
let active = true;
|
|
328
|
-
const facade = new ServiceFacade(this.#service.id, address, this.#transport, () => active && !this.#closed, this.#assertAccess, this.#reportError);
|
|
329
|
-
facade.install(snapshot, context);
|
|
330
|
-
this.#instances.replace({
|
|
331
|
-
key: address.key,
|
|
332
|
-
generation: address.generation,
|
|
333
|
-
service: facade.proxy,
|
|
334
|
-
facade,
|
|
335
|
-
deactivate: () => {
|
|
336
|
-
active = false;
|
|
337
|
-
facade.clear();
|
|
338
|
-
},
|
|
339
|
-
});
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
export class RemoteServiceBindingImpl {
|
|
343
|
-
#transport;
|
|
344
|
-
#allowlist = new Set();
|
|
345
|
-
#reportError;
|
|
346
|
-
#modes = new Map();
|
|
347
|
-
#assertAccess;
|
|
348
|
-
#singletons = new Map();
|
|
349
|
-
#keyed = new Map();
|
|
350
|
-
#bound;
|
|
351
|
-
#readinessRevision = 0;
|
|
352
|
-
#bindingTransition = Promise.resolve();
|
|
353
|
-
#disposed = false;
|
|
354
|
-
constructor(options) {
|
|
355
|
-
this.#transport = options.transport;
|
|
356
|
-
const ids = options.services.map(({ id }) => id);
|
|
357
|
-
if (new Set(ids).size !== ids.length)
|
|
358
|
-
throw new TypeError("Remote service binding has duplicate service IDs");
|
|
359
|
-
for (const id of ids)
|
|
360
|
-
this.#allowlist.add(id);
|
|
361
|
-
this.#reportError = options.onError ?? (() => { });
|
|
362
|
-
this.#assertAccess = options.assertAccess ?? (() => { });
|
|
363
|
-
this.#bound = options.bound ?? true;
|
|
364
|
-
}
|
|
365
|
-
use(service) {
|
|
366
|
-
this.#assertRemotable(service);
|
|
367
|
-
this.#assertAvailable(service.id, "singleton");
|
|
368
|
-
let binding = this.#singletons.get(service.id);
|
|
369
|
-
if (binding !== undefined)
|
|
370
|
-
return binding.facade.proxy;
|
|
371
|
-
binding = { facade: undefined, active: true, revision: 0 };
|
|
372
|
-
binding.facade = new ServiceFacade(service.id, undefined, this.#transport, () => binding.active && !this.#disposed && this.#bound, () => this.#assertHandleAccess(), this.#reportError);
|
|
373
|
-
this.#singletons.set(service.id, binding);
|
|
374
|
-
this.#readinessRevision += 1;
|
|
375
|
-
if (this.#bound) {
|
|
376
|
-
const revision = binding.revision;
|
|
377
|
-
const starting = this.#startSingleton(service.id, binding, revision);
|
|
378
|
-
binding.starting = starting;
|
|
379
|
-
void starting.catch((error) => {
|
|
380
|
-
if (binding.active && binding.revision === revision && !this.#disposed && this.#bound) {
|
|
381
|
-
this.#reportError(toError(error));
|
|
382
|
-
}
|
|
383
|
-
});
|
|
384
|
-
}
|
|
385
|
-
return binding.facade.proxy;
|
|
386
|
-
}
|
|
387
|
-
observe(service, handler) {
|
|
388
|
-
this.#assertRemotable(service);
|
|
389
|
-
this.#assertAvailable(service.id, "keyed");
|
|
390
|
-
let binding = this.#keyed.get(service.id);
|
|
391
|
-
if (binding === undefined) {
|
|
392
|
-
binding = new KeyedBinding(service, this.#transport, this.#reportError, () => this.#assertHandleAccess(), () => {
|
|
393
|
-
if (this.#keyed.get(service.id) !== binding)
|
|
394
|
-
return;
|
|
395
|
-
this.#keyed.delete(service.id);
|
|
396
|
-
this.#readinessRevision += 1;
|
|
397
|
-
void binding.close(BACKGROUND_CONTEXT).catch(this.#reportError);
|
|
398
|
-
}, this.#bound);
|
|
399
|
-
this.#keyed.set(service.id, binding);
|
|
400
|
-
this.#readinessRevision += 1;
|
|
401
|
-
}
|
|
402
|
-
return binding.observe(handler);
|
|
403
|
-
}
|
|
404
|
-
async ready(context) {
|
|
405
|
-
if (this.#disposed)
|
|
406
|
-
throw new Error("Remote service binding is disposed");
|
|
407
|
-
while (true) {
|
|
408
|
-
const revision = this.#readinessRevision;
|
|
409
|
-
const starts = [
|
|
410
|
-
this.#bindingTransition,
|
|
411
|
-
...[...this.#singletons.values()].flatMap((binding) => binding.starting === undefined ? [] : [binding.starting]),
|
|
412
|
-
...[...this.#keyed.values()].map((binding) => binding.ready()),
|
|
413
|
-
];
|
|
414
|
-
await awaitWithContext(Promise.all(starts).then(() => undefined), context);
|
|
415
|
-
if (this.#disposed)
|
|
416
|
-
throw new Error("Remote service binding is disposed");
|
|
417
|
-
if (revision === this.#readinessRevision)
|
|
418
|
-
return;
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
|
-
async rebind(bound, context) {
|
|
422
|
-
if (this.#disposed)
|
|
423
|
-
throw new Error("Remote service binding is disposed");
|
|
424
|
-
this.#bound = bound;
|
|
425
|
-
this.#readinessRevision += 1;
|
|
426
|
-
const transitions = [];
|
|
427
|
-
for (const [serviceId, binding] of this.#singletons) {
|
|
428
|
-
binding.revision += 1;
|
|
429
|
-
binding.facade.clear();
|
|
430
|
-
const subscription = binding.subscription;
|
|
431
|
-
delete binding.subscription;
|
|
432
|
-
const revision = binding.revision;
|
|
433
|
-
const starting = (async () => {
|
|
434
|
-
await subscription?.close(context);
|
|
435
|
-
if (bound)
|
|
436
|
-
await this.#startSingleton(serviceId, binding, revision);
|
|
437
|
-
})();
|
|
438
|
-
binding.starting = starting;
|
|
439
|
-
transitions.push(starting);
|
|
440
|
-
}
|
|
441
|
-
for (const binding of this.#keyed.values())
|
|
442
|
-
transitions.push(binding.rebind(bound, context));
|
|
443
|
-
const completion = (async () => {
|
|
444
|
-
const results = await Promise.allSettled(transitions);
|
|
445
|
-
const errors = results.filter((result) => result.status === "rejected");
|
|
446
|
-
if (errors.length > 0)
|
|
447
|
-
throw new AggregateError(errors.map(({ reason }) => reason), "Failed to rebind services");
|
|
448
|
-
})();
|
|
449
|
-
this.#bindingTransition = completion;
|
|
450
|
-
await completion;
|
|
451
|
-
}
|
|
452
|
-
async dispose(context) {
|
|
453
|
-
if (this.#disposed)
|
|
454
|
-
return;
|
|
455
|
-
this.#disposed = true;
|
|
456
|
-
const closes = [];
|
|
457
|
-
for (const binding of this.#singletons.values()) {
|
|
458
|
-
binding.active = false;
|
|
459
|
-
binding.facade.clear();
|
|
460
|
-
if (binding.starting)
|
|
461
|
-
closes.push(binding.starting.catch(() => { }));
|
|
462
|
-
if (binding.subscription)
|
|
463
|
-
closes.push(Promise.resolve(binding.subscription.close(context)));
|
|
464
|
-
}
|
|
465
|
-
for (const binding of this.#keyed.values())
|
|
466
|
-
closes.push(binding.close(context));
|
|
467
|
-
this.#singletons.clear();
|
|
468
|
-
this.#keyed.clear();
|
|
469
|
-
const results = await Promise.allSettled(closes);
|
|
470
|
-
const errors = results.filter((result) => result.status === "rejected");
|
|
471
|
-
if (errors.length > 0)
|
|
472
|
-
throw new AggregateError(errors.map(({ reason }) => reason), "Failed to dispose services");
|
|
473
|
-
}
|
|
474
|
-
async #startSingleton(serviceId, binding, revision) {
|
|
475
|
-
const subscription = await this.#transport.subscribe(serviceId, "singleton", (update, context) => {
|
|
476
|
-
if (!binding.active || binding.revision !== revision)
|
|
477
|
-
return;
|
|
478
|
-
try {
|
|
479
|
-
if (update.type === "reset") {
|
|
480
|
-
validateResetSnapshot(update.snapshot, serviceId, "singleton");
|
|
481
|
-
const snapshot = update.snapshot.instances[0];
|
|
482
|
-
if (snapshot === undefined)
|
|
483
|
-
binding.facade.clear();
|
|
484
|
-
else
|
|
485
|
-
binding.facade.install(snapshot, context);
|
|
486
|
-
}
|
|
487
|
-
else if (update.type === "unavailable") {
|
|
488
|
-
binding.facade.clear();
|
|
489
|
-
}
|
|
490
|
-
else if (update.type === "replaced") {
|
|
491
|
-
if (update.snapshot.instance !== undefined) {
|
|
492
|
-
throw new Error("Singleton replacement has an instance address");
|
|
493
|
-
}
|
|
494
|
-
binding.facade.install(update.snapshot, context);
|
|
495
|
-
}
|
|
496
|
-
else if (update.type === "state" && update.instance === undefined) {
|
|
497
|
-
binding.facade.update(update.member, update.sequence, update.ops, context);
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
|
-
catch (error) {
|
|
501
|
-
this.#reportError(toError(error));
|
|
502
|
-
}
|
|
503
|
-
}, BACKGROUND_CONTEXT);
|
|
504
|
-
if (!binding.active || this.#disposed || !this.#bound || binding.revision !== revision) {
|
|
505
|
-
await subscription.close(BACKGROUND_CONTEXT);
|
|
506
|
-
return;
|
|
507
|
-
}
|
|
508
|
-
binding.subscription = subscription;
|
|
509
|
-
const snapshot = subscription.snapshot;
|
|
510
|
-
if (snapshot.mode !== "singleton" || snapshot.serviceId !== serviceId || snapshot.instances.length !== 1) {
|
|
511
|
-
throw new Error(`Remote service ${serviceId} returned an invalid singleton snapshot`);
|
|
512
|
-
}
|
|
513
|
-
binding.facade.install(snapshot.instances[0], serviceDeliveryContext());
|
|
514
|
-
subscription.activate();
|
|
515
|
-
}
|
|
516
|
-
#assertHandleAccess() {
|
|
517
|
-
if (this.#disposed)
|
|
518
|
-
throw new Error("Remote service binding is disposed");
|
|
519
|
-
this.#assertAccess();
|
|
520
|
-
}
|
|
521
|
-
#assertRemotable(service) {
|
|
522
|
-
if (service.local)
|
|
523
|
-
throw new RemoteServiceError("service_not_allowed", `Service ${service.id} is process-local`);
|
|
524
|
-
}
|
|
525
|
-
#assertAvailable(serviceId, mode) {
|
|
526
|
-
if (this.#disposed)
|
|
527
|
-
throw new Error("Remote service binding is disposed");
|
|
528
|
-
if (!this.#allowlist.has(serviceId)) {
|
|
529
|
-
throw new RemoteServiceError("service_not_allowed", `Remote service ${serviceId} is not allowlisted`);
|
|
530
|
-
}
|
|
531
|
-
const existing = this.#modes.get(serviceId);
|
|
532
|
-
if (existing !== undefined && existing !== mode) {
|
|
533
|
-
throw new RemoteServiceError("service_mode_mismatch", `Remote service ${serviceId} is already used as ${existing}`);
|
|
534
|
-
}
|
|
535
|
-
this.#modes.set(serviceId, mode);
|
|
536
|
-
}
|
|
537
|
-
}
|
|
538
|
-
function validateResetSnapshot(snapshot, serviceId, mode) {
|
|
539
|
-
if (snapshot.serviceId !== serviceId ||
|
|
540
|
-
snapshot.mode !== mode ||
|
|
541
|
-
(mode === "singleton" && snapshot.instances.length > 1)) {
|
|
542
|
-
throw new Error("Remote service reset has the wrong service or mode");
|
|
543
|
-
}
|
|
544
|
-
const keys = new Set();
|
|
545
|
-
for (const instance of snapshot.instances) {
|
|
546
|
-
if (mode === "singleton" ? instance.instance !== undefined : instance.instance === undefined) {
|
|
547
|
-
throw new Error("Remote service reset has an invalid instance address");
|
|
548
|
-
}
|
|
549
|
-
if (instance.instance !== undefined) {
|
|
550
|
-
if (keys.has(instance.instance.key))
|
|
551
|
-
throw new Error("Remote service reset repeats an instance key");
|
|
552
|
-
keys.add(instance.instance.key);
|
|
553
|
-
}
|
|
554
|
-
for (const member of instance.members) {
|
|
555
|
-
if (member.kind === "state" && (member.ops.length !== 1 || member.ops[0]?.[0] !== "r")) {
|
|
556
|
-
throw new Error("Remote service reset must contain full root replacements");
|
|
557
|
-
}
|
|
558
|
-
}
|
|
559
|
-
}
|
|
560
|
-
}
|
|
561
|
-
function validateMembers(members) {
|
|
562
|
-
const result = new Map();
|
|
563
|
-
for (const member of members) {
|
|
564
|
-
if (member.name.length === 0 || result.has(member.name)) {
|
|
565
|
-
throw new Error("Remote service has invalid member descriptions");
|
|
566
|
-
}
|
|
567
|
-
result.set(member.name, member);
|
|
568
|
-
}
|
|
569
|
-
return result;
|
|
570
|
-
}
|
|
571
|
-
function sameAddress(left, right) {
|
|
572
|
-
if (left === undefined || right === undefined)
|
|
573
|
-
return left === right;
|
|
574
|
-
return left.key === right.key && left.generation === right.generation;
|
|
575
|
-
}
|
|
576
|
-
function isContext(value) {
|
|
577
|
-
if (typeof value !== "object" || value === null)
|
|
578
|
-
return false;
|
|
579
|
-
const candidate = value;
|
|
580
|
-
return typeof candidate.value === "function" && typeof candidate.toString === "function";
|
|
581
|
-
}
|
|
582
|
-
function toError(error) {
|
|
583
|
-
return error instanceof Error ? error : new Error(String(error));
|
|
584
|
-
}
|
|
585
|
-
//# sourceMappingURL=consumer.js.map
|