memeloop 0.2.8 → 0.2.9

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 (36) hide show
  1. package/dist/{chunk-NVJCRIEK.js → chunk-34B7MUI6.js} +2 -2
  2. package/dist/{chunk-DACM5AMS.js → chunk-7W4FMKMO.js} +190 -56
  3. package/dist/chunk-7W4FMKMO.js.map +1 -0
  4. package/dist/{chunk-OD6U6VAR.js → chunk-GH5RDPLJ.js} +2 -2
  5. package/dist/{chunk-OD6U6VAR.js.map → chunk-GH5RDPLJ.js.map} +1 -1
  6. package/dist/device-network/cloudDeviceFetchClient.d.ts +9 -7
  7. package/dist/device-network/cloudDeviceFetchClient.d.ts.map +1 -1
  8. package/dist/device-network/deviceCloudConnectionCoordinator.d.ts +5 -5
  9. package/dist/device-network/deviceCloudConnectionCoordinator.d.ts.map +1 -1
  10. package/dist/device-network/deviceOrchestrationTransport.d.ts +7 -0
  11. package/dist/device-network/deviceOrchestrationTransport.d.ts.map +1 -1
  12. package/dist/device-network/standardDeviceCloudConnectionAdapter.d.ts +16 -8
  13. package/dist/device-network/standardDeviceCloudConnectionAdapter.d.ts.map +1 -1
  14. package/dist/device-network/types.d.ts +4 -2
  15. package/dist/device-network/types.d.ts.map +1 -1
  16. package/dist/device-network-portable.cjs +190 -55
  17. package/dist/device-network-portable.cjs.map +1 -1
  18. package/dist/device-network-portable.js +189 -55
  19. package/dist/device-network-portable.js.map +1 -1
  20. package/dist/device-network.cjs +190 -55
  21. package/dist/device-network.cjs.map +1 -1
  22. package/dist/device-network.js +4 -2
  23. package/dist/index.cjs +488 -180
  24. package/dist/index.cjs.map +1 -1
  25. package/dist/index.js +302 -127
  26. package/dist/index.js.map +1 -1
  27. package/dist/loop-api.cjs +1 -1
  28. package/dist/loop-api.cjs.map +1 -1
  29. package/dist/loop-api.js +1 -1
  30. package/dist/mobile.cjs.map +1 -1
  31. package/dist/orchestration/externalOrchestrationController.d.ts.map +1 -1
  32. package/dist/orchestration/workloadExecutionController.d.ts.map +1 -1
  33. package/dist/plugin/loader.d.ts +1 -1
  34. package/package.json +2 -1
  35. package/dist/chunk-DACM5AMS.js.map +0 -1
  36. /package/dist/{chunk-NVJCRIEK.js.map → chunk-34B7MUI6.js.map} +0 -0
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  DeviceNetworkUnavailableError
3
- } from "./chunk-DACM5AMS.js";
3
+ } from "./chunk-7W4FMKMO.js";
4
4
 
5
5
  // src/device-network/memoryDeviceNetworkService.ts
6
6
  var emptyCapabilities = {
@@ -197,4 +197,4 @@ export {
197
197
  MemoryDeviceNetworkService,
198
198
  syncCloudDevices
199
199
  };
200
- //# sourceMappingURL=chunk-NVJCRIEK.js.map
200
+ //# sourceMappingURL=chunk-34B7MUI6.js.map
@@ -1213,14 +1213,28 @@ var MemoryDeviceCloudTokenStorage = class {
1213
1213
  loadConnectionGrant(input) {
1214
1214
  return this.grants.get(connectionGrantCacheKey(input));
1215
1215
  }
1216
- saveConnectionGrant(input, grant) {
1217
- this.grants.set(connectionGrantCacheKey(input), grant);
1216
+ saveConnectionGrant(input, grant, fence) {
1217
+ const write = () => {
1218
+ this.grants.set(connectionGrantCacheKey(input), grant);
1219
+ };
1220
+ if (!fence) {
1221
+ write();
1222
+ return;
1223
+ }
1224
+ if (!fence.commitSynchronous(write)) fence.throwIfStale();
1218
1225
  }
1219
1226
  loadRelayReservation(peerId) {
1220
1227
  return this.relayReservations.get(peerId);
1221
1228
  }
1222
- saveRelayReservation(peerId, token) {
1223
- this.relayReservations.set(peerId, token);
1229
+ saveRelayReservation(peerId, token, fence) {
1230
+ const write = () => {
1231
+ this.relayReservations.set(peerId, token);
1232
+ };
1233
+ if (!fence) {
1234
+ write();
1235
+ return;
1236
+ }
1237
+ if (!fence.commitSynchronous(write)) fence.throwIfStale();
1224
1238
  }
1225
1239
  clear() {
1226
1240
  this.grants.clear();
@@ -1335,13 +1349,16 @@ var CloudDeviceFetchClient = class {
1335
1349
  }
1336
1350
  return { issuer: value.issuer, publicKeyMultibase: value.publicKeyMultibase };
1337
1351
  }
1338
- async createConnectionGrant(input, signal) {
1352
+ async createConnectionGrant(input, signal, fence) {
1353
+ assertFenceSignal(signal, fence);
1354
+ fence?.throwIfStale();
1339
1355
  if (!isCanonicalConnectionGrantRequest(input)) {
1340
1356
  throw new TypeError("invalid_connection_grant_scope");
1341
1357
  }
1342
1358
  const cacheInput = normalizedConnectionGrantRequest(input);
1343
1359
  const cached = await this.loadCachedGrant(cacheInput);
1344
1360
  throwIfAborted(signal);
1361
+ fence?.throwIfStale();
1345
1362
  if (isUsableConnectionGrant(cached, cacheInput, this.now() + this.tokenSafetyMarginMs)) {
1346
1363
  return cached;
1347
1364
  }
@@ -1350,12 +1367,17 @@ var CloudDeviceFetchClient = class {
1350
1367
  body: JSON.stringify(input)
1351
1368
  }, signal);
1352
1369
  if (!isUsableConnectionGrant(value, cacheInput, this.now())) throw invalidShape();
1353
- await this.saveCachedGrant(cacheInput, value);
1370
+ fence?.throwIfStale();
1371
+ await this.saveCachedGrant(cacheInput, value, fence);
1372
+ fence?.throwIfStale();
1354
1373
  return value;
1355
1374
  }
1356
- async createRelayReservation(input, signal) {
1375
+ async createRelayReservation(input, signal, fence) {
1376
+ assertFenceSignal(signal, fence);
1377
+ fence?.throwIfStale();
1357
1378
  const cached = await this.loadCachedRelayReservation(input.peerId);
1358
1379
  throwIfAborted(signal);
1380
+ fence?.throwIfStale();
1359
1381
  if (isUsableRelayReservation(cached, input.peerId, this.now() + this.tokenSafetyMarginMs)) {
1360
1382
  return cached;
1361
1383
  }
@@ -1364,7 +1386,9 @@ var CloudDeviceFetchClient = class {
1364
1386
  body: JSON.stringify(input)
1365
1387
  }, signal);
1366
1388
  if (!isUsableRelayReservation(value, input.peerId, this.now())) throw invalidShape();
1367
- await this.saveCachedRelayReservation(input.peerId, value);
1389
+ fence?.throwIfStale();
1390
+ await this.saveCachedRelayReservation(input.peerId, value, fence);
1391
+ fence?.throwIfStale();
1368
1392
  return value;
1369
1393
  }
1370
1394
  async heartbeat(input, signal) {
@@ -1438,10 +1462,11 @@ var CloudDeviceFetchClient = class {
1438
1462
  return void 0;
1439
1463
  }
1440
1464
  }
1441
- async saveCachedGrant(input, grant) {
1465
+ async saveCachedGrant(input, grant, fence) {
1442
1466
  try {
1443
- await this.tokenStorage.saveConnectionGrant(input, grant);
1467
+ await this.tokenStorage.saveConnectionGrant(input, grant, fence);
1444
1468
  } catch (error) {
1469
+ if (fence && !fence.isCurrent()) fence.throwIfStale();
1445
1470
  this.options.onTokenStorageError?.("save", error);
1446
1471
  }
1447
1472
  }
@@ -1453,14 +1478,20 @@ var CloudDeviceFetchClient = class {
1453
1478
  return void 0;
1454
1479
  }
1455
1480
  }
1456
- async saveCachedRelayReservation(peerId, token) {
1481
+ async saveCachedRelayReservation(peerId, token, fence) {
1457
1482
  try {
1458
- await this.tokenStorage.saveRelayReservation(peerId, token);
1483
+ await this.tokenStorage.saveRelayReservation(peerId, token, fence);
1459
1484
  } catch (error) {
1485
+ if (fence && !fence.isCurrent()) fence.throwIfStale();
1460
1486
  this.options.onTokenStorageError?.("save", error);
1461
1487
  }
1462
1488
  }
1463
1489
  };
1490
+ function assertFenceSignal(signal, fence) {
1491
+ if (fence && signal && fence.signal !== signal) {
1492
+ throw new TypeError("device_cloud_generation_signal_mismatch");
1493
+ }
1494
+ }
1464
1495
  function normalizeCloudDeviceBaseUrl(value) {
1465
1496
  const baseUrl = value.trim();
1466
1497
  if (!baseUrl || baseUrl.length > CLOUD_URL_MAX_CHARACTERS) throw new Error("invalid_cloud_url");
@@ -1887,16 +1918,16 @@ var DeviceCloudConnectionCoordinator = class {
1887
1918
  try {
1888
1919
  if (this.snapshotValue.components.authorizer !== "ready") {
1889
1920
  activeComponent = "authorizer";
1890
- await this.runStep(activeComponent, generation, signal, () => this.options.adapter.ensureAuthorizer(configuration, signal));
1921
+ await this.runStep(activeComponent, generation, signal, (fence) => this.options.adapter.ensureAuthorizer(configuration, signal, fence));
1891
1922
  }
1892
1923
  if (this.snapshotValue.components.registration !== "ready") {
1893
1924
  activeComponent = "registration";
1894
- await this.runStep(activeComponent, generation, signal, () => this.options.adapter.registerDevice(configuration, signal));
1925
+ await this.runStep(activeComponent, generation, signal, (fence) => this.options.adapter.registerDevice(configuration, signal, fence));
1895
1926
  }
1896
1927
  let relayFailure;
1897
1928
  try {
1898
1929
  activeComponent = "relay";
1899
- await this.runStep(activeComponent, generation, signal, () => this.options.adapter.ensureRelay(configuration, signal));
1930
+ await this.runStep(activeComponent, generation, signal, (fence) => this.options.adapter.ensureRelay(configuration, signal, fence));
1900
1931
  } catch (error) {
1901
1932
  const classification = this.classify(error);
1902
1933
  if (classification === "registration-invalid") throw error;
@@ -1904,11 +1935,11 @@ var DeviceCloudConnectionCoordinator = class {
1904
1935
  this.warn("Device Cloud relay maintenance failed", relayFailure);
1905
1936
  }
1906
1937
  activeComponent = "heartbeat";
1907
- await this.runStep(activeComponent, generation, signal, () => this.options.adapter.heartbeat(configuration, signal));
1938
+ await this.runStep(activeComponent, generation, signal, (fence) => this.options.adapter.heartbeat(configuration, signal, fence));
1908
1939
  let directoryFailure;
1909
1940
  try {
1910
1941
  activeComponent = "directory";
1911
- await this.runStep(activeComponent, generation, signal, () => this.options.adapter.syncDirectory(configuration, signal));
1942
+ await this.runStep(activeComponent, generation, signal, (fence) => this.options.adapter.syncDirectory(configuration, signal, fence));
1912
1943
  } catch (error) {
1913
1944
  const classification = this.classify(error);
1914
1945
  if (classification === "registration-invalid") throw error;
@@ -1948,9 +1979,9 @@ var DeviceCloudConnectionCoordinator = class {
1948
1979
  if (!this.isCurrent(generation, signal)) return;
1949
1980
  await this.setComponent(component, "pending", generation);
1950
1981
  try {
1951
- const result = await operation();
1952
- if (!this.isCurrent(generation, signal)) return;
1953
1982
  const fence = this.createCommitFence(generation, signal);
1983
+ const result = await operation(fence);
1984
+ if (!this.isCurrent(generation, signal)) return;
1954
1985
  await result?.commit?.(fence);
1955
1986
  if (!this.isCurrent(generation, signal)) return;
1956
1987
  await this.setComponent(component, "ready", generation);
@@ -2414,11 +2445,18 @@ function createJsonFrameReader(source, options) {
2414
2445
 
2415
2446
  // src/device-network/deviceOrchestrationTransport.ts
2416
2447
  var DEVICE_ORCHESTRATION_PROTOCOL = "/memeloop/orchestration/2.0.0";
2417
- var DEFAULT_MAX_FRAME_BYTES = 1024 * 1024;
2418
- var REQUEST_IDLE_TIMEOUT_MS = 1e4;
2419
- var REQUEST_TOTAL_TIMEOUT_MS = 3e4;
2420
- var WATCH_IDLE_TIMEOUT_MS = 9e4;
2421
- var WATCH_BOOKMARK_INTERVAL_MS = 3e4;
2448
+ var DEVICE_ORCHESTRATION_FRAME_LIMITS = Object.freeze({
2449
+ maxPayloadBytes: 1024 * 1024,
2450
+ requestIdleTimeoutMs: 1e4,
2451
+ requestTotalTimeoutMs: 3e4,
2452
+ watchIdleTimeoutMs: 9e4,
2453
+ watchBookmarkIntervalMs: 3e4
2454
+ });
2455
+ var DEFAULT_MAX_FRAME_BYTES = DEVICE_ORCHESTRATION_FRAME_LIMITS.maxPayloadBytes;
2456
+ var REQUEST_IDLE_TIMEOUT_MS = DEVICE_ORCHESTRATION_FRAME_LIMITS.requestIdleTimeoutMs;
2457
+ var REQUEST_TOTAL_TIMEOUT_MS = DEVICE_ORCHESTRATION_FRAME_LIMITS.requestTotalTimeoutMs;
2458
+ var WATCH_IDLE_TIMEOUT_MS = DEVICE_ORCHESTRATION_FRAME_LIMITS.watchIdleTimeoutMs;
2459
+ var WATCH_BOOKMARK_INTERVAL_MS = DEVICE_ORCHESTRATION_FRAME_LIMITS.watchBookmarkIntervalMs;
2422
2460
  function orchestrationTransportError(code, message) {
2423
2461
  return new OrchestrationError({
2424
2462
  code,
@@ -2699,6 +2737,13 @@ function createDeviceOrchestrationStreamHandler(options) {
2699
2737
  assertFrameLimit(maxFrameBytes);
2700
2738
  return async ({ remotePeerId, stream, authorize }) => {
2701
2739
  const abort = new AbortController();
2740
+ const abortFromStream = () => {
2741
+ if (!abort.signal.aborted) {
2742
+ abort.abort(stream.signal?.reason ?? new Error("device orchestration stream closed"));
2743
+ }
2744
+ };
2745
+ stream.signal?.addEventListener("abort", abortFromStream, { once: true });
2746
+ if (stream.signal?.aborted) abortFromStream();
2702
2747
  try {
2703
2748
  const envelope = await readSingleRequest(stream, maxFrameBytes);
2704
2749
  if (authorize && !await authorize(envelope.grant)) {
@@ -2722,7 +2767,8 @@ function createDeviceOrchestrationStreamHandler(options) {
2722
2767
  await stream.sink(encodeJsonFrames([response], maxFrameBytes));
2723
2768
  }
2724
2769
  } finally {
2725
- abort.abort();
2770
+ stream.signal?.removeEventListener("abort", abortFromStream);
2771
+ if (!abort.signal.aborted) abort.abort();
2726
2772
  await stream.close().catch(() => void 0);
2727
2773
  }
2728
2774
  };
@@ -3154,6 +3200,23 @@ function sameTrustedDevice(left, right) {
3154
3200
 
3155
3201
  // src/device-network/standardDeviceCloudConnectionAdapter.ts
3156
3202
  var DEFAULT_RELAY_TOKEN_SAFETY_MARGIN_MS = 2 * 6e4;
3203
+ var REGISTRATION_INVALID_ERROR_CODES = /* @__PURE__ */ new Set([
3204
+ "device_not_found",
3205
+ "device_registration_invalid",
3206
+ "device_registration_not_found",
3207
+ "invalid_device_registration",
3208
+ "registration_invalid"
3209
+ ]);
3210
+ var DeviceCloudRegistrationInvalidError = class extends Error {
3211
+ code = "DEVICE_CLOUD_REGISTRATION_INVALID";
3212
+ constructor(cause) {
3213
+ super(
3214
+ "cloud device heartbeat rejected",
3215
+ cause === void 0 ? void 0 : { cause }
3216
+ );
3217
+ this.name = "DeviceCloudRegistrationInvalidError";
3218
+ }
3219
+ };
3157
3220
  var StandardDeviceCloudConnectionAdapter = class {
3158
3221
  constructor(options) {
3159
3222
  this.options = options;
@@ -3173,9 +3236,9 @@ var StandardDeviceCloudConnectionAdapter = class {
3173
3236
  }
3174
3237
  relayRequiredForOnline(_configuration) {
3175
3238
  const addresses = this.options.network.getMultiaddrs();
3176
- return this.options.relayRequiredForOnline?.(addresses) ?? !hasValidDirectCloudDeviceAddress(addresses);
3239
+ return this.options.relayRequiredForOnline?.(addresses) ?? !hasValidDirectCloudDeviceAddress(addresses, this.options.identity.peerId);
3177
3240
  }
3178
- async ensureAuthorizer(client, signal) {
3241
+ async ensureAuthorizer(client, signal, _fence) {
3179
3242
  const publicKey = await client.getConnectionGrantPublicKey(signal);
3180
3243
  return {
3181
3244
  commit: async (fence) => {
@@ -3185,7 +3248,7 @@ var StandardDeviceCloudConnectionAdapter = class {
3185
3248
  }
3186
3249
  };
3187
3250
  }
3188
- async registerDevice(client, signal) {
3251
+ async registerDevice(client, signal, _fence) {
3189
3252
  const nonce = await client.createBindingNonce(signal);
3190
3253
  throwIfAborted3(signal);
3191
3254
  const signature = await this.options.signDeviceBinding({
@@ -3213,27 +3276,28 @@ var StandardDeviceCloudConnectionAdapter = class {
3213
3276
  }
3214
3277
  return void 0;
3215
3278
  }
3216
- async ensureRelay(client, signal) {
3279
+ async ensureRelay(client, signal, fence) {
3217
3280
  if (this.relayReservationClient === client && this.relayReservation && this.relayReservation.expiresAt > this.now() + this.relayTokenSafetyMarginMs) {
3218
3281
  return void 0;
3219
3282
  }
3220
3283
  const relayReservation = await client.createRelayReservation(
3221
3284
  { peerId: this.options.identity.peerId },
3222
- signal
3285
+ signal,
3286
+ fence
3223
3287
  );
3224
3288
  return {
3225
- commit: async (fence) => {
3226
- fence.throwIfStale();
3227
- await this.options.network.configureRelayReservation(relayReservation, signal, fence);
3228
- fence.throwIfStale();
3229
- fence.commitSynchronous(() => {
3289
+ commit: async (fence2) => {
3290
+ fence2.throwIfStale();
3291
+ await this.options.network.configureRelayReservation(relayReservation, signal, fence2);
3292
+ fence2.throwIfStale();
3293
+ fence2.commitSynchronous(() => {
3230
3294
  this.relayReservation = relayReservation;
3231
3295
  this.relayReservationClient = client;
3232
3296
  });
3233
3297
  }
3234
3298
  };
3235
3299
  }
3236
- async heartbeat(client, signal) {
3300
+ async heartbeat(client, signal, _fence) {
3237
3301
  throwIfAborted3(signal);
3238
3302
  const capabilities = await this.options.capabilities();
3239
3303
  throwIfAborted3(signal);
@@ -3251,8 +3315,16 @@ var StandardDeviceCloudConnectionAdapter = class {
3251
3315
  if (!boundedProofSignature(heartbeat.signature)) {
3252
3316
  throw new Error("invalid device heartbeat signature");
3253
3317
  }
3254
- const result = await client.heartbeat(heartbeat, signal);
3255
- if (!result.ok) throw new Error("cloud device heartbeat rejected");
3318
+ let result;
3319
+ try {
3320
+ result = await client.heartbeat(heartbeat, signal);
3321
+ } catch (error) {
3322
+ if (isHeartbeatRegistrationInvalid(error)) {
3323
+ throw new DeviceCloudRegistrationInvalidError(error);
3324
+ }
3325
+ throw error;
3326
+ }
3327
+ if (!result.ok) throw new DeviceCloudRegistrationInvalidError();
3256
3328
  return void 0;
3257
3329
  }
3258
3330
  async dispose(client, signal) {
@@ -3288,7 +3360,7 @@ var StandardDeviceCloudConnectionAdapter = class {
3288
3360
  throw new AggregateError(errors, "device cloud generation cleanup failed");
3289
3361
  }
3290
3362
  }
3291
- async syncDirectory(client, signal) {
3363
+ async syncDirectory(client, signal, _fence) {
3292
3364
  const cloudDevices = await client.listDevices(signal);
3293
3365
  return {
3294
3366
  commit: async (fence) => {
@@ -3316,6 +3388,7 @@ var StandardDeviceCloudConnectionAdapter = class {
3316
3388
  return this.options.syncDevice(client, peerId, signal);
3317
3389
  }
3318
3390
  classifyError(error) {
3391
+ if (error instanceof DeviceCloudRegistrationInvalidError) return "registration-invalid";
3319
3392
  if (error instanceof CloudDeviceFetchError) {
3320
3393
  return error.code === "cloud_request_failed" ? "offline" : "error";
3321
3394
  }
@@ -3326,6 +3399,35 @@ var StandardDeviceCloudConnectionAdapter = class {
3326
3399
  return active.length > 0 ? [...active] : [...this.relayReservation?.relayMultiaddrs ?? []];
3327
3400
  }
3328
3401
  };
3402
+ function isHeartbeatRegistrationInvalid(error) {
3403
+ if (!(error instanceof CloudDeviceFetchError) || error.code !== "cloud_http_error") {
3404
+ return false;
3405
+ }
3406
+ if (error.status === 404) return true;
3407
+ return error.status === 401 && hasExplicitRegistrationInvalidCode(error.responseBody);
3408
+ }
3409
+ function hasExplicitRegistrationInvalidCode(responseBody) {
3410
+ const body = responseBody?.trim();
3411
+ if (!body) return false;
3412
+ let value;
3413
+ try {
3414
+ value = JSON.parse(body);
3415
+ } catch {
3416
+ return REGISTRATION_INVALID_ERROR_CODES.has(normalizeErrorCode(body));
3417
+ }
3418
+ return registrationInvalidCodeFromValue(value);
3419
+ }
3420
+ function registrationInvalidCodeFromValue(value) {
3421
+ if (typeof value === "string") {
3422
+ return REGISTRATION_INVALID_ERROR_CODES.has(normalizeErrorCode(value));
3423
+ }
3424
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
3425
+ const record = value;
3426
+ return registrationInvalidCodeFromValue(record.code) || registrationInvalidCodeFromValue(record.errorCode) || registrationInvalidCodeFromValue(record.error);
3427
+ }
3428
+ function normalizeErrorCode(value) {
3429
+ return value.trim().toLowerCase().replaceAll("-", "_");
3430
+ }
3329
3431
  function toPublicDeviceIdentity(identity) {
3330
3432
  return {
3331
3433
  peerId: identity.peerId,
@@ -3335,21 +3437,42 @@ function toPublicDeviceIdentity(identity) {
3335
3437
  platform: identity.platform
3336
3438
  };
3337
3439
  }
3338
- function hasValidDirectCloudDeviceAddress(addresses) {
3339
- return addresses.some((address) => {
3340
- if (address.includes("/p2p-circuit")) return false;
3341
- const parts = address.split("/");
3342
- const protocolIndex = parts.findIndex(
3343
- (part) => part === "ip4" || part === "ip6" || part === "dns" || part === "dns4" || part === "dns6"
3344
- );
3345
- if (protocolIndex < 0) return false;
3346
- const host = parts[protocolIndex + 1]?.toLowerCase();
3347
- if (!host) return false;
3348
- const protocol = parts[protocolIndex];
3349
- if (protocol === "ip4") return isPublicIpv4(host);
3350
- if (protocol === "ip6") return isPublicIpv6(host);
3351
- return isPlausiblePublicDnsHost(host);
3352
- });
3440
+ function hasValidDirectCloudDeviceAddress(addresses, expectedPeerId) {
3441
+ return addresses.some((address) => isDialableDirectMultiaddr(address, expectedPeerId));
3442
+ }
3443
+ function isDialableDirectMultiaddr(address, expectedPeerId) {
3444
+ if (address.length === 0 || address.length > 4096 || address !== address.trim() || !address.startsWith("/") || address.endsWith("/") || address.includes("//") || address.includes("/p2p-circuit")) return false;
3445
+ const parts = address.split("/").slice(1);
3446
+ if (parts.some((part) => part.length === 0 || containsAsciiControlOrSpace3(part))) return false;
3447
+ const hostProtocol = parts[0];
3448
+ const host = parts[1]?.toLowerCase();
3449
+ if (host === void 0 || hostProtocol !== "ip4" && hostProtocol !== "ip6" && hostProtocol !== "dns" && hostProtocol !== "dns4" && hostProtocol !== "dns6") return false;
3450
+ const publicHost = hostProtocol === "ip4" ? isPublicIpv4(host) : hostProtocol === "ip6" ? isPublicIpv6(host) : isPlausiblePublicDnsHost(host);
3451
+ if (!publicHost) return false;
3452
+ const transport = parts[2];
3453
+ const port = parsePort(parts[3]);
3454
+ if (transport !== "tcp" || port === void 0) return false;
3455
+ let index = 4;
3456
+ if (parts[index] === "ws" || parts[index] === "wss") index += 1;
3457
+ if (parts[index] === "p2p") {
3458
+ const peerId = parts[index + 1];
3459
+ if (!peerId || containsAsciiControlOrSpace3(peerId)) return false;
3460
+ if (expectedPeerId !== void 0 && peerId !== expectedPeerId) return false;
3461
+ index += 2;
3462
+ }
3463
+ return index === parts.length;
3464
+ }
3465
+ function parsePort(value) {
3466
+ if (value === void 0 || !/^\d{1,5}$/u.test(value)) return void 0;
3467
+ const port = Number(value);
3468
+ return port >= 1 && port <= 65535 ? port : void 0;
3469
+ }
3470
+ function containsAsciiControlOrSpace3(value) {
3471
+ for (let index = 0; index < value.length; index += 1) {
3472
+ const code = value.charCodeAt(index);
3473
+ if (code <= 32 || code === 127) return true;
3474
+ }
3475
+ return false;
3353
3476
  }
3354
3477
  function isPublicIpv4(host) {
3355
3478
  const octets = host.split(".").map((part) => Number(part));
@@ -3389,7 +3512,17 @@ function isPlausiblePublicDnsHost(host) {
3389
3512
  const normalized = host.endsWith(".") ? host.slice(0, -1) : host;
3390
3513
  if (isIpv4Syntax(normalized)) return isPublicIpv4(normalized);
3391
3514
  if (normalized.includes(":")) return isPublicIpv6(normalized);
3392
- if (normalized === "localhost" || normalized.endsWith(".localhost") || normalized.endsWith(".local") || normalized.endsWith(".internal")) return false;
3515
+ const specialUseSuffixes = [
3516
+ "example",
3517
+ "home.arpa",
3518
+ "internal",
3519
+ "invalid",
3520
+ "local",
3521
+ "localhost",
3522
+ "onion",
3523
+ "test"
3524
+ ];
3525
+ if (specialUseSuffixes.some((suffix) => normalized === suffix || normalized.endsWith(`.${suffix}`))) return false;
3393
3526
  const labels = normalized.split(".");
3394
3527
  return labels.length > 1 && labels.every(
3395
3528
  (label) => label.length > 0 && label.length <= 63 && /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/u.test(label)
@@ -3467,6 +3600,7 @@ export {
3467
3600
  encodeJsonFrames,
3468
3601
  createJsonFrameReader,
3469
3602
  DEVICE_ORCHESTRATION_PROTOCOL,
3603
+ DEVICE_ORCHESTRATION_FRAME_LIMITS,
3470
3604
  createDeviceOrchestrationTransport,
3471
3605
  createDeviceOrchestrationStreamHandler,
3472
3606
  Libp2pDeviceSyncTransport,
@@ -3488,4 +3622,4 @@ export {
3488
3622
  StandardDeviceCloudConnectionAdapter,
3489
3623
  hasValidDirectCloudDeviceAddress
3490
3624
  };
3491
- //# sourceMappingURL=chunk-DACM5AMS.js.map
3625
+ //# sourceMappingURL=chunk-7W4FMKMO.js.map