@tinycloud/sdk-core 2.1.0-beta.5 → 2.2.0-beta.0

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 CHANGED
@@ -30,12 +30,16 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/index.ts
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
+ ACCOUNT_REGISTRY_PATH: () => ACCOUNT_REGISTRY_PATH,
34
+ ACCOUNT_REGISTRY_SPACE: () => ACCOUNT_REGISTRY_SPACE,
33
35
  AutoApproveSpaceCreationHandler: () => AutoApproveSpaceCreationHandler,
34
36
  CapabilityKeyRegistry: () => CapabilityKeyRegistry,
35
37
  CapabilityKeyRegistryErrorCodes: () => CapabilityKeyRegistryErrorCodes,
36
38
  ClientSessionSchema: () => ClientSessionSchema,
37
39
  DEFAULT_DEFAULTS: () => DEFAULT_DEFAULTS,
38
40
  DEFAULT_EXPIRY: () => DEFAULT_EXPIRY,
41
+ DEFAULT_MANIFEST_SPACE: () => DEFAULT_MANIFEST_SPACE,
42
+ DEFAULT_MANIFEST_VERSION: () => DEFAULT_MANIFEST_VERSION,
39
43
  DataVaultService: () => import_sdk_services4.DataVaultService,
40
44
  DatabaseHandle: () => import_sdk_services4.DatabaseHandle,
41
45
  DelegationErrorCodes: () => DelegationErrorCodes,
@@ -73,6 +77,7 @@ __export(index_exports, {
73
77
  applyPrefix: () => applyPrefix,
74
78
  buildSpaceUri: () => buildSpaceUri,
75
79
  checkNodeInfo: () => checkNodeInfo,
80
+ composeManifestRequest: () => composeManifestRequest,
76
81
  createCapabilityKeyRegistry: () => createCapabilityKeyRegistry,
77
82
  createSharingService: () => createSharingService,
78
83
  createSpaceService: () => createSpaceService,
@@ -94,6 +99,7 @@ __export(index_exports, {
94
99
  parseSpaceUri: () => parseSpaceUri,
95
100
  resolveManifest: () => resolveManifest,
96
101
  resourceCapabilitiesToAbilitiesMap: () => resourceCapabilitiesToAbilitiesMap,
102
+ resourceCapabilitiesToSpaceAbilitiesMap: () => resourceCapabilitiesToSpaceAbilitiesMap,
97
103
  serviceError: () => import_sdk_services4.serviceError,
98
104
  submitHostDelegation: () => submitHostDelegation,
99
105
  validateClientSession: () => validateClientSession,
@@ -2740,6 +2746,10 @@ var ManifestValidationError = class extends Error {
2740
2746
  };
2741
2747
  var DEFAULT_EXPIRY = "30d";
2742
2748
  var DEFAULT_DEFAULTS = true;
2749
+ var DEFAULT_MANIFEST_VERSION = 1;
2750
+ var DEFAULT_MANIFEST_SPACE = "applications";
2751
+ var ACCOUNT_REGISTRY_SPACE = "account";
2752
+ var ACCOUNT_REGISTRY_PATH = "applications/";
2743
2753
  var SERVICE_SHORT_TO_LONG = Object.freeze({
2744
2754
  kv: "tinycloud.kv",
2745
2755
  sql: "tinycloud.sql",
@@ -2755,19 +2765,19 @@ var SERVICE_LONG_TO_SHORT = Object.freeze(
2755
2765
  var DEFAULT_STANDARD_ENTRIES = [
2756
2766
  {
2757
2767
  service: "tinycloud.kv",
2758
- space: "default",
2768
+ space: DEFAULT_MANIFEST_SPACE,
2759
2769
  path: "/",
2760
2770
  actions: ["get", "put", "del", "list", "metadata"]
2761
2771
  },
2762
2772
  {
2763
2773
  service: "tinycloud.sql",
2764
- space: "default",
2774
+ space: DEFAULT_MANIFEST_SPACE,
2765
2775
  path: "/",
2766
2776
  actions: ["read", "write"]
2767
2777
  },
2768
2778
  {
2769
2779
  service: "tinycloud.capabilities",
2770
- space: "default",
2780
+ space: DEFAULT_MANIFEST_SPACE,
2771
2781
  path: "/",
2772
2782
  actions: ["read"]
2773
2783
  }
@@ -2775,19 +2785,19 @@ var DEFAULT_STANDARD_ENTRIES = [
2775
2785
  var DEFAULT_ADMIN_ENTRIES = [
2776
2786
  {
2777
2787
  service: "tinycloud.kv",
2778
- space: "default",
2788
+ space: DEFAULT_MANIFEST_SPACE,
2779
2789
  path: "/",
2780
2790
  actions: ["get", "put", "del", "list", "metadata"]
2781
2791
  },
2782
2792
  {
2783
2793
  service: "tinycloud.sql",
2784
- space: "default",
2794
+ space: DEFAULT_MANIFEST_SPACE,
2785
2795
  path: "/",
2786
2796
  actions: ["read", "write", "ddl"]
2787
2797
  },
2788
2798
  {
2789
2799
  service: "tinycloud.capabilities",
2790
- space: "default",
2800
+ space: DEFAULT_MANIFEST_SPACE,
2791
2801
  path: "/",
2792
2802
  actions: ["read", "admin"]
2793
2803
  }
@@ -2795,25 +2805,25 @@ var DEFAULT_ADMIN_ENTRIES = [
2795
2805
  var DEFAULT_ALL_ENTRIES = [
2796
2806
  {
2797
2807
  service: "tinycloud.kv",
2798
- space: "default",
2808
+ space: DEFAULT_MANIFEST_SPACE,
2799
2809
  path: "/",
2800
2810
  actions: ["get", "put", "del", "list", "metadata"]
2801
2811
  },
2802
2812
  {
2803
2813
  service: "tinycloud.sql",
2804
- space: "default",
2814
+ space: DEFAULT_MANIFEST_SPACE,
2805
2815
  path: "/",
2806
2816
  actions: ["read", "write", "ddl"]
2807
2817
  },
2808
2818
  {
2809
2819
  service: "tinycloud.duckdb",
2810
- space: "default",
2820
+ space: DEFAULT_MANIFEST_SPACE,
2811
2821
  path: "/",
2812
2822
  actions: ["read", "write"]
2813
2823
  },
2814
2824
  {
2815
2825
  service: "tinycloud.capabilities",
2816
- space: "default",
2826
+ space: DEFAULT_MANIFEST_SPACE,
2817
2827
  path: "/",
2818
2828
  actions: ["read", "admin"]
2819
2829
  }
@@ -2875,12 +2885,23 @@ function validateManifest(input) {
2875
2885
  throw new ManifestValidationError("manifest must be an object");
2876
2886
  }
2877
2887
  const m = input;
2878
- if (typeof m.id !== "string" || m.id.length === 0) {
2879
- throw new ManifestValidationError("manifest.id is required and must be a non-empty string");
2888
+ if (m.manifest_version !== void 0 && m.manifest_version !== DEFAULT_MANIFEST_VERSION) {
2889
+ throw new ManifestValidationError(
2890
+ `manifest.manifest_version must be ${DEFAULT_MANIFEST_VERSION}`
2891
+ );
2892
+ }
2893
+ if (typeof m.app_id !== "string" || m.app_id.length === 0) {
2894
+ throw new ManifestValidationError("manifest.app_id is required and must be a non-empty string");
2880
2895
  }
2881
2896
  if (typeof m.name !== "string" || m.name.length === 0) {
2882
2897
  throw new ManifestValidationError("manifest.name is required and must be a non-empty string");
2883
2898
  }
2899
+ if (m.did !== void 0 && (typeof m.did !== "string" || m.did.length === 0)) {
2900
+ throw new ManifestValidationError("manifest.did must be a non-empty DID string");
2901
+ }
2902
+ if (m.space !== void 0 && (typeof m.space !== "string" || m.space.length === 0)) {
2903
+ throw new ManifestValidationError("manifest.space must be a non-empty string");
2904
+ }
2884
2905
  if (m.expiry !== void 0) {
2885
2906
  parseExpiry(m.expiry);
2886
2907
  }
@@ -2892,29 +2913,6 @@ function validateManifest(input) {
2892
2913
  (p, i) => validatePermissionEntry(p, `permissions[${i}]`)
2893
2914
  );
2894
2915
  }
2895
- if (m.delegations !== void 0) {
2896
- if (!Array.isArray(m.delegations)) {
2897
- throw new ManifestValidationError("manifest.delegations must be an array");
2898
- }
2899
- m.delegations.forEach((d, i) => {
2900
- if (typeof d?.to !== "string" || d.to.length === 0) {
2901
- throw new ManifestValidationError(
2902
- `delegations[${i}].to is required and must be a non-empty DID string`
2903
- );
2904
- }
2905
- if (d.expiry !== void 0) {
2906
- parseExpiry(d.expiry);
2907
- }
2908
- if (!Array.isArray(d.permissions)) {
2909
- throw new ManifestValidationError(
2910
- `delegations[${i}].permissions must be an array`
2911
- );
2912
- }
2913
- d.permissions.forEach(
2914
- (p, j) => validatePermissionEntry(p, `delegations[${i}].permissions[${j}]`)
2915
- );
2916
- });
2917
- }
2918
2916
  return m;
2919
2917
  }
2920
2918
  function validatePermissionEntry(p, path) {
@@ -2925,8 +2923,8 @@ function validatePermissionEntry(p, path) {
2925
2923
  if (typeof entry.service !== "string" || entry.service.length === 0) {
2926
2924
  throw new ManifestValidationError(`${path}.service is required`);
2927
2925
  }
2928
- if (typeof entry.space !== "string" || entry.space.length === 0) {
2929
- throw new ManifestValidationError(`${path}.space is required`);
2926
+ if (entry.space !== void 0 && (typeof entry.space !== "string" || entry.space.length === 0)) {
2927
+ throw new ManifestValidationError(`${path}.space must be a non-empty string`);
2930
2928
  }
2931
2929
  if (typeof entry.path !== "string") {
2932
2930
  throw new ManifestValidationError(
@@ -2972,7 +2970,8 @@ function defaultEntriesForTier(tier) {
2972
2970
  }
2973
2971
  function resolveManifest(input) {
2974
2972
  const manifest = validateManifest(input);
2975
- const prefix = manifest.prefix !== void 0 ? manifest.prefix : manifest.id;
2973
+ const prefix = manifest.prefix !== void 0 ? manifest.prefix : manifest.app_id;
2974
+ const space = manifest.space ?? DEFAULT_MANIFEST_SPACE;
2976
2975
  const expiryMs = parseExpiry(manifest.expiry ?? DEFAULT_EXPIRY);
2977
2976
  const includePublicSpace = manifest.includePublicSpace ?? true;
2978
2977
  const tier = normalizeDefaults(manifest.defaults);
@@ -2980,29 +2979,27 @@ function resolveManifest(input) {
2980
2979
  const explicitEntries = manifest.permissions ?? [];
2981
2980
  const allEntries = [...defaultEntries, ...explicitEntries];
2982
2981
  const resources = allEntries.map(
2983
- (entry) => resolveEntry(entry, prefix, expiryMs)
2982
+ (entry) => resolveEntry(entry, prefix, expiryMs, space)
2984
2983
  );
2985
- const additionalDelegates = (manifest.delegations ?? []).map((d) => ({
2986
- did: d.to,
2987
- name: d.name,
2988
- expiryMs: parseExpiry(d.expiry ?? manifest.expiry ?? DEFAULT_EXPIRY),
2989
- permissions: d.permissions.map(
2990
- (entry) => resolveEntry(
2991
- entry,
2992
- prefix,
2993
- parseExpiry(d.expiry ?? manifest.expiry ?? DEFAULT_EXPIRY)
2994
- )
2995
- )
2996
- }));
2984
+ const additionalDelegates = manifest.did === void 0 ? [] : [
2985
+ {
2986
+ did: manifest.did,
2987
+ name: manifest.name,
2988
+ expiryMs,
2989
+ permissions: resources.map(cloneResourceCapability)
2990
+ }
2991
+ ];
2997
2992
  return {
2998
- id: manifest.id,
2993
+ app_id: manifest.app_id,
2994
+ ...manifest.did !== void 0 ? { did: manifest.did } : {},
2995
+ space,
2999
2996
  resources,
3000
2997
  expiryMs,
3001
2998
  includePublicSpace,
3002
2999
  additionalDelegates
3003
3000
  };
3004
3001
  }
3005
- function resolveEntry(entry, prefix, _inheritedExpiryMs) {
3002
+ function resolveEntry(entry, prefix, _inheritedExpiryMs, inheritedSpace) {
3006
3003
  const resolvedPath = applyPrefix(
3007
3004
  prefix,
3008
3005
  entry.path,
@@ -3012,7 +3009,7 @@ function resolveEntry(entry, prefix, _inheritedExpiryMs) {
3012
3009
  const entryExpiryMs = entry.expiry !== void 0 ? parseExpiry(entry.expiry) : void 0;
3013
3010
  return {
3014
3011
  service: entry.service,
3015
- space: entry.space,
3012
+ space: entry.space ?? inheritedSpace,
3016
3013
  path: resolvedPath,
3017
3014
  actions: resolvedActions,
3018
3015
  // Only populate `expiryMs` when the entry had its own expiry override.
@@ -3021,6 +3018,101 @@ function resolveEntry(entry, prefix, _inheritedExpiryMs) {
3021
3018
  ...entryExpiryMs !== void 0 ? { expiryMs: entryExpiryMs } : {}
3022
3019
  };
3023
3020
  }
3021
+ function cloneResourceCapability(entry) {
3022
+ return {
3023
+ service: entry.service,
3024
+ space: entry.space,
3025
+ path: entry.path,
3026
+ actions: [...entry.actions],
3027
+ ...entry.expiryMs !== void 0 ? { expiryMs: entry.expiryMs } : {}
3028
+ };
3029
+ }
3030
+ function clonePermissionEntry(entry) {
3031
+ return {
3032
+ service: entry.service,
3033
+ ...entry.space !== void 0 ? { space: entry.space } : {},
3034
+ path: entry.path,
3035
+ actions: [...entry.actions],
3036
+ ...entry.skipPrefix !== void 0 ? { skipPrefix: entry.skipPrefix } : {},
3037
+ ...entry.expiry !== void 0 ? { expiry: entry.expiry } : {}
3038
+ };
3039
+ }
3040
+ function dedupeResources(resources) {
3041
+ const byKey = /* @__PURE__ */ new Map();
3042
+ for (const resource of resources) {
3043
+ const key = `${resource.service}\0${resource.space}\0${resource.path}\0${resource.expiryMs ?? ""}`;
3044
+ const existing = byKey.get(key);
3045
+ if (existing === void 0) {
3046
+ byKey.set(key, cloneResourceCapability(resource));
3047
+ continue;
3048
+ }
3049
+ const seen = new Set(existing.actions);
3050
+ for (const action of resource.actions) {
3051
+ if (!seen.has(action)) {
3052
+ existing.actions.push(action);
3053
+ seen.add(action);
3054
+ }
3055
+ }
3056
+ }
3057
+ return [...byKey.values()];
3058
+ }
3059
+ function accountRegistryPermission() {
3060
+ return {
3061
+ service: "tinycloud.kv",
3062
+ space: ACCOUNT_REGISTRY_SPACE,
3063
+ path: ACCOUNT_REGISTRY_PATH,
3064
+ actions: [
3065
+ "tinycloud.kv/get",
3066
+ "tinycloud.kv/put",
3067
+ "tinycloud.kv/list"
3068
+ ]
3069
+ };
3070
+ }
3071
+ function composeManifestRequest(inputs, options = {}) {
3072
+ if (!Array.isArray(inputs) || inputs.length === 0) {
3073
+ throw new ManifestValidationError(
3074
+ "composeManifestRequest requires at least one manifest"
3075
+ );
3076
+ }
3077
+ const includeAccountRegistryPermissions = options.includeAccountRegistryPermissions ?? true;
3078
+ const manifests = inputs.map(validateManifest);
3079
+ const resolved = manifests.map(resolveManifest);
3080
+ const resources = resolved.flatMap((entry) => entry.resources);
3081
+ const delegationTargets = resolved.flatMap(
3082
+ (entry) => entry.additionalDelegates.map((delegate) => ({
3083
+ ...delegate,
3084
+ permissions: dedupeResources(delegate.permissions)
3085
+ }))
3086
+ );
3087
+ if (includeAccountRegistryPermissions) {
3088
+ resources.push(accountRegistryPermission());
3089
+ }
3090
+ const manifestsByAppId = /* @__PURE__ */ new Map();
3091
+ for (const manifest of manifests) {
3092
+ const current = manifestsByAppId.get(manifest.app_id);
3093
+ if (current === void 0) {
3094
+ manifestsByAppId.set(manifest.app_id, [manifest]);
3095
+ } else {
3096
+ current.push(manifest);
3097
+ }
3098
+ }
3099
+ const registryRecords = includeAccountRegistryPermissions ? [...manifestsByAppId.entries()].map(([app_id, appManifests]) => ({
3100
+ key: `${ACCOUNT_REGISTRY_PATH}${app_id}`,
3101
+ app_id,
3102
+ manifests: appManifests.map((manifest) => ({
3103
+ ...manifest,
3104
+ permissions: manifest.permissions?.map(clonePermissionEntry)
3105
+ }))
3106
+ })) : [];
3107
+ return {
3108
+ manifests,
3109
+ resources: dedupeResources(resources),
3110
+ delegationTargets,
3111
+ registryRecords,
3112
+ expiryMs: Math.max(...resolved.map((entry) => entry.expiryMs)),
3113
+ includePublicSpace: resolved.some((entry) => entry.includePublicSpace)
3114
+ };
3115
+ }
3024
3116
  function resourceCapabilitiesToAbilitiesMap(resources) {
3025
3117
  const out = {};
3026
3118
  for (const r of resources) {
@@ -3049,6 +3141,22 @@ function resourceCapabilitiesToAbilitiesMap(resources) {
3049
3141
  }
3050
3142
  return out;
3051
3143
  }
3144
+ function resourceCapabilitiesToSpaceAbilitiesMap(resources) {
3145
+ const grouped = /* @__PURE__ */ new Map();
3146
+ for (const resource of resources) {
3147
+ const entries = grouped.get(resource.space);
3148
+ if (entries === void 0) {
3149
+ grouped.set(resource.space, [resource]);
3150
+ } else {
3151
+ entries.push(resource);
3152
+ }
3153
+ }
3154
+ const out = {};
3155
+ for (const [space, entries] of grouped.entries()) {
3156
+ out[space] = resourceCapabilitiesToAbilitiesMap(entries);
3157
+ }
3158
+ return out;
3159
+ }
3052
3160
  function manifestAbilitiesUnion(resolved) {
3053
3161
  const all = [...resolved.resources];
3054
3162
  for (const delegate of resolved.additionalDelegates) {
@@ -4253,7 +4361,7 @@ function canonicalizeEntryMatches(requested, granted) {
4253
4361
  if (requested.service !== granted.service) {
4254
4362
  return false;
4255
4363
  }
4256
- if (normalizeSpace(requested.space) !== normalizeSpace(granted.space)) {
4364
+ if (normalizeSpace(requested.space ?? DEFAULT_MANIFEST_SPACE) !== normalizeSpace(granted.space ?? DEFAULT_MANIFEST_SPACE)) {
4257
4365
  return false;
4258
4366
  }
4259
4367
  if (!pathContains(granted.path, requested.path)) {
@@ -4284,7 +4392,7 @@ function pathContains(grantedPath, requestedPath) {
4284
4392
  function cloneEntry(entry) {
4285
4393
  return {
4286
4394
  service: entry.service,
4287
- space: entry.space,
4395
+ ...entry.space !== void 0 ? { space: entry.space } : {},
4288
4396
  path: entry.path,
4289
4397
  actions: [...entry.actions],
4290
4398
  ...entry.skipPrefix !== void 0 ? { skipPrefix: entry.skipPrefix } : {},
@@ -4314,7 +4422,9 @@ function parseRecapCapabilities(parseWasm, siwe) {
4314
4422
  };
4315
4423
  });
4316
4424
  normalized.sort((a, b) => {
4317
- if (a.space !== b.space) return a.space < b.space ? -1 : 1;
4425
+ const aSpace = a.space ?? DEFAULT_MANIFEST_SPACE;
4426
+ const bSpace = b.space ?? DEFAULT_MANIFEST_SPACE;
4427
+ if (aSpace !== bSpace) return aSpace < bSpace ? -1 : 1;
4318
4428
  if (a.service !== b.service) return a.service < b.service ? -1 : 1;
4319
4429
  if (a.path !== b.path) return a.path < b.path ? -1 : 1;
4320
4430
  return 0;
@@ -4323,12 +4433,16 @@ function parseRecapCapabilities(parseWasm, siwe) {
4323
4433
  }
4324
4434
  // Annotate the CommonJS export names for ESM import in node:
4325
4435
  0 && (module.exports = {
4436
+ ACCOUNT_REGISTRY_PATH,
4437
+ ACCOUNT_REGISTRY_SPACE,
4326
4438
  AutoApproveSpaceCreationHandler,
4327
4439
  CapabilityKeyRegistry,
4328
4440
  CapabilityKeyRegistryErrorCodes,
4329
4441
  ClientSessionSchema,
4330
4442
  DEFAULT_DEFAULTS,
4331
4443
  DEFAULT_EXPIRY,
4444
+ DEFAULT_MANIFEST_SPACE,
4445
+ DEFAULT_MANIFEST_VERSION,
4332
4446
  DataVaultService,
4333
4447
  DatabaseHandle,
4334
4448
  DelegationErrorCodes,
@@ -4366,6 +4480,7 @@ function parseRecapCapabilities(parseWasm, siwe) {
4366
4480
  applyPrefix,
4367
4481
  buildSpaceUri,
4368
4482
  checkNodeInfo,
4483
+ composeManifestRequest,
4369
4484
  createCapabilityKeyRegistry,
4370
4485
  createSharingService,
4371
4486
  createSpaceService,
@@ -4387,6 +4502,7 @@ function parseRecapCapabilities(parseWasm, siwe) {
4387
4502
  parseSpaceUri,
4388
4503
  resolveManifest,
4389
4504
  resourceCapabilitiesToAbilitiesMap,
4505
+ resourceCapabilitiesToSpaceAbilitiesMap,
4390
4506
  serviceError,
4391
4507
  submitHostDelegation,
4392
4508
  validateClientSession,