@tinycloud/sdk-core 2.2.0-beta.6 → 2.2.0-beta.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/index.cjs +259 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +93 -44
- package/dist/index.d.ts +93 -44
- package/dist/index.js +257 -8
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -154,6 +154,7 @@ var Space = class {
|
|
|
154
154
|
this._id = config.id;
|
|
155
155
|
this._name = config.name;
|
|
156
156
|
this._kv = config.createKV(config.id);
|
|
157
|
+
this._vault = config.createVault(config.id);
|
|
157
158
|
this._delegations = config.createDelegations(config.id);
|
|
158
159
|
this._sharing = config.createSharing(config.id);
|
|
159
160
|
this._getInfo = config.getInfo;
|
|
@@ -176,6 +177,12 @@ var Space = class {
|
|
|
176
177
|
get kv() {
|
|
177
178
|
return this._kv;
|
|
178
179
|
}
|
|
180
|
+
/**
|
|
181
|
+
* Data Vault operations scoped to this space.
|
|
182
|
+
*/
|
|
183
|
+
get vault() {
|
|
184
|
+
return this._vault;
|
|
185
|
+
}
|
|
179
186
|
/**
|
|
180
187
|
* Delegation operations scoped to this space.
|
|
181
188
|
*/
|
|
@@ -559,6 +566,8 @@ var SpaceConfigSchema = z4.object({
|
|
|
559
566
|
name: z4.string(),
|
|
560
567
|
/** Factory function to create a space-scoped KV service */
|
|
561
568
|
createKV: z4.function(),
|
|
569
|
+
/** Factory function to create a space-scoped Data Vault service */
|
|
570
|
+
createVault: z4.function(),
|
|
562
571
|
/** Factory function to create space-scoped delegations */
|
|
563
572
|
createDelegations: z4.function(),
|
|
564
573
|
/** Factory function to create space-scoped sharing */
|
|
@@ -579,6 +588,8 @@ var SpaceServiceConfigSchema = z4.object({
|
|
|
579
588
|
capabilityRegistry: z4.unknown().optional(),
|
|
580
589
|
/** Factory function to create a space-scoped KV service */
|
|
581
590
|
createKVService: z4.function().optional(),
|
|
591
|
+
/** Factory function to create a space-scoped Data Vault service */
|
|
592
|
+
createVaultService: z4.function().optional(),
|
|
582
593
|
/** User's PKH DID (derived from address or provided explicitly) */
|
|
583
594
|
userDid: z4.string().optional(),
|
|
584
595
|
/** Optional SharingService for v2 sharing links (client-side) */
|
|
@@ -820,6 +831,7 @@ var SpaceService = class {
|
|
|
820
831
|
this.fetchFn = config.fetch ?? globalThis.fetch.bind(globalThis);
|
|
821
832
|
this.capabilityRegistry = config.capabilityRegistry;
|
|
822
833
|
this.createKVServiceFn = config.createKVService;
|
|
834
|
+
this.createVaultServiceFn = config.createVaultService;
|
|
823
835
|
this._userDid = config.userDid;
|
|
824
836
|
this.sharingService = config.sharingService;
|
|
825
837
|
this.createDelegationFn = config.createDelegation;
|
|
@@ -834,6 +846,7 @@ var SpaceService = class {
|
|
|
834
846
|
if (config.fetch) this.fetchFn = config.fetch;
|
|
835
847
|
if (config.capabilityRegistry) this.capabilityRegistry = config.capabilityRegistry;
|
|
836
848
|
if (config.createKVService) this.createKVServiceFn = config.createKVService;
|
|
849
|
+
if (config.createVaultService) this.createVaultServiceFn = config.createVaultService;
|
|
837
850
|
if (config.userDid !== void 0) this._userDid = config.userDid;
|
|
838
851
|
if (config.sharingService) this.sharingService = config.sharingService;
|
|
839
852
|
if (config.createDelegation) this.createDelegationFn = config.createDelegation;
|
|
@@ -1116,6 +1129,7 @@ var SpaceService = class {
|
|
|
1116
1129
|
id: spaceId,
|
|
1117
1130
|
name,
|
|
1118
1131
|
createKV: this.createSpaceScopedKV.bind(this),
|
|
1132
|
+
createVault: this.createSpaceScopedVault.bind(this),
|
|
1119
1133
|
createDelegations: this.createSpaceScopedDelegations.bind(this),
|
|
1120
1134
|
createSharing: this.createSpaceScopedSharing.bind(this),
|
|
1121
1135
|
getInfo: this.getSpaceInfo.bind(this)
|
|
@@ -1245,6 +1259,21 @@ var SpaceService = class {
|
|
|
1245
1259
|
}
|
|
1246
1260
|
});
|
|
1247
1261
|
}
|
|
1262
|
+
/**
|
|
1263
|
+
* Create a space-scoped Data Vault service.
|
|
1264
|
+
*/
|
|
1265
|
+
createSpaceScopedVault(spaceId) {
|
|
1266
|
+
if (this.createVaultServiceFn) {
|
|
1267
|
+
return this.createVaultServiceFn(spaceId);
|
|
1268
|
+
}
|
|
1269
|
+
return new Proxy({}, {
|
|
1270
|
+
get: () => {
|
|
1271
|
+
throw new Error(
|
|
1272
|
+
"Vault service factory not configured. Provide createVaultService in SpaceServiceConfig."
|
|
1273
|
+
);
|
|
1274
|
+
}
|
|
1275
|
+
});
|
|
1276
|
+
}
|
|
1248
1277
|
/**
|
|
1249
1278
|
* Create space-scoped delegation operations.
|
|
1250
1279
|
*/
|
|
@@ -1989,7 +2018,8 @@ import {
|
|
|
1989
2018
|
DataVaultService,
|
|
1990
2019
|
VaultHeaders,
|
|
1991
2020
|
VaultPublicSpaceKVActions,
|
|
1992
|
-
createVaultCrypto
|
|
2021
|
+
createVaultCrypto,
|
|
2022
|
+
SecretsService
|
|
1993
2023
|
} from "@tinycloud/sdk-services";
|
|
1994
2024
|
|
|
1995
2025
|
// src/space.ts
|
|
@@ -2670,6 +2700,9 @@ var DEFAULT_MANIFEST_VERSION = 1;
|
|
|
2670
2700
|
var DEFAULT_MANIFEST_SPACE = "applications";
|
|
2671
2701
|
var ACCOUNT_REGISTRY_SPACE = "account";
|
|
2672
2702
|
var ACCOUNT_REGISTRY_PATH = "applications/";
|
|
2703
|
+
var SECRETS_SPACE = "secrets";
|
|
2704
|
+
var SECRET_NAME_RE = /^[A-Z][A-Z0-9_]*$/;
|
|
2705
|
+
var VAULT_PERMISSION_SERVICE = "tinycloud.vault";
|
|
2673
2706
|
var SERVICE_SHORT_TO_LONG = Object.freeze({
|
|
2674
2707
|
kv: "tinycloud.kv",
|
|
2675
2708
|
sql: "tinycloud.sql",
|
|
@@ -2752,6 +2785,20 @@ function expandActionShortNames(service, actions) {
|
|
|
2752
2785
|
return `${service}/${a}`;
|
|
2753
2786
|
});
|
|
2754
2787
|
}
|
|
2788
|
+
function expandPermissionEntry(entry) {
|
|
2789
|
+
if (entry.service !== VAULT_PERMISSION_SERVICE) {
|
|
2790
|
+
return [
|
|
2791
|
+
{
|
|
2792
|
+
...entry,
|
|
2793
|
+
actions: expandActionShortNames(entry.service, entry.actions)
|
|
2794
|
+
}
|
|
2795
|
+
];
|
|
2796
|
+
}
|
|
2797
|
+
return expandVaultPermissionEntry(entry);
|
|
2798
|
+
}
|
|
2799
|
+
function expandPermissionEntries(entries) {
|
|
2800
|
+
return entries.flatMap(expandPermissionEntry);
|
|
2801
|
+
}
|
|
2755
2802
|
function applyPrefix(prefix, path, skipPrefix) {
|
|
2756
2803
|
if (skipPrefix) {
|
|
2757
2804
|
return path;
|
|
@@ -2823,8 +2870,39 @@ function validateManifest(input) {
|
|
|
2823
2870
|
(p, i) => validatePermissionEntry(p, `permissions[${i}]`)
|
|
2824
2871
|
);
|
|
2825
2872
|
}
|
|
2873
|
+
if (m.secrets !== void 0) {
|
|
2874
|
+
validateManifestSecrets(m.secrets);
|
|
2875
|
+
}
|
|
2826
2876
|
return m;
|
|
2827
2877
|
}
|
|
2878
|
+
function validateManifestSecrets(secrets) {
|
|
2879
|
+
if (secrets === null || typeof secrets !== "object" || Array.isArray(secrets)) {
|
|
2880
|
+
throw new ManifestValidationError("manifest.secrets must be an object");
|
|
2881
|
+
}
|
|
2882
|
+
for (const [name, spec] of Object.entries(secrets)) {
|
|
2883
|
+
if (!SECRET_NAME_RE.test(name)) {
|
|
2884
|
+
throw new ManifestValidationError(
|
|
2885
|
+
`manifest.secrets.${name} must match ${SECRET_NAME_RE.source}`
|
|
2886
|
+
);
|
|
2887
|
+
}
|
|
2888
|
+
const actions = secretActionsFromSpec(name, spec);
|
|
2889
|
+
if (actions.length === 0) {
|
|
2890
|
+
throw new ManifestValidationError(
|
|
2891
|
+
`manifest.secrets.${name} actions must be non-empty`
|
|
2892
|
+
);
|
|
2893
|
+
}
|
|
2894
|
+
for (const action of actions) {
|
|
2895
|
+
if (typeof action !== "string" || action.length === 0) {
|
|
2896
|
+
throw new ManifestValidationError(
|
|
2897
|
+
`manifest.secrets.${name} actions must be non-empty strings`
|
|
2898
|
+
);
|
|
2899
|
+
}
|
|
2900
|
+
}
|
|
2901
|
+
if (spec !== null && typeof spec === "object" && !Array.isArray(spec) && spec.expiry !== void 0) {
|
|
2902
|
+
parseExpiry(spec.expiry);
|
|
2903
|
+
}
|
|
2904
|
+
}
|
|
2905
|
+
}
|
|
2828
2906
|
function validatePermissionEntry(p, path) {
|
|
2829
2907
|
if (p === null || typeof p !== "object") {
|
|
2830
2908
|
throw new ManifestValidationError(`${path} must be an object`);
|
|
@@ -2848,6 +2926,16 @@ function validatePermissionEntry(p, path) {
|
|
|
2848
2926
|
`${path}.actions must be a non-empty array`
|
|
2849
2927
|
);
|
|
2850
2928
|
}
|
|
2929
|
+
for (const action of entry.actions) {
|
|
2930
|
+
if (typeof action !== "string" || action.length === 0) {
|
|
2931
|
+
throw new ManifestValidationError(
|
|
2932
|
+
`${path}.actions must contain non-empty strings`
|
|
2933
|
+
);
|
|
2934
|
+
}
|
|
2935
|
+
if (entry.service === VAULT_PERMISSION_SERVICE) {
|
|
2936
|
+
vaultActionExpansion(action);
|
|
2937
|
+
}
|
|
2938
|
+
}
|
|
2851
2939
|
if (entry.expiry !== void 0) {
|
|
2852
2940
|
parseExpiry(entry.expiry);
|
|
2853
2941
|
}
|
|
@@ -2890,9 +2978,14 @@ function resolveManifest(input) {
|
|
|
2890
2978
|
const tier = normalizeDefaults(manifest.defaults);
|
|
2891
2979
|
const defaultEntries = defaultEntriesForTier(tier);
|
|
2892
2980
|
const explicitEntries = manifest.permissions ?? [];
|
|
2893
|
-
const
|
|
2981
|
+
const secretEntries = secretEntriesForManifest(manifest.secrets);
|
|
2982
|
+
const allEntries = [
|
|
2983
|
+
...defaultEntries,
|
|
2984
|
+
...explicitEntries,
|
|
2985
|
+
...secretEntries
|
|
2986
|
+
];
|
|
2894
2987
|
const resources = withCapabilitiesReadForSpaces(
|
|
2895
|
-
allEntries.
|
|
2988
|
+
allEntries.flatMap((entry) => resolveEntry(entry, prefix, expiryMs, space))
|
|
2896
2989
|
);
|
|
2897
2990
|
const additionalDelegates = manifest.did === void 0 ? [] : [
|
|
2898
2991
|
{
|
|
@@ -2912,25 +3005,177 @@ function resolveManifest(input) {
|
|
|
2912
3005
|
additionalDelegates
|
|
2913
3006
|
};
|
|
2914
3007
|
}
|
|
3008
|
+
function normalizeSecretActions(actions) {
|
|
3009
|
+
const out = [];
|
|
3010
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3011
|
+
const add = (action) => {
|
|
3012
|
+
if (!seen.has(action)) {
|
|
3013
|
+
out.push(action);
|
|
3014
|
+
seen.add(action);
|
|
3015
|
+
}
|
|
3016
|
+
};
|
|
3017
|
+
for (const action of actions) {
|
|
3018
|
+
if (action === "read") {
|
|
3019
|
+
add("get");
|
|
3020
|
+
continue;
|
|
3021
|
+
}
|
|
3022
|
+
if (action === "write") {
|
|
3023
|
+
add("put");
|
|
3024
|
+
continue;
|
|
3025
|
+
}
|
|
3026
|
+
if (action === "delete") {
|
|
3027
|
+
add("del");
|
|
3028
|
+
continue;
|
|
3029
|
+
}
|
|
3030
|
+
if (action === "get" || action === "put" || action === "del" || action === "list" || action === "metadata") {
|
|
3031
|
+
add(action);
|
|
3032
|
+
continue;
|
|
3033
|
+
}
|
|
3034
|
+
if (action === "tinycloud.kv/get" || action === "tinycloud.kv/put" || action === "tinycloud.kv/del" || action === "tinycloud.kv/list" || action === "tinycloud.kv/metadata") {
|
|
3035
|
+
add(action);
|
|
3036
|
+
continue;
|
|
3037
|
+
}
|
|
3038
|
+
throw new ManifestValidationError(
|
|
3039
|
+
`unknown secret action ${JSON.stringify(action)}; expected read, write, delete, list, or metadata`
|
|
3040
|
+
);
|
|
3041
|
+
}
|
|
3042
|
+
return out;
|
|
3043
|
+
}
|
|
3044
|
+
function secretActionsFromSpec(name, spec) {
|
|
3045
|
+
if (spec === true) {
|
|
3046
|
+
return ["read"];
|
|
3047
|
+
}
|
|
3048
|
+
if (typeof spec === "string") {
|
|
3049
|
+
return [spec];
|
|
3050
|
+
}
|
|
3051
|
+
if (Array.isArray(spec)) {
|
|
3052
|
+
return spec;
|
|
3053
|
+
}
|
|
3054
|
+
if (spec === null || typeof spec !== "object") {
|
|
3055
|
+
throw new ManifestValidationError(
|
|
3056
|
+
`manifest.secrets.${name} must be true, a string action, an actions array, or an object`
|
|
3057
|
+
);
|
|
3058
|
+
}
|
|
3059
|
+
if (spec.actions === void 0) {
|
|
3060
|
+
return ["read"];
|
|
3061
|
+
}
|
|
3062
|
+
if (typeof spec.actions === "string") {
|
|
3063
|
+
return [spec.actions];
|
|
3064
|
+
}
|
|
3065
|
+
if (Array.isArray(spec.actions)) {
|
|
3066
|
+
return spec.actions;
|
|
3067
|
+
}
|
|
3068
|
+
throw new ManifestValidationError(
|
|
3069
|
+
`manifest.secrets.${name}.actions must be a string or array`
|
|
3070
|
+
);
|
|
3071
|
+
}
|
|
3072
|
+
function secretEntriesForManifest(secrets) {
|
|
3073
|
+
if (secrets === void 0) {
|
|
3074
|
+
return [];
|
|
3075
|
+
}
|
|
3076
|
+
const entries = [];
|
|
3077
|
+
for (const [name, spec] of Object.entries(secrets)) {
|
|
3078
|
+
const actions = secretActionsFromSpec(name, spec);
|
|
3079
|
+
const extra = spec !== true && typeof spec === "object" && !Array.isArray(spec) ? spec : {};
|
|
3080
|
+
for (const base of ["keys", "vault"]) {
|
|
3081
|
+
entries.push({
|
|
3082
|
+
service: "tinycloud.kv",
|
|
3083
|
+
space: SECRETS_SPACE,
|
|
3084
|
+
path: `${base}/secrets/${name}`,
|
|
3085
|
+
actions: normalizeSecretActions(actions),
|
|
3086
|
+
skipPrefix: true,
|
|
3087
|
+
...extra.expiry !== void 0 ? { expiry: extra.expiry } : {},
|
|
3088
|
+
...extra.description !== void 0 ? { description: extra.description } : {}
|
|
3089
|
+
});
|
|
3090
|
+
}
|
|
3091
|
+
}
|
|
3092
|
+
return entries;
|
|
3093
|
+
}
|
|
2915
3094
|
function resolveEntry(entry, prefix, _inheritedExpiryMs, inheritedSpace) {
|
|
2916
3095
|
const resolvedPath = applyPrefix(
|
|
2917
3096
|
prefix,
|
|
2918
3097
|
entry.path,
|
|
2919
3098
|
entry.skipPrefix === true
|
|
2920
3099
|
);
|
|
2921
|
-
const resolvedActions = expandActionShortNames(entry.service, entry.actions);
|
|
2922
3100
|
const entryExpiryMs = entry.expiry !== void 0 ? parseExpiry(entry.expiry) : void 0;
|
|
2923
|
-
return {
|
|
2924
|
-
|
|
3101
|
+
return expandPermissionEntry({
|
|
3102
|
+
...entry,
|
|
2925
3103
|
space: entry.space ?? inheritedSpace,
|
|
2926
3104
|
path: resolvedPath,
|
|
2927
|
-
|
|
3105
|
+
skipPrefix: true
|
|
3106
|
+
}).map((expanded) => ({
|
|
3107
|
+
service: expanded.service,
|
|
3108
|
+
space: expanded.space ?? inheritedSpace,
|
|
3109
|
+
path: expanded.path,
|
|
3110
|
+
actions: expanded.actions,
|
|
2928
3111
|
// Only populate `expiryMs` when the entry had its own expiry override.
|
|
2929
3112
|
// When absent, callers use the parent (delegation or manifest) expiry
|
|
2930
3113
|
// which is carried on ResolvedDelegate.expiryMs / ResolvedCapabilities.expiryMs.
|
|
2931
3114
|
...entryExpiryMs !== void 0 ? { expiryMs: entryExpiryMs } : {},
|
|
2932
3115
|
...entry.description !== void 0 ? { description: entry.description } : {}
|
|
2933
|
-
};
|
|
3116
|
+
}));
|
|
3117
|
+
}
|
|
3118
|
+
function expandVaultPermissionEntry(entry) {
|
|
3119
|
+
const byBase = /* @__PURE__ */ new Map();
|
|
3120
|
+
for (const action of entry.actions) {
|
|
3121
|
+
const expansion = vaultActionExpansion(action);
|
|
3122
|
+
for (const base of expansion.bases) {
|
|
3123
|
+
const actions = byBase.get(base) ?? [];
|
|
3124
|
+
if (!actions.includes(expansion.action)) {
|
|
3125
|
+
actions.push(expansion.action);
|
|
3126
|
+
}
|
|
3127
|
+
byBase.set(base, actions);
|
|
3128
|
+
}
|
|
3129
|
+
}
|
|
3130
|
+
return [...byBase.entries()].map(([base, actions]) => ({
|
|
3131
|
+
...entry,
|
|
3132
|
+
service: "tinycloud.kv",
|
|
3133
|
+
path: vaultKVPath(base, entry.path),
|
|
3134
|
+
actions,
|
|
3135
|
+
skipPrefix: true
|
|
3136
|
+
}));
|
|
3137
|
+
}
|
|
3138
|
+
function vaultActionExpansion(action) {
|
|
3139
|
+
const normalized = normalizeVaultAction(action);
|
|
3140
|
+
if (normalized === "read" || normalized === "get") {
|
|
3141
|
+
return { bases: ["keys", "vault"], action: "tinycloud.kv/get" };
|
|
3142
|
+
}
|
|
3143
|
+
if (normalized === "write" || normalized === "put") {
|
|
3144
|
+
return { bases: ["keys", "vault"], action: "tinycloud.kv/put" };
|
|
3145
|
+
}
|
|
3146
|
+
if (normalized === "delete" || normalized === "del") {
|
|
3147
|
+
return { bases: ["keys", "vault"], action: "tinycloud.kv/del" };
|
|
3148
|
+
}
|
|
3149
|
+
if (normalized === "list") {
|
|
3150
|
+
return { bases: ["vault"], action: "tinycloud.kv/list" };
|
|
3151
|
+
}
|
|
3152
|
+
if (normalized === "head") {
|
|
3153
|
+
return { bases: ["vault"], action: "tinycloud.kv/get" };
|
|
3154
|
+
}
|
|
3155
|
+
if (normalized === "metadata") {
|
|
3156
|
+
return { bases: ["vault"], action: "tinycloud.kv/metadata" };
|
|
3157
|
+
}
|
|
3158
|
+
throw new ManifestValidationError(
|
|
3159
|
+
`unknown vault action ${JSON.stringify(action)}; expected read, write, delete, get, put, del, list, head, or metadata`
|
|
3160
|
+
);
|
|
3161
|
+
}
|
|
3162
|
+
function normalizeVaultAction(action) {
|
|
3163
|
+
if (action.startsWith(`${VAULT_PERMISSION_SERVICE}/`)) {
|
|
3164
|
+
return action.slice(`${VAULT_PERMISSION_SERVICE}/`.length);
|
|
3165
|
+
}
|
|
3166
|
+
if (action.startsWith("tinycloud.kv/")) {
|
|
3167
|
+
return action.slice("tinycloud.kv/".length);
|
|
3168
|
+
}
|
|
3169
|
+
if (action.includes("/")) {
|
|
3170
|
+
throw new ManifestValidationError(
|
|
3171
|
+
`unknown vault action ${JSON.stringify(action)}; expected a tinycloud.vault or tinycloud.kv action`
|
|
3172
|
+
);
|
|
3173
|
+
}
|
|
3174
|
+
return action;
|
|
3175
|
+
}
|
|
3176
|
+
function vaultKVPath(base, path) {
|
|
3177
|
+
const normalized = path.startsWith("/") ? path.slice(1) : path;
|
|
3178
|
+
return `${base}/${normalized}`;
|
|
2934
3179
|
}
|
|
2935
3180
|
function cloneResourceCapability(entry) {
|
|
2936
3181
|
return {
|
|
@@ -4787,6 +5032,7 @@ export {
|
|
|
4787
5032
|
SERVICE_SHORT_TO_LONG,
|
|
4788
5033
|
SQLAction,
|
|
4789
5034
|
SQLService2 as SQLService,
|
|
5035
|
+
SecretsService,
|
|
4790
5036
|
ServiceContext2 as ServiceContext,
|
|
4791
5037
|
SessionExpiredError,
|
|
4792
5038
|
SharingService,
|
|
@@ -4798,6 +5044,7 @@ export {
|
|
|
4798
5044
|
SpaceService,
|
|
4799
5045
|
TinyCloud,
|
|
4800
5046
|
UnsupportedFeatureError,
|
|
5047
|
+
VAULT_PERMISSION_SERVICE,
|
|
4801
5048
|
VaultHeaders,
|
|
4802
5049
|
VaultPublicSpaceKVActions,
|
|
4803
5050
|
VersionCheckError,
|
|
@@ -4816,6 +5063,8 @@ export {
|
|
|
4816
5063
|
defaultSpaceCreationHandler,
|
|
4817
5064
|
err4 as err,
|
|
4818
5065
|
expandActionShortNames,
|
|
5066
|
+
expandPermissionEntries,
|
|
5067
|
+
expandPermissionEntry,
|
|
4819
5068
|
fetchLocationRecord,
|
|
4820
5069
|
fetchPeerId,
|
|
4821
5070
|
httpUrlToMultiaddr,
|