@tinycloud/sdk-core 2.1.0-beta.0 → 2.1.0-beta.2
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/index.cjs +559 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +579 -73
- package/dist/index.d.ts +579 -73
- package/dist/index.js +531 -13
- package/dist/index.js.map +1 -1
- package/package.json +4 -2
package/dist/index.cjs
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
8
|
var __export = (target, all) => {
|
|
7
9
|
for (var name in all)
|
|
@@ -15,6 +17,14 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
15
17
|
}
|
|
16
18
|
return to;
|
|
17
19
|
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
18
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
29
|
|
|
20
30
|
// src/index.ts
|
|
@@ -24,6 +34,8 @@ __export(index_exports, {
|
|
|
24
34
|
CapabilityKeyRegistry: () => CapabilityKeyRegistry,
|
|
25
35
|
CapabilityKeyRegistryErrorCodes: () => CapabilityKeyRegistryErrorCodes,
|
|
26
36
|
ClientSessionSchema: () => ClientSessionSchema,
|
|
37
|
+
DEFAULT_DEFAULTS: () => DEFAULT_DEFAULTS,
|
|
38
|
+
DEFAULT_EXPIRY: () => DEFAULT_EXPIRY,
|
|
27
39
|
DataVaultService: () => import_sdk_services4.DataVaultService,
|
|
28
40
|
DatabaseHandle: () => import_sdk_services4.DatabaseHandle,
|
|
29
41
|
DelegationErrorCodes: () => DelegationErrorCodes,
|
|
@@ -35,11 +47,16 @@ __export(index_exports, {
|
|
|
35
47
|
ErrorCodes: () => import_sdk_services4.ErrorCodes,
|
|
36
48
|
HooksService: () => import_sdk_services4.HooksService,
|
|
37
49
|
KVService: () => import_sdk_services4.KVService,
|
|
50
|
+
ManifestValidationError: () => ManifestValidationError,
|
|
51
|
+
PermissionNotInManifestError: () => PermissionNotInManifestError,
|
|
38
52
|
PrefixedKVService: () => import_sdk_services4.PrefixedKVService,
|
|
39
53
|
ProtocolMismatchError: () => ProtocolMismatchError,
|
|
54
|
+
SERVICE_LONG_TO_SHORT: () => SERVICE_LONG_TO_SHORT,
|
|
55
|
+
SERVICE_SHORT_TO_LONG: () => SERVICE_SHORT_TO_LONG,
|
|
40
56
|
SQLAction: () => import_sdk_services4.SQLAction,
|
|
41
57
|
SQLService: () => import_sdk_services4.SQLService,
|
|
42
58
|
ServiceContext: () => import_sdk_services4.ServiceContext,
|
|
59
|
+
SessionExpiredError: () => SessionExpiredError,
|
|
43
60
|
SharingService: () => SharingService,
|
|
44
61
|
SilentNotificationHandler: () => SilentNotificationHandler,
|
|
45
62
|
SiweConfigSchema: () => SiweConfigSchema,
|
|
@@ -53,6 +70,7 @@ __export(index_exports, {
|
|
|
53
70
|
VaultPublicSpaceKVActions: () => import_sdk_services4.VaultPublicSpaceKVActions,
|
|
54
71
|
VersionCheckError: () => VersionCheckError,
|
|
55
72
|
activateSessionWithHost: () => activateSessionWithHost,
|
|
73
|
+
applyPrefix: () => applyPrefix,
|
|
56
74
|
buildSpaceUri: () => buildSpaceUri,
|
|
57
75
|
checkNodeInfo: () => checkNodeInfo,
|
|
58
76
|
createCapabilityKeyRegistry: () => createCapabilityKeyRegistry,
|
|
@@ -63,13 +81,23 @@ __export(index_exports, {
|
|
|
63
81
|
defaultSignStrategy: () => defaultSignStrategy,
|
|
64
82
|
defaultSpaceCreationHandler: () => defaultSpaceCreationHandler,
|
|
65
83
|
err: () => import_sdk_services4.err,
|
|
84
|
+
expandActionShortNames: () => expandActionShortNames,
|
|
66
85
|
fetchPeerId: () => fetchPeerId,
|
|
86
|
+
isCapabilitySubset: () => isCapabilitySubset,
|
|
87
|
+
loadManifest: () => loadManifest,
|
|
67
88
|
makePublicSpaceId: () => makePublicSpaceId,
|
|
89
|
+
manifestAbilitiesUnion: () => manifestAbilitiesUnion,
|
|
90
|
+
normalizeDefaults: () => normalizeDefaults,
|
|
68
91
|
ok: () => import_sdk_services4.ok,
|
|
92
|
+
parseExpiry: () => parseExpiry,
|
|
93
|
+
parseRecapCapabilities: () => parseRecapCapabilities,
|
|
69
94
|
parseSpaceUri: () => parseSpaceUri,
|
|
95
|
+
resolveManifest: () => resolveManifest,
|
|
96
|
+
resourceCapabilitiesToAbilitiesMap: () => resourceCapabilitiesToAbilitiesMap,
|
|
70
97
|
serviceError: () => import_sdk_services4.serviceError,
|
|
71
98
|
submitHostDelegation: () => submitHostDelegation,
|
|
72
99
|
validateClientSession: () => validateClientSession,
|
|
100
|
+
validateManifest: () => validateManifest,
|
|
73
101
|
validatePersistedSessionData: () => validatePersistedSessionData
|
|
74
102
|
});
|
|
75
103
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -559,6 +587,16 @@ var DelegationApiResponseSchema = import_zod3.z.object({
|
|
|
559
587
|
/** CID of the created delegation */
|
|
560
588
|
cid: import_zod3.z.string().optional()
|
|
561
589
|
});
|
|
590
|
+
var DelegatedResourceSchema = import_zod3.z.object({
|
|
591
|
+
/** Short-form service name, e.g. "kv", "sql", "duckdb", "capabilities", "hooks". */
|
|
592
|
+
service: import_zod3.z.string(),
|
|
593
|
+
/** Full space id string, e.g. "tinycloud:pkh:eip155:1:0x....:default". */
|
|
594
|
+
space: import_zod3.z.string(),
|
|
595
|
+
/** Resource path; empty string when the resource URI had no path segment. */
|
|
596
|
+
path: import_zod3.z.string(),
|
|
597
|
+
/** Full-URN ability strings, e.g. ["tinycloud.kv/get", "tinycloud.kv/put"]. */
|
|
598
|
+
actions: import_zod3.z.array(import_zod3.z.string())
|
|
599
|
+
});
|
|
562
600
|
var CreateDelegationWasmParamsSchema = import_zod3.z.object({
|
|
563
601
|
/** The session containing delegation credentials */
|
|
564
602
|
session: import_zod3.z.unknown().refine(
|
|
@@ -569,10 +607,23 @@ var CreateDelegationWasmParamsSchema = import_zod3.z.object({
|
|
|
569
607
|
delegateDID: import_zod3.z.string(),
|
|
570
608
|
/** Space ID this delegation applies to */
|
|
571
609
|
spaceId: import_zod3.z.string(),
|
|
572
|
-
/**
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
610
|
+
/**
|
|
611
|
+
* Multi-resource abilities map: short-service → path → full-URN actions.
|
|
612
|
+
* Matches the shape accepted by `prepareSession`.
|
|
613
|
+
*
|
|
614
|
+
* Example:
|
|
615
|
+
* ```
|
|
616
|
+
* {
|
|
617
|
+
* kv: {
|
|
618
|
+
* "com.listen.app/": ["tinycloud.kv/get", "tinycloud.kv/put"]
|
|
619
|
+
* },
|
|
620
|
+
* sql: {
|
|
621
|
+
* "com.listen.app/data.sqlite": ["tinycloud.sql/read"]
|
|
622
|
+
* }
|
|
623
|
+
* }
|
|
624
|
+
* ```
|
|
625
|
+
*/
|
|
626
|
+
abilities: import_zod3.z.record(import_zod3.z.string(), import_zod3.z.record(import_zod3.z.string(), import_zod3.z.array(import_zod3.z.string()))),
|
|
576
627
|
/** Expiration time in seconds since Unix epoch */
|
|
577
628
|
expirationSecs: import_zod3.z.number(),
|
|
578
629
|
/** Optional not-before time in seconds since Unix epoch */
|
|
@@ -585,12 +636,13 @@ var CreateDelegationWasmResultSchema = import_zod3.z.object({
|
|
|
585
636
|
cid: import_zod3.z.string(),
|
|
586
637
|
/** DID of the delegate */
|
|
587
638
|
delegateDID: import_zod3.z.string(),
|
|
588
|
-
/** Resource path the delegation grants access to */
|
|
589
|
-
path: import_zod3.z.string(),
|
|
590
|
-
/** Actions the delegation authorizes */
|
|
591
|
-
actions: import_zod3.z.array(import_zod3.z.string()),
|
|
592
639
|
/** Expiration time */
|
|
593
|
-
expiry: import_zod3.z.coerce.date()
|
|
640
|
+
expiry: import_zod3.z.coerce.date(),
|
|
641
|
+
/**
|
|
642
|
+
* All (service, space, path, actions) entries granted by this delegation.
|
|
643
|
+
* Always non-empty on success.
|
|
644
|
+
*/
|
|
645
|
+
resources: import_zod3.z.array(DelegatedResourceSchema)
|
|
594
646
|
});
|
|
595
647
|
|
|
596
648
|
// src/spaces/spaces.schema.ts
|
|
@@ -2677,7 +2729,352 @@ function validateEncodedShareData(data) {
|
|
|
2677
2729
|
return { ok: true, data: result.data };
|
|
2678
2730
|
}
|
|
2679
2731
|
|
|
2732
|
+
// src/manifest.ts
|
|
2733
|
+
var import_ms = __toESM(require("ms"), 1);
|
|
2734
|
+
var ManifestValidationError = class extends Error {
|
|
2735
|
+
constructor(message) {
|
|
2736
|
+
super(`Manifest validation failed: ${message}`);
|
|
2737
|
+
this.name = "ManifestValidationError";
|
|
2738
|
+
}
|
|
2739
|
+
};
|
|
2740
|
+
var DEFAULT_EXPIRY = "30d";
|
|
2741
|
+
var DEFAULT_DEFAULTS = true;
|
|
2742
|
+
var SERVICE_SHORT_TO_LONG = Object.freeze({
|
|
2743
|
+
kv: "tinycloud.kv",
|
|
2744
|
+
sql: "tinycloud.sql",
|
|
2745
|
+
duckdb: "tinycloud.duckdb",
|
|
2746
|
+
capabilities: "tinycloud.capabilities",
|
|
2747
|
+
hooks: "tinycloud.hooks"
|
|
2748
|
+
});
|
|
2749
|
+
var SERVICE_LONG_TO_SHORT = Object.freeze(
|
|
2750
|
+
Object.fromEntries(
|
|
2751
|
+
Object.entries(SERVICE_SHORT_TO_LONG).map(([s, l]) => [l, s])
|
|
2752
|
+
)
|
|
2753
|
+
);
|
|
2754
|
+
var DEFAULT_STANDARD_ENTRIES = [
|
|
2755
|
+
{
|
|
2756
|
+
service: "tinycloud.kv",
|
|
2757
|
+
space: "default",
|
|
2758
|
+
path: "/",
|
|
2759
|
+
actions: ["get", "put", "del", "list", "metadata"]
|
|
2760
|
+
},
|
|
2761
|
+
{
|
|
2762
|
+
service: "tinycloud.sql",
|
|
2763
|
+
space: "default",
|
|
2764
|
+
path: "/",
|
|
2765
|
+
actions: ["read", "write"]
|
|
2766
|
+
},
|
|
2767
|
+
{
|
|
2768
|
+
service: "tinycloud.capabilities",
|
|
2769
|
+
space: "default",
|
|
2770
|
+
path: "/",
|
|
2771
|
+
actions: ["read"]
|
|
2772
|
+
}
|
|
2773
|
+
];
|
|
2774
|
+
var DEFAULT_ADMIN_ENTRIES = [
|
|
2775
|
+
{
|
|
2776
|
+
service: "tinycloud.kv",
|
|
2777
|
+
space: "default",
|
|
2778
|
+
path: "/",
|
|
2779
|
+
actions: ["get", "put", "del", "list", "metadata"]
|
|
2780
|
+
},
|
|
2781
|
+
{
|
|
2782
|
+
service: "tinycloud.sql",
|
|
2783
|
+
space: "default",
|
|
2784
|
+
path: "/",
|
|
2785
|
+
actions: ["read", "write", "ddl"]
|
|
2786
|
+
},
|
|
2787
|
+
{
|
|
2788
|
+
service: "tinycloud.capabilities",
|
|
2789
|
+
space: "default",
|
|
2790
|
+
path: "/",
|
|
2791
|
+
actions: ["read", "admin"]
|
|
2792
|
+
}
|
|
2793
|
+
];
|
|
2794
|
+
var DEFAULT_ALL_ENTRIES = [
|
|
2795
|
+
{
|
|
2796
|
+
service: "tinycloud.kv",
|
|
2797
|
+
space: "default",
|
|
2798
|
+
path: "/",
|
|
2799
|
+
actions: ["get", "put", "del", "list", "metadata"]
|
|
2800
|
+
},
|
|
2801
|
+
{
|
|
2802
|
+
service: "tinycloud.sql",
|
|
2803
|
+
space: "default",
|
|
2804
|
+
path: "/",
|
|
2805
|
+
actions: ["read", "write", "ddl"]
|
|
2806
|
+
},
|
|
2807
|
+
{
|
|
2808
|
+
service: "tinycloud.duckdb",
|
|
2809
|
+
space: "default",
|
|
2810
|
+
path: "/",
|
|
2811
|
+
actions: ["read", "write"]
|
|
2812
|
+
},
|
|
2813
|
+
{
|
|
2814
|
+
service: "tinycloud.capabilities",
|
|
2815
|
+
space: "default",
|
|
2816
|
+
path: "/",
|
|
2817
|
+
actions: ["read", "admin"]
|
|
2818
|
+
}
|
|
2819
|
+
];
|
|
2820
|
+
function parseExpiry(duration) {
|
|
2821
|
+
if (typeof duration !== "string" || duration.length === 0) {
|
|
2822
|
+
throw new ManifestValidationError(
|
|
2823
|
+
`expiry must be a non-empty duration string (got ${JSON.stringify(duration)})`
|
|
2824
|
+
);
|
|
2825
|
+
}
|
|
2826
|
+
const parsed = (0, import_ms.default)(
|
|
2827
|
+
duration
|
|
2828
|
+
);
|
|
2829
|
+
if (typeof parsed !== "number" || !Number.isFinite(parsed) || parsed <= 0) {
|
|
2830
|
+
throw new ManifestValidationError(
|
|
2831
|
+
`invalid expiry duration: ${JSON.stringify(duration)}`
|
|
2832
|
+
);
|
|
2833
|
+
}
|
|
2834
|
+
return parsed;
|
|
2835
|
+
}
|
|
2836
|
+
function expandActionShortNames(service, actions) {
|
|
2837
|
+
return actions.map((a) => {
|
|
2838
|
+
if (a.includes("/")) {
|
|
2839
|
+
return a;
|
|
2840
|
+
}
|
|
2841
|
+
return `${service}/${a}`;
|
|
2842
|
+
});
|
|
2843
|
+
}
|
|
2844
|
+
function applyPrefix(prefix, path, skipPrefix) {
|
|
2845
|
+
if (skipPrefix) {
|
|
2846
|
+
return path;
|
|
2847
|
+
}
|
|
2848
|
+
if (prefix === "") {
|
|
2849
|
+
return path;
|
|
2850
|
+
}
|
|
2851
|
+
if (path.startsWith("/")) {
|
|
2852
|
+
return `${prefix}${path}`;
|
|
2853
|
+
}
|
|
2854
|
+
return `${prefix}/${path}`;
|
|
2855
|
+
}
|
|
2856
|
+
async function loadManifest(url) {
|
|
2857
|
+
const fetchFn = globalThis.fetch;
|
|
2858
|
+
if (typeof fetchFn !== "function") {
|
|
2859
|
+
throw new ManifestValidationError(
|
|
2860
|
+
"loadManifest requires a global fetch; pass the manifest object directly on runtimes without fetch"
|
|
2861
|
+
);
|
|
2862
|
+
}
|
|
2863
|
+
const res = await fetchFn(url);
|
|
2864
|
+
if (!res.ok) {
|
|
2865
|
+
throw new ManifestValidationError(
|
|
2866
|
+
`failed to fetch manifest from ${url}: HTTP ${res.status}`
|
|
2867
|
+
);
|
|
2868
|
+
}
|
|
2869
|
+
const json = await res.json();
|
|
2870
|
+
return validateManifest(json);
|
|
2871
|
+
}
|
|
2872
|
+
function validateManifest(input) {
|
|
2873
|
+
if (input === null || typeof input !== "object") {
|
|
2874
|
+
throw new ManifestValidationError("manifest must be an object");
|
|
2875
|
+
}
|
|
2876
|
+
const m = input;
|
|
2877
|
+
if (typeof m.id !== "string" || m.id.length === 0) {
|
|
2878
|
+
throw new ManifestValidationError("manifest.id is required and must be a non-empty string");
|
|
2879
|
+
}
|
|
2880
|
+
if (typeof m.name !== "string" || m.name.length === 0) {
|
|
2881
|
+
throw new ManifestValidationError("manifest.name is required and must be a non-empty string");
|
|
2882
|
+
}
|
|
2883
|
+
if (m.expiry !== void 0) {
|
|
2884
|
+
parseExpiry(m.expiry);
|
|
2885
|
+
}
|
|
2886
|
+
if (m.permissions !== void 0) {
|
|
2887
|
+
if (!Array.isArray(m.permissions)) {
|
|
2888
|
+
throw new ManifestValidationError("manifest.permissions must be an array");
|
|
2889
|
+
}
|
|
2890
|
+
m.permissions.forEach(
|
|
2891
|
+
(p, i) => validatePermissionEntry(p, `permissions[${i}]`)
|
|
2892
|
+
);
|
|
2893
|
+
}
|
|
2894
|
+
if (m.delegations !== void 0) {
|
|
2895
|
+
if (!Array.isArray(m.delegations)) {
|
|
2896
|
+
throw new ManifestValidationError("manifest.delegations must be an array");
|
|
2897
|
+
}
|
|
2898
|
+
m.delegations.forEach((d, i) => {
|
|
2899
|
+
if (typeof d?.to !== "string" || d.to.length === 0) {
|
|
2900
|
+
throw new ManifestValidationError(
|
|
2901
|
+
`delegations[${i}].to is required and must be a non-empty DID string`
|
|
2902
|
+
);
|
|
2903
|
+
}
|
|
2904
|
+
if (d.expiry !== void 0) {
|
|
2905
|
+
parseExpiry(d.expiry);
|
|
2906
|
+
}
|
|
2907
|
+
if (!Array.isArray(d.permissions)) {
|
|
2908
|
+
throw new ManifestValidationError(
|
|
2909
|
+
`delegations[${i}].permissions must be an array`
|
|
2910
|
+
);
|
|
2911
|
+
}
|
|
2912
|
+
d.permissions.forEach(
|
|
2913
|
+
(p, j) => validatePermissionEntry(p, `delegations[${i}].permissions[${j}]`)
|
|
2914
|
+
);
|
|
2915
|
+
});
|
|
2916
|
+
}
|
|
2917
|
+
return m;
|
|
2918
|
+
}
|
|
2919
|
+
function validatePermissionEntry(p, path) {
|
|
2920
|
+
if (p === null || typeof p !== "object") {
|
|
2921
|
+
throw new ManifestValidationError(`${path} must be an object`);
|
|
2922
|
+
}
|
|
2923
|
+
const entry = p;
|
|
2924
|
+
if (typeof entry.service !== "string" || entry.service.length === 0) {
|
|
2925
|
+
throw new ManifestValidationError(`${path}.service is required`);
|
|
2926
|
+
}
|
|
2927
|
+
if (typeof entry.space !== "string" || entry.space.length === 0) {
|
|
2928
|
+
throw new ManifestValidationError(`${path}.space is required`);
|
|
2929
|
+
}
|
|
2930
|
+
if (typeof entry.path !== "string") {
|
|
2931
|
+
throw new ManifestValidationError(
|
|
2932
|
+
`${path}.path is required (use "" or "/" for root)`
|
|
2933
|
+
);
|
|
2934
|
+
}
|
|
2935
|
+
if (!Array.isArray(entry.actions) || entry.actions.length === 0) {
|
|
2936
|
+
throw new ManifestValidationError(
|
|
2937
|
+
`${path}.actions must be a non-empty array`
|
|
2938
|
+
);
|
|
2939
|
+
}
|
|
2940
|
+
if (entry.expiry !== void 0) {
|
|
2941
|
+
parseExpiry(entry.expiry);
|
|
2942
|
+
}
|
|
2943
|
+
}
|
|
2944
|
+
function normalizeDefaults(value) {
|
|
2945
|
+
if (value === void 0) {
|
|
2946
|
+
return DEFAULT_DEFAULTS;
|
|
2947
|
+
}
|
|
2948
|
+
if (typeof value === "boolean") {
|
|
2949
|
+
return value;
|
|
2950
|
+
}
|
|
2951
|
+
if (typeof value !== "string") {
|
|
2952
|
+
return true;
|
|
2953
|
+
}
|
|
2954
|
+
const normalized = value.trim().toLowerCase();
|
|
2955
|
+
if (normalized === "admin" || normalized === "all") {
|
|
2956
|
+
return normalized;
|
|
2957
|
+
}
|
|
2958
|
+
return true;
|
|
2959
|
+
}
|
|
2960
|
+
function defaultEntriesForTier(tier) {
|
|
2961
|
+
if (tier === false) {
|
|
2962
|
+
return [];
|
|
2963
|
+
}
|
|
2964
|
+
const source = tier === "admin" ? DEFAULT_ADMIN_ENTRIES : tier === "all" ? DEFAULT_ALL_ENTRIES : DEFAULT_STANDARD_ENTRIES;
|
|
2965
|
+
return source.map((e) => ({
|
|
2966
|
+
service: e.service,
|
|
2967
|
+
space: e.space,
|
|
2968
|
+
path: e.path,
|
|
2969
|
+
actions: [...e.actions]
|
|
2970
|
+
}));
|
|
2971
|
+
}
|
|
2972
|
+
function resolveManifest(input) {
|
|
2973
|
+
const manifest = validateManifest(input);
|
|
2974
|
+
const prefix = manifest.prefix !== void 0 ? manifest.prefix : manifest.id;
|
|
2975
|
+
const expiryMs = parseExpiry(manifest.expiry ?? DEFAULT_EXPIRY);
|
|
2976
|
+
const includePublicSpace = manifest.includePublicSpace ?? true;
|
|
2977
|
+
const tier = normalizeDefaults(manifest.defaults);
|
|
2978
|
+
const defaultEntries = defaultEntriesForTier(tier);
|
|
2979
|
+
const explicitEntries = manifest.permissions ?? [];
|
|
2980
|
+
const allEntries = [...defaultEntries, ...explicitEntries];
|
|
2981
|
+
const resources = allEntries.map(
|
|
2982
|
+
(entry) => resolveEntry(entry, prefix, expiryMs)
|
|
2983
|
+
);
|
|
2984
|
+
const additionalDelegates = (manifest.delegations ?? []).map((d) => ({
|
|
2985
|
+
did: d.to,
|
|
2986
|
+
name: d.name,
|
|
2987
|
+
expiryMs: parseExpiry(d.expiry ?? manifest.expiry ?? DEFAULT_EXPIRY),
|
|
2988
|
+
permissions: d.permissions.map(
|
|
2989
|
+
(entry) => resolveEntry(
|
|
2990
|
+
entry,
|
|
2991
|
+
prefix,
|
|
2992
|
+
parseExpiry(d.expiry ?? manifest.expiry ?? DEFAULT_EXPIRY)
|
|
2993
|
+
)
|
|
2994
|
+
)
|
|
2995
|
+
}));
|
|
2996
|
+
return {
|
|
2997
|
+
id: manifest.id,
|
|
2998
|
+
resources,
|
|
2999
|
+
expiryMs,
|
|
3000
|
+
includePublicSpace,
|
|
3001
|
+
additionalDelegates
|
|
3002
|
+
};
|
|
3003
|
+
}
|
|
3004
|
+
function resolveEntry(entry, prefix, _inheritedExpiryMs) {
|
|
3005
|
+
const resolvedPath = applyPrefix(
|
|
3006
|
+
prefix,
|
|
3007
|
+
entry.path,
|
|
3008
|
+
entry.skipPrefix === true
|
|
3009
|
+
);
|
|
3010
|
+
const resolvedActions = expandActionShortNames(entry.service, entry.actions);
|
|
3011
|
+
const entryExpiryMs = entry.expiry !== void 0 ? parseExpiry(entry.expiry) : void 0;
|
|
3012
|
+
return {
|
|
3013
|
+
service: entry.service,
|
|
3014
|
+
space: entry.space,
|
|
3015
|
+
path: resolvedPath,
|
|
3016
|
+
actions: resolvedActions,
|
|
3017
|
+
// Only populate `expiryMs` when the entry had its own expiry override.
|
|
3018
|
+
// When absent, callers use the parent (delegation or manifest) expiry
|
|
3019
|
+
// which is carried on ResolvedDelegate.expiryMs / ResolvedCapabilities.expiryMs.
|
|
3020
|
+
...entryExpiryMs !== void 0 ? { expiryMs: entryExpiryMs } : {}
|
|
3021
|
+
};
|
|
3022
|
+
}
|
|
3023
|
+
function resourceCapabilitiesToAbilitiesMap(resources) {
|
|
3024
|
+
const out = {};
|
|
3025
|
+
for (const r of resources) {
|
|
3026
|
+
const shortService = SERVICE_LONG_TO_SHORT[r.service];
|
|
3027
|
+
if (shortService === void 0) {
|
|
3028
|
+
throw new ManifestValidationError(
|
|
3029
|
+
`unknown service '${r.service}' \u2014 no short-form mapping. Known services: ${Object.keys(SERVICE_LONG_TO_SHORT).join(", ")}`
|
|
3030
|
+
);
|
|
3031
|
+
}
|
|
3032
|
+
if (out[shortService] === void 0) {
|
|
3033
|
+
out[shortService] = {};
|
|
3034
|
+
}
|
|
3035
|
+
const pathsMap = out[shortService];
|
|
3036
|
+
const existing = pathsMap[r.path];
|
|
3037
|
+
if (existing === void 0) {
|
|
3038
|
+
pathsMap[r.path] = [...r.actions];
|
|
3039
|
+
} else {
|
|
3040
|
+
const seen = new Set(existing);
|
|
3041
|
+
for (const action of r.actions) {
|
|
3042
|
+
if (!seen.has(action)) {
|
|
3043
|
+
existing.push(action);
|
|
3044
|
+
seen.add(action);
|
|
3045
|
+
}
|
|
3046
|
+
}
|
|
3047
|
+
}
|
|
3048
|
+
}
|
|
3049
|
+
return out;
|
|
3050
|
+
}
|
|
3051
|
+
function manifestAbilitiesUnion(resolved) {
|
|
3052
|
+
const all = [...resolved.resources];
|
|
3053
|
+
for (const delegate of resolved.additionalDelegates) {
|
|
3054
|
+
for (const perm of delegate.permissions) {
|
|
3055
|
+
all.push(perm);
|
|
3056
|
+
}
|
|
3057
|
+
}
|
|
3058
|
+
return resourceCapabilitiesToAbilitiesMap(all);
|
|
3059
|
+
}
|
|
3060
|
+
|
|
2680
3061
|
// src/delegations/SharingService.ts
|
|
3062
|
+
function inferShortServiceFromActionUrns(actions) {
|
|
3063
|
+
let short;
|
|
3064
|
+
for (const action of actions) {
|
|
3065
|
+
const slash = action.indexOf("/");
|
|
3066
|
+
if (slash === -1) return void 0;
|
|
3067
|
+
const longService = action.slice(0, slash);
|
|
3068
|
+
const candidate = SERVICE_LONG_TO_SHORT[longService];
|
|
3069
|
+
if (candidate === void 0) return void 0;
|
|
3070
|
+
if (short === void 0) {
|
|
3071
|
+
short = candidate;
|
|
3072
|
+
} else if (short !== candidate) {
|
|
3073
|
+
return void 0;
|
|
3074
|
+
}
|
|
3075
|
+
}
|
|
3076
|
+
return short;
|
|
3077
|
+
}
|
|
2681
3078
|
var DEFAULT_READ_ACTIONS = ["tinycloud.kv/get", "tinycloud.kv/metadata"];
|
|
2682
3079
|
var DEFAULT_EXPIRY_MS = 24 * 60 * 60 * 1e3;
|
|
2683
3080
|
var BASE64_PREFIX = "tc1:";
|
|
@@ -3021,12 +3418,34 @@ var SharingService = class {
|
|
|
3021
3418
|
}
|
|
3022
3419
|
if (this.createDelegationWasmFn) {
|
|
3023
3420
|
try {
|
|
3421
|
+
if (actions.length === 0) {
|
|
3422
|
+
return {
|
|
3423
|
+
ok: false,
|
|
3424
|
+
error: createError2(
|
|
3425
|
+
DelegationErrorCodes.VALIDATION_ERROR,
|
|
3426
|
+
"createDelegation requires at least one action"
|
|
3427
|
+
)
|
|
3428
|
+
};
|
|
3429
|
+
}
|
|
3430
|
+
const shortService = inferShortServiceFromActionUrns(actions);
|
|
3431
|
+
if (shortService === void 0) {
|
|
3432
|
+
return {
|
|
3433
|
+
ok: false,
|
|
3434
|
+
error: createError2(
|
|
3435
|
+
DelegationErrorCodes.VALIDATION_ERROR,
|
|
3436
|
+
`createDelegation: cannot infer service from actions ${JSON.stringify(actions)} \u2014 expected full URNs like "tinycloud.kv/get"`
|
|
3437
|
+
)
|
|
3438
|
+
};
|
|
3439
|
+
}
|
|
3024
3440
|
const wasmResult = this.createDelegationWasmFn({
|
|
3025
3441
|
session: this.session,
|
|
3026
3442
|
delegateDID,
|
|
3027
3443
|
spaceId: this.session.spaceId,
|
|
3028
|
-
|
|
3029
|
-
|
|
3444
|
+
abilities: {
|
|
3445
|
+
[shortService]: {
|
|
3446
|
+
[path]: [...actions]
|
|
3447
|
+
}
|
|
3448
|
+
},
|
|
3030
3449
|
expirationSecs: Math.floor(expiry.getTime() / 1e3)
|
|
3031
3450
|
});
|
|
3032
3451
|
const registerRes = await this.fetchFn(`${this.host}/delegate`, {
|
|
@@ -3045,12 +3464,22 @@ var SharingService = class {
|
|
|
3045
3464
|
)
|
|
3046
3465
|
};
|
|
3047
3466
|
}
|
|
3467
|
+
if (wasmResult.resources.length === 0) {
|
|
3468
|
+
return {
|
|
3469
|
+
ok: false,
|
|
3470
|
+
error: createError2(
|
|
3471
|
+
DelegationErrorCodes.CREATION_FAILED,
|
|
3472
|
+
"createDelegation WASM returned empty resources array for a single-entry request"
|
|
3473
|
+
)
|
|
3474
|
+
};
|
|
3475
|
+
}
|
|
3476
|
+
const primary = wasmResult.resources[0];
|
|
3048
3477
|
return {
|
|
3049
3478
|
cid: wasmResult.cid,
|
|
3050
3479
|
delegateDID: wasmResult.delegateDID,
|
|
3051
3480
|
spaceId: this.session.spaceId,
|
|
3052
|
-
path:
|
|
3053
|
-
actions:
|
|
3481
|
+
path: primary.path,
|
|
3482
|
+
actions: primary.actions,
|
|
3054
3483
|
expiry: wasmResult.expiry,
|
|
3055
3484
|
isRevoked: false,
|
|
3056
3485
|
authHeader: wasmResult.delegation,
|
|
@@ -3779,12 +4208,113 @@ async function checkNodeInfo(host, sdkProtocol, fetchFn = globalThis.fetch.bind(
|
|
|
3779
4208
|
quotaUrl: data.quota_url
|
|
3780
4209
|
};
|
|
3781
4210
|
}
|
|
4211
|
+
|
|
4212
|
+
// src/capabilities.ts
|
|
4213
|
+
var PermissionNotInManifestError = class extends Error {
|
|
4214
|
+
constructor(missing, granted) {
|
|
4215
|
+
super(
|
|
4216
|
+
`Requested capabilities exceed current session. Missing ${missing.length} entries.`
|
|
4217
|
+
);
|
|
4218
|
+
this.name = "PermissionNotInManifestError";
|
|
4219
|
+
this.missing = missing;
|
|
4220
|
+
this.granted = granted;
|
|
4221
|
+
}
|
|
4222
|
+
};
|
|
4223
|
+
var SessionExpiredError = class extends Error {
|
|
4224
|
+
constructor(expiredAt) {
|
|
4225
|
+
super(`Session expired at ${expiredAt.toISOString()}`);
|
|
4226
|
+
this.name = "SessionExpiredError";
|
|
4227
|
+
this.expiredAt = expiredAt;
|
|
4228
|
+
}
|
|
4229
|
+
};
|
|
4230
|
+
function isCapabilitySubset(requested, granted) {
|
|
4231
|
+
const missing = [];
|
|
4232
|
+
for (const req of requested) {
|
|
4233
|
+
const match = granted.find((g) => canonicalizeEntryMatches(req, g));
|
|
4234
|
+
if (match === void 0) {
|
|
4235
|
+
missing.push(cloneEntry(req));
|
|
4236
|
+
continue;
|
|
4237
|
+
}
|
|
4238
|
+
}
|
|
4239
|
+
return { subset: missing.length === 0, missing };
|
|
4240
|
+
}
|
|
4241
|
+
function canonicalizeEntryMatches(requested, granted) {
|
|
4242
|
+
if (requested.service !== granted.service) {
|
|
4243
|
+
return false;
|
|
4244
|
+
}
|
|
4245
|
+
if (requested.space !== granted.space) {
|
|
4246
|
+
return false;
|
|
4247
|
+
}
|
|
4248
|
+
if (!pathContains(granted.path, requested.path)) {
|
|
4249
|
+
return false;
|
|
4250
|
+
}
|
|
4251
|
+
const reqActions = new Set(
|
|
4252
|
+
expandActionShortNames(requested.service, requested.actions)
|
|
4253
|
+
);
|
|
4254
|
+
const grantedActions = new Set(
|
|
4255
|
+
expandActionShortNames(granted.service, granted.actions)
|
|
4256
|
+
);
|
|
4257
|
+
for (const a of reqActions) {
|
|
4258
|
+
if (!grantedActions.has(a)) {
|
|
4259
|
+
return false;
|
|
4260
|
+
}
|
|
4261
|
+
}
|
|
4262
|
+
return true;
|
|
4263
|
+
}
|
|
4264
|
+
function pathContains(grantedPath, requestedPath) {
|
|
4265
|
+
if (grantedPath === "" || grantedPath === "/") {
|
|
4266
|
+
return true;
|
|
4267
|
+
}
|
|
4268
|
+
if (grantedPath.endsWith("/")) {
|
|
4269
|
+
return requestedPath.startsWith(grantedPath);
|
|
4270
|
+
}
|
|
4271
|
+
return requestedPath === grantedPath;
|
|
4272
|
+
}
|
|
4273
|
+
function cloneEntry(entry) {
|
|
4274
|
+
return {
|
|
4275
|
+
service: entry.service,
|
|
4276
|
+
space: entry.space,
|
|
4277
|
+
path: entry.path,
|
|
4278
|
+
actions: [...entry.actions],
|
|
4279
|
+
...entry.skipPrefix !== void 0 ? { skipPrefix: entry.skipPrefix } : {},
|
|
4280
|
+
...entry.expiry !== void 0 ? { expiry: entry.expiry } : {}
|
|
4281
|
+
};
|
|
4282
|
+
}
|
|
4283
|
+
function parseRecapCapabilities(parseWasm, siwe) {
|
|
4284
|
+
const raw = parseWasm(siwe);
|
|
4285
|
+
if (!Array.isArray(raw)) {
|
|
4286
|
+
throw new Error(
|
|
4287
|
+
"parseRecapFromSiwe returned a non-array value; wasm binding may be out of sync"
|
|
4288
|
+
);
|
|
4289
|
+
}
|
|
4290
|
+
const normalized = raw.map((entry) => {
|
|
4291
|
+
const longService = SERVICE_SHORT_TO_LONG[entry.service] ?? // Unknown short names pass through. If the recap already contained a
|
|
4292
|
+
// long-form service (e.g. a future tinycloud-node version emits long
|
|
4293
|
+
// form directly), don't double-prefix.
|
|
4294
|
+
(entry.service.startsWith("tinycloud.") ? entry.service : `tinycloud.${entry.service}`);
|
|
4295
|
+
return {
|
|
4296
|
+
service: longService,
|
|
4297
|
+
space: entry.space,
|
|
4298
|
+
path: entry.path,
|
|
4299
|
+
actions: [...entry.actions]
|
|
4300
|
+
};
|
|
4301
|
+
});
|
|
4302
|
+
normalized.sort((a, b) => {
|
|
4303
|
+
if (a.space !== b.space) return a.space < b.space ? -1 : 1;
|
|
4304
|
+
if (a.service !== b.service) return a.service < b.service ? -1 : 1;
|
|
4305
|
+
if (a.path !== b.path) return a.path < b.path ? -1 : 1;
|
|
4306
|
+
return 0;
|
|
4307
|
+
});
|
|
4308
|
+
return normalized;
|
|
4309
|
+
}
|
|
3782
4310
|
// Annotate the CommonJS export names for ESM import in node:
|
|
3783
4311
|
0 && (module.exports = {
|
|
3784
4312
|
AutoApproveSpaceCreationHandler,
|
|
3785
4313
|
CapabilityKeyRegistry,
|
|
3786
4314
|
CapabilityKeyRegistryErrorCodes,
|
|
3787
4315
|
ClientSessionSchema,
|
|
4316
|
+
DEFAULT_DEFAULTS,
|
|
4317
|
+
DEFAULT_EXPIRY,
|
|
3788
4318
|
DataVaultService,
|
|
3789
4319
|
DatabaseHandle,
|
|
3790
4320
|
DelegationErrorCodes,
|
|
@@ -3796,11 +4326,16 @@ async function checkNodeInfo(host, sdkProtocol, fetchFn = globalThis.fetch.bind(
|
|
|
3796
4326
|
ErrorCodes,
|
|
3797
4327
|
HooksService,
|
|
3798
4328
|
KVService,
|
|
4329
|
+
ManifestValidationError,
|
|
4330
|
+
PermissionNotInManifestError,
|
|
3799
4331
|
PrefixedKVService,
|
|
3800
4332
|
ProtocolMismatchError,
|
|
4333
|
+
SERVICE_LONG_TO_SHORT,
|
|
4334
|
+
SERVICE_SHORT_TO_LONG,
|
|
3801
4335
|
SQLAction,
|
|
3802
4336
|
SQLService,
|
|
3803
4337
|
ServiceContext,
|
|
4338
|
+
SessionExpiredError,
|
|
3804
4339
|
SharingService,
|
|
3805
4340
|
SilentNotificationHandler,
|
|
3806
4341
|
SiweConfigSchema,
|
|
@@ -3814,6 +4349,7 @@ async function checkNodeInfo(host, sdkProtocol, fetchFn = globalThis.fetch.bind(
|
|
|
3814
4349
|
VaultPublicSpaceKVActions,
|
|
3815
4350
|
VersionCheckError,
|
|
3816
4351
|
activateSessionWithHost,
|
|
4352
|
+
applyPrefix,
|
|
3817
4353
|
buildSpaceUri,
|
|
3818
4354
|
checkNodeInfo,
|
|
3819
4355
|
createCapabilityKeyRegistry,
|
|
@@ -3824,13 +4360,23 @@ async function checkNodeInfo(host, sdkProtocol, fetchFn = globalThis.fetch.bind(
|
|
|
3824
4360
|
defaultSignStrategy,
|
|
3825
4361
|
defaultSpaceCreationHandler,
|
|
3826
4362
|
err,
|
|
4363
|
+
expandActionShortNames,
|
|
3827
4364
|
fetchPeerId,
|
|
4365
|
+
isCapabilitySubset,
|
|
4366
|
+
loadManifest,
|
|
3828
4367
|
makePublicSpaceId,
|
|
4368
|
+
manifestAbilitiesUnion,
|
|
4369
|
+
normalizeDefaults,
|
|
3829
4370
|
ok,
|
|
4371
|
+
parseExpiry,
|
|
4372
|
+
parseRecapCapabilities,
|
|
3830
4373
|
parseSpaceUri,
|
|
4374
|
+
resolveManifest,
|
|
4375
|
+
resourceCapabilitiesToAbilitiesMap,
|
|
3831
4376
|
serviceError,
|
|
3832
4377
|
submitHostDelegation,
|
|
3833
4378
|
validateClientSession,
|
|
4379
|
+
validateManifest,
|
|
3834
4380
|
validatePersistedSessionData
|
|
3835
4381
|
});
|
|
3836
4382
|
//# sourceMappingURL=index.cjs.map
|