@undefineds.co/xpod 0.3.53 → 0.3.54

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 (117) hide show
  1. package/config/cli.json +72 -0
  2. package/config/components-ignore.json +21 -0
  3. package/config/extensions.local.initializer.json +77 -8
  4. package/config/resolver.json +72 -4
  5. package/dist/api/ApiServer.d.ts +12 -0
  6. package/dist/api/ApiServer.js +14 -3
  7. package/dist/api/ApiServer.js.map +1 -1
  8. package/dist/api/auth/NodeTokenAuthenticator.d.ts +0 -8
  9. package/dist/api/auth/NodeTokenAuthenticator.js +3 -46
  10. package/dist/api/auth/NodeTokenAuthenticator.js.map +1 -1
  11. package/dist/api/container/local.js +5 -36
  12. package/dist/api/container/local.js.map +1 -1
  13. package/dist/api/container/routes.js +6 -0
  14. package/dist/api/container/routes.js.map +1 -1
  15. package/dist/api/handlers/EdgeNodeSignalHandler.js +25 -3
  16. package/dist/api/handlers/EdgeNodeSignalHandler.js.map +1 -1
  17. package/dist/api/handlers/ReachabilityHandler.d.ts +13 -0
  18. package/dist/api/handlers/ReachabilityHandler.js +388 -0
  19. package/dist/api/handlers/ReachabilityHandler.js.map +1 -0
  20. package/dist/api/runs/InngestRunExecutionBackend.d.ts +2 -2
  21. package/dist/api/tasks/InngestTaskScheduler.d.ts +4 -4
  22. package/dist/components/components.jsonld +14 -2
  23. package/dist/components/context.jsonld +439 -3
  24. package/dist/edge/EdgeNodeAgent.d.ts +43 -0
  25. package/dist/edge/EdgeNodeAgent.js +208 -1
  26. package/dist/edge/EdgeNodeAgent.js.map +1 -1
  27. package/dist/edge/EdgeNodeAgent.jsonld +166 -0
  28. package/dist/edge/EdgeNodeAgentInitializer.d.ts +20 -2
  29. package/dist/edge/EdgeNodeAgentInitializer.js +53 -2
  30. package/dist/edge/EdgeNodeAgentInitializer.js.map +1 -1
  31. package/dist/edge/EdgeNodeAgentInitializer.jsonld +409 -0
  32. package/dist/edge/reachability/CanonicalFetch.d.ts +7 -0
  33. package/dist/edge/reachability/CanonicalFetch.js +49 -0
  34. package/dist/edge/reachability/CanonicalFetch.js.map +1 -0
  35. package/dist/edge/reachability/CanonicalFetch.jsonld +25 -0
  36. package/dist/edge/reachability/ManagedClientFetch.d.ts +26 -0
  37. package/dist/edge/reachability/ManagedClientFetch.js +155 -0
  38. package/dist/edge/reachability/ManagedClientFetch.js.map +1 -0
  39. package/dist/edge/reachability/ManagedClientFetch.jsonld +83 -0
  40. package/dist/edge/reachability/ManagedClientP2PSmoke.d.ts +16 -0
  41. package/dist/edge/reachability/ManagedClientP2PSmoke.js +31 -0
  42. package/dist/edge/reachability/ManagedClientP2PSmoke.js.map +1 -0
  43. package/dist/edge/reachability/ManagedClientP2PSmoke.jsonld +65 -0
  44. package/dist/edge/reachability/ManagedRouteSelector.d.ts +7 -0
  45. package/dist/edge/reachability/ManagedRouteSelector.js +43 -0
  46. package/dist/edge/reachability/ManagedRouteSelector.js.map +1 -0
  47. package/dist/edge/reachability/ManagedRouteSelector.jsonld +29 -0
  48. package/dist/edge/reachability/P2PDataPlane.d.ts +37 -0
  49. package/dist/edge/reachability/P2PDataPlane.js +160 -0
  50. package/dist/edge/reachability/P2PDataPlane.js.map +1 -0
  51. package/dist/edge/reachability/P2PDataPlane.jsonld +134 -0
  52. package/dist/edge/reachability/P2PRealnetAcceptance.d.ts +74 -0
  53. package/dist/edge/reachability/P2PRealnetAcceptance.js +240 -0
  54. package/dist/edge/reachability/P2PRealnetAcceptance.js.map +1 -0
  55. package/dist/edge/reachability/P2PRealnetAcceptance.jsonld +283 -0
  56. package/dist/edge/reachability/P2PSignalingClient.d.ts +24 -0
  57. package/dist/edge/reachability/P2PSignalingClient.js +138 -0
  58. package/dist/edge/reachability/P2PSignalingClient.js.map +1 -0
  59. package/dist/edge/reachability/P2PSignalingClient.jsonld +79 -0
  60. package/dist/edge/reachability/ReachabilitySessionService.d.ts +55 -0
  61. package/dist/edge/reachability/ReachabilitySessionService.js +439 -0
  62. package/dist/edge/reachability/ReachabilitySessionService.js.map +1 -0
  63. package/dist/edge/reachability/ReachabilitySessionService.jsonld +196 -0
  64. package/dist/edge/reachability/RouteSetBuilder.d.ts +2 -0
  65. package/dist/edge/reachability/RouteSetBuilder.js +205 -0
  66. package/dist/edge/reachability/RouteSetBuilder.js.map +1 -0
  67. package/dist/edge/reachability/TcpP2PDataPlaneTransport.d.ts +47 -0
  68. package/dist/edge/reachability/TcpP2PDataPlaneTransport.js +281 -0
  69. package/dist/edge/reachability/TcpP2PDataPlaneTransport.js.map +1 -0
  70. package/dist/edge/reachability/TcpP2PDataPlaneTransport.jsonld +183 -0
  71. package/dist/edge/reachability/TcpP2PSignalingSession.d.ts +149 -0
  72. package/dist/edge/reachability/TcpP2PSignalingSession.js +699 -0
  73. package/dist/edge/reachability/TcpP2PSignalingSession.js.map +1 -0
  74. package/dist/edge/reachability/TcpP2PSignalingSession.jsonld +474 -0
  75. package/dist/edge/reachability/index.d.ts +12 -0
  76. package/dist/edge/reachability/index.js +29 -0
  77. package/dist/edge/reachability/index.js.map +1 -0
  78. package/dist/edge/reachability/types.d.ts +114 -0
  79. package/dist/edge/reachability/types.js +3 -0
  80. package/dist/edge/reachability/types.js.map +1 -0
  81. package/dist/edge/reachability/types.jsonld +457 -0
  82. package/dist/http/EdgeNodeProxyHttpHandler.d.ts +2 -0
  83. package/dist/http/EdgeNodeProxyHttpHandler.js +19 -1
  84. package/dist/http/EdgeNodeProxyHttpHandler.js.map +1 -1
  85. package/dist/http/EdgeNodeProxyHttpHandler.jsonld +8 -0
  86. package/dist/identity/drizzle/EdgeNodeRepository.js +1 -1
  87. package/dist/identity/drizzle/EdgeNodeRepository.js.map +1 -1
  88. package/dist/index.d.ts +4 -1
  89. package/dist/index.js +5 -2
  90. package/dist/index.js.map +1 -1
  91. package/dist/runtime/bootstrap.js +8 -0
  92. package/dist/runtime/bootstrap.js.map +1 -1
  93. package/dist/service/EdgeNodeSignalClient.js +5 -1
  94. package/dist/service/EdgeNodeSignalClient.js.map +1 -1
  95. package/dist/storage/rdf/PostgresRdfEngine.d.ts +1 -0
  96. package/dist/storage/rdf/PostgresRdfEngine.js +53 -37
  97. package/dist/storage/rdf/PostgresRdfEngine.js.map +1 -1
  98. package/dist/storage/rdf/PostgresRdfEngine.jsonld +4 -0
  99. package/dist/test-utils/index.d.ts +2 -0
  100. package/dist/test-utils/index.js +3 -1
  101. package/dist/test-utils/index.js.map +1 -1
  102. package/dist/test-utils/local-managed-client-p2p-e2e-smoke.d.ts +63 -0
  103. package/dist/test-utils/local-managed-client-p2p-e2e-smoke.js +478 -0
  104. package/dist/test-utils/local-managed-client-p2p-e2e-smoke.js.map +1 -0
  105. package/package.json +11 -4
  106. package/static/app/assets/_commonjsHelpers-B-UnjaXt.js +1 -0
  107. package/static/app/assets/index-AaQ1qxhy.js +171 -0
  108. package/static/app/assets/inrupt-smoke.js +131 -0
  109. package/static/app/assets/main.css +1 -0
  110. package/static/app/assets/main.js +6 -6
  111. package/static/app/index.html +2 -1
  112. package/static/app/inrupt-smoke.html +14 -0
  113. package/static/app/reachability.html +221 -0
  114. package/static/app/reachability.svg +7 -0
  115. package/static/app/reachability.webmanifest +18 -0
  116. package/static/app/signal-pod.html +293 -0
  117. package/static/app/assets/index.css +0 -1
@@ -0,0 +1,196 @@
1
+ {
2
+ "@context": [
3
+ "https://linkedsoftwaredependencies.org/bundles/npm/@undefineds.co/xpod/^0.0.0/components/context.jsonld"
4
+ ],
5
+ "@id": "npmd:@undefineds.co/xpod",
6
+ "components": [
7
+ {
8
+ "@id": "undefineds:dist/edge/reachability/ReachabilitySessionService.jsonld#ReachabilitySessionService",
9
+ "@type": "Class",
10
+ "requireElement": "ReachabilitySessionService",
11
+ "parameters": [
12
+ {
13
+ "@id": "undefineds:dist/edge/reachability/ReachabilitySessionService.jsonld#ReachabilitySessionService_options",
14
+ "range": "undefineds:dist/edge/reachability/ReachabilitySessionService.jsonld#ReachabilitySessionServiceOptions"
15
+ }
16
+ ],
17
+ "memberFields": [
18
+ {
19
+ "@id": "undefineds:dist/edge/reachability/ReachabilitySessionService.jsonld#ReachabilitySessionService__member_options",
20
+ "memberFieldName": "options"
21
+ },
22
+ {
23
+ "@id": "undefineds:dist/edge/reachability/ReachabilitySessionService.jsonld#ReachabilitySessionService__member_now",
24
+ "memberFieldName": "now"
25
+ },
26
+ {
27
+ "@id": "undefineds:dist/edge/reachability/ReachabilitySessionService.jsonld#ReachabilitySessionService__member_randomId",
28
+ "memberFieldName": "randomId"
29
+ },
30
+ {
31
+ "@id": "undefineds:dist/edge/reachability/ReachabilitySessionService.jsonld#ReachabilitySessionService__member_defaultP2PTtlSeconds",
32
+ "memberFieldName": "defaultP2PTtlSeconds"
33
+ },
34
+ {
35
+ "@id": "undefineds:dist/edge/reachability/ReachabilitySessionService.jsonld#ReachabilitySessionService__member_defaultRelayTtlSeconds",
36
+ "memberFieldName": "defaultRelayTtlSeconds"
37
+ },
38
+ {
39
+ "@id": "undefineds:dist/edge/reachability/ReachabilitySessionService.jsonld#ReachabilitySessionService__member_defaultRelayBandwidthLimitBytes",
40
+ "memberFieldName": "defaultRelayBandwidthLimitBytes"
41
+ },
42
+ {
43
+ "@id": "undefineds:dist/edge/reachability/ReachabilitySessionService.jsonld#ReachabilitySessionService__member_maxActiveP2PSessionsPerNode",
44
+ "memberFieldName": "maxActiveP2PSessionsPerNode"
45
+ },
46
+ {
47
+ "@id": "undefineds:dist/edge/reachability/ReachabilitySessionService.jsonld#ReachabilitySessionService__member_maxP2PCandidatesPerUpdate",
48
+ "memberFieldName": "maxP2PCandidatesPerUpdate"
49
+ },
50
+ {
51
+ "@id": "undefineds:dist/edge/reachability/ReachabilitySessionService.jsonld#ReachabilitySessionService__member_maxP2PCandidatesPerSession",
52
+ "memberFieldName": "maxP2PCandidatesPerSession"
53
+ },
54
+ {
55
+ "@id": "undefineds:dist/edge/reachability/ReachabilitySessionService.jsonld#ReachabilitySessionService__member_constructor",
56
+ "memberFieldName": "constructor"
57
+ },
58
+ {
59
+ "@id": "undefineds:dist/edge/reachability/ReachabilitySessionService.jsonld#ReachabilitySessionService__member_createP2PSession",
60
+ "memberFieldName": "createP2PSession"
61
+ },
62
+ {
63
+ "@id": "undefineds:dist/edge/reachability/ReachabilitySessionService.jsonld#ReachabilitySessionService__member_getP2PSession",
64
+ "memberFieldName": "getP2PSession"
65
+ },
66
+ {
67
+ "@id": "undefineds:dist/edge/reachability/ReachabilitySessionService.jsonld#ReachabilitySessionService__member_listP2PSessions",
68
+ "memberFieldName": "listP2PSessions"
69
+ },
70
+ {
71
+ "@id": "undefineds:dist/edge/reachability/ReachabilitySessionService.jsonld#ReachabilitySessionService__member_addP2PCandidates",
72
+ "memberFieldName": "addP2PCandidates"
73
+ },
74
+ {
75
+ "@id": "undefineds:dist/edge/reachability/ReachabilitySessionService.jsonld#ReachabilitySessionService__member_createRelaySession",
76
+ "memberFieldName": "createRelaySession"
77
+ },
78
+ {
79
+ "@id": "undefineds:dist/edge/reachability/ReachabilitySessionService.jsonld#ReachabilitySessionService__member_loadNodeRouteSource",
80
+ "memberFieldName": "loadNodeRouteSource"
81
+ },
82
+ {
83
+ "@id": "undefineds:dist/edge/reachability/ReachabilitySessionService.jsonld#ReachabilitySessionService__member_readActiveP2PSessions",
84
+ "memberFieldName": "readActiveP2PSessions"
85
+ },
86
+ {
87
+ "@id": "undefineds:dist/edge/reachability/ReachabilitySessionService.jsonld#ReachabilitySessionService__member_p2pSessionLimits",
88
+ "memberFieldName": "p2pSessionLimits"
89
+ },
90
+ {
91
+ "@id": "undefineds:dist/edge/reachability/ReachabilitySessionService.jsonld#ReachabilitySessionService__member_resolveP2PSessionLimits",
92
+ "memberFieldName": "resolveP2PSessionLimits"
93
+ },
94
+ {
95
+ "@id": "undefineds:dist/edge/reachability/ReachabilitySessionService.jsonld#ReachabilitySessionService__member_appendSession",
96
+ "memberFieldName": "appendSession"
97
+ },
98
+ {
99
+ "@id": "undefineds:dist/edge/reachability/ReachabilitySessionService.jsonld#ReachabilitySessionService__member_loadP2PSession",
100
+ "memberFieldName": "loadP2PSession"
101
+ },
102
+ {
103
+ "@id": "undefineds:dist/edge/reachability/ReachabilitySessionService.jsonld#ReachabilitySessionService__member_assertP2PSessionActive",
104
+ "memberFieldName": "assertP2PSessionActive"
105
+ },
106
+ {
107
+ "@id": "undefineds:dist/edge/reachability/ReachabilitySessionService.jsonld#ReachabilitySessionService__member_isP2PSessionActive",
108
+ "memberFieldName": "isP2PSessionActive"
109
+ },
110
+ {
111
+ "@id": "undefineds:dist/edge/reachability/ReachabilitySessionService.jsonld#ReachabilitySessionService__member_normalizeP2PCandidates",
112
+ "memberFieldName": "normalizeP2PCandidates"
113
+ }
114
+ ],
115
+ "constructorArguments": [
116
+ {
117
+ "@id": "undefineds:dist/edge/reachability/ReachabilitySessionService.jsonld#ReachabilitySessionService_options"
118
+ }
119
+ ]
120
+ },
121
+ {
122
+ "@id": "undefineds:dist/edge/reachability/ReachabilitySessionService.jsonld#P2PActiveSessionLimitExceededError",
123
+ "@type": "Class",
124
+ "requireElement": "P2PActiveSessionLimitExceededError",
125
+ "parameters": [],
126
+ "constructorArguments": []
127
+ },
128
+ {
129
+ "@id": "undefineds:dist/edge/reachability/ReachabilitySessionService.jsonld#P2PCandidateUpdateLimitExceededError",
130
+ "@type": "Class",
131
+ "requireElement": "P2PCandidateUpdateLimitExceededError",
132
+ "parameters": [],
133
+ "constructorArguments": []
134
+ },
135
+ {
136
+ "@id": "undefineds:dist/edge/reachability/ReachabilitySessionService.jsonld#P2PCandidateSessionLimitExceededError",
137
+ "@type": "Class",
138
+ "requireElement": "P2PCandidateSessionLimitExceededError",
139
+ "parameters": [],
140
+ "constructorArguments": []
141
+ },
142
+ {
143
+ "@id": "undefineds:dist/edge/reachability/ReachabilitySessionService.jsonld#ReachabilitySessionServiceOptions",
144
+ "@type": "AbstractClass",
145
+ "requireElement": "ReachabilitySessionServiceOptions",
146
+ "parameters": [],
147
+ "memberFields": [
148
+ {
149
+ "@id": "undefineds:dist/edge/reachability/ReachabilitySessionService.jsonld#ReachabilitySessionServiceOptions__member_repository",
150
+ "memberFieldName": "repository"
151
+ },
152
+ {
153
+ "@id": "undefineds:dist/edge/reachability/ReachabilitySessionService.jsonld#ReachabilitySessionServiceOptions__member_baseStorageDomain",
154
+ "memberFieldName": "baseStorageDomain"
155
+ },
156
+ {
157
+ "@id": "undefineds:dist/edge/reachability/ReachabilitySessionService.jsonld#ReachabilitySessionServiceOptions__member_apiBaseUrl",
158
+ "memberFieldName": "apiBaseUrl"
159
+ },
160
+ {
161
+ "@id": "undefineds:dist/edge/reachability/ReachabilitySessionService.jsonld#ReachabilitySessionServiceOptions__member_now",
162
+ "memberFieldName": "now"
163
+ },
164
+ {
165
+ "@id": "undefineds:dist/edge/reachability/ReachabilitySessionService.jsonld#ReachabilitySessionServiceOptions__member_randomId",
166
+ "memberFieldName": "randomId"
167
+ },
168
+ {
169
+ "@id": "undefineds:dist/edge/reachability/ReachabilitySessionService.jsonld#ReachabilitySessionServiceOptions__member_defaultP2PTtlSeconds",
170
+ "memberFieldName": "defaultP2PTtlSeconds"
171
+ },
172
+ {
173
+ "@id": "undefineds:dist/edge/reachability/ReachabilitySessionService.jsonld#ReachabilitySessionServiceOptions__member_defaultRelayTtlSeconds",
174
+ "memberFieldName": "defaultRelayTtlSeconds"
175
+ },
176
+ {
177
+ "@id": "undefineds:dist/edge/reachability/ReachabilitySessionService.jsonld#ReachabilitySessionServiceOptions__member_defaultRelayBandwidthLimitBytes",
178
+ "memberFieldName": "defaultRelayBandwidthLimitBytes"
179
+ },
180
+ {
181
+ "@id": "undefineds:dist/edge/reachability/ReachabilitySessionService.jsonld#ReachabilitySessionServiceOptions__member_maxActiveP2PSessionsPerNode",
182
+ "memberFieldName": "maxActiveP2PSessionsPerNode"
183
+ },
184
+ {
185
+ "@id": "undefineds:dist/edge/reachability/ReachabilitySessionService.jsonld#ReachabilitySessionServiceOptions__member_maxP2PCandidatesPerUpdate",
186
+ "memberFieldName": "maxP2PCandidatesPerUpdate"
187
+ },
188
+ {
189
+ "@id": "undefineds:dist/edge/reachability/ReachabilitySessionService.jsonld#ReachabilitySessionServiceOptions__member_maxP2PCandidatesPerSession",
190
+ "memberFieldName": "maxP2PCandidatesPerSession"
191
+ }
192
+ ],
193
+ "constructorArguments": []
194
+ }
195
+ ]
196
+ }
@@ -0,0 +1,2 @@
1
+ import type { BuildRouteSetOptions, BuildRouteSetSource, RouteSet } from './types';
2
+ export declare function buildRouteSet(source: BuildRouteSetSource, options?: BuildRouteSetOptions): RouteSet;
@@ -0,0 +1,205 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildRouteSet = buildRouteSet;
4
+ const DEFAULT_PRIORITY = {
5
+ loopback: 10,
6
+ lan: 20,
7
+ 'public-direct': 30,
8
+ p2p: 40,
9
+ 'user-tunnel': 50,
10
+ 'xpod-relay': 90,
11
+ };
12
+ const PUBLIC_KINDS = new Set(['public-direct', 'user-tunnel', 'xpod-relay']);
13
+ function buildRouteSet(source, options = {}) {
14
+ const audience = options.audience ?? 'managed';
15
+ const now = options.now ?? new Date();
16
+ const metadata = source.metadata ?? {};
17
+ const canonicalUrl = normalizeCanonicalUrl(source.canonicalUrl
18
+ ?? getString(metadata.canonicalUrl)
19
+ ?? getString(metadata.baseUrl)
20
+ ?? source.publicUrl
21
+ ?? deriveManagedDomainUrl(source.subdomain, options.baseStorageDomain ?? source.baseStorageDomain));
22
+ const routes = uniqueRoutes([
23
+ ...routesFromMetadata(source, canonicalUrl, metadata),
24
+ ...routesFromDirectCandidates(source, canonicalUrl, metadata),
25
+ ...routesFromTunnel(source, canonicalUrl, metadata),
26
+ ...routesFromConnectivity(source, canonicalUrl),
27
+ ])
28
+ .filter((route) => isVisibleToAudience(route, audience))
29
+ .sort((left, right) => left.priority - right.priority || left.id.localeCompare(right.id));
30
+ return {
31
+ nodeId: source.nodeId,
32
+ canonicalUrl,
33
+ generatedAt: now.toISOString(),
34
+ routes,
35
+ };
36
+ }
37
+ function routesFromMetadata(source, canonicalUrl, metadata) {
38
+ const rawRoutes = Array.isArray(metadata.routes) ? metadata.routes : [];
39
+ return rawRoutes
40
+ .map((value, index) => normalizeAccessRoute(source.nodeId, canonicalUrl, value, `metadata-${index}`))
41
+ .filter((route) => Boolean(route));
42
+ }
43
+ function routesFromDirectCandidates(source, canonicalUrl, metadata) {
44
+ const candidates = [
45
+ ...normalizeStringArray(source.metadata?.directCandidates),
46
+ ...normalizeStringArray(metadata.directCandidates),
47
+ ];
48
+ return candidates
49
+ .map((targetUrl, index) => normalizeAccessRoute(source.nodeId, canonicalUrl, {
50
+ id: `public-direct-${index}`,
51
+ kind: 'public-direct',
52
+ targetUrl,
53
+ priority: DEFAULT_PRIORITY['public-direct'],
54
+ requiresManagedClient: false,
55
+ visibility: 'public',
56
+ health: source.connectivityStatus === 'unreachable' ? 'unreachable' : 'healthy',
57
+ }, `public-direct-${index}`))
58
+ .filter((route) => Boolean(route));
59
+ }
60
+ function routesFromTunnel(source, canonicalUrl, metadata) {
61
+ const tunnel = isRecord(metadata.tunnel) ? metadata.tunnel : undefined;
62
+ const entrypoint = getString(tunnel?.entrypoint) ?? getString(tunnel?.endpoint) ?? getString(tunnel?.url);
63
+ const status = getString(tunnel?.status);
64
+ if (!entrypoint || status === 'inactive' || status === 'standby') {
65
+ return [];
66
+ }
67
+ const route = normalizeAccessRoute(source.nodeId, canonicalUrl, {
68
+ id: 'user-tunnel',
69
+ kind: 'user-tunnel',
70
+ targetUrl: entrypoint,
71
+ priority: DEFAULT_PRIORITY['user-tunnel'],
72
+ requiresManagedClient: false,
73
+ visibility: 'public',
74
+ health: status === 'error' ? 'degraded' : 'healthy',
75
+ metadata: { tunnel },
76
+ }, 'user-tunnel');
77
+ return route ? [route] : [];
78
+ }
79
+ function routesFromConnectivity(source, canonicalUrl) {
80
+ if (!source.publicUrl || source.connectivityStatus === 'unreachable') {
81
+ return [];
82
+ }
83
+ const route = normalizeAccessRoute(source.nodeId, canonicalUrl, {
84
+ id: 'public-direct',
85
+ kind: 'public-direct',
86
+ targetUrl: source.publicUrl,
87
+ priority: DEFAULT_PRIORITY['public-direct'],
88
+ requiresManagedClient: false,
89
+ visibility: 'public',
90
+ health: source.connectivityStatus === 'reachable' ? 'healthy' : 'unknown',
91
+ }, 'public-direct');
92
+ return route ? [route] : [];
93
+ }
94
+ function normalizeAccessRoute(nodeId, canonicalUrl, value, fallbackId) {
95
+ if (!isRecord(value)) {
96
+ return undefined;
97
+ }
98
+ const kind = normalizeKind(value.kind);
99
+ const targetUrl = normalizeUrlString(getString(value.targetUrl));
100
+ if (!kind || !targetUrl) {
101
+ return undefined;
102
+ }
103
+ const visibility = normalizeVisibility(value.visibility) ?? defaultVisibility(kind);
104
+ const requiresManagedClient = typeof value.requiresManagedClient === 'boolean'
105
+ ? value.requiresManagedClient
106
+ : visibility !== 'public';
107
+ return {
108
+ id: getString(value.id) ?? fallbackId,
109
+ nodeId: getString(value.nodeId) ?? nodeId,
110
+ canonicalUrl: normalizeCanonicalUrl(getString(value.canonicalUrl) ?? canonicalUrl),
111
+ kind,
112
+ targetUrl,
113
+ priority: normalizePriority(value.priority) ?? DEFAULT_PRIORITY[kind],
114
+ requiresManagedClient,
115
+ visibility,
116
+ health: normalizeHealth(value.health) ?? 'unknown',
117
+ lastCheckedAt: getString(value.lastCheckedAt),
118
+ expiresAt: getString(value.expiresAt),
119
+ metadata: isRecord(value.metadata) ? value.metadata : undefined,
120
+ };
121
+ }
122
+ function normalizeCanonicalUrl(value) {
123
+ const normalized = normalizeUrlString(value);
124
+ if (normalized) {
125
+ return normalized;
126
+ }
127
+ return 'about:blank';
128
+ }
129
+ function normalizeUrlString(value) {
130
+ if (!value) {
131
+ return undefined;
132
+ }
133
+ try {
134
+ return new URL(value).toString();
135
+ }
136
+ catch {
137
+ return undefined;
138
+ }
139
+ }
140
+ function normalizeKind(value) {
141
+ const kind = getString(value);
142
+ return kind && kind in DEFAULT_PRIORITY ? kind : undefined;
143
+ }
144
+ function normalizeVisibility(value) {
145
+ const visibility = getString(value);
146
+ if (visibility === 'local-only' || visibility === 'same-account' || visibility === 'authorized-client' || visibility === 'public') {
147
+ return visibility;
148
+ }
149
+ return undefined;
150
+ }
151
+ function normalizeHealth(value) {
152
+ const health = getString(value);
153
+ if (health === 'unknown' || health === 'healthy' || health === 'degraded' || health === 'unreachable') {
154
+ return health;
155
+ }
156
+ return undefined;
157
+ }
158
+ function normalizePriority(value) {
159
+ if (typeof value !== 'number' || !Number.isFinite(value)) {
160
+ return undefined;
161
+ }
162
+ return value;
163
+ }
164
+ function defaultVisibility(kind) {
165
+ return PUBLIC_KINDS.has(kind) ? 'public' : 'authorized-client';
166
+ }
167
+ function isVisibleToAudience(route, audience) {
168
+ if (audience === 'managed') {
169
+ return true;
170
+ }
171
+ return route.visibility === 'public' && !route.requiresManagedClient && PUBLIC_KINDS.has(route.kind);
172
+ }
173
+ function uniqueRoutes(routes) {
174
+ const byKey = new Map();
175
+ for (const route of routes) {
176
+ const key = `${route.kind}\n${route.targetUrl}`;
177
+ const previous = byKey.get(key);
178
+ if (!previous || route.priority < previous.priority) {
179
+ byKey.set(key, route);
180
+ }
181
+ }
182
+ return [...byKey.values()];
183
+ }
184
+ function normalizeStringArray(value) {
185
+ if (Array.isArray(value)) {
186
+ return value.filter((entry) => typeof entry === 'string' && entry.trim().length > 0);
187
+ }
188
+ if (typeof value === 'string' && value.trim().length > 0) {
189
+ return [value.trim()];
190
+ }
191
+ return [];
192
+ }
193
+ function deriveManagedDomainUrl(subdomain, baseStorageDomain) {
194
+ if (!subdomain || !baseStorageDomain) {
195
+ return undefined;
196
+ }
197
+ return `https://${subdomain}.${baseStorageDomain}/`;
198
+ }
199
+ function getString(value) {
200
+ return typeof value === 'string' && value.trim().length > 0 ? value.trim() : undefined;
201
+ }
202
+ function isRecord(value) {
203
+ return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
204
+ }
205
+ //# sourceMappingURL=RouteSetBuilder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RouteSetBuilder.js","sourceRoot":"","sources":["../../../src/edge/reachability/RouteSetBuilder.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n AccessRoute,\n AccessRouteHealth,\n AccessRouteKind,\n AccessRouteVisibility,\n BuildRouteSetOptions,\n BuildRouteSetSource,\n RouteAudience,\n RouteSet,\n} from './types';\n\nconst DEFAULT_PRIORITY: Record<AccessRouteKind, number> = {\n loopback: 10,\n lan: 20,\n 'public-direct': 30,\n p2p: 40,\n 'user-tunnel': 50,\n 'xpod-relay': 90,\n};\n\nconst PUBLIC_KINDS = new Set<AccessRouteKind>(['public-direct', 'user-tunnel', 'xpod-relay']);\n\nexport function buildRouteSet(source: BuildRouteSetSource, options: BuildRouteSetOptions = {}): RouteSet {\n const audience = options.audience ?? 'managed';\n const now = options.now ?? new Date();\n const metadata = source.metadata ?? {};\n const canonicalUrl = normalizeCanonicalUrl(\n source.canonicalUrl\n ?? getString(metadata.canonicalUrl)\n ?? getString(metadata.baseUrl)\n ?? source.publicUrl\n ?? deriveManagedDomainUrl(source.subdomain, options.baseStorageDomain ?? source.baseStorageDomain),\n );\n\n const routes = uniqueRoutes([\n ...routesFromMetadata(source, canonicalUrl, metadata),\n ...routesFromDirectCandidates(source, canonicalUrl, metadata),\n ...routesFromTunnel(source, canonicalUrl, metadata),\n ...routesFromConnectivity(source, canonicalUrl),\n ])\n .filter((route) => isVisibleToAudience(route, audience))\n .sort((left, right) => left.priority - right.priority || left.id.localeCompare(right.id));\n\n return {\n nodeId: source.nodeId,\n canonicalUrl,\n generatedAt: now.toISOString(),\n routes,\n };\n}\n\nfunction routesFromMetadata(source: BuildRouteSetSource, canonicalUrl: string, metadata: Record<string, unknown>): AccessRoute[] {\n const rawRoutes = Array.isArray(metadata.routes) ? metadata.routes : [];\n return rawRoutes\n .map((value, index) => normalizeAccessRoute(source.nodeId, canonicalUrl, value, `metadata-${index}`))\n .filter((route): route is AccessRoute => Boolean(route));\n}\n\nfunction routesFromDirectCandidates(source: BuildRouteSetSource, canonicalUrl: string, metadata: Record<string, unknown>): AccessRoute[] {\n const candidates = [\n ...normalizeStringArray(source.metadata?.directCandidates),\n ...normalizeStringArray(metadata.directCandidates),\n ];\n return candidates\n .map((targetUrl, index) => normalizeAccessRoute(source.nodeId, canonicalUrl, {\n id: `public-direct-${index}`,\n kind: 'public-direct',\n targetUrl,\n priority: DEFAULT_PRIORITY['public-direct'],\n requiresManagedClient: false,\n visibility: 'public',\n health: source.connectivityStatus === 'unreachable' ? 'unreachable' : 'healthy',\n }, `public-direct-${index}`))\n .filter((route): route is AccessRoute => Boolean(route));\n}\n\nfunction routesFromTunnel(source: BuildRouteSetSource, canonicalUrl: string, metadata: Record<string, unknown>): AccessRoute[] {\n const tunnel = isRecord(metadata.tunnel) ? metadata.tunnel : undefined;\n const entrypoint = getString(tunnel?.entrypoint) ?? getString(tunnel?.endpoint) ?? getString(tunnel?.url);\n const status = getString(tunnel?.status);\n if (!entrypoint || status === 'inactive' || status === 'standby') {\n return [];\n }\n const route = normalizeAccessRoute(source.nodeId, canonicalUrl, {\n id: 'user-tunnel',\n kind: 'user-tunnel',\n targetUrl: entrypoint,\n priority: DEFAULT_PRIORITY['user-tunnel'],\n requiresManagedClient: false,\n visibility: 'public',\n health: status === 'error' ? 'degraded' : 'healthy',\n metadata: { tunnel },\n }, 'user-tunnel');\n return route ? [route] : [];\n}\n\nfunction routesFromConnectivity(source: BuildRouteSetSource, canonicalUrl: string): AccessRoute[] {\n if (!source.publicUrl || source.connectivityStatus === 'unreachable') {\n return [];\n }\n const route = normalizeAccessRoute(source.nodeId, canonicalUrl, {\n id: 'public-direct',\n kind: 'public-direct',\n targetUrl: source.publicUrl,\n priority: DEFAULT_PRIORITY['public-direct'],\n requiresManagedClient: false,\n visibility: 'public',\n health: source.connectivityStatus === 'reachable' ? 'healthy' : 'unknown',\n }, 'public-direct');\n return route ? [route] : [];\n}\n\nfunction normalizeAccessRoute(\n nodeId: string,\n canonicalUrl: string,\n value: unknown,\n fallbackId: string,\n): AccessRoute | undefined {\n if (!isRecord(value)) {\n return undefined;\n }\n const kind = normalizeKind(value.kind);\n const targetUrl = normalizeUrlString(getString(value.targetUrl));\n if (!kind || !targetUrl) {\n return undefined;\n }\n const visibility = normalizeVisibility(value.visibility) ?? defaultVisibility(kind);\n const requiresManagedClient = typeof value.requiresManagedClient === 'boolean'\n ? value.requiresManagedClient\n : visibility !== 'public';\n return {\n id: getString(value.id) ?? fallbackId,\n nodeId: getString(value.nodeId) ?? nodeId,\n canonicalUrl: normalizeCanonicalUrl(getString(value.canonicalUrl) ?? canonicalUrl),\n kind,\n targetUrl,\n priority: normalizePriority(value.priority) ?? DEFAULT_PRIORITY[kind],\n requiresManagedClient,\n visibility,\n health: normalizeHealth(value.health) ?? 'unknown',\n lastCheckedAt: getString(value.lastCheckedAt),\n expiresAt: getString(value.expiresAt),\n metadata: isRecord(value.metadata) ? value.metadata : undefined,\n };\n}\n\nfunction normalizeCanonicalUrl(value?: string): string {\n const normalized = normalizeUrlString(value);\n if (normalized) {\n return normalized;\n }\n return 'about:blank';\n}\n\nfunction normalizeUrlString(value?: string): string | undefined {\n if (!value) {\n return undefined;\n }\n try {\n return new URL(value).toString();\n } catch {\n return undefined;\n }\n}\n\nfunction normalizeKind(value: unknown): AccessRouteKind | undefined {\n const kind = getString(value) as AccessRouteKind | undefined;\n return kind && kind in DEFAULT_PRIORITY ? kind : undefined;\n}\n\nfunction normalizeVisibility(value: unknown): AccessRouteVisibility | undefined {\n const visibility = getString(value) as AccessRouteVisibility | undefined;\n if (visibility === 'local-only' || visibility === 'same-account' || visibility === 'authorized-client' || visibility === 'public') {\n return visibility;\n }\n return undefined;\n}\n\nfunction normalizeHealth(value: unknown): AccessRouteHealth | undefined {\n const health = getString(value) as AccessRouteHealth | undefined;\n if (health === 'unknown' || health === 'healthy' || health === 'degraded' || health === 'unreachable') {\n return health;\n }\n return undefined;\n}\n\nfunction normalizePriority(value: unknown): number | undefined {\n if (typeof value !== 'number' || !Number.isFinite(value)) {\n return undefined;\n }\n return value;\n}\n\nfunction defaultVisibility(kind: AccessRouteKind): AccessRouteVisibility {\n return PUBLIC_KINDS.has(kind) ? 'public' : 'authorized-client';\n}\n\nfunction isVisibleToAudience(route: AccessRoute, audience: RouteAudience): boolean {\n if (audience === 'managed') {\n return true;\n }\n return route.visibility === 'public' && !route.requiresManagedClient && PUBLIC_KINDS.has(route.kind);\n}\n\nfunction uniqueRoutes(routes: AccessRoute[]): AccessRoute[] {\n const byKey = new Map<string, AccessRoute>();\n for (const route of routes) {\n const key = `${route.kind}\\n${route.targetUrl}`;\n const previous = byKey.get(key);\n if (!previous || route.priority < previous.priority) {\n byKey.set(key, route);\n }\n }\n return [...byKey.values()];\n}\n\nfunction normalizeStringArray(value: unknown): string[] {\n if (Array.isArray(value)) {\n return value.filter((entry): entry is string => typeof entry === 'string' && entry.trim().length > 0);\n }\n if (typeof value === 'string' && value.trim().length > 0) {\n return [value.trim()];\n }\n return [];\n}\n\nfunction deriveManagedDomainUrl(subdomain?: string, baseStorageDomain?: string): string | undefined {\n if (!subdomain || !baseStorageDomain) {\n return undefined;\n }\n return `https://${subdomain}.${baseStorageDomain}/`;\n}\n\nfunction getString(value: unknown): string | undefined {\n return typeof value === 'string' && value.trim().length > 0 ? value.trim() : undefined;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return Boolean(value) && typeof value === 'object' && !Array.isArray(value);\n}\n"]}
@@ -0,0 +1,47 @@
1
+ import { type AddressInfo, type Socket } from 'node:net';
2
+ import type { P2PDataPlaneHandler, P2PDataPlaneTransport } from './P2PDataPlane';
3
+ export interface TcpP2PDataPlaneTransportOptions {
4
+ remoteHost: string;
5
+ remotePort: number;
6
+ socket?: Socket;
7
+ timeoutMs?: number;
8
+ randomId?: () => string;
9
+ }
10
+ export interface TcpP2PDataPlaneTransport extends P2PDataPlaneTransport {
11
+ close(): void;
12
+ }
13
+ export interface TcpP2PDataPlaneServerOptions {
14
+ handler: P2PDataPlaneHandler;
15
+ host?: string;
16
+ }
17
+ export interface TcpP2PDataPlaneServer {
18
+ listen(port?: number): Promise<void>;
19
+ address(): AddressInfo;
20
+ close(): Promise<void>;
21
+ }
22
+ export interface TcpP2PDataPlaneSocketOptions {
23
+ socket: Socket;
24
+ handler: P2PDataPlaneHandler;
25
+ }
26
+ export interface TcpP2PDataPlaneSocketHandle {
27
+ close(): void;
28
+ }
29
+ export interface TcpHolePunchPlanOptions {
30
+ nowSeconds?: number;
31
+ windowSeconds?: number;
32
+ maxClockErrorSeconds?: number;
33
+ minRunWindowSeconds?: number;
34
+ numPorts?: number;
35
+ basePort?: number;
36
+ portRange?: number;
37
+ }
38
+ export interface TcpHolePunchPlan {
39
+ bucket: number;
40
+ boundary: number;
41
+ rendezvousTimeSeconds: number;
42
+ ports: number[];
43
+ }
44
+ export declare function createTcpP2PDataPlaneTransport(options: TcpP2PDataPlaneTransportOptions): TcpP2PDataPlaneTransport;
45
+ export declare function createTcpP2PDataPlaneServer(options: TcpP2PDataPlaneServerOptions): TcpP2PDataPlaneServer;
46
+ export declare function attachTcpP2PDataPlaneSocket(options: TcpP2PDataPlaneSocketOptions): TcpP2PDataPlaneSocketHandle;
47
+ export declare function computeTcpHolePunchPlan(options?: TcpHolePunchPlanOptions): TcpHolePunchPlan;