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.
- package/dist/{chunk-NVJCRIEK.js → chunk-34B7MUI6.js} +2 -2
- package/dist/{chunk-DACM5AMS.js → chunk-7W4FMKMO.js} +190 -56
- package/dist/chunk-7W4FMKMO.js.map +1 -0
- package/dist/{chunk-OD6U6VAR.js → chunk-GH5RDPLJ.js} +2 -2
- package/dist/{chunk-OD6U6VAR.js.map → chunk-GH5RDPLJ.js.map} +1 -1
- package/dist/device-network/cloudDeviceFetchClient.d.ts +9 -7
- package/dist/device-network/cloudDeviceFetchClient.d.ts.map +1 -1
- package/dist/device-network/deviceCloudConnectionCoordinator.d.ts +5 -5
- package/dist/device-network/deviceCloudConnectionCoordinator.d.ts.map +1 -1
- package/dist/device-network/deviceOrchestrationTransport.d.ts +7 -0
- package/dist/device-network/deviceOrchestrationTransport.d.ts.map +1 -1
- package/dist/device-network/standardDeviceCloudConnectionAdapter.d.ts +16 -8
- package/dist/device-network/standardDeviceCloudConnectionAdapter.d.ts.map +1 -1
- package/dist/device-network/types.d.ts +4 -2
- package/dist/device-network/types.d.ts.map +1 -1
- package/dist/device-network-portable.cjs +190 -55
- package/dist/device-network-portable.cjs.map +1 -1
- package/dist/device-network-portable.js +189 -55
- package/dist/device-network-portable.js.map +1 -1
- package/dist/device-network.cjs +190 -55
- package/dist/device-network.cjs.map +1 -1
- package/dist/device-network.js +4 -2
- package/dist/index.cjs +488 -180
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +302 -127
- package/dist/index.js.map +1 -1
- package/dist/loop-api.cjs +1 -1
- package/dist/loop-api.cjs.map +1 -1
- package/dist/loop-api.js +1 -1
- package/dist/mobile.cjs.map +1 -1
- package/dist/orchestration/externalOrchestrationController.d.ts.map +1 -1
- package/dist/orchestration/workloadExecutionController.d.ts.map +1 -1
- package/dist/plugin/loader.d.ts +1 -1
- package/package.json +2 -1
- package/dist/chunk-DACM5AMS.js.map +0 -1
- /package/dist/{chunk-NVJCRIEK.js.map → chunk-34B7MUI6.js.map} +0 -0
package/dist/device-network.cjs
CHANGED
|
@@ -42,6 +42,7 @@ __export(device_network_entry_exports, {
|
|
|
42
42
|
DEVICE_HEARTBEAT_DEFAULT_MAX_CLOCK_SKEW_MS: () => DEVICE_HEARTBEAT_DEFAULT_MAX_CLOCK_SKEW_MS,
|
|
43
43
|
DEVICE_HEARTBEAT_LIMITS: () => DEVICE_HEARTBEAT_LIMITS,
|
|
44
44
|
DEVICE_HEARTBEAT_SIGNATURE_DOMAIN: () => DEVICE_HEARTBEAT_SIGNATURE_DOMAIN,
|
|
45
|
+
DEVICE_ORCHESTRATION_FRAME_LIMITS: () => DEVICE_ORCHESTRATION_FRAME_LIMITS,
|
|
45
46
|
DEVICE_ORCHESTRATION_PROTOCOL: () => DEVICE_ORCHESTRATION_PROTOCOL,
|
|
46
47
|
DEVICE_PAIRING_INVITE_MAX_CLOCK_SKEW_MS: () => DEVICE_PAIRING_INVITE_MAX_CLOCK_SKEW_MS,
|
|
47
48
|
DEVICE_PAIRING_INVITE_PROTOCOL: () => DEVICE_PAIRING_INVITE_PROTOCOL,
|
|
@@ -4640,14 +4641,28 @@ var MemoryDeviceCloudTokenStorage = class {
|
|
|
4640
4641
|
loadConnectionGrant(input) {
|
|
4641
4642
|
return this.grants.get(connectionGrantCacheKey(input));
|
|
4642
4643
|
}
|
|
4643
|
-
saveConnectionGrant(input, grant) {
|
|
4644
|
-
|
|
4644
|
+
saveConnectionGrant(input, grant, fence) {
|
|
4645
|
+
const write = () => {
|
|
4646
|
+
this.grants.set(connectionGrantCacheKey(input), grant);
|
|
4647
|
+
};
|
|
4648
|
+
if (!fence) {
|
|
4649
|
+
write();
|
|
4650
|
+
return;
|
|
4651
|
+
}
|
|
4652
|
+
if (!fence.commitSynchronous(write)) fence.throwIfStale();
|
|
4645
4653
|
}
|
|
4646
4654
|
loadRelayReservation(peerId) {
|
|
4647
4655
|
return this.relayReservations.get(peerId);
|
|
4648
4656
|
}
|
|
4649
|
-
saveRelayReservation(peerId, token) {
|
|
4650
|
-
|
|
4657
|
+
saveRelayReservation(peerId, token, fence) {
|
|
4658
|
+
const write = () => {
|
|
4659
|
+
this.relayReservations.set(peerId, token);
|
|
4660
|
+
};
|
|
4661
|
+
if (!fence) {
|
|
4662
|
+
write();
|
|
4663
|
+
return;
|
|
4664
|
+
}
|
|
4665
|
+
if (!fence.commitSynchronous(write)) fence.throwIfStale();
|
|
4651
4666
|
}
|
|
4652
4667
|
clear() {
|
|
4653
4668
|
this.grants.clear();
|
|
@@ -4762,13 +4777,16 @@ var CloudDeviceFetchClient = class {
|
|
|
4762
4777
|
}
|
|
4763
4778
|
return { issuer: value.issuer, publicKeyMultibase: value.publicKeyMultibase };
|
|
4764
4779
|
}
|
|
4765
|
-
async createConnectionGrant(input, signal) {
|
|
4780
|
+
async createConnectionGrant(input, signal, fence) {
|
|
4781
|
+
assertFenceSignal(signal, fence);
|
|
4782
|
+
fence?.throwIfStale();
|
|
4766
4783
|
if (!isCanonicalConnectionGrantRequest(input)) {
|
|
4767
4784
|
throw new TypeError("invalid_connection_grant_scope");
|
|
4768
4785
|
}
|
|
4769
4786
|
const cacheInput = normalizedConnectionGrantRequest(input);
|
|
4770
4787
|
const cached = await this.loadCachedGrant(cacheInput);
|
|
4771
4788
|
throwIfAborted(signal);
|
|
4789
|
+
fence?.throwIfStale();
|
|
4772
4790
|
if (isUsableConnectionGrant(cached, cacheInput, this.now() + this.tokenSafetyMarginMs)) {
|
|
4773
4791
|
return cached;
|
|
4774
4792
|
}
|
|
@@ -4777,12 +4795,17 @@ var CloudDeviceFetchClient = class {
|
|
|
4777
4795
|
body: JSON.stringify(input)
|
|
4778
4796
|
}, signal);
|
|
4779
4797
|
if (!isUsableConnectionGrant(value, cacheInput, this.now())) throw invalidShape();
|
|
4780
|
-
|
|
4798
|
+
fence?.throwIfStale();
|
|
4799
|
+
await this.saveCachedGrant(cacheInput, value, fence);
|
|
4800
|
+
fence?.throwIfStale();
|
|
4781
4801
|
return value;
|
|
4782
4802
|
}
|
|
4783
|
-
async createRelayReservation(input, signal) {
|
|
4803
|
+
async createRelayReservation(input, signal, fence) {
|
|
4804
|
+
assertFenceSignal(signal, fence);
|
|
4805
|
+
fence?.throwIfStale();
|
|
4784
4806
|
const cached = await this.loadCachedRelayReservation(input.peerId);
|
|
4785
4807
|
throwIfAborted(signal);
|
|
4808
|
+
fence?.throwIfStale();
|
|
4786
4809
|
if (isUsableRelayReservation(cached, input.peerId, this.now() + this.tokenSafetyMarginMs)) {
|
|
4787
4810
|
return cached;
|
|
4788
4811
|
}
|
|
@@ -4791,7 +4814,9 @@ var CloudDeviceFetchClient = class {
|
|
|
4791
4814
|
body: JSON.stringify(input)
|
|
4792
4815
|
}, signal);
|
|
4793
4816
|
if (!isUsableRelayReservation(value, input.peerId, this.now())) throw invalidShape();
|
|
4794
|
-
|
|
4817
|
+
fence?.throwIfStale();
|
|
4818
|
+
await this.saveCachedRelayReservation(input.peerId, value, fence);
|
|
4819
|
+
fence?.throwIfStale();
|
|
4795
4820
|
return value;
|
|
4796
4821
|
}
|
|
4797
4822
|
async heartbeat(input, signal) {
|
|
@@ -4865,10 +4890,11 @@ var CloudDeviceFetchClient = class {
|
|
|
4865
4890
|
return void 0;
|
|
4866
4891
|
}
|
|
4867
4892
|
}
|
|
4868
|
-
async saveCachedGrant(input, grant) {
|
|
4893
|
+
async saveCachedGrant(input, grant, fence) {
|
|
4869
4894
|
try {
|
|
4870
|
-
await this.tokenStorage.saveConnectionGrant(input, grant);
|
|
4895
|
+
await this.tokenStorage.saveConnectionGrant(input, grant, fence);
|
|
4871
4896
|
} catch (error) {
|
|
4897
|
+
if (fence && !fence.isCurrent()) fence.throwIfStale();
|
|
4872
4898
|
this.options.onTokenStorageError?.("save", error);
|
|
4873
4899
|
}
|
|
4874
4900
|
}
|
|
@@ -4880,14 +4906,20 @@ var CloudDeviceFetchClient = class {
|
|
|
4880
4906
|
return void 0;
|
|
4881
4907
|
}
|
|
4882
4908
|
}
|
|
4883
|
-
async saveCachedRelayReservation(peerId, token) {
|
|
4909
|
+
async saveCachedRelayReservation(peerId, token, fence) {
|
|
4884
4910
|
try {
|
|
4885
|
-
await this.tokenStorage.saveRelayReservation(peerId, token);
|
|
4911
|
+
await this.tokenStorage.saveRelayReservation(peerId, token, fence);
|
|
4886
4912
|
} catch (error) {
|
|
4913
|
+
if (fence && !fence.isCurrent()) fence.throwIfStale();
|
|
4887
4914
|
this.options.onTokenStorageError?.("save", error);
|
|
4888
4915
|
}
|
|
4889
4916
|
}
|
|
4890
4917
|
};
|
|
4918
|
+
function assertFenceSignal(signal, fence) {
|
|
4919
|
+
if (fence && signal && fence.signal !== signal) {
|
|
4920
|
+
throw new TypeError("device_cloud_generation_signal_mismatch");
|
|
4921
|
+
}
|
|
4922
|
+
}
|
|
4891
4923
|
function normalizeCloudDeviceBaseUrl(value) {
|
|
4892
4924
|
const baseUrl = value.trim();
|
|
4893
4925
|
if (!baseUrl || baseUrl.length > CLOUD_URL_MAX_CHARACTERS) throw new Error("invalid_cloud_url");
|
|
@@ -5314,16 +5346,16 @@ var DeviceCloudConnectionCoordinator = class {
|
|
|
5314
5346
|
try {
|
|
5315
5347
|
if (this.snapshotValue.components.authorizer !== "ready") {
|
|
5316
5348
|
activeComponent = "authorizer";
|
|
5317
|
-
await this.runStep(activeComponent, generation, signal, () => this.options.adapter.ensureAuthorizer(configuration, signal));
|
|
5349
|
+
await this.runStep(activeComponent, generation, signal, (fence) => this.options.adapter.ensureAuthorizer(configuration, signal, fence));
|
|
5318
5350
|
}
|
|
5319
5351
|
if (this.snapshotValue.components.registration !== "ready") {
|
|
5320
5352
|
activeComponent = "registration";
|
|
5321
|
-
await this.runStep(activeComponent, generation, signal, () => this.options.adapter.registerDevice(configuration, signal));
|
|
5353
|
+
await this.runStep(activeComponent, generation, signal, (fence) => this.options.adapter.registerDevice(configuration, signal, fence));
|
|
5322
5354
|
}
|
|
5323
5355
|
let relayFailure;
|
|
5324
5356
|
try {
|
|
5325
5357
|
activeComponent = "relay";
|
|
5326
|
-
await this.runStep(activeComponent, generation, signal, () => this.options.adapter.ensureRelay(configuration, signal));
|
|
5358
|
+
await this.runStep(activeComponent, generation, signal, (fence) => this.options.adapter.ensureRelay(configuration, signal, fence));
|
|
5327
5359
|
} catch (error) {
|
|
5328
5360
|
const classification = this.classify(error);
|
|
5329
5361
|
if (classification === "registration-invalid") throw error;
|
|
@@ -5331,11 +5363,11 @@ var DeviceCloudConnectionCoordinator = class {
|
|
|
5331
5363
|
this.warn("Device Cloud relay maintenance failed", relayFailure);
|
|
5332
5364
|
}
|
|
5333
5365
|
activeComponent = "heartbeat";
|
|
5334
|
-
await this.runStep(activeComponent, generation, signal, () => this.options.adapter.heartbeat(configuration, signal));
|
|
5366
|
+
await this.runStep(activeComponent, generation, signal, (fence) => this.options.adapter.heartbeat(configuration, signal, fence));
|
|
5335
5367
|
let directoryFailure;
|
|
5336
5368
|
try {
|
|
5337
5369
|
activeComponent = "directory";
|
|
5338
|
-
await this.runStep(activeComponent, generation, signal, () => this.options.adapter.syncDirectory(configuration, signal));
|
|
5370
|
+
await this.runStep(activeComponent, generation, signal, (fence) => this.options.adapter.syncDirectory(configuration, signal, fence));
|
|
5339
5371
|
} catch (error) {
|
|
5340
5372
|
const classification = this.classify(error);
|
|
5341
5373
|
if (classification === "registration-invalid") throw error;
|
|
@@ -5375,9 +5407,9 @@ var DeviceCloudConnectionCoordinator = class {
|
|
|
5375
5407
|
if (!this.isCurrent(generation, signal)) return;
|
|
5376
5408
|
await this.setComponent(component, "pending", generation);
|
|
5377
5409
|
try {
|
|
5378
|
-
const result = await operation();
|
|
5379
|
-
if (!this.isCurrent(generation, signal)) return;
|
|
5380
5410
|
const fence = this.createCommitFence(generation, signal);
|
|
5411
|
+
const result = await operation(fence);
|
|
5412
|
+
if (!this.isCurrent(generation, signal)) return;
|
|
5381
5413
|
await result?.commit?.(fence);
|
|
5382
5414
|
if (!this.isCurrent(generation, signal)) return;
|
|
5383
5415
|
await this.setComponent(component, "ready", generation);
|
|
@@ -6105,11 +6137,18 @@ function createJsonFrameReader(source, options) {
|
|
|
6105
6137
|
|
|
6106
6138
|
// src/device-network/deviceOrchestrationTransport.ts
|
|
6107
6139
|
var DEVICE_ORCHESTRATION_PROTOCOL = "/memeloop/orchestration/2.0.0";
|
|
6108
|
-
var
|
|
6109
|
-
|
|
6110
|
-
|
|
6111
|
-
|
|
6112
|
-
|
|
6140
|
+
var DEVICE_ORCHESTRATION_FRAME_LIMITS = Object.freeze({
|
|
6141
|
+
maxPayloadBytes: 1024 * 1024,
|
|
6142
|
+
requestIdleTimeoutMs: 1e4,
|
|
6143
|
+
requestTotalTimeoutMs: 3e4,
|
|
6144
|
+
watchIdleTimeoutMs: 9e4,
|
|
6145
|
+
watchBookmarkIntervalMs: 3e4
|
|
6146
|
+
});
|
|
6147
|
+
var DEFAULT_MAX_FRAME_BYTES = DEVICE_ORCHESTRATION_FRAME_LIMITS.maxPayloadBytes;
|
|
6148
|
+
var REQUEST_IDLE_TIMEOUT_MS = DEVICE_ORCHESTRATION_FRAME_LIMITS.requestIdleTimeoutMs;
|
|
6149
|
+
var REQUEST_TOTAL_TIMEOUT_MS = DEVICE_ORCHESTRATION_FRAME_LIMITS.requestTotalTimeoutMs;
|
|
6150
|
+
var WATCH_IDLE_TIMEOUT_MS = DEVICE_ORCHESTRATION_FRAME_LIMITS.watchIdleTimeoutMs;
|
|
6151
|
+
var WATCH_BOOKMARK_INTERVAL_MS = DEVICE_ORCHESTRATION_FRAME_LIMITS.watchBookmarkIntervalMs;
|
|
6113
6152
|
function orchestrationTransportError(code, message) {
|
|
6114
6153
|
return new OrchestrationError({
|
|
6115
6154
|
code,
|
|
@@ -6390,6 +6429,13 @@ function createDeviceOrchestrationStreamHandler(options) {
|
|
|
6390
6429
|
assertFrameLimit(maxFrameBytes);
|
|
6391
6430
|
return async ({ remotePeerId, stream, authorize }) => {
|
|
6392
6431
|
const abort = new AbortController();
|
|
6432
|
+
const abortFromStream = () => {
|
|
6433
|
+
if (!abort.signal.aborted) {
|
|
6434
|
+
abort.abort(stream.signal?.reason ?? new Error("device orchestration stream closed"));
|
|
6435
|
+
}
|
|
6436
|
+
};
|
|
6437
|
+
stream.signal?.addEventListener("abort", abortFromStream, { once: true });
|
|
6438
|
+
if (stream.signal?.aborted) abortFromStream();
|
|
6393
6439
|
try {
|
|
6394
6440
|
const envelope = await readSingleRequest(stream, maxFrameBytes);
|
|
6395
6441
|
if (authorize && !await authorize(envelope.grant)) {
|
|
@@ -6413,7 +6459,8 @@ function createDeviceOrchestrationStreamHandler(options) {
|
|
|
6413
6459
|
await stream.sink(encodeJsonFrames([response], maxFrameBytes));
|
|
6414
6460
|
}
|
|
6415
6461
|
} finally {
|
|
6416
|
-
|
|
6462
|
+
stream.signal?.removeEventListener("abort", abortFromStream);
|
|
6463
|
+
if (!abort.signal.aborted) abort.abort();
|
|
6417
6464
|
await stream.close().catch(() => void 0);
|
|
6418
6465
|
}
|
|
6419
6466
|
};
|
|
@@ -6948,6 +6995,23 @@ function sameTrustedDevice(left, right) {
|
|
|
6948
6995
|
|
|
6949
6996
|
// src/device-network/standardDeviceCloudConnectionAdapter.ts
|
|
6950
6997
|
var DEFAULT_RELAY_TOKEN_SAFETY_MARGIN_MS = 2 * 6e4;
|
|
6998
|
+
var REGISTRATION_INVALID_ERROR_CODES = /* @__PURE__ */ new Set([
|
|
6999
|
+
"device_not_found",
|
|
7000
|
+
"device_registration_invalid",
|
|
7001
|
+
"device_registration_not_found",
|
|
7002
|
+
"invalid_device_registration",
|
|
7003
|
+
"registration_invalid"
|
|
7004
|
+
]);
|
|
7005
|
+
var DeviceCloudRegistrationInvalidError = class extends Error {
|
|
7006
|
+
code = "DEVICE_CLOUD_REGISTRATION_INVALID";
|
|
7007
|
+
constructor(cause) {
|
|
7008
|
+
super(
|
|
7009
|
+
"cloud device heartbeat rejected",
|
|
7010
|
+
cause === void 0 ? void 0 : { cause }
|
|
7011
|
+
);
|
|
7012
|
+
this.name = "DeviceCloudRegistrationInvalidError";
|
|
7013
|
+
}
|
|
7014
|
+
};
|
|
6951
7015
|
var StandardDeviceCloudConnectionAdapter = class {
|
|
6952
7016
|
constructor(options) {
|
|
6953
7017
|
this.options = options;
|
|
@@ -6967,9 +7031,9 @@ var StandardDeviceCloudConnectionAdapter = class {
|
|
|
6967
7031
|
}
|
|
6968
7032
|
relayRequiredForOnline(_configuration) {
|
|
6969
7033
|
const addresses = this.options.network.getMultiaddrs();
|
|
6970
|
-
return this.options.relayRequiredForOnline?.(addresses) ?? !hasValidDirectCloudDeviceAddress(addresses);
|
|
7034
|
+
return this.options.relayRequiredForOnline?.(addresses) ?? !hasValidDirectCloudDeviceAddress(addresses, this.options.identity.peerId);
|
|
6971
7035
|
}
|
|
6972
|
-
async ensureAuthorizer(client, signal) {
|
|
7036
|
+
async ensureAuthorizer(client, signal, _fence) {
|
|
6973
7037
|
const publicKey = await client.getConnectionGrantPublicKey(signal);
|
|
6974
7038
|
return {
|
|
6975
7039
|
commit: async (fence) => {
|
|
@@ -6979,7 +7043,7 @@ var StandardDeviceCloudConnectionAdapter = class {
|
|
|
6979
7043
|
}
|
|
6980
7044
|
};
|
|
6981
7045
|
}
|
|
6982
|
-
async registerDevice(client, signal) {
|
|
7046
|
+
async registerDevice(client, signal, _fence) {
|
|
6983
7047
|
const nonce = await client.createBindingNonce(signal);
|
|
6984
7048
|
throwIfAborted3(signal);
|
|
6985
7049
|
const signature = await this.options.signDeviceBinding({
|
|
@@ -7007,27 +7071,28 @@ var StandardDeviceCloudConnectionAdapter = class {
|
|
|
7007
7071
|
}
|
|
7008
7072
|
return void 0;
|
|
7009
7073
|
}
|
|
7010
|
-
async ensureRelay(client, signal) {
|
|
7074
|
+
async ensureRelay(client, signal, fence) {
|
|
7011
7075
|
if (this.relayReservationClient === client && this.relayReservation && this.relayReservation.expiresAt > this.now() + this.relayTokenSafetyMarginMs) {
|
|
7012
7076
|
return void 0;
|
|
7013
7077
|
}
|
|
7014
7078
|
const relayReservation = await client.createRelayReservation(
|
|
7015
7079
|
{ peerId: this.options.identity.peerId },
|
|
7016
|
-
signal
|
|
7080
|
+
signal,
|
|
7081
|
+
fence
|
|
7017
7082
|
);
|
|
7018
7083
|
return {
|
|
7019
|
-
commit: async (
|
|
7020
|
-
|
|
7021
|
-
await this.options.network.configureRelayReservation(relayReservation, signal,
|
|
7022
|
-
|
|
7023
|
-
|
|
7084
|
+
commit: async (fence2) => {
|
|
7085
|
+
fence2.throwIfStale();
|
|
7086
|
+
await this.options.network.configureRelayReservation(relayReservation, signal, fence2);
|
|
7087
|
+
fence2.throwIfStale();
|
|
7088
|
+
fence2.commitSynchronous(() => {
|
|
7024
7089
|
this.relayReservation = relayReservation;
|
|
7025
7090
|
this.relayReservationClient = client;
|
|
7026
7091
|
});
|
|
7027
7092
|
}
|
|
7028
7093
|
};
|
|
7029
7094
|
}
|
|
7030
|
-
async heartbeat(client, signal) {
|
|
7095
|
+
async heartbeat(client, signal, _fence) {
|
|
7031
7096
|
throwIfAborted3(signal);
|
|
7032
7097
|
const capabilities = await this.options.capabilities();
|
|
7033
7098
|
throwIfAborted3(signal);
|
|
@@ -7045,8 +7110,16 @@ var StandardDeviceCloudConnectionAdapter = class {
|
|
|
7045
7110
|
if (!boundedProofSignature(heartbeat.signature)) {
|
|
7046
7111
|
throw new Error("invalid device heartbeat signature");
|
|
7047
7112
|
}
|
|
7048
|
-
|
|
7049
|
-
|
|
7113
|
+
let result;
|
|
7114
|
+
try {
|
|
7115
|
+
result = await client.heartbeat(heartbeat, signal);
|
|
7116
|
+
} catch (error) {
|
|
7117
|
+
if (isHeartbeatRegistrationInvalid(error)) {
|
|
7118
|
+
throw new DeviceCloudRegistrationInvalidError(error);
|
|
7119
|
+
}
|
|
7120
|
+
throw error;
|
|
7121
|
+
}
|
|
7122
|
+
if (!result.ok) throw new DeviceCloudRegistrationInvalidError();
|
|
7050
7123
|
return void 0;
|
|
7051
7124
|
}
|
|
7052
7125
|
async dispose(client, signal) {
|
|
@@ -7082,7 +7155,7 @@ var StandardDeviceCloudConnectionAdapter = class {
|
|
|
7082
7155
|
throw new AggregateError(errors, "device cloud generation cleanup failed");
|
|
7083
7156
|
}
|
|
7084
7157
|
}
|
|
7085
|
-
async syncDirectory(client, signal) {
|
|
7158
|
+
async syncDirectory(client, signal, _fence) {
|
|
7086
7159
|
const cloudDevices = await client.listDevices(signal);
|
|
7087
7160
|
return {
|
|
7088
7161
|
commit: async (fence) => {
|
|
@@ -7110,6 +7183,7 @@ var StandardDeviceCloudConnectionAdapter = class {
|
|
|
7110
7183
|
return this.options.syncDevice(client, peerId, signal);
|
|
7111
7184
|
}
|
|
7112
7185
|
classifyError(error) {
|
|
7186
|
+
if (error instanceof DeviceCloudRegistrationInvalidError) return "registration-invalid";
|
|
7113
7187
|
if (error instanceof CloudDeviceFetchError) {
|
|
7114
7188
|
return error.code === "cloud_request_failed" ? "offline" : "error";
|
|
7115
7189
|
}
|
|
@@ -7120,6 +7194,35 @@ var StandardDeviceCloudConnectionAdapter = class {
|
|
|
7120
7194
|
return active.length > 0 ? [...active] : [...this.relayReservation?.relayMultiaddrs ?? []];
|
|
7121
7195
|
}
|
|
7122
7196
|
};
|
|
7197
|
+
function isHeartbeatRegistrationInvalid(error) {
|
|
7198
|
+
if (!(error instanceof CloudDeviceFetchError) || error.code !== "cloud_http_error") {
|
|
7199
|
+
return false;
|
|
7200
|
+
}
|
|
7201
|
+
if (error.status === 404) return true;
|
|
7202
|
+
return error.status === 401 && hasExplicitRegistrationInvalidCode(error.responseBody);
|
|
7203
|
+
}
|
|
7204
|
+
function hasExplicitRegistrationInvalidCode(responseBody) {
|
|
7205
|
+
const body = responseBody?.trim();
|
|
7206
|
+
if (!body) return false;
|
|
7207
|
+
let value;
|
|
7208
|
+
try {
|
|
7209
|
+
value = JSON.parse(body);
|
|
7210
|
+
} catch {
|
|
7211
|
+
return REGISTRATION_INVALID_ERROR_CODES.has(normalizeErrorCode(body));
|
|
7212
|
+
}
|
|
7213
|
+
return registrationInvalidCodeFromValue(value);
|
|
7214
|
+
}
|
|
7215
|
+
function registrationInvalidCodeFromValue(value) {
|
|
7216
|
+
if (typeof value === "string") {
|
|
7217
|
+
return REGISTRATION_INVALID_ERROR_CODES.has(normalizeErrorCode(value));
|
|
7218
|
+
}
|
|
7219
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
|
|
7220
|
+
const record = value;
|
|
7221
|
+
return registrationInvalidCodeFromValue(record.code) || registrationInvalidCodeFromValue(record.errorCode) || registrationInvalidCodeFromValue(record.error);
|
|
7222
|
+
}
|
|
7223
|
+
function normalizeErrorCode(value) {
|
|
7224
|
+
return value.trim().toLowerCase().replaceAll("-", "_");
|
|
7225
|
+
}
|
|
7123
7226
|
function toPublicDeviceIdentity(identity) {
|
|
7124
7227
|
return {
|
|
7125
7228
|
peerId: identity.peerId,
|
|
@@ -7129,21 +7232,42 @@ function toPublicDeviceIdentity(identity) {
|
|
|
7129
7232
|
platform: identity.platform
|
|
7130
7233
|
};
|
|
7131
7234
|
}
|
|
7132
|
-
function hasValidDirectCloudDeviceAddress(addresses) {
|
|
7133
|
-
return addresses.some((address) =>
|
|
7134
|
-
|
|
7135
|
-
|
|
7136
|
-
|
|
7137
|
-
|
|
7138
|
-
|
|
7139
|
-
|
|
7140
|
-
|
|
7141
|
-
|
|
7142
|
-
|
|
7143
|
-
|
|
7144
|
-
|
|
7145
|
-
|
|
7146
|
-
|
|
7235
|
+
function hasValidDirectCloudDeviceAddress(addresses, expectedPeerId) {
|
|
7236
|
+
return addresses.some((address) => isDialableDirectMultiaddr(address, expectedPeerId));
|
|
7237
|
+
}
|
|
7238
|
+
function isDialableDirectMultiaddr(address, expectedPeerId) {
|
|
7239
|
+
if (address.length === 0 || address.length > 4096 || address !== address.trim() || !address.startsWith("/") || address.endsWith("/") || address.includes("//") || address.includes("/p2p-circuit")) return false;
|
|
7240
|
+
const parts = address.split("/").slice(1);
|
|
7241
|
+
if (parts.some((part) => part.length === 0 || containsAsciiControlOrSpace3(part))) return false;
|
|
7242
|
+
const hostProtocol = parts[0];
|
|
7243
|
+
const host = parts[1]?.toLowerCase();
|
|
7244
|
+
if (host === void 0 || hostProtocol !== "ip4" && hostProtocol !== "ip6" && hostProtocol !== "dns" && hostProtocol !== "dns4" && hostProtocol !== "dns6") return false;
|
|
7245
|
+
const publicHost = hostProtocol === "ip4" ? isPublicIpv4(host) : hostProtocol === "ip6" ? isPublicIpv6(host) : isPlausiblePublicDnsHost(host);
|
|
7246
|
+
if (!publicHost) return false;
|
|
7247
|
+
const transport = parts[2];
|
|
7248
|
+
const port = parsePort(parts[3]);
|
|
7249
|
+
if (transport !== "tcp" || port === void 0) return false;
|
|
7250
|
+
let index = 4;
|
|
7251
|
+
if (parts[index] === "ws" || parts[index] === "wss") index += 1;
|
|
7252
|
+
if (parts[index] === "p2p") {
|
|
7253
|
+
const peerId = parts[index + 1];
|
|
7254
|
+
if (!peerId || containsAsciiControlOrSpace3(peerId)) return false;
|
|
7255
|
+
if (expectedPeerId !== void 0 && peerId !== expectedPeerId) return false;
|
|
7256
|
+
index += 2;
|
|
7257
|
+
}
|
|
7258
|
+
return index === parts.length;
|
|
7259
|
+
}
|
|
7260
|
+
function parsePort(value) {
|
|
7261
|
+
if (value === void 0 || !/^\d{1,5}$/u.test(value)) return void 0;
|
|
7262
|
+
const port = Number(value);
|
|
7263
|
+
return port >= 1 && port <= 65535 ? port : void 0;
|
|
7264
|
+
}
|
|
7265
|
+
function containsAsciiControlOrSpace3(value) {
|
|
7266
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
7267
|
+
const code = value.charCodeAt(index);
|
|
7268
|
+
if (code <= 32 || code === 127) return true;
|
|
7269
|
+
}
|
|
7270
|
+
return false;
|
|
7147
7271
|
}
|
|
7148
7272
|
function isPublicIpv4(host) {
|
|
7149
7273
|
const octets = host.split(".").map((part) => Number(part));
|
|
@@ -7183,7 +7307,17 @@ function isPlausiblePublicDnsHost(host) {
|
|
|
7183
7307
|
const normalized = host.endsWith(".") ? host.slice(0, -1) : host;
|
|
7184
7308
|
if (isIpv4Syntax(normalized)) return isPublicIpv4(normalized);
|
|
7185
7309
|
if (normalized.includes(":")) return isPublicIpv6(normalized);
|
|
7186
|
-
|
|
7310
|
+
const specialUseSuffixes = [
|
|
7311
|
+
"example",
|
|
7312
|
+
"home.arpa",
|
|
7313
|
+
"internal",
|
|
7314
|
+
"invalid",
|
|
7315
|
+
"local",
|
|
7316
|
+
"localhost",
|
|
7317
|
+
"onion",
|
|
7318
|
+
"test"
|
|
7319
|
+
];
|
|
7320
|
+
if (specialUseSuffixes.some((suffix) => normalized === suffix || normalized.endsWith(`.${suffix}`))) return false;
|
|
7187
7321
|
const labels = normalized.split(".");
|
|
7188
7322
|
return labels.length > 1 && labels.every(
|
|
7189
7323
|
(label) => label.length > 0 && label.length <= 63 && /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/u.test(label)
|
|
@@ -8345,6 +8479,7 @@ function sameTrustedDevice2(left, right) {
|
|
|
8345
8479
|
DEVICE_HEARTBEAT_DEFAULT_MAX_CLOCK_SKEW_MS,
|
|
8346
8480
|
DEVICE_HEARTBEAT_LIMITS,
|
|
8347
8481
|
DEVICE_HEARTBEAT_SIGNATURE_DOMAIN,
|
|
8482
|
+
DEVICE_ORCHESTRATION_FRAME_LIMITS,
|
|
8348
8483
|
DEVICE_ORCHESTRATION_PROTOCOL,
|
|
8349
8484
|
DEVICE_PAIRING_INVITE_MAX_CLOCK_SKEW_MS,
|
|
8350
8485
|
DEVICE_PAIRING_INVITE_PROTOCOL,
|