@serve.zone/interfaces 32.2.0 → 32.4.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.
Files changed (35) hide show
  1. package/changelog.md +69 -0
  2. package/dist_ts/00_commitinfo_data.js +1 -1
  3. package/dist_ts/data/cluster.d.ts +30 -0
  4. package/dist_ts/data/cluster.js +46 -2
  5. package/dist_ts/data/clusternode.d.ts +21 -0
  6. package/dist_ts/data/clusternode.js +345 -11
  7. package/dist_ts/data/clustervpn.d.ts +135 -0
  8. package/dist_ts/data/clustervpn.js +147 -0
  9. package/dist_ts/data/index.d.ts +1 -0
  10. package/dist_ts/data/index.js +2 -1
  11. package/dist_ts/data/networkaddressplan.d.ts +54 -11
  12. package/dist_ts/data/networkaddressplan.js +67 -23
  13. package/dist_ts/data/networkcredential.d.ts +13 -4
  14. package/dist_ts/data/networkcredential.js +41 -23
  15. package/dist_ts/data/runtimeassignment.d.ts +23 -0
  16. package/dist_ts/data/runtimeassignment.js +42 -7
  17. package/dist_ts/platform/storage.d.ts +19 -0
  18. package/dist_ts/platform/storage.js +23 -3
  19. package/dist_ts/private/networkcontract.d.ts +6 -0
  20. package/dist_ts/private/networkcontract.js +12 -1
  21. package/dist_ts/requests/cluster.d.ts +27 -0
  22. package/dist_ts/requests/cluster.js +1 -1
  23. package/package.json +1 -1
  24. package/readme.md +139 -21
  25. package/ts/00_commitinfo_data.ts +1 -1
  26. package/ts/data/cluster.ts +76 -1
  27. package/ts/data/clusternode.ts +457 -10
  28. package/ts/data/clustervpn.ts +248 -0
  29. package/ts/data/index.ts +1 -0
  30. package/ts/data/networkaddressplan.ts +103 -27
  31. package/ts/data/networkcredential.ts +52 -24
  32. package/ts/data/runtimeassignment.ts +58 -5
  33. package/ts/platform/storage.ts +27 -5
  34. package/ts/private/networkcontract.ts +11 -0
  35. package/ts/requests/cluster.ts +35 -0
@@ -0,0 +1,135 @@
1
+ /**
2
+ * One workload prefix a node owns inside its cluster's managed VPN, and the policy domain that
3
+ * names it in a grant. Both are Cloudly's words: the relay matches them, it never invents one.
4
+ */
5
+ export interface IClusterVpnNetworkPrefix {
6
+ cidr: string;
7
+ policyDomain: string;
8
+ }
9
+ /**
10
+ * One member of a cluster's managed VPN.
11
+ *
12
+ * Membership is presence: a node the network does not list is not a member, so there is no
13
+ * disabled state to carry. `publicKey` is the node's own Noise public key, the one Cloudly issued
14
+ * the node's credential for, and `expiresAt` is that credential's expiry in Unix milliseconds — the
15
+ * hub stops relaying for a member whose window ended even if nothing pushes a new network.
16
+ */
17
+ export interface IClusterVpnNetworkNode {
18
+ nodeId: string;
19
+ publicKey: string;
20
+ controlAddress: string;
21
+ expiresAt: number;
22
+ workloadPrefixes: IClusterVpnNetworkPrefix[];
23
+ }
24
+ /** One directed relay permission between two workload policy domains of two different nodes. */
25
+ export interface IClusterVpnNetworkGrant {
26
+ sourceDomain: string;
27
+ destinationDomain: string;
28
+ }
29
+ /**
30
+ * The complete managed VPN of one cluster, as Cloudly states it to that cluster's relay.
31
+ *
32
+ * Complete, never a patch: a relay applies it as the whole authority its hub serves, so a member or
33
+ * a grant that is missing is withdrawn. `revision` is Cloudly's own counter for this authority and
34
+ * only ever rises; `authorityId` names the authority the hub is bound to, so a network compiled for
35
+ * another cluster is refused rather than applied.
36
+ */
37
+ export interface IClusterVpnNetwork {
38
+ authorityId: string;
39
+ revision: number;
40
+ nodes: IClusterVpnNetworkNode[];
41
+ grants: IClusterVpnNetworkGrant[];
42
+ }
43
+ export declare const clusterVpnNetworkContract: Readonly<{
44
+ /** The policy domain of a node's control address; the hub relays no grant between control domains. */
45
+ readonly controlPolicyDomainPrefix: "control:";
46
+ /** The policy domain of one workload lease, named by that lease's digest. */
47
+ readonly workloadPolicyDomainPrefix: "workload:";
48
+ readonly maximumNodes: 256;
49
+ /** Per node; one workload lease the node's signed projection carries. */
50
+ readonly maximumWorkloadPrefixes: 128;
51
+ readonly maximumGrants: 4096;
52
+ readonly maximumCanonicalBytes: 917504;
53
+ readonly completeness: "whole-authority-never-a-patch";
54
+ readonly membership: "presence-only-an-absent-node-is-withdrawn";
55
+ }>;
56
+ /**
57
+ * Every reason a relay refuses a pushed network, in the words the refusal leads with.
58
+ *
59
+ * A push is applied to a daemon whose lifetime Cloudly cannot see, so the refusal is the only
60
+ * statement about whether the cluster's hub carries this authority. The relay writes
61
+ * `<name>: <reason>` and Cloudly matches the name, which is why the names are stated here instead
62
+ * of being spelled out on both sides.
63
+ */
64
+ export declare const applyClusterVpnNetworkRefusals: readonly ["vpn-network-authority-foreign", "vpn-network-revision-stale"];
65
+ /** One of the reasons a relay states that its hub did not take a network over. */
66
+ export type TApplyClusterVpnNetworkRefusal = typeof applyClusterVpnNetworkRefusals[number];
67
+ /**
68
+ * Every reason Cloudly states that a cluster has no managed VPN to push.
69
+ *
70
+ * Both are Cloudly reading its own records: a hub it cannot select, and a grant it cannot compile
71
+ * because hubs are per cluster and a grant whose two ends sit in different clusters has no path
72
+ * through any one of them.
73
+ */
74
+ export declare const clusterVpnNetworkSelectionRefusals: readonly ["relay-vpn-hub-absent", "grant-cross-cluster-unsupported"];
75
+ /** One of the reasons Cloudly states that it compiled no managed VPN for a cluster. */
76
+ export type TClusterVpnNetworkSelectionRefusal = typeof clusterVpnNetworkSelectionRefusals[number];
77
+ /** What a pushed network did to the cluster's hub, in the hub's own words. */
78
+ export type TClusterVpnNetworkState = 'idle' | 'applying' | 'failed';
79
+ export interface IApplyClusterVpnNetworkRequest {
80
+ network: IClusterVpnNetwork;
81
+ }
82
+ /**
83
+ * What the relay answers: the revision its hub has applied, or `null` while it has applied none,
84
+ * and what the hub is doing. `idle` means the pushed revision is the applied one.
85
+ */
86
+ export interface IApplyClusterVpnNetworkResponse {
87
+ appliedRevision: number | null;
88
+ state: TClusterVpnNetworkState;
89
+ }
90
+ /**
91
+ * The pull carries no body. The relay's own socket names the cluster, and a hub daemon that just
92
+ * started holds nothing it could state about what it is missing.
93
+ */
94
+ export type TGetClusterVpnNetworkRequest = Record<string, never>;
95
+ /** `null` while the cluster has no managed VPN: no address plan, or no hub selected for it yet. */
96
+ export interface IGetClusterVpnNetworkResponse {
97
+ network: IClusterVpnNetwork | null;
98
+ }
99
+ /** The policy domain of one node's control address. One rule, so both sides name it identically. */
100
+ export declare const clusterVpnControlPolicyDomain: (addressValue: unknown) => string;
101
+ /** The policy domain of one workload lease, from that lease's canonical digest. */
102
+ export declare const clusterVpnWorkloadPolicyDomain: (digestValue: unknown) => string;
103
+ /**
104
+ * Structural snapshot of a complete cluster network.
105
+ *
106
+ * Every node, prefix and grant is stated once and in canonical order, and every grant names a
107
+ * workload domain this network itself carries, on two different nodes. That last rule is what a
108
+ * per-cluster hub means: a grant whose other end sits on another cluster's hub cannot be expressed
109
+ * here at all, which is why Cloudly refuses it by name while it compiles instead of pushing it.
110
+ */
111
+ export declare const snapshotClusterVpnNetwork: (value: unknown) => IClusterVpnNetwork;
112
+ export type TClusterVpnNetworkAdmission = {
113
+ status: 'accepted';
114
+ } | {
115
+ status: 'replay';
116
+ } | {
117
+ status: 'refused';
118
+ reason: TApplyClusterVpnNetworkRefusal;
119
+ };
120
+ /**
121
+ * The pure decision a relay makes about a pushed network against the one its hub holds, or null
122
+ * when the hub holds none — which is every hub that just started, because a daemon restart starts
123
+ * empty. A repeat of the held network is a replay the relay may apply again without effect; a lower
124
+ * revision, or the same revision with different content, is stale and refused by name.
125
+ */
126
+ export declare const admitClusterVpnNetwork: (heldValue: unknown | null, nextValue: unknown) => TClusterVpnNetworkAdmission;
127
+ export declare const snapshotApplyClusterVpnNetworkRequest: (value: unknown) => IApplyClusterVpnNetworkRequest;
128
+ export declare const snapshotApplyClusterVpnNetworkResponse: (value: unknown) => IApplyClusterVpnNetworkResponse;
129
+ /**
130
+ * Compare the answer with the exact SENT network: a hub that reports itself idle has applied the
131
+ * revision it was sent, and no hub can report having applied a later one than exists.
132
+ */
133
+ export declare const bindApplyClusterVpnNetworkResponse: (value: unknown, sentRequestValue: unknown) => IApplyClusterVpnNetworkResponse;
134
+ export declare const snapshotGetClusterVpnNetworkRequest: (value: unknown) => TGetClusterVpnNetworkRequest;
135
+ export declare const snapshotGetClusterVpnNetworkResponse: (value: unknown) => IGetClusterVpnNetworkResponse;
@@ -0,0 +1,147 @@
1
+ import { captureNetwork, failNetwork, networkCanonical, networkCounter, networkEqual, networkId, networkIpv4, networkList, networkNoiseKey, networkPrivatePrefix, networkRecord, networkSafe, networkSorted, requireNetwork } from '../private/networkcontract.js';
2
+ export const clusterVpnNetworkContract = Object.freeze({
3
+ /** The policy domain of a node's control address; the hub relays no grant between control domains. */
4
+ controlPolicyDomainPrefix: 'control:',
5
+ /** The policy domain of one workload lease, named by that lease's digest. */
6
+ workloadPolicyDomainPrefix: 'workload:',
7
+ maximumNodes: 256,
8
+ /** Per node; one workload lease the node's signed projection carries. */
9
+ maximumWorkloadPrefixes: 128,
10
+ maximumGrants: 4096,
11
+ maximumCanonicalBytes: 917_504,
12
+ completeness: 'whole-authority-never-a-patch',
13
+ membership: 'presence-only-an-absent-node-is-withdrawn',
14
+ });
15
+ /**
16
+ * Every reason a relay refuses a pushed network, in the words the refusal leads with.
17
+ *
18
+ * A push is applied to a daemon whose lifetime Cloudly cannot see, so the refusal is the only
19
+ * statement about whether the cluster's hub carries this authority. The relay writes
20
+ * `<name>: <reason>` and Cloudly matches the name, which is why the names are stated here instead
21
+ * of being spelled out on both sides.
22
+ */
23
+ export const applyClusterVpnNetworkRefusals = Object.freeze([
24
+ /** The network names another authority than the one this cluster's hub is bound to. */
25
+ 'vpn-network-authority-foreign',
26
+ /** A revision the hub has already passed, or the same revision with different content. */
27
+ 'vpn-network-revision-stale',
28
+ ]);
29
+ /**
30
+ * Every reason Cloudly states that a cluster has no managed VPN to push.
31
+ *
32
+ * Both are Cloudly reading its own records: a hub it cannot select, and a grant it cannot compile
33
+ * because hubs are per cluster and a grant whose two ends sit in different clusters has no path
34
+ * through any one of them.
35
+ */
36
+ export const clusterVpnNetworkSelectionRefusals = Object.freeze([
37
+ /** The cluster's relay registered no hub, so no node of it may be sent to one. */
38
+ 'relay-vpn-hub-absent',
39
+ /** The grant's two workloads are placed on two clusters; hub federation is a later lane. */
40
+ 'grant-cross-cluster-unsupported',
41
+ ]);
42
+ /** The policy domain of one node's control address. One rule, so both sides name it identically. */
43
+ export const clusterVpnControlPolicyDomain = (addressValue) => networkSafe(() => `${clusterVpnNetworkContract.controlPolicyDomainPrefix}${networkIpv4(addressValue)}`);
44
+ /** The policy domain of one workload lease, from that lease's canonical digest. */
45
+ export const clusterVpnWorkloadPolicyDomain = (digestValue) => networkSafe(() => {
46
+ requireNetwork(typeof digestValue === 'string' && /^sha256:[a-f0-9]{64}$/.test(digestValue));
47
+ return `${clusterVpnNetworkContract.workloadPolicyDomainPrefix}${digestValue.slice(7)}`;
48
+ });
49
+ const workloadPolicyDomain = (value) => {
50
+ requireNetwork(typeof value === 'string'
51
+ && value.startsWith(clusterVpnNetworkContract.workloadPolicyDomainPrefix)
52
+ && /^[a-f0-9]{64}$/.test(value.slice(clusterVpnNetworkContract.workloadPolicyDomainPrefix.length)));
53
+ return value;
54
+ };
55
+ const prefixOf = (value) => {
56
+ const item = networkRecord(value, ['cidr', 'policyDomain']);
57
+ return { cidr: networkPrivatePrefix(item.cidr), policyDomain: workloadPolicyDomain(item.policyDomain) };
58
+ };
59
+ const nodeOf = (value) => {
60
+ const item = networkRecord(value, ['nodeId', 'publicKey', 'controlAddress', 'expiresAt', 'workloadPrefixes']);
61
+ return { nodeId: networkId(item.nodeId), publicKey: networkNoiseKey(item.publicKey), controlAddress: networkIpv4(item.controlAddress),
62
+ expiresAt: networkCounter(item.expiresAt),
63
+ workloadPrefixes: networkSorted(networkList(item.workloadPrefixes, clusterVpnNetworkContract.maximumWorkloadPrefixes, prefixOf), prefix => prefix.cidr) };
64
+ };
65
+ const grantOf = (value) => {
66
+ const item = networkRecord(value, ['sourceDomain', 'destinationDomain']);
67
+ return { sourceDomain: workloadPolicyDomain(item.sourceDomain), destinationDomain: workloadPolicyDomain(item.destinationDomain) };
68
+ };
69
+ const grantKey = (grant) => `${grant.sourceDomain}\0${grant.destinationDomain}`;
70
+ /**
71
+ * Structural snapshot of a complete cluster network.
72
+ *
73
+ * Every node, prefix and grant is stated once and in canonical order, and every grant names a
74
+ * workload domain this network itself carries, on two different nodes. That last rule is what a
75
+ * per-cluster hub means: a grant whose other end sits on another cluster's hub cannot be expressed
76
+ * here at all, which is why Cloudly refuses it by name while it compiles instead of pushing it.
77
+ */
78
+ export const snapshotClusterVpnNetwork = (value) => networkSafe(() => {
79
+ const captured = captureNetwork(value);
80
+ requireNetwork(new TextEncoder().encode(networkCanonical(captured)).length <= clusterVpnNetworkContract.maximumCanonicalBytes);
81
+ const item = networkRecord(captured, ['authorityId', 'revision', 'nodes', 'grants']);
82
+ const nodes = networkSorted(networkList(item.nodes, clusterVpnNetworkContract.maximumNodes, nodeOf), node => node.nodeId);
83
+ const grants = networkSorted(networkList(item.grants, clusterVpnNetworkContract.maximumGrants, grantOf), grantKey);
84
+ const domainOwners = new Map();
85
+ const addresses = new Set(), keys = new Set(), cidrs = new Set();
86
+ for (const node of nodes) {
87
+ requireNetwork(!keys.has(node.publicKey) && !addresses.has(node.controlAddress));
88
+ keys.add(node.publicKey);
89
+ addresses.add(node.controlAddress);
90
+ for (const prefix of node.workloadPrefixes) {
91
+ requireNetwork(!cidrs.has(prefix.cidr) && !domainOwners.has(prefix.policyDomain));
92
+ cidrs.add(prefix.cidr);
93
+ domainOwners.set(prefix.policyDomain, node.nodeId);
94
+ }
95
+ }
96
+ for (const grant of grants) {
97
+ const source = domainOwners.get(grant.sourceDomain), destination = domainOwners.get(grant.destinationDomain);
98
+ requireNetwork(source && destination && source !== destination);
99
+ }
100
+ return { authorityId: networkId(item.authorityId), revision: networkCounter(item.revision), nodes, grants };
101
+ });
102
+ /**
103
+ * The pure decision a relay makes about a pushed network against the one its hub holds, or null
104
+ * when the hub holds none — which is every hub that just started, because a daemon restart starts
105
+ * empty. A repeat of the held network is a replay the relay may apply again without effect; a lower
106
+ * revision, or the same revision with different content, is stale and refused by name.
107
+ */
108
+ export const admitClusterVpnNetwork = (heldValue, nextValue) => networkSafe(() => {
109
+ const next = snapshotClusterVpnNetwork(nextValue);
110
+ if (heldValue === null)
111
+ return { status: 'accepted' };
112
+ const held = snapshotClusterVpnNetwork(heldValue);
113
+ if (held.authorityId !== next.authorityId)
114
+ return { status: 'refused', reason: 'vpn-network-authority-foreign' };
115
+ if (next.revision > held.revision)
116
+ return { status: 'accepted' };
117
+ return networkEqual(held, next) ? { status: 'replay' } : { status: 'refused', reason: 'vpn-network-revision-stale' };
118
+ });
119
+ export const snapshotApplyClusterVpnNetworkRequest = (value) => networkSafe(() => {
120
+ const item = networkRecord(captureNetwork(value), ['network']);
121
+ return { network: snapshotClusterVpnNetwork(item.network) };
122
+ });
123
+ export const snapshotApplyClusterVpnNetworkResponse = (value) => networkSafe(() => {
124
+ const item = networkRecord(captureNetwork(value), ['appliedRevision', 'state']);
125
+ requireNetwork(item.state === 'idle' || item.state === 'applying' || item.state === 'failed');
126
+ return { appliedRevision: item.appliedRevision === null ? null : networkCounter(item.appliedRevision), state: item.state };
127
+ });
128
+ /**
129
+ * Compare the answer with the exact SENT network: a hub that reports itself idle has applied the
130
+ * revision it was sent, and no hub can report having applied a later one than exists.
131
+ */
132
+ export const bindApplyClusterVpnNetworkResponse = (value, sentRequestValue) => networkSafe(() => {
133
+ const response = snapshotApplyClusterVpnNetworkResponse(value);
134
+ const sent = snapshotApplyClusterVpnNetworkRequest(sentRequestValue);
135
+ requireNetwork(response.appliedRevision === null || response.appliedRevision <= sent.network.revision);
136
+ requireNetwork(response.state !== 'idle' || response.appliedRevision === sent.network.revision);
137
+ return response;
138
+ });
139
+ export const snapshotGetClusterVpnNetworkRequest = (value) => networkSafe(() => {
140
+ networkRecord(captureNetwork(value), []);
141
+ return {};
142
+ });
143
+ export const snapshotGetClusterVpnNetworkResponse = (value) => networkSafe(() => {
144
+ const item = networkRecord(captureNetwork(value), ['network']);
145
+ return { network: item.network === null ? null : snapshotClusterVpnNetwork(item.network) };
146
+ });
147
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2x1c3RlcnZwbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3RzL2RhdGEvY2x1c3RlcnZwbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsY0FBYyxFQUFFLFdBQVcsRUFBRSxnQkFBZ0IsRUFBRSxjQUFjLEVBQUUsWUFBWSxFQUFFLFNBQVMsRUFBRSxXQUFXLEVBQUUsV0FBVyxFQUN2SCxlQUFlLEVBQUUsb0JBQW9CLEVBQUUsYUFBYSxFQUFFLFdBQVcsRUFBRSxhQUFhLEVBQ2hGLGNBQWMsRUFBRSxNQUFNLCtCQUErQixDQUFDO0FBZ0R4RCxNQUFNLENBQUMsTUFBTSx5QkFBeUIsR0FBRyxNQUFNLENBQUMsTUFBTSxDQUFDO0lBQ3JELHNHQUFzRztJQUN0Ryx5QkFBeUIsRUFBRSxVQUFVO0lBQ3JDLDZFQUE2RTtJQUM3RSwwQkFBMEIsRUFBRSxXQUFXO0lBQ3ZDLFlBQVksRUFBRSxHQUFHO0lBQ2pCLHlFQUF5RTtJQUN6RSx1QkFBdUIsRUFBRSxHQUFHO0lBQzVCLGFBQWEsRUFBRSxJQUFJO0lBQ25CLHFCQUFxQixFQUFFLE9BQU87SUFDOUIsWUFBWSxFQUFFLCtCQUErQjtJQUM3QyxVQUFVLEVBQUUsMkNBQTJDO0NBQy9DLENBQUMsQ0FBQztBQUVaOzs7Ozs7O0dBT0c7QUFDSCxNQUFNLENBQUMsTUFBTSw4QkFBOEIsR0FBRyxNQUFNLENBQUMsTUFBTSxDQUFDO0lBQzFELHVGQUF1RjtJQUN2RiwrQkFBK0I7SUFDL0IsMEZBQTBGO0lBQzFGLDRCQUE0QjtDQUNwQixDQUFDLENBQUM7QUFLWjs7Ozs7O0dBTUc7QUFDSCxNQUFNLENBQUMsTUFBTSxrQ0FBa0MsR0FBRyxNQUFNLENBQUMsTUFBTSxDQUFDO0lBQzlELGtGQUFrRjtJQUNsRixzQkFBc0I7SUFDdEIsNEZBQTRGO0lBQzVGLGlDQUFpQztDQUN6QixDQUFDLENBQUM7QUFnQ1osb0dBQW9HO0FBQ3BHLE1BQU0sQ0FBQyxNQUFNLDZCQUE2QixHQUFH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
@@ -1,6 +1,7 @@
1
1
  export * from './cloudlyconfig.js';
2
2
  export * from './cluster.js';
3
3
  export * from './clusterruntime.js';
4
+ export * from './clustervpn.js';
4
5
  export * from './clusteringress.js';
5
6
  export * from './config.js';
6
7
  export * from './corestore.js';
@@ -1,6 +1,7 @@
1
1
  export * from './cloudlyconfig.js';
2
2
  export * from './cluster.js';
3
3
  export * from './clusterruntime.js';
4
+ export * from './clustervpn.js';
4
5
  export * from './clusteringress.js';
5
6
  export * from './config.js';
6
7
  export * from './corestore.js';
@@ -58,4 +59,4 @@ export * from './traffic.js';
58
59
  export * from './user.js';
59
60
  export * from './version.js';
60
61
  export * from './webpush.js';
61
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi90cy9kYXRhL2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLGNBQWMsb0JBQW9CLENBQUM7QUFDbkMsY0FBYyxjQUFjLENBQUM7QUFDN0IsY0FBYyxxQkFBcUIsQ0FBQztBQUNwQyxjQUFjLHFCQUFxQixDQUFDO0FBQ3BDLGNBQWMsYUFBYSxDQUFDO0FBQzVCLGNBQWMsZ0JBQWdCLENBQUM7QUFDL0IsY0FBYyxlQUFlLENBQUM7QUFDOUIsY0FBYyx1QkFBdUIsQ0FBQztBQUN0QyxjQUFjLGlCQUFpQixDQUFDO0FBQ2hDLGNBQWMseUJBQXlCLENBQUM7QUFDeEMsY0FBYywwQkFBMEIsQ0FBQztBQUN6QyxjQUFjLDBCQUEwQixDQUFDO0FBQ3pDLGNBQWMsZ0JBQWdCLENBQUM7QUFDL0IsY0FBYyxVQUFVLENBQUM7QUFDekIsY0FBYyxhQUFhLENBQUM7QUFDNUIsY0FBYyxhQUFhLENBQUM7QUFDNUIsY0FBYyxZQUFZLENBQUM7QUFDM0IsY0FBYyx1QkFBdUIsQ0FBQztBQUN0QyxjQUFjLGNBQWMsQ0FBQztBQUM3QixjQUFjLGdCQUFnQixDQUFDO0FBQy9CLGNBQWMsWUFBWSxDQUFDO0FBQzNCLGNBQWMscUJBQXFCLENBQUM7QUFDcEMsY0FBYyxzQkFBc0IsQ0FBQztBQUNyQyxjQUFjLDZCQUE2QixDQUFDO0FBQzVDLGNBQWMsV0FBVyxDQUFDO0FBQzFCLGNBQWMscUJBQXFCLENBQUM7QUFDcEMsY0FBYyxxQkFBcUIsQ0FBQztBQUNwQyxjQUFjLHFCQUFxQixDQUFDO0FBQ3BDLGNBQWMseUJBQXlCLENBQUM7QUFDeEMsY0FBYyx1QkFBdUIsQ0FBQztBQUN0QyxjQUFjLHdCQUF3QixDQUFDO0FBQ3ZDLGNBQWMsc0JBQXNCLENBQUM7QUFDckMsY0FBYyxtQkFBbUIsQ0FBQztBQUNsQyxjQUFjLGtCQUFrQixDQUFDO0FBQ2pDLGNBQWMsd0JBQXdCLENBQUM7QUFFdkMsY0FBYyx3QkFBd0IsQ0FBQztBQUN2QyxjQUFjLHFCQUFxQixDQUFDO0FBQ3BDLGNBQWMscUJBQXFCLENBQUM7QUFDcEMsY0FBYyxlQUFlLENBQUM7QUFDOUIsY0FBYyx3QkFBd0IsQ0FBQztBQUN2QyxjQUFjLG9CQUFvQixDQUFDO0FBQ25DLGNBQWMscUJBQXFCLENBQUM7QUFDcEMsY0FBYyw2QkFBNkIsQ0FBQztBQUM1QyxjQUFjLGFBQWEsQ0FBQztBQUM1QixjQUFjLGdCQUFnQixDQUFDO0FBQy9CLGNBQWMsYUFBYSxDQUFDO0FBQzVCLGNBQWMsYUFBYSxDQUFDO0FBQzVCLGNBQWMsa0JBQWtCLENBQUM7QUFDakMsY0FBYyxlQUFlLENBQUM7QUFDOUIsY0FBYyxzQkFBc0IsQ0FBQztBQUNyQyxjQUFjLGNBQWMsQ0FBQztBQUM3QixjQUFjLHdCQUF3QixDQUFDO0FBQ3ZDLGNBQWMsbUJBQW1CLENBQUM7QUFDbEMsY0FBYyxxQkFBcUIsQ0FBQztBQUNwQyxjQUFjLGFBQWEsQ0FBQztBQUM1QixjQUFjLG9CQUFvQixDQUFDO0FBQ25DLGNBQWMsY0FBYyxDQUFDO0FBQzdCLGNBQWMsV0FBVyxDQUFDO0FBQzFCLGNBQWMsY0FBYyxDQUFDO0FBQzdCLGNBQWMsY0FBYyxDQUFDIn0=
62
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi90cy9kYXRhL2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLGNBQWMsb0JBQW9CLENBQUM7QUFDbkMsY0FBYyxjQUFjLENBQUM7QUFDN0IsY0FBYyxxQkFBcUIsQ0FBQztBQUNwQyxjQUFjLGlCQUFpQixDQUFDO0FBQ2hDLGNBQWMscUJBQXFCLENBQUM7QUFDcEMsY0FBYyxhQUFhLENBQUM7QUFDNUIsY0FBYyxnQkFBZ0IsQ0FBQztBQUMvQixjQUFjLGVBQWUsQ0FBQztBQUM5QixjQUFjLHVCQUF1QixDQUFDO0FBQ3RDLGNBQWMsaUJBQWlCLENBQUM7QUFDaEMsY0FBYyx5QkFBeUIsQ0FBQztBQUN4QyxjQUFjLDBCQUEwQixDQUFDO0FBQ3pDLGNBQWMsMEJBQTBCLENBQUM7QUFDekMsY0FBYyxnQkFBZ0IsQ0FBQztBQUMvQixjQUFjLFVBQVUsQ0FBQztBQUN6QixjQUFjLGFBQWEsQ0FBQztBQUM1QixjQUFjLGFBQWEsQ0FBQztBQUM1QixjQUFjLFlBQVksQ0FBQztBQUMzQixjQUFjLHVCQUF1QixDQUFDO0FBQ3RDLGNBQWMsY0FBYyxDQUFDO0FBQzdCLGNBQWMsZ0JBQWdCLENBQUM7QUFDL0IsY0FBYyxZQUFZLENBQUM7QUFDM0IsY0FBYyxxQkFBcUIsQ0FBQztBQUNwQyxjQUFjLHNCQUFzQixDQUFDO0FBQ3JDLGNBQWMsNkJBQTZCLENBQUM7QUFDNUMsY0FBYyxXQUFXLENBQUM7QUFDMUIsY0FBYyxxQkFBcUIsQ0FBQztBQUNwQyxjQUFjLHFCQUFxQixDQUFDO0FBQ3BDLGNBQWMscUJBQXFCLENBQUM7QUFDcEMsY0FBYyx5QkFBeUIsQ0FBQztBQUN4QyxjQUFjLHVCQUF1QixDQUFDO0FBQ3RDLGNBQWMsd0JBQXdCLENBQUM7QUFDdkMsY0FBYyxzQkFBc0IsQ0FBQztBQUNyQyxjQUFjLG1CQUFtQixDQUFDO0FBQ2xDLGNBQWMsa0JBQWtCLENBQUM7QUFDakMsY0FBYyx3QkFBd0IsQ0FBQztBQUV2QyxjQUFjLHdCQUF3QixDQUFDO0FBQ3ZDLGNBQWMscUJBQXFCLENBQUM7QUFDcEMsY0FBYyxxQkFBcUIsQ0FBQztBQUNwQyxjQUFjLGVBQWUsQ0FBQztBQUM5QixjQUFjLHdCQUF3QixDQUFDO0FBQ3ZDLGNBQWMsb0JBQW9CLENBQUM7QUFDbkMsY0FBYyxxQkFBcUIsQ0FBQztBQUNwQyxjQUFjLDZCQUE2QixDQUFDO0FBQzVDLGNBQWMsYUFBYSxDQUFDO0FBQzVCLGNBQWMsZ0JBQWdCLENBQUM7QUFDL0IsY0FBYyxhQUFhLENBQUM7QUFDNUIsY0FBYyxhQUFhLENBQUM7QUFDNUIsY0FBYyxrQkFBa0IsQ0FBQztBQUNqQyxjQUFjLGVBQWUsQ0FBQztBQUM5QixjQUFjLHNCQUFzQixDQUFDO0FBQ3JDLGNBQWMsY0FBYyxDQUFDO0FBQzdCLGNBQWMsd0JBQXdCLENBQUM7QUFDdkMsY0FBYyxtQkFBbUIsQ0FBQztBQUNsQyxjQUFjLHFCQUFxQixDQUFDO0FBQ3BDLGNBQWMsYUFBYSxDQUFDO0FBQzVCLGNBQWMsb0JBQW9CLENBQUM7QUFDbkMsY0FBYyxjQUFjLENBQUM7QUFDN0IsY0FBYyxXQUFXLENBQUM7QUFDMUIsY0FBYyxjQUFjLENBQUM7QUFDN0IsY0FBYyxjQUFjLENBQUMifQ==
@@ -1,5 +1,4 @@
1
1
  import type { IRuntimeNetworkProtectedAuthority } from './networkauthority.js';
2
- import type { IGetRuntimeManagedVpnCredentialResponse } from './networkcredential.js';
3
2
  /**
4
3
  * The address space an administrator gives the runtime network, and the one input the protected
5
4
  * authority is composed from. Cloudly keeps a single plan; pools and prefixes only grow, and the
@@ -13,15 +12,34 @@ export interface IRuntimeNetworkAddressPlan {
13
12
  prefixes: string[];
14
13
  pools: IRuntimeNetworkProtectedAuthority['pools'];
15
14
  resolvers: IRuntimeNetworkProtectedAuthority['resolvers'];
16
- /** Without the VPN relay, which the composed authority adds as a UDP platform endpoint. */
15
+ /** Without the cluster hubs, which the composed authority adds from the hubs it is given. */
17
16
  platformEndpoints: IRuntimeNetworkProtectedAuthority['platformEndpoints'];
18
17
  vpn: {
19
18
  /** The private prefix VPN control addresses are allocated from. */
20
19
  controlPrefix: string;
21
- /** The endpoint every node dials for the managed VPN. */
22
- relay: IGetRuntimeManagedVpnCredentialResponse['relay'];
20
+ /**
21
+ * The protected prefix every cluster hub binds inside.
22
+ *
23
+ * The endpoints themselves are no administrator's input: a cluster's relay reports the one it
24
+ * bound and the composition turns it into platform endpoints, so this prefix is what an
25
+ * administrator reserves for them.
26
+ */
27
+ hubPrefix: string;
23
28
  };
24
29
  }
30
+ /**
31
+ * One cluster's managed VPN hub, as the cluster's relay bound it.
32
+ *
33
+ * The hub is its cluster's own packet relay, so `clusterId` names both the hub and the authority
34
+ * that may select it, and `address` is an underlay address inside the plan's `vpn.hubPrefix`. A hub
35
+ * offers at least one transport; the port of a transport it did not bind is `null`.
36
+ */
37
+ export interface IRuntimeNetworkVpnHub {
38
+ clusterId: string;
39
+ address: string;
40
+ quicPort: number | null;
41
+ websocketPort: number | null;
42
+ }
25
43
  /** What an administrator writes; Cloudly supplies the id and the revision. */
26
44
  export type TRuntimeNetworkAddressPlanWritableData = Omit<IRuntimeNetworkAddressPlan, 'id' | 'revision'>;
27
45
  /** What a protection producer fixes around a plan: the authority's identity, revision chain and egress. */
@@ -54,20 +72,45 @@ export declare const runtimeNetworkAddressPlanContract: Readonly<{
54
72
  * is stated: the private-range rule already keeps the control prefix at /8 or longer.
55
73
  */
56
74
  readonly maximumControlPrefixLength: 30;
57
- readonly relayProtocol: "udp";
75
+ /**
76
+ * Every transport a hub may offer, in the order a node prefers them.
77
+ *
78
+ * One row states all three facts that belong together: the transport a credential names, the
79
+ * suffix its platform endpoint id carries, and the protocol the endpoint is composed with. A hub
80
+ * that bound both transports therefore contributes exactly two endpoints of one address.
81
+ */
82
+ readonly hubTransports: readonly (Readonly<{
83
+ transport: "quic";
84
+ endpointSuffix: "quic";
85
+ protocol: "udp";
86
+ }> | Readonly<{
87
+ transport: "websocket";
88
+ endpointSuffix: "ws";
89
+ protocol: "tcp";
90
+ }>)[];
58
91
  }>;
92
+ /** How a node reaches its cluster's hub, read off the one table that states the transports. */
93
+ export type TRuntimeNetworkVpnTransport = typeof runtimeNetworkAddressPlanContract.hubTransports[number]['transport'];
94
+ /**
95
+ * The platform endpoints one hub contributes to a protected authority: one per transport it bound,
96
+ * in id order. Every reader derives the same ids from this one function — the composition that seals
97
+ * the authority, and the router selection that names which of them a node may dial.
98
+ */
99
+ export declare const runtimeNetworkVpnHubEndpoints: (hubValue: unknown) => IRuntimeNetworkProtectedAuthority["platformEndpoints"];
59
100
  /**
60
- * Structural snapshot for exact persistence and for a plan write. A plan passes only when both
61
- * authorities it can describe pass the protected authority's own validator: its sets alone, and
62
- * its sets with the relay added, so no plan can compose an authority that contract refuses.
101
+ * Structural snapshot for exact persistence and for a plan write. The plan's own sets pass the
102
+ * protected authority's own validator, so no plan can describe an authority that contract refuses,
103
+ * and both VPN prefixes are reserved inside the protected space the plan states.
63
104
  */
64
105
  export declare const snapshotRuntimeNetworkAddressPlan: (value: unknown) => IRuntimeNetworkAddressPlan;
65
106
  /**
66
107
  * The protected authority a plan describes inside a producer's frame, digest included: the plan's
67
- * sets with the VPN relay as the UDP platform endpoint every node dials. Both inputs are read before
68
- * the digest is computed.
108
+ * sets plus the endpoints of every cluster hub it is given, each bound inside `vpn.hubPrefix`. One
109
+ * cluster contributes one hub, so `hubs` never names a cluster twice. All inputs are read before the
110
+ * digest is computed; an empty `hubs` composes the authority of a runtime network whose clusters
111
+ * have not registered a hub yet.
69
112
  */
70
- export declare const composeRuntimeNetworkProtectedAuthority: (planValue: unknown, frameValue: unknown) => Promise<IRuntimeNetworkProtectedAuthority>;
113
+ export declare const composeRuntimeNetworkProtectedAuthority: (planValue: unknown, frameValue: unknown, hubsValue: unknown) => Promise<IRuntimeNetworkProtectedAuthority>;
71
114
  /**
72
115
  * The pure decision for replacing `previousValue`, the stored plan or null, with `nextValue` at the
73
116
  * following revision. Leases and the managed VPN outlive a plan revision, so every pool stays exactly
@@ -1,5 +1,5 @@
1
- import { computeRuntimeNetworkProtectedAuthorityDigest, snapshotRuntimeNetworkProtectedAuthority } from './networkauthority.js';
2
- import { captureNetwork, failNetwork, networkContains, networkCounter, networkEqual, networkId, networkIpv4, networkOverlaps, networkPrefixBounds, networkPrivatePrefix, networkRecord, networkSafe, requireNetwork } from '../private/networkcontract.js';
1
+ import { computeRuntimeNetworkProtectedAuthorityDigest, runtimeNetworkAuthorityContract, snapshotRuntimeNetworkProtectedAuthority } from './networkauthority.js';
2
+ import { captureNetwork, failNetwork, networkContains, networkCounter, networkEqual, networkId, networkIpv4, networkList, networkOverlaps, networkPrefix, networkPrefixBounds, networkPrivatePrefix, networkRecord, networkSafe, requireNetwork } from '../private/networkcontract.js';
3
3
  export const runtimeNetworkAddressPlanContract = Object.freeze({
4
4
  id: 'address-plan',
5
5
  /**
@@ -7,7 +7,42 @@ export const runtimeNetworkAddressPlanContract = Object.freeze({
7
7
  * is stated: the private-range rule already keeps the control prefix at /8 or longer.
8
8
  */
9
9
  maximumControlPrefixLength: 30,
10
- relayProtocol: 'udp',
10
+ /**
11
+ * Every transport a hub may offer, in the order a node prefers them.
12
+ *
13
+ * One row states all three facts that belong together: the transport a credential names, the
14
+ * suffix its platform endpoint id carries, and the protocol the endpoint is composed with. A hub
15
+ * that bound both transports therefore contributes exactly two endpoints of one address.
16
+ */
17
+ hubTransports: Object.freeze([
18
+ Object.freeze({ transport: 'quic', endpointSuffix: 'quic', protocol: 'udp' }),
19
+ Object.freeze({ transport: 'websocket', endpointSuffix: 'ws', protocol: 'tcp' }),
20
+ ]),
21
+ });
22
+ /** The port a hub bound for one transport, or null when it did not bind that transport. */
23
+ const hubPort = (hub, transport) => transport === 'quic' ? hub.quicPort : hub.websocketPort;
24
+ const byEndpointId = (left, right) => left.id < right.id ? -1 : left.id > right.id ? 1 : 0;
25
+ const hubOf = (value) => {
26
+ const item = networkRecord(value, ['clusterId', 'address', 'quicPort', 'websocketPort']);
27
+ const port = (value) => value === null ? null : networkCounter(value, 65535);
28
+ const hub = { clusterId: networkId(item.clusterId), address: networkIpv4(item.address),
29
+ quicPort: port(item.quicPort), websocketPort: port(item.websocketPort) };
30
+ // A hub that bound no transport is not reachable, so it is not a hub a node could be sent to.
31
+ requireNetwork(runtimeNetworkAddressPlanContract.hubTransports.some(row => hubPort(hub, row.transport) !== null));
32
+ return hub;
33
+ };
34
+ /**
35
+ * The platform endpoints one hub contributes to a protected authority: one per transport it bound,
36
+ * in id order. Every reader derives the same ids from this one function — the composition that seals
37
+ * the authority, and the router selection that names which of them a node may dial.
38
+ */
39
+ export const runtimeNetworkVpnHubEndpoints = (hubValue) => networkSafe(() => {
40
+ const hub = hubOf(captureNetwork(hubValue));
41
+ return runtimeNetworkAddressPlanContract.hubTransports
42
+ .filter(row => hubPort(hub, row.transport) !== null)
43
+ .map(row => ({ id: `${hub.clusterId}:${row.endpointSuffix}`, address: hub.address,
44
+ protocol: row.protocol, port: hubPort(hub, row.transport) }))
45
+ .sort(byEndpointId);
11
46
  });
12
47
  /**
13
48
  * The structural authority validator reads a frame's shape and nothing else, and a plan fixes none of
@@ -23,28 +58,32 @@ const unsealedDigest = `sha256:${'0'.repeat(64)}`;
23
58
  const authorityOf = (sets, frame) => snapshotRuntimeNetworkProtectedAuthority({ id: frame.id,
24
59
  generation: frame.generation, controller: frame.controller, previous: frame.previous, egressAuthorities: frame.egressAuthorities,
25
60
  prefixes: sets.prefixes, pools: sets.pools, resolvers: sets.resolvers, platformEndpoints: sets.platformEndpoints, digest: unsealedDigest });
26
- const setsWithRelay = (plan) => ({
61
+ const setsWithHubs = (plan, hubs) => ({
27
62
  prefixes: plan.prefixes, pools: plan.pools, resolvers: plan.resolvers,
28
- platformEndpoints: [...plan.platformEndpoints, { ...plan.vpn.relay, protocol: runtimeNetworkAddressPlanContract.relayProtocol }]
29
- .sort((left, right) => left.id < right.id ? -1 : left.id > right.id ? 1 : 0),
63
+ platformEndpoints: [...plan.platformEndpoints, ...hubs.flatMap(runtimeNetworkVpnHubEndpoints)].sort(byEndpointId),
30
64
  });
31
65
  const vpnOf = (value) => {
32
- const item = networkRecord(value, ['controlPrefix', 'relay']);
33
- const relay = networkRecord(item.relay, ['id', 'address', 'port']);
66
+ const item = networkRecord(value, ['controlPrefix', 'hubPrefix']);
34
67
  const controlPrefix = networkPrivatePrefix(item.controlPrefix);
35
68
  requireNetwork(Number(controlPrefix.split('/')[1]) <= runtimeNetworkAddressPlanContract.maximumControlPrefixLength);
36
- return { controlPrefix, relay: { id: networkId(relay.id), address: networkIpv4(relay.address), port: networkCounter(relay.port, 65535) } };
69
+ return { controlPrefix, hubPrefix: networkPrefix(item.hubPrefix) };
37
70
  };
38
- /** The control prefix is protected, and no pool, resolver or platform endpoint, the relay included, sits inside it. */
39
- const requireVpnProtected = (authority, controlPrefix) => {
40
- requireNetwork(authority.prefixes.some(prefix => networkContains(prefix, controlPrefix))
41
- && authority.pools.every(pool => !networkOverlaps(pool.prefix, controlPrefix))
42
- && [...authority.resolvers, ...authority.platformEndpoints].every(endpoint => !networkContains(controlPrefix, `${endpoint.address}/32`)));
71
+ /**
72
+ * Both VPN prefixes are protected, they hold none of the plan's own pools, resolvers or platform
73
+ * endpoints, and they do not overlap each other: control addresses live inside the tunnel and hub
74
+ * endpoints on the underlay, so one prefix can never contain the other's addresses.
75
+ */
76
+ const requireVpnProtected = (authority, vpn) => {
77
+ const endpoints = [...authority.resolvers, ...authority.platformEndpoints];
78
+ requireNetwork([vpn.controlPrefix, vpn.hubPrefix].every(prefix => authority.prefixes.some(range => networkContains(range, prefix))
79
+ && authority.pools.every(pool => !networkOverlaps(pool.prefix, prefix))
80
+ && endpoints.every(endpoint => !networkContains(prefix, `${endpoint.address}/32`)))
81
+ && !networkOverlaps(vpn.controlPrefix, vpn.hubPrefix));
43
82
  };
44
83
  /**
45
- * Structural snapshot for exact persistence and for a plan write. A plan passes only when both
46
- * authorities it can describe pass the protected authority's own validator: its sets alone, and
47
- * its sets with the relay added, so no plan can compose an authority that contract refuses.
84
+ * Structural snapshot for exact persistence and for a plan write. The plan's own sets pass the
85
+ * protected authority's own validator, so no plan can describe an authority that contract refuses,
86
+ * and both VPN prefixes are reserved inside the protected space the plan states.
48
87
  */
49
88
  export const snapshotRuntimeNetworkAddressPlan = (value) => networkSafe(() => {
50
89
  const item = networkRecord(captureNetwork(value), ['id', 'revision', 'prefixes', 'pools', 'resolvers', 'platformEndpoints', 'vpn']);
@@ -53,19 +92,24 @@ export const snapshotRuntimeNetworkAddressPlan = (value) => networkSafe(() => {
53
92
  platformEndpoints: item.platformEndpoints }, validationFrame);
54
93
  const plan = { id: runtimeNetworkAddressPlanContract.id, revision: networkCounter(item.revision),
55
94
  prefixes: own.prefixes, pools: own.pools, resolvers: own.resolvers, platformEndpoints: own.platformEndpoints, vpn: vpnOf(item.vpn) };
56
- requireVpnProtected(authorityOf(setsWithRelay(plan), validationFrame), plan.vpn.controlPrefix);
95
+ requireVpnProtected(own, plan.vpn);
57
96
  return plan;
58
97
  });
59
98
  /**
60
99
  * The protected authority a plan describes inside a producer's frame, digest included: the plan's
61
- * sets with the VPN relay as the UDP platform endpoint every node dials. Both inputs are read before
62
- * the digest is computed.
100
+ * sets plus the endpoints of every cluster hub it is given, each bound inside `vpn.hubPrefix`. One
101
+ * cluster contributes one hub, so `hubs` never names a cluster twice. All inputs are read before the
102
+ * digest is computed; an empty `hubs` composes the authority of a runtime network whose clusters
103
+ * have not registered a hub yet.
63
104
  */
64
- export const composeRuntimeNetworkProtectedAuthority = async (planValue, frameValue) => {
105
+ export const composeRuntimeNetworkProtectedAuthority = async (planValue, frameValue, hubsValue) => {
65
106
  try {
66
107
  const plan = snapshotRuntimeNetworkAddressPlan(planValue);
67
108
  const frame = networkRecord(captureNetwork(frameValue), ['id', 'generation', 'controller', 'previous', 'egressAuthorities']);
68
- const authority = authorityOf(setsWithRelay(plan), frame);
109
+ const hubs = networkList(captureNetwork(hubsValue), runtimeNetworkAuthorityContract.maximumPlatformEndpoints, hubOf);
110
+ requireNetwork(new Set(hubs.map(hub => hub.clusterId)).size === hubs.length
111
+ && hubs.every(hub => networkContains(plan.vpn.hubPrefix, `${hub.address}/32`)));
112
+ const authority = authorityOf(setsWithHubs(plan, hubs), frame);
69
113
  return { ...authority, digest: await computeRuntimeNetworkProtectedAuthorityDigest(authority) };
70
114
  }
71
115
  catch {
@@ -111,4 +155,4 @@ export const admitRuntimeNetworkAddressPlanChange = (previousValue, nextValue) =
111
155
  return { status: 'accepted', removed: { resolverIds: idsOf(removedOrChanged(previous.resolvers, next.resolvers)),
112
156
  platformEndpointIds: idsOf(removedOrChanged(previous.platformEndpoints, next.platformEndpoints)) } };
113
157
  });
114
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmV0d29ya2FkZHJlc3NwbGFuLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vdHMvZGF0YS9uZXR3b3JrYWRkcmVzc3BsYW4udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBRUEsT0FBTyxFQUFFLDZDQUE2QyxFQUFFLHdDQUF3QyxFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFFaEksT0FBTyxFQUFFLGNBQWMsRUFBRSxXQUFXLEVBQUUsZUFBZSxFQUFFLGNBQWMsRUFBRSxZQUFZLEVBQUUsU0FBUyxFQUFFLFdBQVcsRUFBRSxlQUFlLEVBQzFILG1CQUFtQixFQUFFLG9CQUFvQixFQUFFLGFBQWEsRUFBRSxXQUFXLEVBQUUsY0FBYyxFQUFFLE1BQU0sK0JBQStCLENBQUM7QUFnRC9ILE1BQU0sQ0FBQyxNQUFNLGlDQUFpQyxHQUFHLE1BQU0sQ0FBQyxNQUFNLENBQUM7SUFDN0QsRUFBRSxFQUFFLGNBQWM7SUFDbEI7OztPQUdHO0lBQ0gsMEJBQTBCLEVBQUUsRUFBRTtJQUM5QixhQUFhLEVBQUUsS0FBSztDQUNaLENBQUMsQ0FBQztBQUVaOzs7O0dBSUc7QUFDSCxNQUFNLGVBQWUsR0FBMkM7SUFDOUQsRUFBRSxFQUFFLGNBQWMsRUFBRSxVQUFVLEVBQUUsQ0FBQyxFQUFFLFVBQVUsRUFBRSxFQUFFLElBQUksRUFBRSxTQUFTLEVBQUUsRUFBRSxFQUFFLGNBQWMsRUFBRSxLQUFLLEVBQUUsY0FBYyxFQUFFO0lBQzdHLFFBQVEsRUFBRSxJQUFJLEVBQUUsaUJBQWlCLEVBQUUsQ0FBQyxFQUFFLE1BQU0sRUFBRSxjQUFjLEVBQUUsZ0JBQWdCLEVBQUUsY0FBYyxFQUFFLENBQUM7Q0FDbEcsQ0FBQztBQUNGLE1BQU0sY0FBYyxHQUFHLFVBQVUsR0FBRyxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUMsRUFBbUIsQ0FBQztBQUluRSxzRkFBc0Y7QUFDdEYsTUFBTSxXQUFXLEdBQUcsQ0FDbEIsSUFBMkMsRUFBRSxLQUFvRSxFQUM5RSxFQUFFLENB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
158
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmV0d29ya2FkZHJlc3NwbGFuLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vdHMvZGF0YS9uZXR3b3JrYWRkcmVzc3BsYW4udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBRUEsT0FBTyxFQUFFLDZDQUE2QyxFQUFFLCtCQUErQixFQUNyRix3Q0FBd0MsRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBQzFFLE9BQU8sRUFBRSxjQUFjLEVBQUUsV0FBVyxFQUFFLGVBQWUsRUFBRSxjQUFjLEVBQUUsWUFBWSxFQUFFLFNBQVMsRUFBRSxXQUFXLEVBQUUsV0FBVyxFQUN0SCxlQUFlLEVBQUUsYUFBYSxFQUFFLG1CQUFtQixFQUFFLG9CQUFvQixFQUFFLGFBQWEsRUFBRSxXQUFXLEVBQ3JHLGNBQWMsRUFBRSxNQUFNLCtCQUErQixDQUFDO0FBb0V4RCxNQUFNLENBQUMsTUFBTSxpQ0FBaUMsR0FBRyxNQUFNLENBQUMsTUFBTSxDQUFDO0lBQzdELEVBQUUsRUFBRSxjQUFjO0lBQ2xCOzs7T0FHRztJQUNILDBCQUEwQixFQUFFLEVBQUU7SUFDOUI7Ozs7OztPQU1HO0lBQ0gsYUFBYSxFQUFFLE1BQU0sQ0FBQyxNQUFNLENBQUM7UUFDM0IsTUFBTSxDQUFDLE1BQU0sQ0FBQyxFQUFFLFNBQVMsRUFBRSxNQUFNLEVBQUUsY0FBYyxFQUFFLE1BQU0sRUFBRSxRQUFRLEVBQUUsS0FBSyxFQUFFLENBQUM7UUFDN0UsTUFBTSxDQUFDLE1BQU0sQ0FBQyxFQUFFLFNBQVMsRUFBRSxXQUFXLEVBQUUsY0FBYyxFQUFFLElBQUksRUFBRSxRQUFRLEVBQUUsS0FBSyxFQUFFLENBQUM7S0FDakYsQ0FBQztDQUNNLENBQUMsQ0FBQztBQUtaLDJGQUEyRjtBQUMzRixNQUFNLE9BQU8sR0FBRyxDQUFDLEdBQTBCLEVBQUUsU0FBc0MsRUFBaUIsRUFBRSxDQUNwRyxTQUFTLEtBQUssTUFBTSxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FB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