@tinycloud/sdk-services 2.7.0-beta.3 → 2.7.0-beta.4
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/BaseService-BwBU5CQ4.d.cts +158 -0
- package/dist/BaseService-CnPTKR5G.d.ts +158 -0
- package/dist/encryption/index.cjs +46 -6
- package/dist/encryption/index.cjs.map +1 -1
- package/dist/encryption/index.d.cts +9 -1
- package/dist/encryption/index.d.ts +9 -1
- package/dist/encryption/index.js +45 -6
- package/dist/encryption/index.js.map +1 -1
- package/dist/index.cjs +299 -21
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +58 -9
- package/dist/index.d.ts +58 -9
- package/dist/index.js +293 -18
- package/dist/index.js.map +1 -1
- package/dist/internal/decrypt-transport-response-error.cjs +38 -0
- package/dist/internal/decrypt-transport-response-error.cjs.map +1 -0
- package/dist/internal/decrypt-transport-response-error.d.cts +10 -0
- package/dist/internal/decrypt-transport-response-error.d.ts +10 -0
- package/dist/internal/decrypt-transport-response-error.js +13 -0
- package/dist/internal/decrypt-transport-response-error.js.map +1 -0
- package/dist/kv/index.cjs +46 -4
- package/dist/kv/index.cjs.map +1 -1
- package/dist/kv/index.d.cts +2 -1
- package/dist/kv/index.d.ts +2 -1
- package/dist/kv/index.js +46 -4
- package/dist/kv/index.js.map +1 -1
- package/dist/sql/index.cjs +6 -2
- package/dist/sql/index.cjs.map +1 -1
- package/dist/sql/index.d.cts +2 -1
- package/dist/sql/index.d.ts +2 -1
- package/dist/sql/index.js +6 -2
- package/dist/sql/index.js.map +1 -1
- package/dist/{BaseService-C-EsEeGo.d.cts → types-DAY1O1kW.d.cts} +12 -156
- package/dist/{BaseService-C-EsEeGo.d.ts → types-DAY1O1kW.d.ts} +12 -156
- package/package.json +11 -3
package/dist/index.js
CHANGED
|
@@ -67,6 +67,63 @@ function serviceError(code, message, service, options) {
|
|
|
67
67
|
};
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
+
// src/diagnostics.ts
|
|
71
|
+
var REDACTED = "[REDACTED]";
|
|
72
|
+
var SAFE_NUMBER_FIELDS = /* @__PURE__ */ new Set([
|
|
73
|
+
"duration",
|
|
74
|
+
"durationMs",
|
|
75
|
+
"endedAt",
|
|
76
|
+
"startedAt",
|
|
77
|
+
"status",
|
|
78
|
+
"timestamp"
|
|
79
|
+
]);
|
|
80
|
+
var SAFE_BOOLEAN_FIELDS = /* @__PURE__ */ new Set(["authenticated", "ok", "persisted"]);
|
|
81
|
+
function finiteNumber(value) {
|
|
82
|
+
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
83
|
+
}
|
|
84
|
+
function isBinaryData(value) {
|
|
85
|
+
try {
|
|
86
|
+
return Array.isArray(value) || ArrayBuffer.isView(value) || value instanceof ArrayBuffer;
|
|
87
|
+
} catch {
|
|
88
|
+
return true;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
function read(value, key) {
|
|
92
|
+
try {
|
|
93
|
+
return value[key];
|
|
94
|
+
} catch {
|
|
95
|
+
return REDACTED;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
function projectDiagnosticError(error) {
|
|
99
|
+
if (typeof error !== "object" || error === null) return {};
|
|
100
|
+
const status = finiteNumber(read(error, "status"));
|
|
101
|
+
return status !== void 0 && status >= 100 && status <= 599 ? { status } : {};
|
|
102
|
+
}
|
|
103
|
+
function projectDiagnosticData(value) {
|
|
104
|
+
if (value === null || value === void 0) return value;
|
|
105
|
+
if (typeof value !== "object") return REDACTED;
|
|
106
|
+
try {
|
|
107
|
+
if (isBinaryData(value)) return REDACTED;
|
|
108
|
+
const projected = {};
|
|
109
|
+
for (const key of SAFE_NUMBER_FIELDS) {
|
|
110
|
+
const number = finiteNumber(read(value, key));
|
|
111
|
+
if (number !== void 0) projected[key] = number;
|
|
112
|
+
}
|
|
113
|
+
for (const key of SAFE_BOOLEAN_FIELDS) {
|
|
114
|
+
const boolean = read(value, key);
|
|
115
|
+
if (typeof boolean === "boolean") projected[key] = boolean;
|
|
116
|
+
}
|
|
117
|
+
const url = read(value, "url");
|
|
118
|
+
if (url !== void 0) projected.url = REDACTED;
|
|
119
|
+
const error = read(value, "error");
|
|
120
|
+
if (error !== void 0) projected.error = projectDiagnosticError(error);
|
|
121
|
+
return projected;
|
|
122
|
+
} catch {
|
|
123
|
+
return REDACTED;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
70
127
|
// src/debug.ts
|
|
71
128
|
var DEBUG_FLAG = "TinyCloud_debug";
|
|
72
129
|
var MAX_EVENTS = 1e3;
|
|
@@ -225,6 +282,8 @@ var TinyCloudDebugLogger = class {
|
|
|
225
282
|
record(event) {
|
|
226
283
|
const debugEvent = {
|
|
227
284
|
...event,
|
|
285
|
+
...event.data === void 0 ? {} : { data: projectDiagnosticData(event.data) },
|
|
286
|
+
...event.message === void 0 ? {} : { message: "[REDACTED]" },
|
|
228
287
|
sequence: ++this.sequence
|
|
229
288
|
};
|
|
230
289
|
this.events.push(debugEvent);
|
|
@@ -504,6 +563,7 @@ var ServiceContext = class {
|
|
|
504
563
|
this._services = /* @__PURE__ */ new Map();
|
|
505
564
|
this._eventHandlers = /* @__PURE__ */ new Map();
|
|
506
565
|
this._abortController = new AbortController();
|
|
566
|
+
this._retired = false;
|
|
507
567
|
this._invoke = this.wrapInvoke(config.invoke);
|
|
508
568
|
this._invokeAny = config.invokeAny ? this.wrapInvokeAny(config.invokeAny) : void 0;
|
|
509
569
|
this._fetch = this.wrapFetch(config.fetch ?? globalThis.fetch.bind(globalThis));
|
|
@@ -523,13 +583,13 @@ var ServiceContext = class {
|
|
|
523
583
|
* Get the current session.
|
|
524
584
|
*/
|
|
525
585
|
get session() {
|
|
526
|
-
return this._session;
|
|
586
|
+
return this._retired ? null : this._session;
|
|
527
587
|
}
|
|
528
588
|
/**
|
|
529
589
|
* Check if the context has an authenticated session.
|
|
530
590
|
*/
|
|
531
591
|
get isAuthenticated() {
|
|
532
|
-
return this._session !== null;
|
|
592
|
+
return !this._retired && this._session !== null;
|
|
533
593
|
}
|
|
534
594
|
/**
|
|
535
595
|
* Update the session and notify all registered services.
|
|
@@ -537,6 +597,7 @@ var ServiceContext = class {
|
|
|
537
597
|
* @param session - New session or null to clear
|
|
538
598
|
*/
|
|
539
599
|
setSession(session) {
|
|
600
|
+
this.assertActive();
|
|
540
601
|
this._session = session;
|
|
541
602
|
this.emit("session.changed", { authenticated: session !== null });
|
|
542
603
|
for (const service of this._services.values()) {
|
|
@@ -550,24 +611,28 @@ var ServiceContext = class {
|
|
|
550
611
|
* Get the invoke function for WASM operations.
|
|
551
612
|
*/
|
|
552
613
|
get invoke() {
|
|
614
|
+
this.assertActive();
|
|
553
615
|
return this._invoke;
|
|
554
616
|
}
|
|
555
617
|
/**
|
|
556
618
|
* Get the multi-resource invoke function when available.
|
|
557
619
|
*/
|
|
558
620
|
get invokeAny() {
|
|
621
|
+
this.assertActive();
|
|
559
622
|
return this._invokeAny;
|
|
560
623
|
}
|
|
561
624
|
/**
|
|
562
625
|
* Get the fetch function for HTTP requests.
|
|
563
626
|
*/
|
|
564
627
|
get fetch() {
|
|
628
|
+
this.assertActive();
|
|
565
629
|
return this._fetch;
|
|
566
630
|
}
|
|
567
631
|
/**
|
|
568
632
|
* Get the list of TinyCloud host URLs.
|
|
569
633
|
*/
|
|
570
634
|
get hosts() {
|
|
635
|
+
this.assertActive();
|
|
571
636
|
return this._hosts;
|
|
572
637
|
}
|
|
573
638
|
// ============================================================
|
|
@@ -612,7 +677,7 @@ var ServiceContext = class {
|
|
|
612
677
|
tinyCloudDebugLogger.log(event, data);
|
|
613
678
|
if (this._telemetryEnabled && this._telemetryHandler) {
|
|
614
679
|
try {
|
|
615
|
-
this._telemetryHandler(event, data);
|
|
680
|
+
this._telemetryHandler(event, projectDiagnosticData(data));
|
|
616
681
|
} catch (error) {
|
|
617
682
|
console.error(`Error in telemetry handler for "${event}":`, error);
|
|
618
683
|
}
|
|
@@ -671,21 +736,45 @@ var ServiceContext = class {
|
|
|
671
736
|
get abortSignal() {
|
|
672
737
|
return this._abortController.signal;
|
|
673
738
|
}
|
|
739
|
+
/**
|
|
740
|
+
* Permanently retire this graph after its owner installs a replacement.
|
|
741
|
+
* Unlike `abort()`, retirement never creates a fresh controller, so captured
|
|
742
|
+
* services cannot resume calls under a superseded session.
|
|
743
|
+
*/
|
|
744
|
+
retire() {
|
|
745
|
+
if (this._retired) return;
|
|
746
|
+
this._retired = true;
|
|
747
|
+
this._session = null;
|
|
748
|
+
this._abortController.abort();
|
|
749
|
+
for (const service of this._services.values()) {
|
|
750
|
+
try {
|
|
751
|
+
service.onSignOut();
|
|
752
|
+
} catch (error) {
|
|
753
|
+
console.error("Error retiring service:", error);
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
}
|
|
674
757
|
/**
|
|
675
758
|
* Abort all pending operations and notify services.
|
|
676
759
|
* Creates a new AbortController for future operations.
|
|
677
760
|
*/
|
|
678
761
|
abort() {
|
|
762
|
+
if (this._retired) return;
|
|
679
763
|
this._abortController.abort();
|
|
680
764
|
this._abortController = new AbortController();
|
|
681
765
|
for (const service of this._services.values()) {
|
|
682
|
-
|
|
766
|
+
try {
|
|
767
|
+
service.onSignOut();
|
|
768
|
+
} catch (error) {
|
|
769
|
+
console.error("Error signing out service:", error);
|
|
770
|
+
}
|
|
683
771
|
}
|
|
684
772
|
}
|
|
685
773
|
/**
|
|
686
774
|
* Sign out - abort operations and clear session.
|
|
687
775
|
*/
|
|
688
776
|
signOut() {
|
|
777
|
+
if (this._retired) return;
|
|
689
778
|
this.abort();
|
|
690
779
|
this.setSession(null);
|
|
691
780
|
this.emit("session.expired", {});
|
|
@@ -701,6 +790,7 @@ var ServiceContext = class {
|
|
|
701
790
|
}
|
|
702
791
|
wrapInvoke(invoke) {
|
|
703
792
|
return (session, service, path, action, facts) => {
|
|
793
|
+
this.assertActive();
|
|
704
794
|
if (!tinyCloudDebugLogger.isEnabled()) {
|
|
705
795
|
return invoke(session, service, path, action, facts);
|
|
706
796
|
}
|
|
@@ -720,8 +810,14 @@ var ServiceContext = class {
|
|
|
720
810
|
}
|
|
721
811
|
};
|
|
722
812
|
}
|
|
813
|
+
assertActive() {
|
|
814
|
+
if (this._retired) {
|
|
815
|
+
throw new Error("Service graph has been retired by session replacement.");
|
|
816
|
+
}
|
|
817
|
+
}
|
|
723
818
|
wrapInvokeAny(invokeAny) {
|
|
724
819
|
return (session, entries, facts) => {
|
|
820
|
+
this.assertActive();
|
|
725
821
|
if (!tinyCloudDebugLogger.isEnabled()) {
|
|
726
822
|
return invokeAny(session, entries, facts);
|
|
727
823
|
}
|
|
@@ -741,20 +837,25 @@ var ServiceContext = class {
|
|
|
741
837
|
}
|
|
742
838
|
wrapFetch(fetchFn) {
|
|
743
839
|
return async (url, init) => {
|
|
840
|
+
this.assertActive();
|
|
841
|
+
const request = {
|
|
842
|
+
...init,
|
|
843
|
+
signal: this.combineSignals(init?.signal)
|
|
844
|
+
};
|
|
744
845
|
if (!tinyCloudDebugLogger.isEnabled()) {
|
|
745
|
-
return fetchFn(url,
|
|
846
|
+
return fetchFn(url, request);
|
|
746
847
|
}
|
|
747
848
|
const timer = tinyCloudDebugLogger.startTimer("sdk.fetch", {
|
|
748
849
|
url,
|
|
749
|
-
method:
|
|
750
|
-
init
|
|
850
|
+
method: request.method ?? "GET",
|
|
851
|
+
init: request
|
|
751
852
|
});
|
|
752
853
|
try {
|
|
753
|
-
const response = await fetchFn(url,
|
|
854
|
+
const response = await fetchFn(url, request);
|
|
754
855
|
timer.stop({
|
|
755
856
|
ok: response.ok,
|
|
756
857
|
url,
|
|
757
|
-
method:
|
|
858
|
+
method: request.method ?? "GET",
|
|
758
859
|
status: response.status,
|
|
759
860
|
statusText: response.statusText
|
|
760
861
|
});
|
|
@@ -763,16 +864,70 @@ var ServiceContext = class {
|
|
|
763
864
|
timer.stop({
|
|
764
865
|
ok: false,
|
|
765
866
|
url,
|
|
766
|
-
method:
|
|
867
|
+
method: request.method ?? "GET",
|
|
767
868
|
error
|
|
768
869
|
});
|
|
769
870
|
throw error;
|
|
770
871
|
}
|
|
771
872
|
};
|
|
772
873
|
}
|
|
874
|
+
combineSignals(signal) {
|
|
875
|
+
if (!signal) return this._abortController.signal;
|
|
876
|
+
const combined = new AbortController();
|
|
877
|
+
const abort = (source) => combined.abort(source.reason);
|
|
878
|
+
if (signal.aborted) {
|
|
879
|
+
abort(signal);
|
|
880
|
+
} else if (this._abortController.signal.aborted) {
|
|
881
|
+
abort(this._abortController.signal);
|
|
882
|
+
} else {
|
|
883
|
+
signal.addEventListener("abort", () => abort(signal), { once: true });
|
|
884
|
+
this._abortController.signal.addEventListener(
|
|
885
|
+
"abort",
|
|
886
|
+
() => abort(this._abortController.signal),
|
|
887
|
+
{ once: true }
|
|
888
|
+
);
|
|
889
|
+
}
|
|
890
|
+
return combined.signal;
|
|
891
|
+
}
|
|
773
892
|
};
|
|
774
893
|
|
|
775
894
|
// src/errors.ts
|
|
895
|
+
function parsePermissionHint(value) {
|
|
896
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return void 0;
|
|
897
|
+
const candidate = value;
|
|
898
|
+
const keys = Object.keys(candidate).sort();
|
|
899
|
+
if (keys.some((key) => !["actions", "path", "service", "space"].includes(key))) return void 0;
|
|
900
|
+
if (candidate.service !== "tinycloud.kv" && candidate.service !== "tinycloud.encryption") return void 0;
|
|
901
|
+
if (typeof candidate.path !== "string" || candidate.path.length === 0 || candidate.path.includes("*")) return void 0;
|
|
902
|
+
if (candidate.service === "tinycloud.kv" && (typeof candidate.space !== "string" || candidate.space.length === 0 || !candidate.path.startsWith("vault/") || candidate.path.endsWith("/"))) {
|
|
903
|
+
return void 0;
|
|
904
|
+
}
|
|
905
|
+
if (candidate.service === "tinycloud.encryption" && (candidate.space !== void 0 || !candidate.path.startsWith("urn:tinycloud:encryption:") || candidate.path.endsWith(":"))) {
|
|
906
|
+
return void 0;
|
|
907
|
+
}
|
|
908
|
+
if (!Array.isArray(candidate.actions) || candidate.actions.length !== 1 || typeof candidate.actions[0] !== "string" || candidate.actions[0].includes("*")) return void 0;
|
|
909
|
+
const expectedAction = candidate.service === "tinycloud.kv" ? "tinycloud.kv/get" : "tinycloud.encryption/decrypt";
|
|
910
|
+
if (candidate.actions[0] !== expectedAction) return void 0;
|
|
911
|
+
const space = typeof candidate.space === "string" ? candidate.space : void 0;
|
|
912
|
+
return {
|
|
913
|
+
service: candidate.service,
|
|
914
|
+
...space === void 0 ? {} : { space },
|
|
915
|
+
path: candidate.path,
|
|
916
|
+
actions: [candidate.actions[0]]
|
|
917
|
+
};
|
|
918
|
+
}
|
|
919
|
+
function parsePermissionHintFromErrorText(text) {
|
|
920
|
+
try {
|
|
921
|
+
const parsed = JSON.parse(text);
|
|
922
|
+
if (typeof parsed !== "object" || parsed === null) return void 0;
|
|
923
|
+
const root = parsed;
|
|
924
|
+
const nested = root.error;
|
|
925
|
+
const nestedRecord = typeof nested === "object" && nested !== null ? nested : void 0;
|
|
926
|
+
return parsePermissionHint(root.permissionHint) ?? parsePermissionHint(nestedRecord?.permissionHint);
|
|
927
|
+
} catch {
|
|
928
|
+
return void 0;
|
|
929
|
+
}
|
|
930
|
+
}
|
|
776
931
|
function authRequiredError(service) {
|
|
777
932
|
return {
|
|
778
933
|
code: ErrorCodes.AUTH_REQUIRED,
|
|
@@ -923,7 +1078,7 @@ var BaseService = class {
|
|
|
923
1078
|
* Combines the service-level abort with context-level abort.
|
|
924
1079
|
*/
|
|
925
1080
|
get abortSignal() {
|
|
926
|
-
return this.
|
|
1081
|
+
return this.combineSignals();
|
|
927
1082
|
}
|
|
928
1083
|
/**
|
|
929
1084
|
* Check if the service is authenticated.
|
|
@@ -1039,7 +1194,11 @@ var BaseService = class {
|
|
|
1039
1194
|
*/
|
|
1040
1195
|
combineSignals(...signals) {
|
|
1041
1196
|
const controller = new AbortController();
|
|
1042
|
-
const allSignals = [
|
|
1197
|
+
const allSignals = [
|
|
1198
|
+
this.abortController.signal,
|
|
1199
|
+
this.context?.abortSignal,
|
|
1200
|
+
...signals.filter(Boolean)
|
|
1201
|
+
].filter(Boolean);
|
|
1043
1202
|
for (const signal of allSignals) {
|
|
1044
1203
|
if (signal.aborted) {
|
|
1045
1204
|
controller.abort(signal.reason);
|
|
@@ -1512,13 +1671,15 @@ var KVService = class extends BaseService {
|
|
|
1512
1671
|
options?.signal
|
|
1513
1672
|
);
|
|
1514
1673
|
if (!response.ok) {
|
|
1515
|
-
if (response.status === 401) {
|
|
1674
|
+
if (response.status === 401 || response.status === 403) {
|
|
1516
1675
|
const errorText2 = await response.text();
|
|
1517
1676
|
const { resource, action } = parseAuthError(errorText2);
|
|
1677
|
+
const permissionHint = parsePermissionHintFromErrorText(errorText2);
|
|
1518
1678
|
return err(authUnauthorizedError("kv", errorText2, {
|
|
1519
1679
|
status: response.status,
|
|
1520
1680
|
...action && { requiredAction: action },
|
|
1521
|
-
...resource && { resource }
|
|
1681
|
+
...resource && { resource },
|
|
1682
|
+
...permissionHint === void 0 ? {} : { permissionHint }
|
|
1522
1683
|
}));
|
|
1523
1684
|
}
|
|
1524
1685
|
if (response.status === 404) {
|
|
@@ -3744,6 +3905,9 @@ function unwrapKVData(value) {
|
|
|
3744
3905
|
}
|
|
3745
3906
|
return value;
|
|
3746
3907
|
}
|
|
3908
|
+
function hasHttpResponse(error) {
|
|
3909
|
+
return typeof error.meta?.status === "number";
|
|
3910
|
+
}
|
|
3747
3911
|
function isUnlockSigner(signer) {
|
|
3748
3912
|
return typeof signer === "object" && signer !== null && typeof signer.signMessage === "function";
|
|
3749
3913
|
}
|
|
@@ -4117,6 +4281,80 @@ var DataVaultService = class extends BaseService {
|
|
|
4117
4281
|
});
|
|
4118
4282
|
}
|
|
4119
4283
|
}
|
|
4284
|
+
/**
|
|
4285
|
+
* Read a network-encrypted entry while preserving safe failure phases.
|
|
4286
|
+
*
|
|
4287
|
+
* Unlike {@link getNetworkEncrypted}, this is intentionally message-free so
|
|
4288
|
+
* an operation layer can distinguish an authorized absence from a failed
|
|
4289
|
+
* read without receiving node, envelope, plaintext, or key material.
|
|
4290
|
+
*/
|
|
4291
|
+
async readNetworkEncrypted(key, options) {
|
|
4292
|
+
const config = this.networkEncryption;
|
|
4293
|
+
if (!config || !this.requireAuth()) {
|
|
4294
|
+
return { status: "read_failed" };
|
|
4295
|
+
}
|
|
4296
|
+
let valueResult;
|
|
4297
|
+
try {
|
|
4298
|
+
valueResult = await this.tc.kv.get(`vault/${key}`, { raw: true });
|
|
4299
|
+
} catch {
|
|
4300
|
+
return { status: "node_unreachable" };
|
|
4301
|
+
}
|
|
4302
|
+
if (!valueResult.ok) {
|
|
4303
|
+
const permissionHint = parsePermissionHint(valueResult.error.meta?.permissionHint);
|
|
4304
|
+
if (valueResult.error.code === "AUTH_UNAUTHORIZED" && permissionHint !== void 0) {
|
|
4305
|
+
return { status: "permission_required", hint: permissionHint };
|
|
4306
|
+
}
|
|
4307
|
+
if ((valueResult.error.code === "NOT_FOUND" || valueResult.error.code === "KV_NOT_FOUND") && !hasHttpResponse(valueResult.error)) {
|
|
4308
|
+
return { status: "not_found" };
|
|
4309
|
+
}
|
|
4310
|
+
if (valueResult.error.code === "NETWORK_ERROR" || valueResult.error.code === "TIMEOUT" || valueResult.error.code === "ABORTED") {
|
|
4311
|
+
return hasHttpResponse(valueResult.error) ? { status: "read_failed" } : { status: "node_unreachable" };
|
|
4312
|
+
}
|
|
4313
|
+
return { status: "read_failed" };
|
|
4314
|
+
}
|
|
4315
|
+
let envelope;
|
|
4316
|
+
try {
|
|
4317
|
+
const rawEnvelope = unwrapKVData(valueResult.data);
|
|
4318
|
+
envelope = typeof rawEnvelope === "string" ? JSON.parse(rawEnvelope) : rawEnvelope;
|
|
4319
|
+
} catch {
|
|
4320
|
+
return { status: "corrupt_envelope" };
|
|
4321
|
+
}
|
|
4322
|
+
let plaintextResult;
|
|
4323
|
+
try {
|
|
4324
|
+
const proof = await this.decryptCapabilityProof();
|
|
4325
|
+
plaintextResult = await config.service.decryptEnvelope(envelope, proof);
|
|
4326
|
+
} catch {
|
|
4327
|
+
return { status: "decrypt_failed" };
|
|
4328
|
+
}
|
|
4329
|
+
if (!plaintextResult.ok) {
|
|
4330
|
+
const permissionHint = parsePermissionHint(
|
|
4331
|
+
plaintextResult.error.permissionHint
|
|
4332
|
+
);
|
|
4333
|
+
if (plaintextResult.error.code === "DECRYPT_DENIED" && permissionHint !== void 0) {
|
|
4334
|
+
return { status: "permission_required", hint: permissionHint };
|
|
4335
|
+
}
|
|
4336
|
+
if (plaintextResult.error.code === "INVALID_ENVELOPE") {
|
|
4337
|
+
return { status: "corrupt_envelope" };
|
|
4338
|
+
}
|
|
4339
|
+
if (plaintextResult.error.code === "TRANSPORT_ERROR") {
|
|
4340
|
+
return { status: "node_unreachable" };
|
|
4341
|
+
}
|
|
4342
|
+
return { status: "decrypt_failed" };
|
|
4343
|
+
}
|
|
4344
|
+
try {
|
|
4345
|
+
const metadata = envelope.metadata ?? {};
|
|
4346
|
+
const contentType = metadata[VaultHeaders.CONTENT_TYPE] ?? "application/json";
|
|
4347
|
+
const keyId = metadata[VaultHeaders.KEY_ID] ?? envelope.encryptedSymmetricKeyHash.slice(0, 16);
|
|
4348
|
+
const value = this.deserializeValue(
|
|
4349
|
+
plaintextResult.data,
|
|
4350
|
+
contentType,
|
|
4351
|
+
options
|
|
4352
|
+
);
|
|
4353
|
+
return { status: "ok", entry: { value, metadata, keyId } };
|
|
4354
|
+
} catch {
|
|
4355
|
+
return { status: "invalid_payload" };
|
|
4356
|
+
}
|
|
4357
|
+
}
|
|
4120
4358
|
async headNetworkEncrypted(key) {
|
|
4121
4359
|
if (!this.requireAuth()) {
|
|
4122
4360
|
return vaultError({
|
|
@@ -5944,6 +6182,8 @@ function openWrappedKey(crypto2, receiverPrivateKey, response) {
|
|
|
5944
6182
|
}
|
|
5945
6183
|
|
|
5946
6184
|
// src/encryption/EncryptionService.ts
|
|
6185
|
+
import { DecryptTransportResponseError } from "@tinycloud/sdk-services/internal/decrypt-transport-response-error";
|
|
6186
|
+
import { DecryptTransportResponseError as DecryptTransportResponseError2 } from "@tinycloud/sdk-services/internal/decrypt-transport-response-error";
|
|
5947
6187
|
function encOk(data) {
|
|
5948
6188
|
return { ok: true, data };
|
|
5949
6189
|
}
|
|
@@ -5962,17 +6202,20 @@ var EncryptionService = class extends BaseService {
|
|
|
5962
6202
|
return this._config.crypto;
|
|
5963
6203
|
}
|
|
5964
6204
|
async discoverNetwork(identifier, ownerDid) {
|
|
6205
|
+
this.assertActive();
|
|
5965
6206
|
const result = await discoverNetwork({
|
|
5966
6207
|
identifier,
|
|
5967
6208
|
...ownerDid !== void 0 ? { ownerDid } : {},
|
|
5968
6209
|
...this._config.node !== void 0 ? { node: this._config.node } : {},
|
|
5969
6210
|
...this._config.wellKnown !== void 0 ? { wellKnown: this._config.wellKnown } : {}
|
|
5970
6211
|
});
|
|
6212
|
+
this.assertActive();
|
|
5971
6213
|
if (!result.ok) return result;
|
|
5972
6214
|
return encOk(result.data.descriptor);
|
|
5973
6215
|
}
|
|
5974
6216
|
async encryptToNetwork(networkId, plaintext, options) {
|
|
5975
6217
|
try {
|
|
6218
|
+
this.assertActive();
|
|
5976
6219
|
const discovered = await this.discoverNetwork(networkId);
|
|
5977
6220
|
if (!discovered.ok) return discovered;
|
|
5978
6221
|
const usable = ensureNetworkUsableForDecrypt(discovered.data);
|
|
@@ -6000,6 +6243,7 @@ var EncryptionService = class extends BaseService {
|
|
|
6000
6243
|
}
|
|
6001
6244
|
async decryptEnvelope(envelope, capabilityProof, options) {
|
|
6002
6245
|
try {
|
|
6246
|
+
this.assertActive();
|
|
6003
6247
|
const validated = validateEnvelope(this.crypto, envelope);
|
|
6004
6248
|
if (!validated.ok) return validated;
|
|
6005
6249
|
if (options?.aad !== void 0 && validated.data.aad !== base64Encode2(options.aad)) {
|
|
@@ -6065,16 +6309,38 @@ var EncryptionService = class extends BaseService {
|
|
|
6065
6309
|
facts,
|
|
6066
6310
|
proof: capabilityProof
|
|
6067
6311
|
});
|
|
6068
|
-
|
|
6312
|
+
this.assertActive();
|
|
6313
|
+
if (!built.ok) {
|
|
6314
|
+
if (built.error.code !== "TRANSPORT_ERROR") return built;
|
|
6315
|
+
return encErr(
|
|
6316
|
+
encryptionError({
|
|
6317
|
+
code: "INVALID_INPUT",
|
|
6318
|
+
message: "Unable to build decrypt request"
|
|
6319
|
+
})
|
|
6320
|
+
);
|
|
6321
|
+
}
|
|
6069
6322
|
let response;
|
|
6070
6323
|
try {
|
|
6071
6324
|
response = await this._config.transport.postDecrypt({
|
|
6072
6325
|
targetNode,
|
|
6073
6326
|
networkId: envelope.networkId,
|
|
6074
6327
|
authorization: built.data.authorization,
|
|
6075
|
-
canonicalBody: built.data.canonicalBody
|
|
6328
|
+
canonicalBody: built.data.canonicalBody,
|
|
6329
|
+
signal: this.abortSignal
|
|
6076
6330
|
});
|
|
6331
|
+
this.assertActive();
|
|
6077
6332
|
} catch (error) {
|
|
6333
|
+
if (error instanceof DecryptTransportResponseError) {
|
|
6334
|
+
return encErr(
|
|
6335
|
+
encryptionError(
|
|
6336
|
+
error.status === 401 || error.status === 403 ? {
|
|
6337
|
+
code: "DECRYPT_DENIED",
|
|
6338
|
+
message: "Node denied decrypt request",
|
|
6339
|
+
...error.permissionHint === void 0 ? {} : { permissionHint: error.permissionHint }
|
|
6340
|
+
} : { code: "INVALID_RESPONSE", message: "Node decrypt request failed" }
|
|
6341
|
+
)
|
|
6342
|
+
);
|
|
6343
|
+
}
|
|
6078
6344
|
return encErr(
|
|
6079
6345
|
encryptionError({
|
|
6080
6346
|
code: "TRANSPORT_ERROR",
|
|
@@ -6105,14 +6371,20 @@ var EncryptionService = class extends BaseService {
|
|
|
6105
6371
|
} catch (error) {
|
|
6106
6372
|
return encErr(
|
|
6107
6373
|
encryptionError({
|
|
6108
|
-
code: "
|
|
6109
|
-
|
|
6374
|
+
code: "INVALID_RESPONSE",
|
|
6375
|
+
message: "Local decryption failed"
|
|
6110
6376
|
})
|
|
6111
6377
|
);
|
|
6112
6378
|
}
|
|
6113
6379
|
}
|
|
6380
|
+
assertActive() {
|
|
6381
|
+
this._config.assertActive?.();
|
|
6382
|
+
}
|
|
6114
6383
|
};
|
|
6115
6384
|
EncryptionService.serviceName = "encryption";
|
|
6385
|
+
|
|
6386
|
+
// src/encryption/index.ts
|
|
6387
|
+
import { DecryptTransportResponseError as DecryptTransportResponseError3 } from "@tinycloud/sdk-services/internal/decrypt-transport-response-error";
|
|
6116
6388
|
export {
|
|
6117
6389
|
BaseService,
|
|
6118
6390
|
DECRYPT_ACTION,
|
|
@@ -6123,6 +6395,7 @@ export {
|
|
|
6123
6395
|
DEFAULT_SIGNED_READ_URL_EXPIRY_MS,
|
|
6124
6396
|
DataVaultService,
|
|
6125
6397
|
DatabaseHandle,
|
|
6398
|
+
DecryptTransportResponseError3 as DecryptTransportResponseError,
|
|
6126
6399
|
DuckDbAction,
|
|
6127
6400
|
DuckDbDatabaseHandle,
|
|
6128
6401
|
DuckDbService,
|
|
@@ -6206,6 +6479,8 @@ export {
|
|
|
6206
6479
|
openWrappedKey,
|
|
6207
6480
|
parseAuthError,
|
|
6208
6481
|
parseNetworkId,
|
|
6482
|
+
parsePermissionHint,
|
|
6483
|
+
parsePermissionHintFromErrorText,
|
|
6209
6484
|
permissionDeniedError,
|
|
6210
6485
|
resolveSecretListPrefix,
|
|
6211
6486
|
resolveSecretPath,
|