@tinycloud/sdk-core 2.4.0-beta.6 → 2.4.0-beta.8

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.js CHANGED
@@ -970,6 +970,7 @@ var SpaceService = class {
970
970
  this._userDid = config.userDid;
971
971
  this.sharingService = config.sharingService;
972
972
  this.createDelegationFn = config.createDelegation;
973
+ this.onSpaceRegisteredFn = config.onSpaceRegistered;
973
974
  }
974
975
  /**
975
976
  * Update the service configuration.
@@ -985,6 +986,7 @@ var SpaceService = class {
985
986
  if (config.userDid !== void 0) this._userDid = config.userDid;
986
987
  if (config.sharingService) this.sharingService = config.sharingService;
987
988
  if (config.createDelegation) this.createDelegationFn = config.createDelegation;
989
+ if (config.onSpaceRegistered) this.onSpaceRegisteredFn = config.onSpaceRegistered;
988
990
  this.spaceCache.clear();
989
991
  this.infoCache.clear();
990
992
  }
@@ -1035,6 +1037,9 @@ var SpaceService = class {
1035
1037
  spaces.push(...delegatedSpaces);
1036
1038
  }
1037
1039
  const uniqueSpaces = this.deduplicateSpaces(spaces);
1040
+ for (const space of uniqueSpaces) {
1041
+ this.notifySpaceRegistered(space);
1042
+ }
1038
1043
  return ok(uniqueSpaces);
1039
1044
  } catch (error) {
1040
1045
  return err(
@@ -1232,6 +1237,7 @@ var SpaceService = class {
1232
1237
  permissions: ["*"]
1233
1238
  };
1234
1239
  this.infoCache.set(spaceInfo.id, { info: spaceInfo, cachedAt: Date.now() });
1240
+ this.notifySpaceRegistered(spaceInfo);
1235
1241
  return ok(spaceInfo);
1236
1242
  } catch (error) {
1237
1243
  return err(
@@ -1244,6 +1250,11 @@ var SpaceService = class {
1244
1250
  );
1245
1251
  }
1246
1252
  }
1253
+ notifySpaceRegistered(space) {
1254
+ if (!this.onSpaceRegisteredFn) return;
1255
+ void Promise.resolve(this.onSpaceRegisteredFn(space)).catch(() => {
1256
+ });
1257
+ }
1247
1258
  // ===========================================================================
1248
1259
  // Get Space
1249
1260
  // ===========================================================================
@@ -2788,12 +2799,20 @@ function withCapabilitiesReadForSpaces(resources) {
2788
2799
  ...[...spaces].map(capabilitiesReadPermission)
2789
2800
  ]);
2790
2801
  }
2791
- function accountRegistryPermission() {
2792
- return {
2802
+ function accountRegistryPermissions() {
2803
+ return [ACCOUNT_REGISTRY_PATH, "spaces/"].map((path) => ({
2793
2804
  service: "tinycloud.kv",
2794
2805
  space: ACCOUNT_REGISTRY_SPACE,
2795
- path: ACCOUNT_REGISTRY_PATH,
2806
+ path,
2796
2807
  actions: ["tinycloud.kv/get", "tinycloud.kv/put", "tinycloud.kv/list"]
2808
+ }));
2809
+ }
2810
+ function accountRegistryIndexPermission() {
2811
+ return {
2812
+ service: "tinycloud.sql",
2813
+ space: ACCOUNT_REGISTRY_SPACE,
2814
+ path: "account",
2815
+ actions: ["tinycloud.sql/read", "tinycloud.sql/write", "tinycloud.sql/ddl"]
2797
2816
  };
2798
2817
  }
2799
2818
  function composeManifestRequest(inputs, options = {}) {
@@ -2813,7 +2832,8 @@ function composeManifestRequest(inputs, options = {}) {
2813
2832
  }))
2814
2833
  );
2815
2834
  if (includeAccountRegistryPermissions) {
2816
- resources.push(accountRegistryPermission());
2835
+ resources.push(...accountRegistryPermissions());
2836
+ resources.push(accountRegistryIndexPermission());
2817
2837
  }
2818
2838
  const resourcesWithImplicitCapabilities = withCapabilitiesReadForSpaces(resources);
2819
2839
  const manifestsByAppId = /* @__PURE__ */ new Map();
@@ -2899,6 +2919,7 @@ function manifestAbilitiesUnion(resolved) {
2899
2919
  // src/account/AccountService.ts
2900
2920
  var SERVICE_NAME2 = "account";
2901
2921
  var ACCOUNT_INDEX_DB = "account";
2922
+ var ACCOUNT_SPACES_PATH = "spaces/";
2902
2923
  var AccountService = class {
2903
2924
  constructor(config) {
2904
2925
  this.config = config;
@@ -2942,14 +2963,28 @@ var AccountService = class {
2942
2963
  if (!kvResult.ok) return kvResult;
2943
2964
  let registered;
2944
2965
  for (const record of request.registryRecords) {
2966
+ const manifestHash = hashJson(record.manifests);
2967
+ if (await this.indexHasApplicationHash(record.app_id, manifestHash)) {
2968
+ registered = {
2969
+ appId: record.app_id,
2970
+ manifests: record.manifests,
2971
+ manifestHash,
2972
+ name: record.manifests[0]?.name,
2973
+ description: record.manifests[0]?.description
2974
+ };
2975
+ continue;
2976
+ }
2945
2977
  const stored = {
2946
2978
  app_id: record.app_id,
2947
2979
  manifests: record.manifests,
2980
+ manifest_hash: manifestHash,
2948
2981
  updated_at: (/* @__PURE__ */ new Date()).toISOString()
2949
2982
  };
2950
2983
  const written = await kvResult.data.put(record.key, stored);
2951
2984
  if (!written.ok) return accountErr(written.error);
2952
2985
  registered = applicationFromRecord(record.key, stored);
2986
+ const indexed = await this.upsertApplicationIndex(registered);
2987
+ if (!indexed.ok) return indexed;
2953
2988
  }
2954
2989
  return ok3(registered);
2955
2990
  },
@@ -2958,6 +2993,63 @@ var AccountService = class {
2958
2993
  if (!kvResult.ok) return kvResult;
2959
2994
  const removed = await kvResult.data.delete(applicationKey(appId));
2960
2995
  if (!removed.ok) return accountErr(removed.error);
2996
+ const indexed = await this.deleteApplicationIndex(appId);
2997
+ if (!indexed.ok) return indexed;
2998
+ return ok3(void 0);
2999
+ }
3000
+ };
3001
+ this.spaces = {
3002
+ list: async () => {
3003
+ const kvResult = this.accountKV();
3004
+ if (!kvResult.ok) return kvResult;
3005
+ const listed = await kvResult.data.list({ prefix: ACCOUNT_SPACES_PATH });
3006
+ if (!listed.ok) return accountErr(listed.error);
3007
+ const spaces = [];
3008
+ for (const key of listed.data.keys) {
3009
+ const loaded = await kvResult.data.get(key);
3010
+ if (!loaded.ok) return accountErr(loaded.error);
3011
+ spaces.push(spaceFromRecord(key, loaded.data.data));
3012
+ }
3013
+ spaces.sort((a, b) => a.name.localeCompare(b.name) || a.spaceId.localeCompare(b.spaceId));
3014
+ return ok3(spaces);
3015
+ },
3016
+ get: async (spaceId) => {
3017
+ const kvResult = this.accountKV();
3018
+ if (!kvResult.ok) return kvResult;
3019
+ const loaded = await kvResult.data.get(spaceKey(spaceId));
3020
+ if (!loaded.ok) return accountErr(loaded.error);
3021
+ return ok3(spaceFromRecord(spaceKey(spaceId), loaded.data.data));
3022
+ },
3023
+ register: async (space) => {
3024
+ await this.config.ensureAccountSpaceHosted?.();
3025
+ const kvResult = this.accountKV();
3026
+ if (!kvResult.ok) return kvResult;
3027
+ const stored = spaceRecordFromInput(space);
3028
+ const written = await kvResult.data.put(spaceKey(stored.space_id), stored);
3029
+ if (!written.ok) return accountErr(written.error);
3030
+ const registered = spaceFromRecord(spaceKey(stored.space_id), stored);
3031
+ const indexed = await this.upsertSpaceIndex(registered);
3032
+ if (!indexed.ok) return indexed;
3033
+ return ok3(registered);
3034
+ },
3035
+ syncAccessible: async () => {
3036
+ const listed = await this.config.getSpaces().list();
3037
+ if (!listed.ok) return accountErr(listed.error);
3038
+ const registered = [];
3039
+ for (const space of listed.data) {
3040
+ const result = await this.spaces.register(space);
3041
+ if (!result.ok) return result;
3042
+ registered.push(result.data);
3043
+ }
3044
+ return ok3(registered);
3045
+ },
3046
+ remove: async (spaceId) => {
3047
+ const kvResult = this.accountKV();
3048
+ if (!kvResult.ok) return kvResult;
3049
+ const removed = await kvResult.data.delete(spaceKey(spaceId));
3050
+ if (!removed.ok) return accountErr(removed.error);
3051
+ const indexed = await this.deleteSpaceIndex(spaceId);
3052
+ if (!indexed.ok) return indexed;
2961
3053
  return ok3(void 0);
2962
3054
  }
2963
3055
  };
@@ -2997,12 +3089,16 @@ var AccountService = class {
2997
3089
  if (!dbResult.ok) return dbResult;
2998
3090
  const applications = await this.applications.list();
2999
3091
  if (!applications.ok) return applications;
3092
+ const spaces = await this.spaces.list();
3093
+ if (!spaces.ok) return spaces;
3000
3094
  const delegations = await this.delegations.list();
3001
3095
  if (!delegations.ok) return delegations;
3002
3096
  const syncedAt = (/* @__PURE__ */ new Date()).toISOString();
3003
3097
  const statements = [
3004
3098
  ...ACCOUNT_INDEX_SCHEMA.map((sql) => ({ sql })),
3005
3099
  { sql: "DELETE FROM applications" },
3100
+ { sql: "DELETE FROM application_state" },
3101
+ { sql: "DELETE FROM spaces" },
3006
3102
  { sql: "DELETE FROM delegations" },
3007
3103
  { sql: "DELETE FROM sync_state" },
3008
3104
  ...applications.data.map((app) => ({
@@ -3015,6 +3111,24 @@ var AccountService = class {
3015
3111
  JSON.stringify(app.manifests)
3016
3112
  ]
3017
3113
  })),
3114
+ ...applications.data.map((app) => ({
3115
+ sql: "INSERT OR REPLACE INTO application_state (app_id, manifest_hash, indexed_at) VALUES (?, ?, ?)",
3116
+ params: [app.appId, app.manifestHash ?? hashJson(app.manifests), syncedAt]
3117
+ })),
3118
+ ...spaces.data.map((space) => ({
3119
+ sql: "INSERT OR REPLACE INTO spaces (space_id, name, owner_did, type, permissions_json, status, registered_at, updated_at, expires_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)",
3120
+ params: [
3121
+ space.spaceId,
3122
+ space.name,
3123
+ space.ownerDid,
3124
+ space.type,
3125
+ JSON.stringify(space.permissions),
3126
+ space.status,
3127
+ space.registeredAt ?? syncedAt,
3128
+ space.updatedAt ?? syncedAt,
3129
+ space.expiresAt?.toISOString() ?? null
3130
+ ]
3131
+ })),
3018
3132
  ...delegations.data.map((delegation) => ({
3019
3133
  sql: "INSERT INTO delegations (cid, direction, space_id, space_name, counterparty_did, delegate_did, delegator_did, path, actions_json, expiry, status, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
3020
3134
  params: [
@@ -3037,6 +3151,10 @@ var AccountService = class {
3037
3151
  sql: "INSERT INTO sync_state (source, synced_at, count) VALUES (?, ?, ?)",
3038
3152
  params: ["applications", syncedAt, applications.data.length]
3039
3153
  },
3154
+ {
3155
+ sql: "INSERT INTO sync_state (source, synced_at, count) VALUES (?, ?, ?)",
3156
+ params: ["spaces", syncedAt, spaces.data.length]
3157
+ },
3040
3158
  {
3041
3159
  sql: "INSERT INTO sync_state (source, synced_at, count) VALUES (?, ?, ?)",
3042
3160
  params: ["delegations", syncedAt, delegations.data.length]
@@ -3047,6 +3165,7 @@ var AccountService = class {
3047
3165
  return ok3({
3048
3166
  database: ACCOUNT_INDEX_DB,
3049
3167
  applications: applications.data.length,
3168
+ spaces: spaces.data.length,
3050
3169
  delegations: delegations.data.length,
3051
3170
  syncedAt
3052
3171
  });
@@ -3056,12 +3175,23 @@ var AccountService = class {
3056
3175
  const dbResult = this.accountDb();
3057
3176
  if (!dbResult.ok) return dbResult;
3058
3177
  const queried = await dbResult.data.query(
3059
- "SELECT app_id, name, description, updated_at, manifest_json FROM applications ORDER BY app_id"
3178
+ "SELECT applications.app_id, name, description, updated_at, manifest_json, application_state.manifest_hash FROM applications LEFT JOIN application_state ON applications.app_id = application_state.app_id ORDER BY applications.app_id"
3060
3179
  );
3061
3180
  if (!queried.ok) return accountErr(queried.error);
3062
3181
  return ok3(queried.data.rows.map(indexedApplicationFromRow));
3063
3182
  }
3064
3183
  },
3184
+ spaces: {
3185
+ list: async () => {
3186
+ const dbResult = this.accountDb();
3187
+ if (!dbResult.ok) return dbResult;
3188
+ const queried = await dbResult.data.query(
3189
+ "SELECT space_id, name, owner_did, type, permissions_json, status, registered_at, updated_at, expires_at FROM spaces ORDER BY name, space_id"
3190
+ );
3191
+ if (!queried.ok) return accountErr(queried.error);
3192
+ return ok3(queried.data.rows.map(indexedSpaceFromRow));
3193
+ }
3194
+ },
3065
3195
  delegations: {
3066
3196
  list: async (options = {}) => {
3067
3197
  const dbResult = this.accountDb();
@@ -3090,6 +3220,22 @@ var AccountService = class {
3090
3220
  const queried = await dbResult.data.query(sql, params);
3091
3221
  if (!queried.ok) return accountErr(queried.error);
3092
3222
  return ok3(queried.data);
3223
+ },
3224
+ status: async () => {
3225
+ const dbResult = this.accountDb();
3226
+ if (!dbResult.ok) return dbResult;
3227
+ const queried = await dbResult.data.query(
3228
+ "SELECT source, synced_at, count FROM sync_state ORDER BY source"
3229
+ );
3230
+ if (!queried.ok) return accountErr(queried.error);
3231
+ return ok3({
3232
+ database: ACCOUNT_INDEX_DB,
3233
+ sources: queried.data.rows.map(([source, syncedAt, count]) => ({
3234
+ source,
3235
+ syncedAt,
3236
+ count
3237
+ }))
3238
+ });
3093
3239
  }
3094
3240
  };
3095
3241
  }
@@ -3098,12 +3244,15 @@ var AccountService = class {
3098
3244
  if (!apps.ok) return apps;
3099
3245
  const delegations = await this.delegations.list();
3100
3246
  if (!delegations.ok) return delegations;
3247
+ const spaces = await this.spaces.list();
3248
+ if (!spaces.ok) return spaces;
3101
3249
  return ok3({
3102
3250
  did: this.config.getDid(),
3103
3251
  host: this.config.getHost(),
3104
3252
  primarySpaceId: this.config.getPrimarySpaceId(),
3105
3253
  accountSpaceId: this.config.getAccountSpaceId(),
3106
3254
  applications: apps.data.length,
3255
+ spaces: spaces.data.length,
3107
3256
  grantedDelegations: delegations.data.filter((d) => d.direction === "granted").length,
3108
3257
  receivedDelegations: delegations.data.filter((d) => d.direction === "received").length
3109
3258
  });
@@ -3134,6 +3283,87 @@ var AccountService = class {
3134
3283
  }
3135
3284
  return ok3(db);
3136
3285
  }
3286
+ async indexHasApplicationHash(appId, manifestHash) {
3287
+ const dbResult = this.accountDb();
3288
+ if (!dbResult.ok) return false;
3289
+ const schema = await dbResult.data.batch(ACCOUNT_INDEX_SCHEMA.map((sql) => ({ sql })));
3290
+ if (!schema.ok) return false;
3291
+ const queried = await dbResult.data.query(
3292
+ "SELECT 1 FROM application_state WHERE app_id = ? AND manifest_hash = ? LIMIT 1",
3293
+ [appId, manifestHash]
3294
+ );
3295
+ return queried.ok && queried.data.rows.length > 0;
3296
+ }
3297
+ async upsertApplicationIndex(app) {
3298
+ const dbResult = this.accountDb();
3299
+ if (!dbResult.ok) return ok3(void 0);
3300
+ const updatedAt = app.updatedAt ?? (/* @__PURE__ */ new Date()).toISOString();
3301
+ const manifestHash = app.manifestHash ?? hashJson(app.manifests);
3302
+ const written = await dbResult.data.batch([
3303
+ ...ACCOUNT_INDEX_SCHEMA.map((sql) => ({ sql })),
3304
+ {
3305
+ sql: "INSERT OR REPLACE INTO applications (app_id, name, description, updated_at, manifest_json) VALUES (?, ?, ?, ?, ?)",
3306
+ params: [
3307
+ app.appId,
3308
+ app.name ?? null,
3309
+ app.description ?? null,
3310
+ updatedAt,
3311
+ JSON.stringify(app.manifests)
3312
+ ]
3313
+ },
3314
+ {
3315
+ sql: "INSERT OR REPLACE INTO application_state (app_id, manifest_hash, indexed_at) VALUES (?, ?, ?)",
3316
+ params: [app.appId, manifestHash, updatedAt]
3317
+ }
3318
+ ]);
3319
+ if (!written.ok) return accountErr(written.error);
3320
+ return ok3(void 0);
3321
+ }
3322
+ async deleteApplicationIndex(appId) {
3323
+ const dbResult = this.accountDb();
3324
+ if (!dbResult.ok) return ok3(void 0);
3325
+ const deleted = await dbResult.data.batch([
3326
+ ...ACCOUNT_INDEX_SCHEMA.map((sql) => ({ sql })),
3327
+ { sql: "DELETE FROM applications WHERE app_id = ?", params: [appId] },
3328
+ { sql: "DELETE FROM application_state WHERE app_id = ?", params: [appId] }
3329
+ ]);
3330
+ if (!deleted.ok) return accountErr(deleted.error);
3331
+ return ok3(void 0);
3332
+ }
3333
+ async upsertSpaceIndex(space) {
3334
+ const dbResult = this.accountDb();
3335
+ if (!dbResult.ok) return ok3(void 0);
3336
+ const updatedAt = space.updatedAt ?? (/* @__PURE__ */ new Date()).toISOString();
3337
+ const written = await dbResult.data.batch([
3338
+ ...ACCOUNT_INDEX_SCHEMA.map((sql) => ({ sql })),
3339
+ {
3340
+ sql: "INSERT OR REPLACE INTO spaces (space_id, name, owner_did, type, permissions_json, status, registered_at, updated_at, expires_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)",
3341
+ params: [
3342
+ space.spaceId,
3343
+ space.name,
3344
+ space.ownerDid,
3345
+ space.type,
3346
+ JSON.stringify(space.permissions),
3347
+ space.status,
3348
+ space.registeredAt ?? updatedAt,
3349
+ updatedAt,
3350
+ space.expiresAt?.toISOString() ?? null
3351
+ ]
3352
+ }
3353
+ ]);
3354
+ if (!written.ok) return accountErr(written.error);
3355
+ return ok3(void 0);
3356
+ }
3357
+ async deleteSpaceIndex(spaceId) {
3358
+ const dbResult = this.accountDb();
3359
+ if (!dbResult.ok) return ok3(void 0);
3360
+ const deleted = await dbResult.data.batch([
3361
+ ...ACCOUNT_INDEX_SCHEMA.map((sql) => ({ sql })),
3362
+ { sql: "DELETE FROM spaces WHERE space_id = ?", params: [spaceId] }
3363
+ ]);
3364
+ if (!deleted.ok) return accountErr(deleted.error);
3365
+ return ok3(void 0);
3366
+ }
3137
3367
  async resolveSpace(space) {
3138
3368
  const listed = await this.config.getSpaces().list();
3139
3369
  if (!listed.ok) return accountErr(listed.error);
@@ -3154,6 +3384,22 @@ var ACCOUNT_INDEX_SCHEMA = [
3154
3384
  updated_at TEXT,
3155
3385
  manifest_json TEXT NOT NULL
3156
3386
  )`,
3387
+ `CREATE TABLE IF NOT EXISTS application_state (
3388
+ app_id TEXT PRIMARY KEY,
3389
+ manifest_hash TEXT NOT NULL,
3390
+ indexed_at TEXT NOT NULL
3391
+ )`,
3392
+ `CREATE TABLE IF NOT EXISTS spaces (
3393
+ space_id TEXT PRIMARY KEY,
3394
+ name TEXT NOT NULL,
3395
+ owner_did TEXT NOT NULL,
3396
+ type TEXT NOT NULL,
3397
+ permissions_json TEXT NOT NULL,
3398
+ status TEXT NOT NULL,
3399
+ registered_at TEXT,
3400
+ updated_at TEXT NOT NULL,
3401
+ expires_at TEXT
3402
+ )`,
3157
3403
  `CREATE TABLE IF NOT EXISTS delegations (
3158
3404
  cid TEXT PRIMARY KEY,
3159
3405
  direction TEXT NOT NULL,
@@ -3176,7 +3422,9 @@ var ACCOUNT_INDEX_SCHEMA = [
3176
3422
  )`,
3177
3423
  "CREATE INDEX IF NOT EXISTS idx_delegations_direction ON delegations(direction)",
3178
3424
  "CREATE INDEX IF NOT EXISTS idx_delegations_space ON delegations(space_id)",
3179
- "CREATE INDEX IF NOT EXISTS idx_delegations_counterparty ON delegations(counterparty_did)"
3425
+ "CREATE INDEX IF NOT EXISTS idx_delegations_counterparty ON delegations(counterparty_did)",
3426
+ "CREATE INDEX IF NOT EXISTS idx_spaces_owner ON spaces(owner_did)",
3427
+ "CREATE INDEX IF NOT EXISTS idx_spaces_type ON spaces(type)"
3180
3428
  ];
3181
3429
  function applicationKey(appId) {
3182
3430
  return `${ACCOUNT_REGISTRY_PATH}${appId}`;
@@ -3192,19 +3440,98 @@ function applicationFromRecord(key, record) {
3192
3440
  manifests,
3193
3441
  updatedAt: record.updated_at ?? record.updatedAt,
3194
3442
  name: first?.name,
3195
- description: first?.description
3443
+ description: first?.description,
3444
+ manifestHash: record.manifest_hash ?? record.manifestHash ?? hashJson(manifests)
3196
3445
  };
3197
3446
  }
3198
3447
  function indexedApplicationFromRow(row) {
3199
- const [appId, name, description, updatedAt, manifestJson] = row;
3448
+ const [appId, name, description, updatedAt, manifestJson, manifestHash] = row;
3200
3449
  return {
3201
3450
  appId,
3202
3451
  name: name ?? void 0,
3203
3452
  description: description ?? void 0,
3204
3453
  updatedAt: updatedAt ?? void 0,
3205
- manifests: JSON.parse(manifestJson)
3454
+ manifests: JSON.parse(manifestJson),
3455
+ manifestHash: manifestHash ?? void 0
3456
+ };
3457
+ }
3458
+ function spaceKey(spaceId) {
3459
+ return `${ACCOUNT_SPACES_PATH}${spaceId}`;
3460
+ }
3461
+ function spaceIdFromKey(key) {
3462
+ return key.startsWith(ACCOUNT_SPACES_PATH) ? key.slice(ACCOUNT_SPACES_PATH.length) : key;
3463
+ }
3464
+ function spaceRecordFromInput(space) {
3465
+ const now = (/* @__PURE__ */ new Date()).toISOString();
3466
+ const accountSpace = "spaceId" in space ? space : {
3467
+ spaceId: space.id,
3468
+ name: space.name ?? space.id.split(":").pop() ?? space.id,
3469
+ ownerDid: space.owner ?? "",
3470
+ type: space.type ?? "discovered",
3471
+ permissions: space.permissions ?? [],
3472
+ status: "active",
3473
+ expiresAt: space.expiresAt
3474
+ };
3475
+ return {
3476
+ space_id: accountSpace.spaceId,
3477
+ name: accountSpace.name,
3478
+ owner_did: accountSpace.ownerDid,
3479
+ type: accountSpace.type,
3480
+ permissions: accountSpace.permissions,
3481
+ status: accountSpace.status,
3482
+ registered_at: accountSpace.registeredAt ?? now,
3483
+ updated_at: now,
3484
+ expires_at: accountSpace.expiresAt instanceof Date ? accountSpace.expiresAt.toISOString() : accountSpace.expiresAt
3206
3485
  };
3207
3486
  }
3487
+ function spaceFromRecord(key, record) {
3488
+ const expiresAt = record.expires_at ?? record.expiresAt;
3489
+ return {
3490
+ spaceId: record.space_id ?? record.spaceId ?? spaceIdFromKey(key),
3491
+ name: record.name ?? spaceIdFromKey(key).split(":").pop() ?? spaceIdFromKey(key),
3492
+ ownerDid: record.owner_did ?? record.ownerDid ?? record.owner ?? "",
3493
+ type: record.type ?? "discovered",
3494
+ permissions: Array.isArray(record.permissions) ? record.permissions : [],
3495
+ status: record.status ?? "active",
3496
+ registeredAt: record.registered_at ?? record.registeredAt,
3497
+ updatedAt: record.updated_at ?? record.updatedAt,
3498
+ expiresAt: expiresAt ? new Date(expiresAt) : void 0
3499
+ };
3500
+ }
3501
+ function indexedSpaceFromRow(row) {
3502
+ const [spaceId, name, ownerDid, type, permissionsJson, status, registeredAt, updatedAt, expiresAt] = row;
3503
+ return {
3504
+ spaceId,
3505
+ name,
3506
+ ownerDid,
3507
+ type,
3508
+ permissions: JSON.parse(permissionsJson),
3509
+ status,
3510
+ registeredAt: registeredAt ?? void 0,
3511
+ updatedAt,
3512
+ expiresAt: expiresAt ? new Date(expiresAt) : void 0
3513
+ };
3514
+ }
3515
+ function hashJson(value) {
3516
+ const input = stableJson(value);
3517
+ let hash = 0xcbf29ce484222325n;
3518
+ const prime = 0x100000001b3n;
3519
+ for (let index = 0; index < input.length; index += 1) {
3520
+ hash ^= BigInt(input.charCodeAt(index));
3521
+ hash = BigInt.asUintN(64, hash * prime);
3522
+ }
3523
+ return hash.toString(16).padStart(16, "0");
3524
+ }
3525
+ function stableJson(value) {
3526
+ if (value === null || typeof value !== "object") {
3527
+ return JSON.stringify(value);
3528
+ }
3529
+ if (Array.isArray(value)) {
3530
+ return `[${value.map(stableJson).join(",")}]`;
3531
+ }
3532
+ const object = value;
3533
+ return `{${Object.keys(object).sort().map((key) => `${JSON.stringify(key)}:${stableJson(object[key])}`).join(",")}}`;
3534
+ }
3208
3535
  function indexedDelegationFromRow(row) {
3209
3536
  const [
3210
3537
  cid,