@tinycloud/node-sdk 3.2.0-beta.2 → 3.2.0-beta.3
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/{core-DjLtgeVT.d.cts → WasmKeyProvider-DjfRu9aL.d.cts} +162 -2
- package/dist/{core-DjLtgeVT.d.ts → WasmKeyProvider-DjfRu9aL.d.ts} +162 -2
- package/dist/authority-mTQEgN56.d.cts +97 -0
- package/dist/authority-mTQEgN56.d.ts +97 -0
- package/dist/core.cjs +1049 -443
- package/dist/core.cjs.map +1 -1
- package/dist/core.d.cts +13 -3
- package/dist/core.d.ts +13 -3
- package/dist/core.js +725 -115
- package/dist/core.js.map +1 -1
- package/dist/index.cjs +2348 -494
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +34 -4
- package/dist/index.d.ts +34 -4
- package/dist/index.js +1996 -128
- package/dist/index.js.map +1 -1
- package/dist/replication/authority.cjs +278 -0
- package/dist/replication/authority.cjs.map +1 -0
- package/dist/replication/authority.d.cts +3 -0
- package/dist/replication/authority.d.ts +3 -0
- package/dist/replication/authority.js +257 -0
- package/dist/replication/authority.js.map +1 -0
- package/dist/replication/runtime.cjs +224 -0
- package/dist/replication/runtime.cjs.map +1 -0
- package/dist/replication/runtime.d.cts +3 -0
- package/dist/replication/runtime.d.ts +3 -0
- package/dist/replication/runtime.js +189 -0
- package/dist/replication/runtime.js.map +1 -0
- package/dist/runtime-DyYwHW8j.d.cts +64 -0
- package/dist/runtime-DyYwHW8j.d.ts +64 -0
- package/package.json +25 -3
package/dist/index.cjs
CHANGED
|
@@ -5,6 +5,9 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
|
5
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
6
|
var __getProtoOf = Object.getPrototypeOf;
|
|
7
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __typeError = (msg) => {
|
|
9
|
+
throw TypeError(msg);
|
|
10
|
+
};
|
|
8
11
|
var __esm = (fn, res) => function __init() {
|
|
9
12
|
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
10
13
|
};
|
|
@@ -32,6 +35,11 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
32
35
|
mod
|
|
33
36
|
));
|
|
34
37
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
38
|
+
var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
|
|
39
|
+
var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
|
|
40
|
+
var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
|
|
41
|
+
var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
|
|
42
|
+
var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
|
|
35
43
|
|
|
36
44
|
// ../../node_modules/bn.js/lib/bn.js
|
|
37
45
|
var require_bn = __commonJS({
|
|
@@ -14350,8 +14358,8 @@ function searchPath(object, path) {
|
|
|
14350
14358
|
}
|
|
14351
14359
|
return currentChild;
|
|
14352
14360
|
}
|
|
14353
|
-
function uuidV4(
|
|
14354
|
-
const bytes = arrayify(
|
|
14361
|
+
function uuidV4(randomBytes3) {
|
|
14362
|
+
const bytes = arrayify(randomBytes3);
|
|
14355
14363
|
bytes[6] = bytes[6] & 15 | 64;
|
|
14356
14364
|
bytes[8] = bytes[8] & 63 | 128;
|
|
14357
14365
|
const value = hexlify(bytes);
|
|
@@ -17022,170 +17030,632 @@ var require_utils2 = __commonJS({
|
|
|
17022
17030
|
}
|
|
17023
17031
|
});
|
|
17024
17032
|
|
|
17033
|
+
// src/replication/config.ts
|
|
17034
|
+
function assertValidReplicationConfig(replication) {
|
|
17035
|
+
if (replication === void 0 || replication.enabled !== true) return;
|
|
17036
|
+
if (replication.storage === void 0 || replication.storage === null) {
|
|
17037
|
+
throw new TypeError("replication.enabled requires replication.storage");
|
|
17038
|
+
}
|
|
17039
|
+
if (!Array.isArray(replication.prefixes) || replication.prefixes.length === 0) {
|
|
17040
|
+
throw new TypeError("replication.prefixes must be a non-empty array");
|
|
17041
|
+
}
|
|
17042
|
+
for (const prefix of replication.prefixes) {
|
|
17043
|
+
if (typeof prefix !== "string" || prefix === "") {
|
|
17044
|
+
throw new TypeError("replication.prefixes must not contain an empty prefix");
|
|
17045
|
+
}
|
|
17046
|
+
}
|
|
17047
|
+
for (const [index, prefix] of replication.prefixes.entries()) {
|
|
17048
|
+
for (const other of replication.prefixes.slice(index + 1)) {
|
|
17049
|
+
if ((0, import_sdk_services.kvPrefixCovers)(prefix, other) || (0, import_sdk_services.kvPrefixCovers)(other, prefix)) {
|
|
17050
|
+
throw new TypeError(
|
|
17051
|
+
`replication.prefixes must not overlap: ${JSON.stringify(prefix)} and ${JSON.stringify(other)}`
|
|
17052
|
+
);
|
|
17053
|
+
}
|
|
17054
|
+
}
|
|
17055
|
+
if (prefix.split("/", 1)[0] === "vault" && replication.allowSecrets !== true) {
|
|
17056
|
+
throw new TypeError(
|
|
17057
|
+
`replication prefix ${JSON.stringify(prefix)} overlaps the vault namespace; pass allowSecrets to opt in`
|
|
17058
|
+
);
|
|
17059
|
+
}
|
|
17060
|
+
}
|
|
17061
|
+
}
|
|
17062
|
+
var import_sdk_services;
|
|
17063
|
+
var init_config = __esm({
|
|
17064
|
+
"src/replication/config.ts"() {
|
|
17065
|
+
"use strict";
|
|
17066
|
+
import_sdk_services = require("@tinycloud/sdk-services");
|
|
17067
|
+
}
|
|
17068
|
+
});
|
|
17069
|
+
|
|
17070
|
+
// src/replication/authority-sign-in.ts
|
|
17071
|
+
function hasUnrestrictedGetCoverage(entries, spaceId, prefix) {
|
|
17072
|
+
const requiredPaths = (0, import_sdk_core2.grantPathsForSelector)(prefix);
|
|
17073
|
+
return (0, import_sdk_core2.isCapabilitySubset)(
|
|
17074
|
+
requiredPaths.map((path) => ({ service: KV_SERVICE, space: spaceId, path, actions: [KV_GET] })),
|
|
17075
|
+
[...entries]
|
|
17076
|
+
).subset;
|
|
17077
|
+
}
|
|
17078
|
+
function augmentSignInEntriesWithReplication(input) {
|
|
17079
|
+
const out = [];
|
|
17080
|
+
const replication = input.replication;
|
|
17081
|
+
if (replication === void 0) return out;
|
|
17082
|
+
for (const prefix of replication.prefixes) {
|
|
17083
|
+
if ((0, import_sdk_services2.requiresSecretsOptIn)(input.primarySpaceId, prefix) && replication.allowSecrets !== true) {
|
|
17084
|
+
continue;
|
|
17085
|
+
}
|
|
17086
|
+
if (!hasUnrestrictedGetCoverage(input.entries, input.primarySpaceId, prefix)) {
|
|
17087
|
+
continue;
|
|
17088
|
+
}
|
|
17089
|
+
for (const path of (0, import_sdk_core2.grantPathsForSelector)(prefix)) {
|
|
17090
|
+
out.push({
|
|
17091
|
+
service: KV_SERVICE,
|
|
17092
|
+
space: input.primarySpaceId,
|
|
17093
|
+
path,
|
|
17094
|
+
actions: [KV_GET, KV_SYNC]
|
|
17095
|
+
});
|
|
17096
|
+
}
|
|
17097
|
+
}
|
|
17098
|
+
return out;
|
|
17099
|
+
}
|
|
17100
|
+
var import_sdk_core2, import_sdk_services2, KV_GET, KV_SYNC, KV_SERVICE;
|
|
17101
|
+
var init_authority_sign_in = __esm({
|
|
17102
|
+
"src/replication/authority-sign-in.ts"() {
|
|
17103
|
+
"use strict";
|
|
17104
|
+
import_sdk_core2 = require("@tinycloud/sdk-core");
|
|
17105
|
+
import_sdk_services2 = require("@tinycloud/sdk-services");
|
|
17106
|
+
KV_GET = import_sdk_core2.KV.GET;
|
|
17107
|
+
KV_SYNC = import_sdk_core2.KV.SYNC;
|
|
17108
|
+
KV_SERVICE = "tinycloud.kv";
|
|
17109
|
+
}
|
|
17110
|
+
});
|
|
17111
|
+
|
|
17112
|
+
// src/replication/runtime.ts
|
|
17113
|
+
var runtime_exports = {};
|
|
17114
|
+
__export(runtime_exports, {
|
|
17115
|
+
ReplicationRuntime: () => ReplicationRuntime
|
|
17116
|
+
});
|
|
17117
|
+
function resolvedOptions(options) {
|
|
17118
|
+
return {
|
|
17119
|
+
...options,
|
|
17120
|
+
syncIntervalMs: options.syncIntervalMs ?? 6e4,
|
|
17121
|
+
maxStalenessMs: options.maxStalenessMs ?? 12e4,
|
|
17122
|
+
staleSyncTimeoutMs: options.staleSyncTimeoutMs ?? 5e3,
|
|
17123
|
+
allowSecrets: options.allowSecrets === true,
|
|
17124
|
+
verify: options.verify === true
|
|
17125
|
+
};
|
|
17126
|
+
}
|
|
17127
|
+
var import_sdk_core10, scheduler, ReplicationRuntime;
|
|
17128
|
+
var init_runtime = __esm({
|
|
17129
|
+
"src/replication/runtime.ts"() {
|
|
17130
|
+
"use strict";
|
|
17131
|
+
import_sdk_core10 = require("@tinycloud/sdk-core");
|
|
17132
|
+
scheduler = {
|
|
17133
|
+
now: () => Date.now(),
|
|
17134
|
+
setTimeout(fn, ms) {
|
|
17135
|
+
const timer = setTimeout(fn, ms);
|
|
17136
|
+
timer.unref?.();
|
|
17137
|
+
return () => clearTimeout(timer);
|
|
17138
|
+
}
|
|
17139
|
+
};
|
|
17140
|
+
ReplicationRuntime = class {
|
|
17141
|
+
constructor(options, clock = scheduler) {
|
|
17142
|
+
this.options = options;
|
|
17143
|
+
this.clock = clock;
|
|
17144
|
+
this.pending = /* @__PURE__ */ new Map();
|
|
17145
|
+
this.attached = /* @__PURE__ */ new Map();
|
|
17146
|
+
this.previous = Promise.resolve();
|
|
17147
|
+
this.binding = Promise.resolve();
|
|
17148
|
+
this.generation = 0;
|
|
17149
|
+
this.bindingActive = false;
|
|
17150
|
+
this.pendingPurgeSet = false;
|
|
17151
|
+
this.closed = false;
|
|
17152
|
+
this.control = {
|
|
17153
|
+
status: async () => {
|
|
17154
|
+
await this.binding;
|
|
17155
|
+
return this.current ? this.current.status() : [];
|
|
17156
|
+
},
|
|
17157
|
+
sync: async (input) => {
|
|
17158
|
+
await this.binding;
|
|
17159
|
+
if (this.purgedGeneration === this.generation) return;
|
|
17160
|
+
if (this.current) await this.current.sync(input);
|
|
17161
|
+
},
|
|
17162
|
+
purge: (input) => {
|
|
17163
|
+
if (this.bindingActive) {
|
|
17164
|
+
this.pendingPurge = input;
|
|
17165
|
+
this.pendingPurgeSet = true;
|
|
17166
|
+
const existing = this.current ?? this.lastController;
|
|
17167
|
+
if (existing) {
|
|
17168
|
+
this.pendingPurgeResult = existing.purge(input);
|
|
17169
|
+
this.purgedGeneration = this.generation;
|
|
17170
|
+
}
|
|
17171
|
+
return this.binding.then(() => this.pendingPurgeResult ?? { purged: [], failed: [] });
|
|
17172
|
+
}
|
|
17173
|
+
const controller = this.current ?? this.lastController;
|
|
17174
|
+
if (!controller) return Promise.resolve({ purged: [], failed: [] });
|
|
17175
|
+
this.purgedGeneration = this.generation;
|
|
17176
|
+
return controller.purge(input);
|
|
17177
|
+
},
|
|
17178
|
+
clearPending: async () => {
|
|
17179
|
+
await this.binding;
|
|
17180
|
+
if (this.current) return this.current.clearPending();
|
|
17181
|
+
const pending = this.lastPending;
|
|
17182
|
+
if (!pending) return 0;
|
|
17183
|
+
return pending.update((state) => {
|
|
17184
|
+
const before = state.records.length;
|
|
17185
|
+
state.records = state.records.filter(
|
|
17186
|
+
(record) => record.state === "committed" || record.state === "in_flight" && this.clock.now() - Date.parse(record.at) <= 10 * 6e4
|
|
17187
|
+
);
|
|
17188
|
+
return before - state.records.length;
|
|
17189
|
+
});
|
|
17190
|
+
},
|
|
17191
|
+
close: async () => {
|
|
17192
|
+
this.closed = true;
|
|
17193
|
+
this.unbind();
|
|
17194
|
+
await this.binding.catch(() => void 0);
|
|
17195
|
+
await this.previous;
|
|
17196
|
+
}
|
|
17197
|
+
};
|
|
17198
|
+
}
|
|
17199
|
+
loadServices() {
|
|
17200
|
+
return this.services ?? (this.services = import("@tinycloud/sdk-services/kv/replication"));
|
|
17201
|
+
}
|
|
17202
|
+
detachAll() {
|
|
17203
|
+
for (const kv of this.attached.keys()) kv.setReadThrough(null);
|
|
17204
|
+
this.attached.clear();
|
|
17205
|
+
}
|
|
17206
|
+
bind(input) {
|
|
17207
|
+
if (this.closed || !this.options.enabled) return Promise.resolve();
|
|
17208
|
+
this.bindingActive = true;
|
|
17209
|
+
const generation = ++this.generation;
|
|
17210
|
+
this.purgedGeneration = void 0;
|
|
17211
|
+
const { context, session } = input;
|
|
17212
|
+
const emit = (event) => {
|
|
17213
|
+
try {
|
|
17214
|
+
this.options.onEvent?.(event);
|
|
17215
|
+
} catch {
|
|
17216
|
+
}
|
|
17217
|
+
const { type, ...data } = event;
|
|
17218
|
+
context.emit(type, data);
|
|
17219
|
+
};
|
|
17220
|
+
const previous = this.current;
|
|
17221
|
+
this.current = void 0;
|
|
17222
|
+
for (const kv of this.attached.keys()) kv.setReadThrough(null);
|
|
17223
|
+
this.primarySpace = session.spaceId;
|
|
17224
|
+
const close = previous ? previous.close().catch(() => void 0) : Promise.resolve();
|
|
17225
|
+
this.previous = this.previous.then(() => close);
|
|
17226
|
+
const previousClose = this.previous;
|
|
17227
|
+
this.binding = this.loadServices().then((services) => {
|
|
17228
|
+
if (generation !== this.generation || this.closed) return;
|
|
17229
|
+
let identity;
|
|
17230
|
+
try {
|
|
17231
|
+
identity = services.canonicalReplicationIdentity({
|
|
17232
|
+
host: context.hosts[0],
|
|
17233
|
+
space: session.spaceId,
|
|
17234
|
+
principal: input.principal ?? (0, import_sdk_core10.pkhDid)(input.address, input.chainId)
|
|
17235
|
+
});
|
|
17236
|
+
} catch {
|
|
17237
|
+
for (const prefix of this.options.prefixes) {
|
|
17238
|
+
emit({ type: "replication.state", at: new Date(this.clock.now()).toISOString(), space: session.spaceId, replica: prefix, state: "unavailable", code: "CONFIG_INVALID" });
|
|
17239
|
+
}
|
|
17240
|
+
return;
|
|
17241
|
+
}
|
|
17242
|
+
const key2 = services.replicationIdentityKey(identity);
|
|
17243
|
+
let pending = this.pending.get(key2);
|
|
17244
|
+
if (!pending) {
|
|
17245
|
+
pending = this.options.storage.pendingWrites?.(identity) ?? services.createMemoryPendingStore(identity);
|
|
17246
|
+
this.pending.set(key2, pending);
|
|
17247
|
+
}
|
|
17248
|
+
this.lastPending = pending;
|
|
17249
|
+
const controller = services.createKVReplication({
|
|
17250
|
+
options: resolvedOptions(this.options),
|
|
17251
|
+
mode: this.options.mode ?? "background",
|
|
17252
|
+
storage: this.options.storage,
|
|
17253
|
+
identity,
|
|
17254
|
+
session: { id: session.delegationCid, did: session.verificationMethod, space: session.spaceId },
|
|
17255
|
+
authority: input.authority,
|
|
17256
|
+
pending,
|
|
17257
|
+
scheduler: this.clock,
|
|
17258
|
+
emit,
|
|
17259
|
+
fetch: context.fetch,
|
|
17260
|
+
previous: previousClose
|
|
17261
|
+
});
|
|
17262
|
+
this.current = controller;
|
|
17263
|
+
this.lastController = controller;
|
|
17264
|
+
this.lastIdentity = identity;
|
|
17265
|
+
for (const [kv, space] of this.attached) {
|
|
17266
|
+
kv.setReadThrough(space === this.primarySpace ? controller : null);
|
|
17267
|
+
}
|
|
17268
|
+
for (const scoped of input.primaryKV) this.attach(scoped.space, scoped.kv);
|
|
17269
|
+
if (this.pendingPurgeSet) {
|
|
17270
|
+
this.pendingPurgeResult = controller.purge(this.pendingPurge);
|
|
17271
|
+
this.purgedGeneration = generation;
|
|
17272
|
+
this.pendingPurge = void 0;
|
|
17273
|
+
this.pendingPurgeSet = false;
|
|
17274
|
+
}
|
|
17275
|
+
}).finally(() => {
|
|
17276
|
+
if (generation === this.generation) this.bindingActive = false;
|
|
17277
|
+
});
|
|
17278
|
+
for (const kv of this.attached.keys()) kv.setReadThroughReady?.(this.binding);
|
|
17279
|
+
return this.binding;
|
|
17280
|
+
}
|
|
17281
|
+
attach(space, kv) {
|
|
17282
|
+
this.attached.set(kv, space);
|
|
17283
|
+
kv.setReadThrough(space === this.primarySpace ? this.current ?? null : null);
|
|
17284
|
+
return this.binding.then(() => {
|
|
17285
|
+
kv.setReadThrough(space === this.primarySpace ? this.current ?? null : null);
|
|
17286
|
+
});
|
|
17287
|
+
}
|
|
17288
|
+
unbind() {
|
|
17289
|
+
this.generation++;
|
|
17290
|
+
this.bindingActive = false;
|
|
17291
|
+
this.pendingPurgeSet = false;
|
|
17292
|
+
const controller = this.current;
|
|
17293
|
+
this.current = void 0;
|
|
17294
|
+
this.primarySpace = void 0;
|
|
17295
|
+
this.detachAll();
|
|
17296
|
+
const binding = this.binding;
|
|
17297
|
+
const close = binding.then(() => controller?.close()).catch(() => void 0);
|
|
17298
|
+
this.previous = this.previous.then(() => close);
|
|
17299
|
+
return this.previous;
|
|
17300
|
+
}
|
|
17301
|
+
get boundIdentity() {
|
|
17302
|
+
return this.lastIdentity;
|
|
17303
|
+
}
|
|
17304
|
+
};
|
|
17305
|
+
}
|
|
17306
|
+
});
|
|
17307
|
+
|
|
17308
|
+
// src/replication/authority.ts
|
|
17309
|
+
var authority_exports = {};
|
|
17310
|
+
__export(authority_exports, {
|
|
17311
|
+
AUTHORITY_EXPIRY_MARGIN_MS: () => AUTHORITY_EXPIRY_MARGIN_MS,
|
|
17312
|
+
assertValidReplicationConfig: () => assertValidReplicationConfig,
|
|
17313
|
+
augmentSignInEntriesWithReplication: () => augmentSignInEntriesWithReplication,
|
|
17314
|
+
createReplicationAuthority: () => createReplicationAuthority,
|
|
17315
|
+
hasUnrestrictedGetCoverage: () => hasUnrestrictedGetCoverage,
|
|
17316
|
+
replicationScopeFromSignedSession: () => replicationScopeFromSignedSession,
|
|
17317
|
+
ucanAttCovers: () => ucanAttCovers,
|
|
17318
|
+
ucanAttUnconstrainedFor: () => ucanAttUnconstrainedFor
|
|
17319
|
+
});
|
|
17320
|
+
function replicationEntries(spaceId, prefix) {
|
|
17321
|
+
return (0, import_sdk_core11.grantPathsForSelector)(prefix).map((path) => ({
|
|
17322
|
+
service: KV_SERVICE2,
|
|
17323
|
+
space: spaceId,
|
|
17324
|
+
path,
|
|
17325
|
+
actions: [KV_GET2, KV_SYNC2]
|
|
17326
|
+
}));
|
|
17327
|
+
}
|
|
17328
|
+
function caveatBranchesUnconstrained(value) {
|
|
17329
|
+
if (value === void 0 || value === null) return true;
|
|
17330
|
+
if (typeof value === "object" && !Array.isArray(value) && Object.keys(value).length === 0) {
|
|
17331
|
+
return true;
|
|
17332
|
+
}
|
|
17333
|
+
if (!Array.isArray(value)) return false;
|
|
17334
|
+
try {
|
|
17335
|
+
return (0, import_sdk_core11.canonicalizeRecapCaveats)(value) === (0, import_sdk_core11.canonicalizeRecapCaveats)(void 0);
|
|
17336
|
+
} catch {
|
|
17337
|
+
return false;
|
|
17338
|
+
}
|
|
17339
|
+
}
|
|
17340
|
+
function kvPathInResource(resource, space) {
|
|
17341
|
+
for (const base2 of [`${space}/kv/`, `tinycloud://${space}/kv/`]) {
|
|
17342
|
+
if (resource.startsWith(base2)) return resource.slice(base2.length);
|
|
17343
|
+
}
|
|
17344
|
+
return void 0;
|
|
17345
|
+
}
|
|
17346
|
+
function ucanAttCovers(att, space, prefix, ability, options) {
|
|
17347
|
+
const requiredPaths = prefix.endsWith("/") ? [prefix] : [prefix, `${prefix}/`];
|
|
17348
|
+
return requiredPaths.every((requestedPath) => {
|
|
17349
|
+
for (const [resource, abilities] of Object.entries(att)) {
|
|
17350
|
+
const path = kvPathInResource(resource, space);
|
|
17351
|
+
if (path === void 0) continue;
|
|
17352
|
+
for (const [granted, caveats] of Object.entries(abilities)) {
|
|
17353
|
+
if (!(0, import_sdk_core11.actionContains)(granted, ability)) continue;
|
|
17354
|
+
if (!(0, import_sdk_core11.isCapabilitySubset)(
|
|
17355
|
+
[{ service: KV_SERVICE2, space, path: requestedPath, actions: [ability] }],
|
|
17356
|
+
[{ service: KV_SERVICE2, space, path, actions: [granted] }]
|
|
17357
|
+
).subset) continue;
|
|
17358
|
+
if (options?.ignoreCaveats === true || caveatBranchesUnconstrained(caveats)) return true;
|
|
17359
|
+
}
|
|
17360
|
+
}
|
|
17361
|
+
return false;
|
|
17362
|
+
});
|
|
17363
|
+
}
|
|
17364
|
+
function ucanAttUnconstrainedFor(att, space, prefix) {
|
|
17365
|
+
return ucanAttCovers(att, space, prefix, KV_GET2) && ucanAttCovers(att, space, prefix, KV_SYNC2);
|
|
17366
|
+
}
|
|
17367
|
+
function replicationScopeFromSignedSession(input) {
|
|
17368
|
+
let grant;
|
|
17369
|
+
try {
|
|
17370
|
+
grant = parseUcanGrant(input.delegationHeader.Authorization);
|
|
17371
|
+
} catch {
|
|
17372
|
+
return void 0;
|
|
17373
|
+
}
|
|
17374
|
+
const bareDid = (value) => value.split("#", 1)[0];
|
|
17375
|
+
if (grant.cid !== input.delegationCid || bareDid(grant.audience) !== bareDid(input.verificationMethod)) return void 0;
|
|
17376
|
+
for (const resource of Object.keys(grant.att)) {
|
|
17377
|
+
const space = resource.match(/^(?:tinycloud:\/\/)?(.+?)\/kv\//)?.[1];
|
|
17378
|
+
if (space !== input.persistedSpace) continue;
|
|
17379
|
+
const owner = (0, import_sdk_core11.parseSpaceUri)(space);
|
|
17380
|
+
if (owner?.owner && owner.address && owner.chainId) return { space, principal: owner.owner };
|
|
17381
|
+
}
|
|
17382
|
+
return void 0;
|
|
17383
|
+
}
|
|
17384
|
+
function createReplicationAuthority(host) {
|
|
17385
|
+
const planOrRefusal = (entries) => {
|
|
17386
|
+
const plan = host.planDelegation(entries);
|
|
17387
|
+
if ("refused" in plan) return plan;
|
|
17388
|
+
return { path: plan.path, parentCid: plan.parentCid, expiresAt: plan.expiresAt };
|
|
17389
|
+
};
|
|
17390
|
+
const sessionAudience = (value) => value.split("#", 1)[0];
|
|
17391
|
+
const signedSessionGrant = (session) => {
|
|
17392
|
+
const grant = parseUcanGrant(session.delegationHeader.Authorization);
|
|
17393
|
+
if (grant.cid !== session.delegationCid || sessionAudience(grant.audience) !== sessionAudience(session.verificationMethod)) return void 0;
|
|
17394
|
+
return grant;
|
|
17395
|
+
};
|
|
17396
|
+
const authority = {
|
|
17397
|
+
get sessionOnly() {
|
|
17398
|
+
const session = host.replicationSession();
|
|
17399
|
+
return session !== void 0 && session.siwe === void 0;
|
|
17400
|
+
},
|
|
17401
|
+
sessionGrant(prefix) {
|
|
17402
|
+
const session = host.replicationSession();
|
|
17403
|
+
if (session === void 0) return { refused: "SESSION_EXPIRING" };
|
|
17404
|
+
const siweExpiry = session.siwe ? host.siweExpiration(session.siwe)?.getTime() : void 0;
|
|
17405
|
+
if (siweExpiry !== void 0 && siweExpiry <= Date.now() + AUTHORITY_EXPIRY_MARGIN_MS) {
|
|
17406
|
+
return { refused: "SESSION_EXPIRING" };
|
|
17407
|
+
}
|
|
17408
|
+
let grant;
|
|
17409
|
+
try {
|
|
17410
|
+
const verified = signedSessionGrant(session);
|
|
17411
|
+
if (!verified) return { refused: "NOT_COVERED" };
|
|
17412
|
+
grant = verified;
|
|
17413
|
+
} catch {
|
|
17414
|
+
return { refused: "NOT_COVERED" };
|
|
17415
|
+
}
|
|
17416
|
+
const tokenExpiry = grant.expiresAt === null ? void 0 : grant.expiresAt * 1e3;
|
|
17417
|
+
if (tokenExpiry === void 0 || tokenExpiry <= Date.now() + AUTHORITY_EXPIRY_MARGIN_MS) {
|
|
17418
|
+
return { refused: "SESSION_EXPIRING" };
|
|
17419
|
+
}
|
|
17420
|
+
const covered = ucanAttCovers(grant.att, session.spaceId, prefix, KV_GET2, { ignoreCaveats: true }) && ucanAttCovers(grant.att, session.spaceId, prefix, KV_SYNC2, { ignoreCaveats: true });
|
|
17421
|
+
if (!covered) return { refused: "NOT_COVERED" };
|
|
17422
|
+
if (!ucanAttUnconstrainedFor(grant.att, session.spaceId, prefix)) {
|
|
17423
|
+
return { refused: "CAVEATED_AUTHORITY" };
|
|
17424
|
+
}
|
|
17425
|
+
return {
|
|
17426
|
+
ucan: grant.jwt,
|
|
17427
|
+
device: { did: session.verificationMethod, jwk: session.jwk }
|
|
17428
|
+
};
|
|
17429
|
+
},
|
|
17430
|
+
plan(prefix) {
|
|
17431
|
+
const session = host.replicationSession();
|
|
17432
|
+
if (session === void 0) return { refused: "SESSION_EXPIRING" };
|
|
17433
|
+
const sessionGrant = this.sessionGrant(prefix);
|
|
17434
|
+
if (!("refused" in sessionGrant)) {
|
|
17435
|
+
const signed2 = signedSessionGrant(session);
|
|
17436
|
+
if (!signed2 || signed2.expiresAt === null) return { refused: "NOT_COVERED" };
|
|
17437
|
+
return {
|
|
17438
|
+
path: "session",
|
|
17439
|
+
parentCid: session.delegationCid,
|
|
17440
|
+
expiresAt: signed2.expiresAt * 1e3
|
|
17441
|
+
};
|
|
17442
|
+
}
|
|
17443
|
+
if (authority.sessionOnly) return sessionGrant;
|
|
17444
|
+
return planOrRefusal(replicationEntries(session.spaceId, prefix));
|
|
17445
|
+
},
|
|
17446
|
+
async mint(deviceDid, prefix, signal) {
|
|
17447
|
+
if (authority.sessionOnly) throw new Error("compact delegate sessions cannot mint device grants");
|
|
17448
|
+
const session = host.replicationSession();
|
|
17449
|
+
if (session === void 0) throw new Error("replication mint without a session");
|
|
17450
|
+
const entries = replicationEntries(session.spaceId, prefix);
|
|
17451
|
+
const plan = planOrRefusal(entries);
|
|
17452
|
+
if ("refused" in plan) {
|
|
17453
|
+
throw Object.assign(
|
|
17454
|
+
new Error(`replication authority refused the mint: ${plan.refused}`),
|
|
17455
|
+
{ refused: plan.refused }
|
|
17456
|
+
);
|
|
17457
|
+
}
|
|
17458
|
+
signal.throwIfAborted();
|
|
17459
|
+
const minted = await new Promise((resolve, reject2) => {
|
|
17460
|
+
const onAbort = () => reject2(signal.reason ?? new Error("replication mint aborted"));
|
|
17461
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
17462
|
+
host.mintDelegation(deviceDid, entries).then(
|
|
17463
|
+
(result) => {
|
|
17464
|
+
signal.removeEventListener("abort", onAbort);
|
|
17465
|
+
resolve(result);
|
|
17466
|
+
},
|
|
17467
|
+
(error) => {
|
|
17468
|
+
signal.removeEventListener("abort", onAbort);
|
|
17469
|
+
reject2(error instanceof Error ? error : new Error(String(error)));
|
|
17470
|
+
}
|
|
17471
|
+
);
|
|
17472
|
+
});
|
|
17473
|
+
return { ucan: minted.ucan, parentCid: plan.parentCid, expiresAt: minted.expiresAt };
|
|
17474
|
+
}
|
|
17475
|
+
};
|
|
17476
|
+
return authority;
|
|
17477
|
+
}
|
|
17478
|
+
var import_sdk_core11, import_replica, parseUcanGrant, KV_GET2, KV_SYNC2, KV_SERVICE2, AUTHORITY_EXPIRY_MARGIN_MS;
|
|
17479
|
+
var init_authority = __esm({
|
|
17480
|
+
"src/replication/authority.ts"() {
|
|
17481
|
+
"use strict";
|
|
17482
|
+
import_sdk_core11 = require("@tinycloud/sdk-core");
|
|
17483
|
+
import_replica = require("@tinycloud/replica");
|
|
17484
|
+
init_config();
|
|
17485
|
+
init_authority_sign_in();
|
|
17486
|
+
parseUcanGrant = import_replica.parseUcanGrant;
|
|
17487
|
+
KV_GET2 = import_sdk_core11.KV.GET;
|
|
17488
|
+
KV_SYNC2 = import_sdk_core11.KV.SYNC;
|
|
17489
|
+
KV_SERVICE2 = "tinycloud.kv";
|
|
17490
|
+
AUTHORITY_EXPIRY_MARGIN_MS = 6e4;
|
|
17491
|
+
}
|
|
17492
|
+
});
|
|
17493
|
+
|
|
17025
17494
|
// src/index.ts
|
|
17026
|
-
var
|
|
17027
|
-
__export(
|
|
17495
|
+
var src_exports = {};
|
|
17496
|
+
__export(src_exports, {
|
|
17028
17497
|
ACCEPTED_MARKER_VERSIONS: () => ACCEPTED_MARKER_VERSIONS,
|
|
17029
|
-
ACCOUNT_REGISTRY_PATH: () =>
|
|
17030
|
-
ACCOUNT_REGISTRY_SPACE: () =>
|
|
17031
|
-
AccountService: () =>
|
|
17032
|
-
AutoApproveSpaceCreationHandler: () =>
|
|
17498
|
+
ACCOUNT_REGISTRY_PATH: () => import_sdk_core16.ACCOUNT_REGISTRY_PATH,
|
|
17499
|
+
ACCOUNT_REGISTRY_SPACE: () => import_sdk_core16.ACCOUNT_REGISTRY_SPACE,
|
|
17500
|
+
AccountService: () => import_sdk_core5.AccountService,
|
|
17501
|
+
AutoApproveSpaceCreationHandler: () => import_sdk_core15.AutoApproveSpaceCreationHandler,
|
|
17033
17502
|
BOOTSTRAP_COMPLETION_MARKER_KEY: () => BOOTSTRAP_COMPLETION_MARKER_KEY,
|
|
17034
17503
|
BOOTSTRAP_COMPLETION_MARKER_VERSION: () => BOOTSTRAP_COMPLETION_MARKER_VERSION,
|
|
17035
|
-
CapabilityKeyRegistry: () =>
|
|
17036
|
-
CapabilityKeyRegistryErrorCodes: () =>
|
|
17037
|
-
CaveatedDelegationUnsupportedError: () =>
|
|
17038
|
-
DECRYPT_ACTION: () =>
|
|
17039
|
-
DECRYPT_FACT_TYPE: () =>
|
|
17040
|
-
DECRYPT_RESULT_TYPE: () =>
|
|
17041
|
-
DEFAULT_ENCRYPTION_ALG: () =>
|
|
17042
|
-
DEFAULT_KEY_VERSION: () =>
|
|
17043
|
-
DEFAULT_MANIFEST_SPACE: () =>
|
|
17044
|
-
DEFAULT_MANIFEST_VERSION: () =>
|
|
17045
|
-
DEFAULT_SIGNED_READ_URL_EXPIRY_MS: () =>
|
|
17046
|
-
DataVaultService: () =>
|
|
17047
|
-
DatabaseHandle: () =>
|
|
17048
|
-
DecryptTransportResponseError: () =>
|
|
17504
|
+
CapabilityKeyRegistry: () => import_sdk_core24.CapabilityKeyRegistry,
|
|
17505
|
+
CapabilityKeyRegistryErrorCodes: () => import_sdk_core24.CapabilityKeyRegistryErrorCodes,
|
|
17506
|
+
CaveatedDelegationUnsupportedError: () => import_sdk_core16.CaveatedDelegationUnsupportedError,
|
|
17507
|
+
DECRYPT_ACTION: () => import_sdk_core21.DECRYPT_ACTION,
|
|
17508
|
+
DECRYPT_FACT_TYPE: () => import_sdk_core21.DECRYPT_FACT_TYPE,
|
|
17509
|
+
DECRYPT_RESULT_TYPE: () => import_sdk_core21.DECRYPT_RESULT_TYPE,
|
|
17510
|
+
DEFAULT_ENCRYPTION_ALG: () => import_sdk_core21.DEFAULT_ENCRYPTION_ALG,
|
|
17511
|
+
DEFAULT_KEY_VERSION: () => import_sdk_core21.DEFAULT_KEY_VERSION,
|
|
17512
|
+
DEFAULT_MANIFEST_SPACE: () => import_sdk_core16.DEFAULT_MANIFEST_SPACE,
|
|
17513
|
+
DEFAULT_MANIFEST_VERSION: () => import_sdk_core16.DEFAULT_MANIFEST_VERSION,
|
|
17514
|
+
DEFAULT_SIGNED_READ_URL_EXPIRY_MS: () => import_sdk_core17.DEFAULT_SIGNED_READ_URL_EXPIRY_MS,
|
|
17515
|
+
DataVaultService: () => import_sdk_core20.DataVaultService,
|
|
17516
|
+
DatabaseHandle: () => import_sdk_core18.DatabaseHandle,
|
|
17517
|
+
DecryptTransportResponseError: () => import_sdk_core21.DecryptTransportResponseError,
|
|
17049
17518
|
DelegatedAccess: () => DelegatedAccess,
|
|
17050
|
-
DelegationErrorCodes: () =>
|
|
17051
|
-
DelegationManager: () =>
|
|
17052
|
-
DuckDbAction: () =>
|
|
17053
|
-
DuckDbDatabaseHandle: () =>
|
|
17054
|
-
DuckDbService: () =>
|
|
17055
|
-
ENCRYPTION_NETWORK_URN_PREFIX: () =>
|
|
17056
|
-
ENCRYPTION_SERVICE: () =>
|
|
17057
|
-
ENCRYPTION_SERVICE_SHORT: () =>
|
|
17058
|
-
ENVELOPE_VERSION: () =>
|
|
17059
|
-
EncryptionService: () =>
|
|
17519
|
+
DelegationErrorCodes: () => import_sdk_core23.DelegationErrorCodes,
|
|
17520
|
+
DelegationManager: () => import_sdk_core23.DelegationManager,
|
|
17521
|
+
DuckDbAction: () => import_sdk_core19.DuckDbAction,
|
|
17522
|
+
DuckDbDatabaseHandle: () => import_sdk_core19.DuckDbDatabaseHandle,
|
|
17523
|
+
DuckDbService: () => import_sdk_core19.DuckDbService,
|
|
17524
|
+
ENCRYPTION_NETWORK_URN_PREFIX: () => import_sdk_core21.ENCRYPTION_NETWORK_URN_PREFIX,
|
|
17525
|
+
ENCRYPTION_SERVICE: () => import_sdk_core21.ENCRYPTION_SERVICE,
|
|
17526
|
+
ENCRYPTION_SERVICE_SHORT: () => import_sdk_core21.ENCRYPTION_SERVICE_SHORT,
|
|
17527
|
+
ENVELOPE_VERSION: () => import_sdk_core21.ENVELOPE_VERSION,
|
|
17528
|
+
EncryptionService: () => import_sdk_core21.EncryptionService,
|
|
17060
17529
|
FileSessionStorage: () => FileSessionStorage,
|
|
17061
|
-
HooksService: () =>
|
|
17062
|
-
IdentityParseError: () =>
|
|
17530
|
+
HooksService: () => import_sdk_core22.HooksService,
|
|
17531
|
+
IdentityParseError: () => import_sdk_core15.IdentityParseError,
|
|
17063
17532
|
InvalidRestoredSessionError: () => InvalidRestoredSessionError,
|
|
17064
|
-
KVService: () =>
|
|
17065
|
-
MAX_SECRET_SCOPE_LENGTH: () =>
|
|
17066
|
-
ManifestValidationError: () =>
|
|
17533
|
+
KVService: () => import_sdk_core17.KVService,
|
|
17534
|
+
MAX_SECRET_SCOPE_LENGTH: () => import_sdk_core20.MAX_SECRET_SCOPE_LENGTH,
|
|
17535
|
+
ManifestValidationError: () => import_sdk_core16.ManifestValidationError,
|
|
17067
17536
|
MemorySessionStorage: () => MemorySessionStorage,
|
|
17068
|
-
NETWORK_NAME_PATTERN: () =>
|
|
17069
|
-
NetworkIdError: () =>
|
|
17537
|
+
NETWORK_NAME_PATTERN: () => import_sdk_core21.NETWORK_NAME_PATTERN,
|
|
17538
|
+
NetworkIdError: () => import_sdk_core21.NetworkIdError,
|
|
17070
17539
|
NodeUserAuthorization: () => NodeUserAuthorization,
|
|
17071
17540
|
NodeWasmBindings: () => NodeWasmBindings,
|
|
17072
|
-
PermissionNotInManifestError: () =>
|
|
17073
|
-
PrefixedKVService: () =>
|
|
17541
|
+
PermissionNotInManifestError: () => import_sdk_core16.PermissionNotInManifestError,
|
|
17542
|
+
PrefixedKVService: () => import_sdk_core17.PrefixedKVService,
|
|
17074
17543
|
PrivateKeySigner: () => PrivateKeySigner,
|
|
17075
|
-
ProtocolMismatchError: () =>
|
|
17544
|
+
ProtocolMismatchError: () => import_sdk_core26.ProtocolMismatchError,
|
|
17076
17545
|
RUNTIME_DELEGATION_REJECTIONS: () => RUNTIME_DELEGATION_REJECTIONS,
|
|
17077
17546
|
RuntimeDelegationRejectedError: () => RuntimeDelegationRejectedError,
|
|
17078
|
-
SECRET_NAME_RE: () =>
|
|
17079
|
-
SECRET_SCOPE_RE: () =>
|
|
17080
|
-
SQLAction: () =>
|
|
17081
|
-
SQLService: () =>
|
|
17082
|
-
STORAGE_FULL_MESSAGE: () =>
|
|
17083
|
-
STORAGE_WRITE_TOO_LARGE_MESSAGE: () =>
|
|
17084
|
-
SecretsService: () =>
|
|
17085
|
-
ServiceContext: () =>
|
|
17086
|
-
SessionExpiredError: () =>
|
|
17087
|
-
SharingService: () =>
|
|
17088
|
-
SilentNotificationHandler: () =>
|
|
17089
|
-
Space: () =>
|
|
17090
|
-
SpaceErrorCodes: () =>
|
|
17091
|
-
SpaceService: () =>
|
|
17092
|
-
TC832_RESERVED_SCOPES: () =>
|
|
17093
|
-
TinyCloud: () =>
|
|
17094
|
-
TinyCloudDebugLogger: () =>
|
|
17547
|
+
SECRET_NAME_RE: () => import_sdk_core20.SECRET_NAME_RE,
|
|
17548
|
+
SECRET_SCOPE_RE: () => import_sdk_core20.SECRET_SCOPE_RE,
|
|
17549
|
+
SQLAction: () => import_sdk_core18.SQLAction,
|
|
17550
|
+
SQLService: () => import_sdk_core18.SQLService,
|
|
17551
|
+
STORAGE_FULL_MESSAGE: () => import_sdk_core15.STORAGE_FULL_MESSAGE,
|
|
17552
|
+
STORAGE_WRITE_TOO_LARGE_MESSAGE: () => import_sdk_core15.STORAGE_WRITE_TOO_LARGE_MESSAGE,
|
|
17553
|
+
SecretsService: () => import_sdk_core20.SecretsService,
|
|
17554
|
+
ServiceContext: () => import_sdk_core27.ServiceContext,
|
|
17555
|
+
SessionExpiredError: () => import_sdk_core16.SessionExpiredError,
|
|
17556
|
+
SharingService: () => import_sdk_core23.SharingService,
|
|
17557
|
+
SilentNotificationHandler: () => import_sdk_core15.SilentNotificationHandler,
|
|
17558
|
+
Space: () => import_sdk_core25.Space,
|
|
17559
|
+
SpaceErrorCodes: () => import_sdk_core25.SpaceErrorCodes,
|
|
17560
|
+
SpaceService: () => import_sdk_core25.SpaceService,
|
|
17561
|
+
TC832_RESERVED_SCOPES: () => import_sdk_core20.TC832_RESERVED_SCOPES,
|
|
17562
|
+
TinyCloud: () => import_sdk_core14.TinyCloud,
|
|
17563
|
+
TinyCloudDebugLogger: () => import_sdk_core15.TinyCloudDebugLogger,
|
|
17095
17564
|
TinyCloudNode: () => TinyCloudNode,
|
|
17096
|
-
UnsupportedFeatureError: () =>
|
|
17565
|
+
UnsupportedFeatureError: () => import_sdk_core26.UnsupportedFeatureError,
|
|
17097
17566
|
UnsupportedSessionRestoreError: () => UnsupportedSessionRestoreError,
|
|
17098
|
-
VAULT_PERMISSION_SERVICE: () =>
|
|
17099
|
-
VaultHeaders: () =>
|
|
17100
|
-
VaultPublicSpaceKVActions: () =>
|
|
17101
|
-
VersionCheckError: () =>
|
|
17567
|
+
VAULT_PERMISSION_SERVICE: () => import_sdk_core16.VAULT_PERMISSION_SERVICE,
|
|
17568
|
+
VaultHeaders: () => import_sdk_core20.VaultHeaders,
|
|
17569
|
+
VaultPublicSpaceKVActions: () => import_sdk_core20.VaultPublicSpaceKVActions,
|
|
17570
|
+
VersionCheckError: () => import_sdk_core26.VersionCheckError,
|
|
17102
17571
|
WasmKeyProvider: () => WasmKeyProvider,
|
|
17103
17572
|
activateCompactRuntimeDelegation: () => activateCompactRuntimeDelegation,
|
|
17104
17573
|
activateValidatedRuntimeDelegation: () => activateValidatedRuntimeDelegation,
|
|
17105
|
-
addressStorageKey: () =>
|
|
17106
|
-
appSecretScope: () =>
|
|
17107
|
-
buildCanonicalDecryptRequest: () =>
|
|
17108
|
-
buildDecryptAttenuation: () =>
|
|
17109
|
-
buildDecryptFacts: () =>
|
|
17110
|
-
buildDecryptInvocation: () =>
|
|
17111
|
-
buildNetworkId: () =>
|
|
17112
|
-
buildSpaceUri: () =>
|
|
17113
|
-
canonicalHashHex: () =>
|
|
17114
|
-
canonicalSignedResponse: () =>
|
|
17115
|
-
canonicalizeAddress: () =>
|
|
17116
|
-
canonicalizeDid: () =>
|
|
17117
|
-
canonicalizeDidUrl: () =>
|
|
17118
|
-
canonicalizeEncryptionJson: () =>
|
|
17119
|
-
canonicalizeNetworkId: () =>
|
|
17120
|
-
canonicalizeSecretScope: () =>
|
|
17121
|
-
checkDecryptInvocationInput: () =>
|
|
17122
|
-
checkNodeInfo: () =>
|
|
17123
|
-
clearTinyCloudDebugLogs: () =>
|
|
17124
|
-
composeManifestRequest: () =>
|
|
17125
|
-
createCapabilityKeyRegistry: () =>
|
|
17126
|
-
createOpenKeyCallbackSigningStrategy: () =>
|
|
17127
|
-
createSharingService: () =>
|
|
17128
|
-
createSpaceService: () =>
|
|
17129
|
-
createVaultCrypto: () =>
|
|
17574
|
+
addressStorageKey: () => import_sdk_core15.addressStorageKey,
|
|
17575
|
+
appSecretScope: () => import_sdk_core20.appSecretScope,
|
|
17576
|
+
buildCanonicalDecryptRequest: () => import_sdk_core21.buildCanonicalDecryptRequest,
|
|
17577
|
+
buildDecryptAttenuation: () => import_sdk_core21.buildDecryptAttenuation,
|
|
17578
|
+
buildDecryptFacts: () => import_sdk_core21.buildDecryptFacts,
|
|
17579
|
+
buildDecryptInvocation: () => import_sdk_core21.buildDecryptInvocation,
|
|
17580
|
+
buildNetworkId: () => import_sdk_core21.buildNetworkId,
|
|
17581
|
+
buildSpaceUri: () => import_sdk_core25.buildSpaceUri,
|
|
17582
|
+
canonicalHashHex: () => import_sdk_core21.canonicalHashHex,
|
|
17583
|
+
canonicalSignedResponse: () => import_sdk_core21.canonicalSignedResponse,
|
|
17584
|
+
canonicalizeAddress: () => import_sdk_core15.canonicalizeAddress,
|
|
17585
|
+
canonicalizeDid: () => import_sdk_core15.canonicalizeDid,
|
|
17586
|
+
canonicalizeDidUrl: () => import_sdk_core15.canonicalizeDidUrl,
|
|
17587
|
+
canonicalizeEncryptionJson: () => import_sdk_core21.canonicalizeEncryptionJson,
|
|
17588
|
+
canonicalizeNetworkId: () => import_sdk_core15.canonicalizeNetworkId,
|
|
17589
|
+
canonicalizeSecretScope: () => import_sdk_core20.canonicalizeSecretScope,
|
|
17590
|
+
checkDecryptInvocationInput: () => import_sdk_core21.checkDecryptInvocationInput,
|
|
17591
|
+
checkNodeInfo: () => import_sdk_core26.checkNodeInfo,
|
|
17592
|
+
clearTinyCloudDebugLogs: () => import_sdk_core15.clearTinyCloudDebugLogs,
|
|
17593
|
+
composeManifestRequest: () => import_sdk_core16.composeManifestRequest,
|
|
17594
|
+
createCapabilityKeyRegistry: () => import_sdk_core24.createCapabilityKeyRegistry,
|
|
17595
|
+
createOpenKeyCallbackSigningStrategy: () => import_sdk_core3.createOpenKeyCallbackSigningStrategy,
|
|
17596
|
+
createSharingService: () => import_sdk_core23.createSharingService,
|
|
17597
|
+
createSpaceService: () => import_sdk_core25.createSpaceService,
|
|
17598
|
+
createVaultCrypto: () => import_sdk_core20.createVaultCrypto,
|
|
17130
17599
|
createWasmKeyProvider: () => createWasmKeyProvider,
|
|
17131
|
-
decryptEnvelopeWithKey: () =>
|
|
17600
|
+
decryptEnvelopeWithKey: () => import_sdk_core21.decryptEnvelopeWithKey,
|
|
17132
17601
|
defaultSignStrategy: () => defaultSignStrategy,
|
|
17133
|
-
defaultSpaceCreationHandler: () =>
|
|
17134
|
-
deriveSignedReceiverKey: () =>
|
|
17602
|
+
defaultSpaceCreationHandler: () => import_sdk_core15.defaultSpaceCreationHandler,
|
|
17603
|
+
deriveSignedReceiverKey: () => import_sdk_core21.deriveSignedReceiverKey,
|
|
17135
17604
|
deserializeDelegation: () => deserializeDelegation,
|
|
17136
|
-
didCacheKey: () =>
|
|
17137
|
-
didEquals: () =>
|
|
17138
|
-
disableTinyCloudDebug: () =>
|
|
17139
|
-
discoverNetwork: () =>
|
|
17140
|
-
enableTinyCloudDebug: () =>
|
|
17141
|
-
encryptToNetwork: () =>
|
|
17142
|
-
encryptionBase64Decode: () =>
|
|
17143
|
-
encryptionBase64Encode: () =>
|
|
17144
|
-
encryptionError: () =>
|
|
17145
|
-
encryptionUtf8Decode: () =>
|
|
17146
|
-
encryptionUtf8Encode: () =>
|
|
17147
|
-
ensureNetworkUsableForDecrypt: () =>
|
|
17148
|
-
expandActionShortNames: () =>
|
|
17149
|
-
expandPermissionEntries: () =>
|
|
17150
|
-
expandPermissionEntry: () =>
|
|
17605
|
+
didCacheKey: () => import_sdk_core15.didCacheKey,
|
|
17606
|
+
didEquals: () => import_sdk_core15.didEquals,
|
|
17607
|
+
disableTinyCloudDebug: () => import_sdk_core15.disableTinyCloudDebug,
|
|
17608
|
+
discoverNetwork: () => import_sdk_core21.discoverNetwork,
|
|
17609
|
+
enableTinyCloudDebug: () => import_sdk_core15.enableTinyCloudDebug,
|
|
17610
|
+
encryptToNetwork: () => import_sdk_core21.encryptToNetwork,
|
|
17611
|
+
encryptionBase64Decode: () => import_sdk_core21.encryptionBase64Decode,
|
|
17612
|
+
encryptionBase64Encode: () => import_sdk_core21.encryptionBase64Encode,
|
|
17613
|
+
encryptionError: () => import_sdk_core21.encryptionError,
|
|
17614
|
+
encryptionUtf8Decode: () => import_sdk_core21.encryptionUtf8Decode,
|
|
17615
|
+
encryptionUtf8Encode: () => import_sdk_core21.encryptionUtf8Encode,
|
|
17616
|
+
ensureNetworkUsableForDecrypt: () => import_sdk_core21.ensureNetworkUsableForDecrypt,
|
|
17617
|
+
expandActionShortNames: () => import_sdk_core16.expandActionShortNames,
|
|
17618
|
+
expandPermissionEntries: () => import_sdk_core16.expandPermissionEntries,
|
|
17619
|
+
expandPermissionEntry: () => import_sdk_core16.expandPermissionEntry,
|
|
17151
17620
|
extractSiweExpiration: () => extractSiweExpiration,
|
|
17152
|
-
generateRandomReceiverKey: () =>
|
|
17153
|
-
getTinyCloudDebugLogs: () =>
|
|
17621
|
+
generateRandomReceiverKey: () => import_sdk_core21.generateRandomReceiverKey,
|
|
17622
|
+
getTinyCloudDebugLogs: () => import_sdk_core15.getTinyCloudDebugLogs,
|
|
17154
17623
|
grantAuthRequest: () => grantAuthRequest,
|
|
17155
|
-
hexDecode: () =>
|
|
17156
|
-
hexEncode: () =>
|
|
17157
|
-
installTinyCloudDebugGlobals: () =>
|
|
17158
|
-
isCapabilitySubset: () =>
|
|
17159
|
-
isEvmAddress: () =>
|
|
17160
|
-
isNetworkId: () =>
|
|
17161
|
-
isStorageFullError: () =>
|
|
17162
|
-
loadManifest: () =>
|
|
17163
|
-
makePkhSpaceId: () =>
|
|
17164
|
-
makePublicSpaceId: () =>
|
|
17165
|
-
networkDiscoveryKey: () =>
|
|
17166
|
-
openWrappedKey: () =>
|
|
17167
|
-
parseCanonicalNetworkId: () =>
|
|
17168
|
-
parseExpiry: () =>
|
|
17169
|
-
parseNetworkId: () =>
|
|
17170
|
-
parsePkhDid: () =>
|
|
17171
|
-
parseSecretCatalogKey: () =>
|
|
17172
|
-
parseSpaceUri: () =>
|
|
17173
|
-
pkhDid: () =>
|
|
17174
|
-
principalDid: () =>
|
|
17175
|
-
principalDidEquals: () =>
|
|
17176
|
-
resolveManifest: () =>
|
|
17177
|
-
resolveSecretListPrefix: () =>
|
|
17178
|
-
resolveSecretPath: () =>
|
|
17179
|
-
resourceCapabilitiesToSpaceAbilitiesMap: () =>
|
|
17624
|
+
hexDecode: () => import_sdk_core21.hexDecode,
|
|
17625
|
+
hexEncode: () => import_sdk_core21.hexEncode,
|
|
17626
|
+
installTinyCloudDebugGlobals: () => import_sdk_core15.installTinyCloudDebugGlobals,
|
|
17627
|
+
isCapabilitySubset: () => import_sdk_core16.isCapabilitySubset,
|
|
17628
|
+
isEvmAddress: () => import_sdk_core15.isEvmAddress,
|
|
17629
|
+
isNetworkId: () => import_sdk_core21.isNetworkId,
|
|
17630
|
+
isStorageFullError: () => import_sdk_core15.isStorageFullError,
|
|
17631
|
+
loadManifest: () => import_sdk_core16.loadManifest,
|
|
17632
|
+
makePkhSpaceId: () => import_sdk_core15.makePkhSpaceId,
|
|
17633
|
+
makePublicSpaceId: () => import_sdk_core25.makePublicSpaceId,
|
|
17634
|
+
networkDiscoveryKey: () => import_sdk_core21.networkDiscoveryKey,
|
|
17635
|
+
openWrappedKey: () => import_sdk_core21.openWrappedKey,
|
|
17636
|
+
parseCanonicalNetworkId: () => import_sdk_core15.parseCanonicalNetworkId,
|
|
17637
|
+
parseExpiry: () => import_sdk_core16.parseExpiry,
|
|
17638
|
+
parseNetworkId: () => import_sdk_core21.parseNetworkId,
|
|
17639
|
+
parsePkhDid: () => import_sdk_core15.parsePkhDid,
|
|
17640
|
+
parseSecretCatalogKey: () => import_sdk_core20.parseSecretCatalogKey,
|
|
17641
|
+
parseSpaceUri: () => import_sdk_core25.parseSpaceUri,
|
|
17642
|
+
pkhDid: () => import_sdk_core15.pkhDid,
|
|
17643
|
+
principalDid: () => import_sdk_core15.principalDid,
|
|
17644
|
+
principalDidEquals: () => import_sdk_core15.principalDidEquals,
|
|
17645
|
+
resolveManifest: () => import_sdk_core16.resolveManifest,
|
|
17646
|
+
resolveSecretListPrefix: () => import_sdk_core20.resolveSecretListPrefix,
|
|
17647
|
+
resolveSecretPath: () => import_sdk_core20.resolveSecretPath,
|
|
17648
|
+
resourceCapabilitiesToSpaceAbilitiesMap: () => import_sdk_core16.resourceCapabilitiesToSpaceAbilitiesMap,
|
|
17180
17649
|
serializeDelegation: () => serializeDelegation,
|
|
17181
17650
|
signedCompactUcanExpiry: () => signedCompactUcanExpiry,
|
|
17182
|
-
|
|
17183
|
-
|
|
17184
|
-
|
|
17185
|
-
|
|
17651
|
+
sqliteReplicaStorage: () => sqliteReplicaStorage,
|
|
17652
|
+
tinyCloudDebugLogger: () => import_sdk_core15.tinyCloudDebugLogger,
|
|
17653
|
+
validateEnvelope: () => import_sdk_core21.validateEnvelope,
|
|
17654
|
+
validateManifest: () => import_sdk_core16.validateManifest,
|
|
17655
|
+
verifyDecryptResponse: () => import_sdk_core21.verifyDecryptResponse,
|
|
17186
17656
|
wireOpenKeyAuthorize: () => wireOpenKeyAuthorize
|
|
17187
17657
|
});
|
|
17188
|
-
module.exports = __toCommonJS(
|
|
17658
|
+
module.exports = __toCommonJS(src_exports);
|
|
17189
17659
|
|
|
17190
17660
|
// src/NodeWasmBindings.ts
|
|
17191
17661
|
var import_node_sdk_wasm = require("@tinycloud/node-sdk-wasm");
|
|
@@ -17817,16 +18287,32 @@ function deserializeDelegation(data) {
|
|
|
17817
18287
|
}
|
|
17818
18288
|
|
|
17819
18289
|
// src/TinyCloudNode.ts
|
|
17820
|
-
|
|
17821
|
-
|
|
18290
|
+
init_config();
|
|
18291
|
+
|
|
18292
|
+
// src/replication/module-registry.ts
|
|
18293
|
+
var nodeLoaders;
|
|
18294
|
+
function registerReplicationLoaders(loaders) {
|
|
18295
|
+
nodeLoaders = loaders;
|
|
18296
|
+
}
|
|
18297
|
+
function getNodeReplicationLoaders() {
|
|
18298
|
+
if (nodeLoaders === void 0) {
|
|
18299
|
+
throw new Error("Replication requires registering replication controller loaders.");
|
|
18300
|
+
}
|
|
18301
|
+
return nodeLoaders;
|
|
18302
|
+
}
|
|
18303
|
+
|
|
18304
|
+
// src/TinyCloudNode.ts
|
|
18305
|
+
var import_sdk_core9 = require("@tinycloud/sdk-core");
|
|
18306
|
+
var import_sdk_services3 = require("@tinycloud/sdk-services");
|
|
17822
18307
|
|
|
17823
18308
|
// src/authorization/NodeUserAuthorization.ts
|
|
17824
18309
|
var import_node_crypto = require("crypto");
|
|
17825
18310
|
var import_siwe = require("siwe");
|
|
17826
|
-
var
|
|
18311
|
+
var import_sdk_core4 = require("@tinycloud/sdk-core");
|
|
18312
|
+
init_authority_sign_in();
|
|
17827
18313
|
|
|
17828
18314
|
// src/authorization/strategies.ts
|
|
17829
|
-
var
|
|
18315
|
+
var import_sdk_core3 = require("@tinycloud/sdk-core");
|
|
17830
18316
|
var defaultSignStrategy = { type: "auto-sign" };
|
|
17831
18317
|
|
|
17832
18318
|
// src/storage/MemorySessionStorage.ts
|
|
@@ -17901,8 +18387,8 @@ var MemorySessionStorage = class {
|
|
|
17901
18387
|
};
|
|
17902
18388
|
|
|
17903
18389
|
// src/authorization/NodeUserAuthorization.ts
|
|
17904
|
-
var DECRYPT_ACTION =
|
|
17905
|
-
var NETWORK_CREATE_ACTION =
|
|
18390
|
+
var DECRYPT_ACTION = import_sdk_core4.ENCRYPTION.DECRYPT;
|
|
18391
|
+
var NETWORK_CREATE_ACTION = import_sdk_core4.ENCRYPTION.NETWORK_CREATE;
|
|
17906
18392
|
function describeHostFailure(result) {
|
|
17907
18393
|
const text = result.error?.trim();
|
|
17908
18394
|
return text ? `${result.status} - ${text}` : `${result.status}`;
|
|
@@ -17930,7 +18416,7 @@ function canonicalOpenKeyManifestSha256Hex(value) {
|
|
|
17930
18416
|
}
|
|
17931
18417
|
function didPrincipalMatches(actual, expected) {
|
|
17932
18418
|
try {
|
|
17933
|
-
return (0,
|
|
18419
|
+
return (0, import_sdk_core4.principalDidEquals)(actual, expected);
|
|
17934
18420
|
} catch {
|
|
17935
18421
|
return actual === expected;
|
|
17936
18422
|
}
|
|
@@ -17971,30 +18457,30 @@ var NodeUserAuthorization = class {
|
|
|
17971
18457
|
this.spacePrefix = config.spacePrefix ?? "default";
|
|
17972
18458
|
this.defaultActions = config.defaultActions ?? {
|
|
17973
18459
|
kv: {
|
|
17974
|
-
"": [
|
|
18460
|
+
"": [import_sdk_core4.KV.PUT, import_sdk_core4.KV.GET, import_sdk_core4.KV.DEL, import_sdk_core4.KV.LIST, import_sdk_core4.KV.METADATA]
|
|
17975
18461
|
},
|
|
17976
18462
|
sql: {
|
|
17977
|
-
"": [
|
|
18463
|
+
"": [import_sdk_core4.SQL.READ, import_sdk_core4.SQL.WRITE, import_sdk_core4.SQL.SCHEMA, import_sdk_core4.SQL.ADMIN, import_sdk_core4.SQL.EXPORT]
|
|
17978
18464
|
},
|
|
17979
18465
|
duckdb: {
|
|
17980
18466
|
"": [
|
|
17981
|
-
|
|
17982
|
-
|
|
17983
|
-
|
|
17984
|
-
|
|
17985
|
-
|
|
17986
|
-
|
|
17987
|
-
|
|
18467
|
+
import_sdk_core4.DUCKDB.READ,
|
|
18468
|
+
import_sdk_core4.DUCKDB.WRITE,
|
|
18469
|
+
import_sdk_core4.DUCKDB.ADMIN,
|
|
18470
|
+
import_sdk_core4.DUCKDB.DESCRIBE,
|
|
18471
|
+
import_sdk_core4.DUCKDB.EXPORT,
|
|
18472
|
+
import_sdk_core4.DUCKDB.IMPORT,
|
|
18473
|
+
import_sdk_core4.DUCKDB.EXECUTE
|
|
17988
18474
|
]
|
|
17989
18475
|
},
|
|
17990
18476
|
capabilities: {
|
|
17991
|
-
"": [
|
|
18477
|
+
"": [import_sdk_core4.CAPABILITIES.READ]
|
|
17992
18478
|
},
|
|
17993
18479
|
hooks: {
|
|
17994
|
-
"": [
|
|
18480
|
+
"": [import_sdk_core4.HOOKS.SUBSCRIBE, import_sdk_core4.HOOKS.REGISTER, import_sdk_core4.HOOKS.LIST, import_sdk_core4.HOOKS.UNREGISTER]
|
|
17995
18481
|
}
|
|
17996
18482
|
};
|
|
17997
|
-
this.sessionExpirationMs = config.sessionExpirationMs ??
|
|
18483
|
+
this.sessionExpirationMs = config.sessionExpirationMs ?? import_sdk_core4.EXPIRY.SESSION_MS;
|
|
17998
18484
|
this.autoCreateSpace = config.autoCreateSpace ?? false;
|
|
17999
18485
|
this.spaceCreationHandler = config.spaceCreationHandler;
|
|
18000
18486
|
this.tinycloudHosts = config.tinycloudHosts;
|
|
@@ -18009,6 +18495,7 @@ var NodeUserAuthorization = class {
|
|
|
18009
18495
|
this.nonce = config.nonce;
|
|
18010
18496
|
this.siweConfig = config.siweConfig;
|
|
18011
18497
|
this.includeAccountRegistryPermissions = config.includeAccountRegistryPermissions ?? true;
|
|
18498
|
+
this.replication = config.replication?.enabled === true ? config.replication : void 0;
|
|
18012
18499
|
this._manifest = config.manifest;
|
|
18013
18500
|
this._capabilityRequest = config.capabilityRequest;
|
|
18014
18501
|
this.sessionManager = config.sessionManager ?? this.wasm.createSessionManager();
|
|
@@ -18073,7 +18560,7 @@ var NodeUserAuthorization = class {
|
|
|
18073
18560
|
* {@link ensureTinyCloudHosts}.
|
|
18074
18561
|
*/
|
|
18075
18562
|
setRestoredTinyCloudSession(session, hosts) {
|
|
18076
|
-
const address = (0,
|
|
18563
|
+
const address = (0, import_sdk_core4.canonicalizeAddress)(session.address);
|
|
18077
18564
|
this._tinyCloudSession = { ...session, address };
|
|
18078
18565
|
this._address = address;
|
|
18079
18566
|
this._chainId = session.chainId;
|
|
@@ -18134,8 +18621,8 @@ var NodeUserAuthorization = class {
|
|
|
18134
18621
|
if (this.tinycloudHosts && this.tinycloudHosts.length > 0) {
|
|
18135
18622
|
return;
|
|
18136
18623
|
}
|
|
18137
|
-
const subject = (0,
|
|
18138
|
-
const resolved = await (0,
|
|
18624
|
+
const subject = (0, import_sdk_core4.pkhDid)(address, chainId);
|
|
18625
|
+
const resolved = await (0, import_sdk_core4.resolveTinyCloudHosts)(subject, {
|
|
18139
18626
|
registryUrl: this.tinycloudRegistryUrl,
|
|
18140
18627
|
fallbackHosts: this.tinycloudFallbackHosts,
|
|
18141
18628
|
autoDiscoverLocalNode: this.autoDiscoverLocalNode,
|
|
@@ -18203,7 +18690,7 @@ var NodeUserAuthorization = class {
|
|
|
18203
18690
|
if (this._manifest === void 0) {
|
|
18204
18691
|
return void 0;
|
|
18205
18692
|
}
|
|
18206
|
-
this._capabilityRequest = (0,
|
|
18693
|
+
this._capabilityRequest = (0, import_sdk_core4.composeManifestRequest)(
|
|
18207
18694
|
Array.isArray(this._manifest) ? this._manifest : [this._manifest],
|
|
18208
18695
|
{
|
|
18209
18696
|
includeAccountRegistryPermissions: this.includeAccountRegistryPermissions
|
|
@@ -18215,50 +18702,173 @@ var NodeUserAuthorization = class {
|
|
|
18215
18702
|
if (space.startsWith("tinycloud:")) {
|
|
18216
18703
|
return space;
|
|
18217
18704
|
}
|
|
18218
|
-
return (0,
|
|
18705
|
+
return (0, import_sdk_core4.makePkhSpaceId)(address, chainId, space);
|
|
18706
|
+
}
|
|
18707
|
+
/**
|
|
18708
|
+
* The plain-session primary abilities: `defaultActions` (the shared table)
|
|
18709
|
+
* unless the primary space IS the account space, where account-registry
|
|
18710
|
+
* permissions merge into a private clone so the shared table is never
|
|
18711
|
+
* mutated. Shared between `resolveSignInCapabilities` and
|
|
18712
|
+
* `signInPermissionInputs` so sign-in and `replicationSignInEntries`
|
|
18713
|
+
* can't disagree (§4.6).
|
|
18714
|
+
*/
|
|
18715
|
+
primaryActionsForSignIn() {
|
|
18716
|
+
const primaryActions = this.includeAccountRegistryPermissions && this.spacePrefix === import_sdk_core4.ACCOUNT_REGISTRY_SPACE ? cloneAbilitiesMap(this.defaultActions) : this.defaultActions;
|
|
18717
|
+
if (this.includeAccountRegistryPermissions && this.spacePrefix === import_sdk_core4.ACCOUNT_REGISTRY_SPACE) {
|
|
18718
|
+
const accountAbilities = (0, import_sdk_core4.resourceCapabilitiesToAbilitiesMap)(
|
|
18719
|
+
import_sdk_core4.ACCOUNT_MANIFEST_PERMISSIONS
|
|
18720
|
+
);
|
|
18721
|
+
for (const [service, paths] of Object.entries(accountAbilities)) {
|
|
18722
|
+
const existingPaths = primaryActions[service] ?? (primaryActions[service] = {});
|
|
18723
|
+
for (const [path, actions] of Object.entries(paths)) {
|
|
18724
|
+
const existingActions = existingPaths[path] ?? (existingPaths[path] = []);
|
|
18725
|
+
for (const action of actions) {
|
|
18726
|
+
if (!existingActions.includes(action)) existingActions.push(action);
|
|
18727
|
+
}
|
|
18728
|
+
}
|
|
18729
|
+
}
|
|
18730
|
+
}
|
|
18731
|
+
return primaryActions;
|
|
18732
|
+
}
|
|
18733
|
+
/**
|
|
18734
|
+
* The abilities a `spacePrefix: "secrets"` plain session actually requests
|
|
18735
|
+
* for its primary space: the vault-secrets subtree only — the
|
|
18736
|
+
* `defaultActions` root `get` is REPLACED, not merged (sign-in installs
|
|
18737
|
+
* this map under the primary space id). Shared between
|
|
18738
|
+
* `resolveSignInCapabilities` and `signInPermissionInputs` so the
|
|
18739
|
+
* replication augmentation measures coverage against the effective
|
|
18740
|
+
* pre-replication request, never the uninstalled `primaryActions` (§4.1).
|
|
18741
|
+
*/
|
|
18742
|
+
secretsPrimaryAbilities() {
|
|
18743
|
+
return {
|
|
18744
|
+
kv: {
|
|
18745
|
+
"vault/secrets/": [
|
|
18746
|
+
import_sdk_core4.KV.GET,
|
|
18747
|
+
import_sdk_core4.KV.PUT,
|
|
18748
|
+
import_sdk_core4.KV.DEL,
|
|
18749
|
+
import_sdk_core4.KV.LIST,
|
|
18750
|
+
import_sdk_core4.KV.METADATA
|
|
18751
|
+
]
|
|
18752
|
+
}
|
|
18753
|
+
};
|
|
18754
|
+
}
|
|
18755
|
+
/**
|
|
18756
|
+
* The effective sign-in request as `PermissionEntry`s plus the resolved
|
|
18757
|
+
* primary space id — the inputs to the replication augmentation (§4.1).
|
|
18758
|
+
* `resolveSignInCapabilities` merges the augmented entries into its
|
|
18759
|
+
* abilities; `replicationSignInEntries()` returns them verbatim, so the
|
|
18760
|
+
* entries the SIWE recap carries and the restore check sees are the same.
|
|
18761
|
+
*/
|
|
18762
|
+
signInPermissionInputs(address, chainId) {
|
|
18763
|
+
const request = this.getCapabilityRequest();
|
|
18764
|
+
if (request === void 0) {
|
|
18765
|
+
const primarySpaceId2 = (0, import_sdk_core4.makePkhSpaceId)(address, chainId, this.spacePrefix);
|
|
18766
|
+
const effectivePrimary = this.spacePrefix === "secrets" ? this.secretsPrimaryAbilities() : this.primaryActionsForSignIn();
|
|
18767
|
+
const kvPaths = effectivePrimary["kv"] ?? {};
|
|
18768
|
+
return {
|
|
18769
|
+
primarySpaceId: primarySpaceId2,
|
|
18770
|
+
entries: Object.entries(kvPaths).map(([path, actions]) => ({
|
|
18771
|
+
service: "tinycloud.kv",
|
|
18772
|
+
space: primarySpaceId2,
|
|
18773
|
+
path,
|
|
18774
|
+
actions: [...actions]
|
|
18775
|
+
}))
|
|
18776
|
+
};
|
|
18777
|
+
}
|
|
18778
|
+
const spaceResources = request.resources.filter(
|
|
18779
|
+
(entry) => entry.service !== import_sdk_core4.ENCRYPTION_PERMISSION_SERVICE
|
|
18780
|
+
);
|
|
18781
|
+
const primarySpaceName = spaceResources.find((entry) => entry.space !== "account")?.space ?? import_sdk_core4.DEFAULT_MANIFEST_SPACE;
|
|
18782
|
+
const primarySpaceId = this.resolveSpaceName(
|
|
18783
|
+
primarySpaceName,
|
|
18784
|
+
address,
|
|
18785
|
+
chainId
|
|
18786
|
+
);
|
|
18787
|
+
return {
|
|
18788
|
+
primarySpaceId,
|
|
18789
|
+
entries: spaceResources.map((entry) => ({
|
|
18790
|
+
service: entry.service,
|
|
18791
|
+
space: this.resolveSpaceName(entry.space, address, chainId),
|
|
18792
|
+
path: entry.path,
|
|
18793
|
+
actions: [...entry.actions]
|
|
18794
|
+
}))
|
|
18795
|
+
};
|
|
18796
|
+
}
|
|
18797
|
+
/**
|
|
18798
|
+
* Merge replication augmentation entries into a space's abilities map
|
|
18799
|
+
* without mutating shared tables (`defaultActions` may back the base map):
|
|
18800
|
+
* the primary entry in `spaceAbilities` is replaced with a copy whose `kv`
|
|
18801
|
+
* paths gain `get`/`sync`. Returns the merged map for `abilities`.
|
|
18802
|
+
*/
|
|
18803
|
+
mergeReplicationEntries(spaceAbilities, primarySpaceId, abilities, entries) {
|
|
18804
|
+
var _a;
|
|
18805
|
+
if (entries.length === 0) {
|
|
18806
|
+
return abilities;
|
|
18807
|
+
}
|
|
18808
|
+
const base2 = spaceAbilities[primarySpaceId] ?? abilities;
|
|
18809
|
+
const kv = {};
|
|
18810
|
+
for (const [path, actions] of Object.entries(base2["kv"] ?? {})) {
|
|
18811
|
+
kv[path] = [...actions];
|
|
18812
|
+
}
|
|
18813
|
+
for (const entry of entries) {
|
|
18814
|
+
const list = kv[_a = entry.path] ?? (kv[_a] = []);
|
|
18815
|
+
for (const action of entry.actions) {
|
|
18816
|
+
if (!list.includes(action)) list.push(action);
|
|
18817
|
+
}
|
|
18818
|
+
}
|
|
18819
|
+
const merged = { ...base2, kv };
|
|
18820
|
+
spaceAbilities[primarySpaceId] = merged;
|
|
18821
|
+
return merged;
|
|
18822
|
+
}
|
|
18823
|
+
/**
|
|
18824
|
+
* The replication entries this authorization's sign-in request carries
|
|
18825
|
+
* for the signed-in or restored address (TC-858 §4.1/§4.6): the output of
|
|
18826
|
+
* the same augmentation `resolveSignInCapabilities` runs — one
|
|
18827
|
+
* `{tinycloud.kv, primarySpace, prefix, [get, sync]}` per configured
|
|
18828
|
+
* prefix that already has an unrestricted covering `get` and passes the
|
|
18829
|
+
* secrets opt-in gate. Empty when replication is off or no address is
|
|
18830
|
+
* known. Pure.
|
|
18831
|
+
*/
|
|
18832
|
+
replicationSignInEntries() {
|
|
18833
|
+
if (this.replication === void 0) return [];
|
|
18834
|
+
const address = this._address ?? this._tinyCloudSession?.address;
|
|
18835
|
+
const chainId = this._chainId ?? this._tinyCloudSession?.chainId;
|
|
18836
|
+
if (address === void 0 || chainId === void 0) return [];
|
|
18837
|
+
const { entries, primarySpaceId } = this.signInPermissionInputs(address, chainId);
|
|
18838
|
+
return augmentSignInEntriesWithReplication({
|
|
18839
|
+
entries,
|
|
18840
|
+
primarySpaceId,
|
|
18841
|
+
replication: this.replication
|
|
18842
|
+
});
|
|
18219
18843
|
}
|
|
18220
18844
|
defaultEncryptionNetworkId(address, chainId) {
|
|
18221
|
-
return `urn:tinycloud:encryption:${(0,
|
|
18845
|
+
return `urn:tinycloud:encryption:${(0, import_sdk_core4.pkhDid)(address, chainId)}:default`;
|
|
18222
18846
|
}
|
|
18223
18847
|
resolveSignInCapabilities(address, chainId) {
|
|
18224
18848
|
const request = this.getCapabilityRequest();
|
|
18225
18849
|
if (request === void 0) {
|
|
18226
18850
|
const defaultNetworkId = this.defaultEncryptionNetworkId(address, chainId);
|
|
18227
|
-
const primarySpaceId2 = (0,
|
|
18228
|
-
const secretsSpaceId = (0,
|
|
18229
|
-
const primaryActions = this.
|
|
18851
|
+
const primarySpaceId2 = (0, import_sdk_core4.makePkhSpaceId)(address, chainId, this.spacePrefix);
|
|
18852
|
+
const secretsSpaceId = (0, import_sdk_core4.makePkhSpaceId)(address, chainId, "secrets");
|
|
18853
|
+
const primaryActions = this.primaryActionsForSignIn();
|
|
18230
18854
|
const spaceAbilities2 = {
|
|
18231
18855
|
[primarySpaceId2]: primaryActions,
|
|
18232
|
-
[secretsSpaceId]:
|
|
18233
|
-
kv: {
|
|
18234
|
-
"vault/secrets/": [
|
|
18235
|
-
import_sdk_core3.KV.GET,
|
|
18236
|
-
import_sdk_core3.KV.PUT,
|
|
18237
|
-
import_sdk_core3.KV.DEL,
|
|
18238
|
-
import_sdk_core3.KV.LIST,
|
|
18239
|
-
import_sdk_core3.KV.METADATA
|
|
18240
|
-
]
|
|
18241
|
-
}
|
|
18242
|
-
}
|
|
18856
|
+
[secretsSpaceId]: this.secretsPrimaryAbilities()
|
|
18243
18857
|
};
|
|
18244
|
-
if (this.includeAccountRegistryPermissions && this.spacePrefix !==
|
|
18245
|
-
spaceAbilities2[(0,
|
|
18246
|
-
}
|
|
18247
|
-
|
|
18248
|
-
|
|
18249
|
-
|
|
18250
|
-
|
|
18251
|
-
|
|
18252
|
-
|
|
18253
|
-
|
|
18254
|
-
|
|
18255
|
-
|
|
18256
|
-
}
|
|
18257
|
-
}
|
|
18258
|
-
}
|
|
18259
|
-
}
|
|
18858
|
+
if (this.includeAccountRegistryPermissions && this.spacePrefix !== import_sdk_core4.ACCOUNT_REGISTRY_SPACE) {
|
|
18859
|
+
spaceAbilities2[(0, import_sdk_core4.makePkhSpaceId)(address, chainId, import_sdk_core4.ACCOUNT_REGISTRY_SPACE)] = (0, import_sdk_core4.resourceCapabilitiesToAbilitiesMap)(import_sdk_core4.ACCOUNT_MANIFEST_PERMISSIONS);
|
|
18860
|
+
}
|
|
18861
|
+
const mergedPrimary = this.mergeReplicationEntries(
|
|
18862
|
+
spaceAbilities2,
|
|
18863
|
+
primarySpaceId2,
|
|
18864
|
+
primaryActions,
|
|
18865
|
+
augmentSignInEntriesWithReplication({
|
|
18866
|
+
...this.signInPermissionInputs(address, chainId),
|
|
18867
|
+
replication: this.replication
|
|
18868
|
+
})
|
|
18869
|
+
);
|
|
18260
18870
|
return {
|
|
18261
|
-
abilities:
|
|
18871
|
+
abilities: mergedPrimary,
|
|
18262
18872
|
spaceId: primarySpaceId2,
|
|
18263
18873
|
spaceAbilities: spaceAbilities2,
|
|
18264
18874
|
rawAbilities: {
|
|
@@ -18267,35 +18877,44 @@ var NodeUserAuthorization = class {
|
|
|
18267
18877
|
};
|
|
18268
18878
|
}
|
|
18269
18879
|
const rawAbilities = {};
|
|
18270
|
-
const currentDid = (0,
|
|
18880
|
+
const currentDid = (0, import_sdk_core4.pkhDid)(address, chainId);
|
|
18271
18881
|
const spaceResources = request.resources.filter((entry) => {
|
|
18272
|
-
if (entry.service !==
|
|
18882
|
+
if (entry.service !== import_sdk_core4.ENCRYPTION_PERMISSION_SERVICE) {
|
|
18273
18883
|
return true;
|
|
18274
18884
|
}
|
|
18275
18885
|
for (const action of entry.actions) {
|
|
18276
18886
|
addRawAbility(rawAbilities, entry.path, action);
|
|
18277
18887
|
}
|
|
18278
18888
|
if (entry.actions.includes(DECRYPT_ACTION)) {
|
|
18279
|
-
const parsed = (0,
|
|
18889
|
+
const parsed = (0, import_sdk_core4.parseNetworkId)(entry.path);
|
|
18280
18890
|
if (didPrincipalMatches(parsed.ownerDid, currentDid)) {
|
|
18281
18891
|
addRawAbility(rawAbilities, entry.path, NETWORK_CREATE_ACTION);
|
|
18282
18892
|
}
|
|
18283
18893
|
}
|
|
18284
18894
|
return false;
|
|
18285
18895
|
});
|
|
18286
|
-
const primarySpaceName = spaceResources.find((entry) => entry.space !== "account")?.space ??
|
|
18896
|
+
const primarySpaceName = spaceResources.find((entry) => entry.space !== "account")?.space ?? import_sdk_core4.DEFAULT_MANIFEST_SPACE;
|
|
18287
18897
|
const primarySpaceId = this.resolveSpaceName(
|
|
18288
18898
|
primarySpaceName,
|
|
18289
18899
|
address,
|
|
18290
18900
|
chainId
|
|
18291
18901
|
);
|
|
18292
|
-
const bySpace = (0,
|
|
18902
|
+
const bySpace = (0, import_sdk_core4.resourceCapabilitiesToSpaceAbilitiesMap)(spaceResources);
|
|
18293
18903
|
const spaceAbilities = {};
|
|
18294
18904
|
for (const [space, abilities] of Object.entries(bySpace)) {
|
|
18295
18905
|
spaceAbilities[this.resolveSpaceName(space, address, chainId)] = abilities;
|
|
18296
18906
|
}
|
|
18907
|
+
const mergedPrimaryAbilities = this.mergeReplicationEntries(
|
|
18908
|
+
spaceAbilities,
|
|
18909
|
+
primarySpaceId,
|
|
18910
|
+
spaceAbilities[primarySpaceId] ?? (0, import_sdk_core4.resourceCapabilitiesToAbilitiesMap)([]),
|
|
18911
|
+
augmentSignInEntriesWithReplication({
|
|
18912
|
+
...this.signInPermissionInputs(address, chainId),
|
|
18913
|
+
replication: this.replication
|
|
18914
|
+
})
|
|
18915
|
+
);
|
|
18297
18916
|
return {
|
|
18298
|
-
abilities:
|
|
18917
|
+
abilities: mergedPrimaryAbilities,
|
|
18299
18918
|
spaceId: primarySpaceId,
|
|
18300
18919
|
spaceAbilities,
|
|
18301
18920
|
rawAbilities: Object.keys(rawAbilities).length > 0 ? rawAbilities : void 0
|
|
@@ -18353,14 +18972,14 @@ var NodeUserAuthorization = class {
|
|
|
18353
18972
|
* Create the space on the TinyCloud server (host delegation).
|
|
18354
18973
|
* This registers the user as the owner of the space.
|
|
18355
18974
|
*/
|
|
18356
|
-
async hostSpace(targetSpaceId, purpose) {
|
|
18975
|
+
async hostSpace(targetSpaceId, purpose, signal) {
|
|
18357
18976
|
if (!this._tinyCloudSession || !this._address || !this._chainId) {
|
|
18358
18977
|
throw new Error("Must be signed in to host space");
|
|
18359
18978
|
}
|
|
18360
18979
|
await this.ensureTinyCloudHosts();
|
|
18361
18980
|
const host = this.primaryTinyCloudHost;
|
|
18362
18981
|
const spaceId = targetSpaceId ?? this._tinyCloudSession.spaceId;
|
|
18363
|
-
const peerId = await (0,
|
|
18982
|
+
const peerId = await (0, import_sdk_core4.fetchPeerId)(host, spaceId, signal);
|
|
18364
18983
|
const siwe = this.wasm.generateHostSIWEMessage({
|
|
18365
18984
|
address: this._address,
|
|
18366
18985
|
chainId: this._chainId,
|
|
@@ -18369,9 +18988,28 @@ var NodeUserAuthorization = class {
|
|
|
18369
18988
|
spaceId,
|
|
18370
18989
|
peerId
|
|
18371
18990
|
});
|
|
18372
|
-
|
|
18991
|
+
if (signal?.aborted) throw signal.reason;
|
|
18992
|
+
const signing = this.signMessage(siwe, purpose);
|
|
18993
|
+
let signature2;
|
|
18994
|
+
if (!signal) {
|
|
18995
|
+
signature2 = await signing;
|
|
18996
|
+
} else {
|
|
18997
|
+
let rejectOnAbort;
|
|
18998
|
+
const aborted = new Promise((_resolve, reject2) => {
|
|
18999
|
+
rejectOnAbort = reject2;
|
|
19000
|
+
});
|
|
19001
|
+
const onAbort = () => rejectOnAbort(signal.reason);
|
|
19002
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
19003
|
+
if (signal.aborted) onAbort();
|
|
19004
|
+
try {
|
|
19005
|
+
signature2 = await Promise.race([signing, aborted]);
|
|
19006
|
+
} finally {
|
|
19007
|
+
signal.removeEventListener("abort", onAbort);
|
|
19008
|
+
}
|
|
19009
|
+
}
|
|
19010
|
+
if (signal?.aborted) throw signal.reason;
|
|
18373
19011
|
const headers = this.wasm.siweToDelegationHeaders({ siwe, signature: signature2 });
|
|
18374
|
-
return (0,
|
|
19012
|
+
return (0, import_sdk_core4.submitHostDelegation)(host, headers, signal);
|
|
18375
19013
|
}
|
|
18376
19014
|
/**
|
|
18377
19015
|
* Create a specific space on the server via host delegation.
|
|
@@ -18392,8 +19030,8 @@ var NodeUserAuthorization = class {
|
|
|
18392
19030
|
* keeps its HTTP status (e.g. a typed 401/403) instead of collapsing to
|
|
18393
19031
|
* `false`.
|
|
18394
19032
|
*/
|
|
18395
|
-
async hostOwnedSpaceResult(spaceId, purpose) {
|
|
18396
|
-
return this.hostSpace(spaceId, purpose);
|
|
19033
|
+
async hostOwnedSpaceResult(spaceId, purpose, signal) {
|
|
19034
|
+
return this.hostSpace(spaceId, purpose, signal);
|
|
18397
19035
|
}
|
|
18398
19036
|
/**
|
|
18399
19037
|
* Ensure the user's space exists on the TinyCloud server.
|
|
@@ -18410,12 +19048,12 @@ var NodeUserAuthorization = class {
|
|
|
18410
19048
|
await this.ensureTinyCloudHosts();
|
|
18411
19049
|
const host = this.primaryTinyCloudHost;
|
|
18412
19050
|
const primarySpaceId = this._tinyCloudSession.spaceId;
|
|
18413
|
-
const result = await (0,
|
|
19051
|
+
const result = await (0, import_sdk_core4.activateSessionWithHost)(
|
|
18414
19052
|
host,
|
|
18415
19053
|
this._tinyCloudSession.delegationHeader
|
|
18416
19054
|
);
|
|
18417
19055
|
this.recordActivationSkippedSpaces(result, primarySpaceId);
|
|
18418
|
-
const handler = this.spaceCreationHandler ?? (this.autoCreateSpace ? new
|
|
19056
|
+
const handler = this.spaceCreationHandler ?? (this.autoCreateSpace ? new import_sdk_core4.AutoApproveSpaceCreationHandler() : void 0);
|
|
18419
19057
|
const creationContext = {
|
|
18420
19058
|
spaceId: primarySpaceId,
|
|
18421
19059
|
address: this._address,
|
|
@@ -18451,7 +19089,7 @@ var NodeUserAuthorization = class {
|
|
|
18451
19089
|
throw error;
|
|
18452
19090
|
}
|
|
18453
19091
|
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
18454
|
-
const retryResult = await (0,
|
|
19092
|
+
const retryResult = await (0, import_sdk_core4.activateSessionWithHost)(
|
|
18455
19093
|
host,
|
|
18456
19094
|
this._tinyCloudSession.delegationHeader
|
|
18457
19095
|
);
|
|
@@ -18491,7 +19129,7 @@ var NodeUserAuthorization = class {
|
|
|
18491
19129
|
throw error;
|
|
18492
19130
|
}
|
|
18493
19131
|
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
18494
|
-
const retryResult = await (0,
|
|
19132
|
+
const retryResult = await (0, import_sdk_core4.activateSessionWithHost)(
|
|
18495
19133
|
host,
|
|
18496
19134
|
this._tinyCloudSession.delegationHeader
|
|
18497
19135
|
);
|
|
@@ -18533,7 +19171,7 @@ var NodeUserAuthorization = class {
|
|
|
18533
19171
|
const jwk = JSON.parse(jwkString);
|
|
18534
19172
|
const now = /* @__PURE__ */ new Date();
|
|
18535
19173
|
const expirationTime = new Date(now.getTime() + this.sessionExpirationMs);
|
|
18536
|
-
const abilities = (0,
|
|
19174
|
+
const abilities = (0, import_sdk_core4.resourceCapabilitiesToAbilitiesMap)(
|
|
18537
19175
|
options.capabilityRequest.resources
|
|
18538
19176
|
);
|
|
18539
19177
|
const prepared = this.wasm.prepareSession({
|
|
@@ -18584,7 +19222,7 @@ var NodeUserAuthorization = class {
|
|
|
18584
19222
|
* @param options - Optional per-call SIWE overrides for this sign-in only
|
|
18585
19223
|
*/
|
|
18586
19224
|
async signIn(options) {
|
|
18587
|
-
this._address = (0,
|
|
19225
|
+
this._address = (0, import_sdk_core4.canonicalizeAddress)(await this.signer.getAddress());
|
|
18588
19226
|
this._chainId = await this.signer.getChainId();
|
|
18589
19227
|
const address = this._address;
|
|
18590
19228
|
const chainId = this._chainId;
|
|
@@ -18633,7 +19271,7 @@ var NodeUserAuthorization = class {
|
|
|
18633
19271
|
siwe: prepared.siwe,
|
|
18634
19272
|
signature: signature2
|
|
18635
19273
|
};
|
|
18636
|
-
const spacesMetadata = this.enablePublicSpace ? { public: (0,
|
|
19274
|
+
const spacesMetadata = this.enablePublicSpace ? { public: (0, import_sdk_core4.makePkhSpaceId)(address, chainId, "public") } : void 0;
|
|
18637
19275
|
const tinyCloudSession = {
|
|
18638
19276
|
address,
|
|
18639
19277
|
chainId,
|
|
@@ -18671,7 +19309,7 @@ var NodeUserAuthorization = class {
|
|
|
18671
19309
|
this._address = address;
|
|
18672
19310
|
this._chainId = chainId;
|
|
18673
19311
|
const infoHost = this.primaryTinyCloudHost;
|
|
18674
|
-
const nodeInfo = await (0,
|
|
19312
|
+
const nodeInfo = await (0, import_sdk_core4.checkNodeInfo)(
|
|
18675
19313
|
infoHost,
|
|
18676
19314
|
this.wasm.protocolVersion()
|
|
18677
19315
|
);
|
|
@@ -18711,7 +19349,7 @@ var NodeUserAuthorization = class {
|
|
|
18711
19349
|
*/
|
|
18712
19350
|
async signMessage(message, purpose) {
|
|
18713
19351
|
if (!this._address) {
|
|
18714
|
-
this._address = (0,
|
|
19352
|
+
this._address = (0, import_sdk_core4.canonicalizeAddress)(await this.signer.getAddress());
|
|
18715
19353
|
}
|
|
18716
19354
|
if (!this._chainId) {
|
|
18717
19355
|
this._chainId = await this.signer.getChainId();
|
|
@@ -18739,7 +19377,7 @@ var NodeUserAuthorization = class {
|
|
|
18739
19377
|
* ```
|
|
18740
19378
|
*/
|
|
18741
19379
|
async prepareSessionForSigning() {
|
|
18742
|
-
const address = (0,
|
|
19380
|
+
const address = (0, import_sdk_core4.canonicalizeAddress)(await this.signer.getAddress());
|
|
18743
19381
|
const chainId = await this.signer.getChainId();
|
|
18744
19382
|
const keyId = `session-${Date.now()}`;
|
|
18745
19383
|
this.sessionManager.renameSessionKeyId(this.activeSessionKeyId, keyId);
|
|
@@ -18790,7 +19428,7 @@ var NodeUserAuthorization = class {
|
|
|
18790
19428
|
...prepared,
|
|
18791
19429
|
signature: signature2
|
|
18792
19430
|
});
|
|
18793
|
-
const address = (0,
|
|
19431
|
+
const address = (0, import_sdk_core4.canonicalizeAddress)(await this.signer.getAddress());
|
|
18794
19432
|
const chainId = await this.signer.getChainId();
|
|
18795
19433
|
await this.resolveTinyCloudHostsForSignIn(address, chainId);
|
|
18796
19434
|
const clientSession = {
|
|
@@ -18801,7 +19439,7 @@ var NodeUserAuthorization = class {
|
|
|
18801
19439
|
siwe: prepared.siwe,
|
|
18802
19440
|
signature: signature2
|
|
18803
19441
|
};
|
|
18804
|
-
const spacesMetadata = this.enablePublicSpace ? { public: (0,
|
|
19442
|
+
const spacesMetadata = this.enablePublicSpace ? { public: (0, import_sdk_core4.makePkhSpaceId)(address, chainId, "public") } : void 0;
|
|
18805
19443
|
const tinyCloudSession = {
|
|
18806
19444
|
address,
|
|
18807
19445
|
chainId,
|
|
@@ -18843,7 +19481,7 @@ var NodeUserAuthorization = class {
|
|
|
18843
19481
|
this._address = address;
|
|
18844
19482
|
this._chainId = chainId;
|
|
18845
19483
|
const infoHost = this.primaryTinyCloudHost;
|
|
18846
|
-
const nodeInfo = await (0,
|
|
19484
|
+
const nodeInfo = await (0, import_sdk_core4.checkNodeInfo)(
|
|
18847
19485
|
infoHost,
|
|
18848
19486
|
this.wasm.protocolVersion()
|
|
18849
19487
|
);
|
|
@@ -18899,7 +19537,7 @@ var NodeUserAuthorization = class {
|
|
|
18899
19537
|
}
|
|
18900
19538
|
this.tinycloudHosts = [overrideHost];
|
|
18901
19539
|
}
|
|
18902
|
-
const signingAddress = (0,
|
|
19540
|
+
const signingAddress = (0, import_sdk_core4.canonicalizeAddress)(await this.signer.getAddress());
|
|
18903
19541
|
const signingChainId = await this.signer.getChainId();
|
|
18904
19542
|
await this.resolveTinyCloudHostsForSignIn(signingAddress, signingChainId);
|
|
18905
19543
|
const { prepared, keyId, jwk } = await this.prepareSessionForSigning();
|
|
@@ -19004,8 +19642,8 @@ var NodeUserAuthorization = class {
|
|
|
19004
19642
|
"signInWithOpenKeyResult requires prepared.siwe (the SDK-generated SIWE the sign-in was proposed with)"
|
|
19005
19643
|
);
|
|
19006
19644
|
}
|
|
19007
|
-
const expectedAddress = (0,
|
|
19008
|
-
if ((0,
|
|
19645
|
+
const expectedAddress = (0, import_sdk_core4.canonicalizeAddress)(await this.signer.getAddress());
|
|
19646
|
+
if ((0, import_sdk_core4.canonicalizeAddress)(result.address) !== expectedAddress) {
|
|
19009
19647
|
throw new Error(
|
|
19010
19648
|
`OpenKey returned signature from ${result.address} but expected ${expectedAddress}`
|
|
19011
19649
|
);
|
|
@@ -19030,15 +19668,15 @@ var NodeUserAuthorization = class {
|
|
|
19030
19668
|
`OpenKey signature verification failed${type ? `: ${type}` : ""}${details}`
|
|
19031
19669
|
);
|
|
19032
19670
|
}
|
|
19033
|
-
if ((0,
|
|
19671
|
+
if ((0, import_sdk_core4.canonicalizeAddress)(parsedSignedSiwe.address) !== expectedAddress) {
|
|
19034
19672
|
throw new Error(
|
|
19035
19673
|
`OpenKey signedMessage.address (${parsedSignedSiwe.address}) does not match local signer address (${expectedAddress})`
|
|
19036
19674
|
);
|
|
19037
19675
|
}
|
|
19038
19676
|
const originalHasRecap = /(?:^|\n)-\s+urn:recap:/i.test(prepared.siwe);
|
|
19039
|
-
const originalFields = (0,
|
|
19040
|
-
const signedFields = (0,
|
|
19041
|
-
const changedFields = (0,
|
|
19677
|
+
const originalFields = (0, import_sdk_core4.extractImmutableSiweFields)(prepared.siwe);
|
|
19678
|
+
const signedFields = (0, import_sdk_core4.extractImmutableSiweFields)(result.signedMessage);
|
|
19679
|
+
const changedFields = (0, import_sdk_core4.diffImmutableSiweFields)(originalFields, signedFields, {
|
|
19042
19680
|
originalHasRecap
|
|
19043
19681
|
});
|
|
19044
19682
|
if (changedFields.length > 0) {
|
|
@@ -19049,20 +19687,20 @@ var NodeUserAuthorization = class {
|
|
|
19049
19687
|
let originalCaps;
|
|
19050
19688
|
let signedCaps;
|
|
19051
19689
|
try {
|
|
19052
|
-
originalCaps = (0,
|
|
19690
|
+
originalCaps = (0, import_sdk_core4.extractRecapAttenuations)(prepared.siwe);
|
|
19053
19691
|
} catch (err) {
|
|
19054
19692
|
throw new Error(
|
|
19055
19693
|
`Failed to decode prepared SIWE recap: ${err.message}`
|
|
19056
19694
|
);
|
|
19057
19695
|
}
|
|
19058
19696
|
try {
|
|
19059
|
-
signedCaps = (0,
|
|
19697
|
+
signedCaps = (0, import_sdk_core4.extractRecapAttenuations)(result.signedMessage);
|
|
19060
19698
|
} catch (err) {
|
|
19061
19699
|
throw new Error(
|
|
19062
19700
|
`Failed to decode OpenKey signedMessage recap: ${err.message}`
|
|
19063
19701
|
);
|
|
19064
19702
|
}
|
|
19065
|
-
const unauthorized = (0,
|
|
19703
|
+
const unauthorized = (0, import_sdk_core4.unauthorizedRecapCapabilities)(signedCaps, originalCaps);
|
|
19066
19704
|
if (unauthorized.length > 0) {
|
|
19067
19705
|
const previewLimit = 5;
|
|
19068
19706
|
const preview = unauthorized.slice(0, previewLimit).map((u) => `${u.resource}::${u.action}`).join(", ");
|
|
@@ -19079,7 +19717,7 @@ var NodeUserAuthorization = class {
|
|
|
19079
19717
|
const grantedPairs = /* @__PURE__ */ new Set();
|
|
19080
19718
|
const grantedFourPartIndex = /* @__PURE__ */ new Map();
|
|
19081
19719
|
for (const [resource, actions] of Object.entries(signedCaps)) {
|
|
19082
|
-
const { space, path } = (0,
|
|
19720
|
+
const { space, path } = (0, import_sdk_core4.parseCanonicalRecapResource)(resource);
|
|
19083
19721
|
for (const action of Object.keys(actions)) {
|
|
19084
19722
|
grantedPairs.add(`${resource}\0${action}`);
|
|
19085
19723
|
const slashIdx = action.indexOf("/");
|
|
@@ -19320,16 +19958,16 @@ var NodeUserAuthorization = class {
|
|
|
19320
19958
|
};
|
|
19321
19959
|
|
|
19322
19960
|
// src/account/AccountService.ts
|
|
19323
|
-
var
|
|
19961
|
+
var import_sdk_core5 = require("@tinycloud/sdk-core");
|
|
19324
19962
|
|
|
19325
19963
|
// src/DelegatedAccess.ts
|
|
19326
|
-
var
|
|
19964
|
+
var import_sdk_core6 = require("@tinycloud/sdk-core");
|
|
19327
19965
|
var DelegatedAccess = class {
|
|
19328
19966
|
constructor(session, delegation, host, invoke2, invokeAny2, telemetry) {
|
|
19329
19967
|
this.session = session;
|
|
19330
19968
|
this._delegation = delegation;
|
|
19331
19969
|
this.host = host;
|
|
19332
|
-
this._serviceContext = new
|
|
19970
|
+
this._serviceContext = new import_sdk_core6.ServiceContext({
|
|
19333
19971
|
invoke: invoke2,
|
|
19334
19972
|
invokeAny: invokeAny2,
|
|
19335
19973
|
fetch: globalThis.fetch.bind(globalThis),
|
|
@@ -19337,16 +19975,16 @@ var DelegatedAccess = class {
|
|
|
19337
19975
|
telemetry
|
|
19338
19976
|
});
|
|
19339
19977
|
const prefix = this._delegation.path.replace(/\/$/, "");
|
|
19340
|
-
this._kv = new
|
|
19978
|
+
this._kv = new import_sdk_core6.KVService({ prefix });
|
|
19341
19979
|
this._kv.initialize(this._serviceContext);
|
|
19342
19980
|
this._serviceContext.registerService("kv", this._kv);
|
|
19343
|
-
this._sql = new
|
|
19981
|
+
this._sql = new import_sdk_core6.SQLService({});
|
|
19344
19982
|
this._sql.initialize(this._serviceContext);
|
|
19345
19983
|
this._serviceContext.registerService("sql", this._sql);
|
|
19346
|
-
this._duckdb = new
|
|
19984
|
+
this._duckdb = new import_sdk_core6.DuckDbService({});
|
|
19347
19985
|
this._duckdb.initialize(this._serviceContext);
|
|
19348
19986
|
this._serviceContext.registerService("duckdb", this._duckdb);
|
|
19349
|
-
this._hooks = new
|
|
19987
|
+
this._hooks = new import_sdk_core6.HooksService({});
|
|
19350
19988
|
this._hooks.initialize(this._serviceContext);
|
|
19351
19989
|
this._serviceContext.registerService("hooks", this._hooks);
|
|
19352
19990
|
const serviceSession = {
|
|
@@ -19496,7 +20134,7 @@ function createWasmKeyProvider(sessionManager) {
|
|
|
19496
20134
|
}
|
|
19497
20135
|
|
|
19498
20136
|
// src/delegateToHelpers.ts
|
|
19499
|
-
var
|
|
20137
|
+
var import_sdk_core7 = require("@tinycloud/sdk-core");
|
|
19500
20138
|
function legacyParamsToPermissionEntries(actions, path, spaceIdOverride) {
|
|
19501
20139
|
const byService = /* @__PURE__ */ new Map();
|
|
19502
20140
|
for (const a of actions) {
|
|
@@ -19527,7 +20165,7 @@ function legacyParamsToPermissionEntries(actions, path, spaceIdOverride) {
|
|
|
19527
20165
|
}
|
|
19528
20166
|
return entries;
|
|
19529
20167
|
}
|
|
19530
|
-
var DEFAULT_DELEGATION_EXPIRY_MS =
|
|
20168
|
+
var DEFAULT_DELEGATION_EXPIRY_MS = import_sdk_core7.EXPIRY.SESSION_MS;
|
|
19531
20169
|
function resolveExpiryMs(expiry) {
|
|
19532
20170
|
if (expiry === void 0) {
|
|
19533
20171
|
return DEFAULT_DELEGATION_EXPIRY_MS;
|
|
@@ -19540,10 +20178,10 @@ function resolveExpiryMs(expiry) {
|
|
|
19540
20178
|
}
|
|
19541
20179
|
return expiry;
|
|
19542
20180
|
}
|
|
19543
|
-
return (0,
|
|
20181
|
+
return (0, import_sdk_core7.parseExpiry)(expiry);
|
|
19544
20182
|
}
|
|
19545
20183
|
function extractSiweExpiration(siwe) {
|
|
19546
|
-
const parsed = new
|
|
20184
|
+
const parsed = new import_sdk_core7.SiweMessage(siwe);
|
|
19547
20185
|
if (parsed.expirationTime === void 0 || parsed.expirationTime === null) {
|
|
19548
20186
|
return void 0;
|
|
19549
20187
|
}
|
|
@@ -19557,7 +20195,7 @@ function extractSiweExpiration(siwe) {
|
|
|
19557
20195
|
}
|
|
19558
20196
|
|
|
19559
20197
|
// src/NodeSecretsService.ts
|
|
19560
|
-
var
|
|
20198
|
+
var import_sdk_core8 = require("@tinycloud/sdk-core");
|
|
19561
20199
|
var SECRETS_SPACE = "secrets";
|
|
19562
20200
|
function ok() {
|
|
19563
20201
|
return { ok: true, data: void 0 };
|
|
@@ -19590,7 +20228,7 @@ function secretActionName(action) {
|
|
|
19590
20228
|
}
|
|
19591
20229
|
function secretPermissionEntries(name, options, action, space, encryptionNetworkId) {
|
|
19592
20230
|
const entries = [];
|
|
19593
|
-
const path = action === "list" ? (0,
|
|
20231
|
+
const path = action === "list" ? (0, import_sdk_core8.resolveSecretListPrefix)(options) : (0, import_sdk_core8.resolveSecretPath)(name, options).permissionPaths.vault;
|
|
19594
20232
|
entries.push({
|
|
19595
20233
|
service: "tinycloud.kv",
|
|
19596
20234
|
space,
|
|
@@ -19687,7 +20325,7 @@ var NodeSecretsService = class {
|
|
|
19687
20325
|
);
|
|
19688
20326
|
} catch (error) {
|
|
19689
20327
|
return secretsError(
|
|
19690
|
-
|
|
20328
|
+
import_sdk_core8.ErrorCodes.INVALID_INPUT,
|
|
19691
20329
|
error instanceof Error ? error.message : String(error),
|
|
19692
20330
|
error instanceof Error ? error : void 0
|
|
19693
20331
|
);
|
|
@@ -19697,7 +20335,7 @@ var NodeSecretsService = class {
|
|
|
19697
20335
|
}
|
|
19698
20336
|
if (!this.config.canEscalate()) {
|
|
19699
20337
|
return secretsError(
|
|
19700
|
-
|
|
20338
|
+
import_sdk_core8.ErrorCodes.PERMISSION_DENIED,
|
|
19701
20339
|
`Cannot autosign ${displayActionUrn(action)} for ${target}; TinyCloudNode needs wallet mode with a signer or privateKey.`
|
|
19702
20340
|
);
|
|
19703
20341
|
}
|
|
@@ -19706,7 +20344,7 @@ var NodeSecretsService = class {
|
|
|
19706
20344
|
return this.restoreUnlockAfterEscalation();
|
|
19707
20345
|
} catch (error) {
|
|
19708
20346
|
return secretsError(
|
|
19709
|
-
|
|
20347
|
+
import_sdk_core8.ErrorCodes.PERMISSION_DENIED,
|
|
19710
20348
|
error instanceof Error ? error.message : `Autosign escalation for ${displayActionUrn(action)} on ${target} failed.`,
|
|
19711
20349
|
error instanceof Error ? error : void 0
|
|
19712
20350
|
);
|
|
@@ -19727,10 +20365,10 @@ var NodeSecretsService = class {
|
|
|
19727
20365
|
return false;
|
|
19728
20366
|
}
|
|
19729
20367
|
const manifests = Array.isArray(manifest) ? manifest : [manifest];
|
|
19730
|
-
const requestedEntries = (0,
|
|
20368
|
+
const requestedEntries = (0, import_sdk_core8.expandPermissionEntries)(permissionEntries);
|
|
19731
20369
|
return requestedEntries.every(
|
|
19732
20370
|
(entry) => manifests.some((candidate) => {
|
|
19733
|
-
const resolved = (0,
|
|
20371
|
+
const resolved = (0, import_sdk_core8.resolveManifest)(candidate);
|
|
19734
20372
|
return resolved.resources.some(
|
|
19735
20373
|
(resource) => resource.service === entry.service && spaceMatches(
|
|
19736
20374
|
resource.space,
|
|
@@ -19746,8 +20384,8 @@ var NodeSecretsService = class {
|
|
|
19746
20384
|
// src/TinyCloudNode.ts
|
|
19747
20385
|
var DEFAULT_HOST = "https://node.tinycloud.xyz";
|
|
19748
20386
|
var DEFAULT_ENCRYPTION_NETWORK_NAME = "default";
|
|
19749
|
-
var NETWORK_CREATE_ACTION2 =
|
|
19750
|
-
var DECRYPT_ACTION2 =
|
|
20387
|
+
var NETWORK_CREATE_ACTION2 = import_sdk_core9.ENCRYPTION.NETWORK_CREATE;
|
|
20388
|
+
var DECRYPT_ACTION2 = import_sdk_core9.ENCRYPTION.DECRYPT;
|
|
19751
20389
|
var BOOTSTRAP_COMPLETION_MARKER_KEY = "system/bootstrap/complete";
|
|
19752
20390
|
var BOOTSTRAP_COMPLETION_MARKER_VERSION = 1;
|
|
19753
20391
|
var ACCEPTED_MARKER_VERSIONS = [BOOTSTRAP_COMPLETION_MARKER_VERSION];
|
|
@@ -19756,24 +20394,24 @@ function isSecretPayload(value) {
|
|
|
19756
20394
|
return typeof value === "object" && value !== null && "value" in value && typeof value.value === "string" && "createdAt" in value && typeof value.createdAt === "string" && "updatedAt" in value && typeof value.updatedAt === "string";
|
|
19757
20395
|
}
|
|
19758
20396
|
var ROOT_DELEGATION_ACTIONS = [
|
|
19759
|
-
|
|
19760
|
-
|
|
19761
|
-
|
|
19762
|
-
|
|
19763
|
-
|
|
19764
|
-
|
|
19765
|
-
|
|
19766
|
-
|
|
19767
|
-
|
|
19768
|
-
|
|
19769
|
-
|
|
19770
|
-
|
|
19771
|
-
|
|
19772
|
-
|
|
19773
|
-
|
|
19774
|
-
|
|
20397
|
+
import_sdk_core9.KV.PUT,
|
|
20398
|
+
import_sdk_core9.KV.GET,
|
|
20399
|
+
import_sdk_core9.KV.DEL,
|
|
20400
|
+
import_sdk_core9.KV.LIST,
|
|
20401
|
+
import_sdk_core9.KV.METADATA,
|
|
20402
|
+
import_sdk_core9.SQL.READ,
|
|
20403
|
+
import_sdk_core9.SQL.WRITE,
|
|
20404
|
+
import_sdk_core9.SQL.ADMIN,
|
|
20405
|
+
import_sdk_core9.SQL.ALL,
|
|
20406
|
+
import_sdk_core9.DUCKDB.READ,
|
|
20407
|
+
import_sdk_core9.DUCKDB.WRITE,
|
|
20408
|
+
import_sdk_core9.DUCKDB.ADMIN,
|
|
20409
|
+
import_sdk_core9.DUCKDB.DESCRIBE,
|
|
20410
|
+
import_sdk_core9.DUCKDB.EXPORT,
|
|
20411
|
+
import_sdk_core9.DUCKDB.IMPORT,
|
|
20412
|
+
import_sdk_core9.DUCKDB.ALL
|
|
19775
20413
|
];
|
|
19776
|
-
var DEFAULT_SESSION_EXPIRATION_MS =
|
|
20414
|
+
var DEFAULT_SESSION_EXPIRATION_MS = import_sdk_core9.EXPIRY.SESSION_MS;
|
|
19777
20415
|
function unifiedRootAttenuation(capabilities) {
|
|
19778
20416
|
const attenuation = {};
|
|
19779
20417
|
for (const capability of capabilities) {
|
|
@@ -19819,7 +20457,7 @@ function isInteractiveSigner(config) {
|
|
|
19819
20457
|
}
|
|
19820
20458
|
function didPrincipalMatches2(actual, expected) {
|
|
19821
20459
|
try {
|
|
19822
|
-
return (0,
|
|
20460
|
+
return (0, import_sdk_core9.principalDidEquals)(actual, expected);
|
|
19823
20461
|
} catch {
|
|
19824
20462
|
return actual === expected;
|
|
19825
20463
|
}
|
|
@@ -20030,7 +20668,7 @@ function ownerDelegationPermissions(params) {
|
|
|
20030
20668
|
}
|
|
20031
20669
|
const slash = action.indexOf("/");
|
|
20032
20670
|
const service = slash === -1 ? "" : action.slice(0, slash);
|
|
20033
|
-
if (
|
|
20671
|
+
if (import_sdk_core9.SERVICE_LONG_TO_SHORT[service] === void 0) {
|
|
20034
20672
|
throw new Error("Owner delegation capabilities are unsupported");
|
|
20035
20673
|
}
|
|
20036
20674
|
const actions = byService.get(service) ?? [];
|
|
@@ -20046,7 +20684,7 @@ function ownerDelegationPermissions(params) {
|
|
|
20046
20684
|
}
|
|
20047
20685
|
const resources = /* @__PURE__ */ new Set();
|
|
20048
20686
|
for (const permission of permissions) {
|
|
20049
|
-
if (typeof permission.service !== "string" ||
|
|
20687
|
+
if (typeof permission.service !== "string" || import_sdk_core9.SERVICE_LONG_TO_SHORT[permission.service] === void 0 || typeof permission.path !== "string" || permission.path.length === 0 || permission.path.trim() !== permission.path || /[\u0000-\u001f\u007f\\*]/.test(permission.path) || !Array.isArray(permission.actions) || permission.actions.length === 0 || permission.actions.length > 32) {
|
|
20050
20688
|
throw new Error("Owner delegation requires bounded capabilities");
|
|
20051
20689
|
}
|
|
20052
20690
|
const resourceKey = `${permission.service}\0${permission.path}`;
|
|
@@ -20061,9 +20699,9 @@ function ownerDelegationPermissions(params) {
|
|
|
20061
20699
|
}
|
|
20062
20700
|
actions.add(action);
|
|
20063
20701
|
}
|
|
20064
|
-
if (permission.service ===
|
|
20702
|
+
if (permission.service === import_sdk_core9.ENCRYPTION_PERMISSION_SERVICE) {
|
|
20065
20703
|
try {
|
|
20066
|
-
(0,
|
|
20704
|
+
(0, import_sdk_core9.parseNetworkId)(permission.path);
|
|
20067
20705
|
} catch {
|
|
20068
20706
|
throw new Error("Owner delegation encryption permission requires a canonical network URN");
|
|
20069
20707
|
}
|
|
@@ -20075,11 +20713,11 @@ function ownerPermissionsToAbilities(permissions) {
|
|
|
20075
20713
|
const abilities = {};
|
|
20076
20714
|
const rawAbilities = {};
|
|
20077
20715
|
for (const permission of permissions) {
|
|
20078
|
-
if (permission.service ===
|
|
20716
|
+
if (permission.service === import_sdk_core9.ENCRYPTION_PERMISSION_SERVICE) {
|
|
20079
20717
|
rawAbilities[permission.path] = [...permission.actions];
|
|
20080
20718
|
continue;
|
|
20081
20719
|
}
|
|
20082
|
-
const shortService =
|
|
20720
|
+
const shortService = import_sdk_core9.SERVICE_LONG_TO_SHORT[permission.service];
|
|
20083
20721
|
abilities[shortService] ?? (abilities[shortService] = {});
|
|
20084
20722
|
abilities[shortService][permission.path] = [...permission.actions];
|
|
20085
20723
|
}
|
|
@@ -20211,6 +20849,8 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20211
20849
|
this.confirmedHostedSpaceIds = /* @__PURE__ */ new Set();
|
|
20212
20850
|
/** Serializes account-registry writes for the active node instance. */
|
|
20213
20851
|
this.accountRegistryTail = Promise.resolve();
|
|
20852
|
+
/** Bounds best-effort registry work on the sign-in critical path. */
|
|
20853
|
+
this.accountRegistryDeadlineMs = 4e3;
|
|
20214
20854
|
/**
|
|
20215
20855
|
* True when the last signIn() detected an interactive signer and skipped
|
|
20216
20856
|
* client-side bootstrap. Apps can read this to know whether bootstrap was
|
|
@@ -20282,18 +20922,53 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20282
20922
|
if (!granted?.caveats?.length) {
|
|
20283
20923
|
return entry;
|
|
20284
20924
|
}
|
|
20285
|
-
if (entry.caveats !== void 0 && !(0,
|
|
20925
|
+
if (entry.caveats !== void 0 && !(0, import_sdk_core9.recapCaveatsEqual)(entry.caveats, granted.caveats)) {
|
|
20286
20926
|
throw new Error("Invocation caveats do not match signed ReCap authority.");
|
|
20287
20927
|
}
|
|
20288
20928
|
return { ...entry, caveats: cloneRecapCaveats(granted.caveats) };
|
|
20289
20929
|
});
|
|
20290
20930
|
return this.wasmBindings.invokeAny(invocationSession, caveatPreservingEntries, facts);
|
|
20291
20931
|
};
|
|
20932
|
+
assertValidReplicationConfig(config.replication);
|
|
20292
20933
|
this.explicitHost = config.host;
|
|
20293
20934
|
this.config = {
|
|
20294
20935
|
...config,
|
|
20295
20936
|
host: config.host ?? DEFAULT_HOST
|
|
20296
20937
|
};
|
|
20938
|
+
if (this.config.replication?.enabled) {
|
|
20939
|
+
const runtime = getNodeReplicationLoaders().runtime().then(({ ReplicationRuntime: ReplicationRuntime2 }) => {
|
|
20940
|
+
const instance = new ReplicationRuntime2(this.config.replication);
|
|
20941
|
+
this.replicationRuntimeInstance = instance;
|
|
20942
|
+
return instance;
|
|
20943
|
+
});
|
|
20944
|
+
this.replicationRuntime = runtime;
|
|
20945
|
+
this.replicationControl = {
|
|
20946
|
+
status: async () => {
|
|
20947
|
+
const status = await runtime.then((ready) => ready.control.status());
|
|
20948
|
+
const scopeError = this.replicationScopeError;
|
|
20949
|
+
if (!scopeError) return status;
|
|
20950
|
+
return this.config.replication.prefixes.map((prefix) => ({
|
|
20951
|
+
prefix,
|
|
20952
|
+
state: "unavailable",
|
|
20953
|
+
lastError: {
|
|
20954
|
+
at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
20955
|
+
code: "SESSION_SCOPE_MISMATCH",
|
|
20956
|
+
message: scopeError
|
|
20957
|
+
},
|
|
20958
|
+
pending: { inFlight: 0, committed: 0, ambiguous: 0 },
|
|
20959
|
+
pinned: [],
|
|
20960
|
+
lagMs: null
|
|
20961
|
+
}));
|
|
20962
|
+
},
|
|
20963
|
+
sync: async (input) => (await runtime).control.sync(input),
|
|
20964
|
+
purge: (input) => {
|
|
20965
|
+
const instance = this.replicationRuntimeInstance;
|
|
20966
|
+
return instance ? instance.control.purge(input) : runtime.then((ready) => ready.control.purge(input));
|
|
20967
|
+
},
|
|
20968
|
+
clearPending: async () => (await runtime).control.clearPending(),
|
|
20969
|
+
close: async () => (await runtime).control.close()
|
|
20970
|
+
};
|
|
20971
|
+
}
|
|
20297
20972
|
if (config.wasmBindings) {
|
|
20298
20973
|
this.wasmBindings = config.wasmBindings;
|
|
20299
20974
|
} else if (_TinyCloudNode.nodeDefaults) {
|
|
@@ -20317,13 +20992,13 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20317
20992
|
}
|
|
20318
20993
|
this.sessionKeyJwk = JSON.parse(jwkStr);
|
|
20319
20994
|
this._serviceGraph = this.createServiceGraphLifetime();
|
|
20320
|
-
this._capabilityRegistry = new
|
|
20995
|
+
this._capabilityRegistry = new import_sdk_core9.CapabilityKeyRegistry();
|
|
20321
20996
|
this._keyProvider = new WasmKeyProvider({
|
|
20322
20997
|
sessionManager: this.sessionManager
|
|
20323
20998
|
});
|
|
20324
|
-
this.notificationHandler = config.notificationHandler ?? new
|
|
20999
|
+
this.notificationHandler = config.notificationHandler ?? new import_sdk_core9.SilentNotificationHandler();
|
|
20325
21000
|
const receiveOnlyGraph = this._serviceGraph;
|
|
20326
|
-
this._sharingService = new
|
|
21001
|
+
this._sharingService = new import_sdk_core9.SharingService({
|
|
20327
21002
|
hosts: [this.config.host],
|
|
20328
21003
|
// session: undefined - not needed for receive()
|
|
20329
21004
|
invoke: receiveOnlyGraph.invoke,
|
|
@@ -20339,8 +21014,8 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20339
21014
|
// delegationManager: undefined - not needed for receive()
|
|
20340
21015
|
createKVService: (config2) => {
|
|
20341
21016
|
const prefix = config2.pathPrefix?.replace(/\/$/, "");
|
|
20342
|
-
const kvService = new
|
|
20343
|
-
const kvContext = receiveOnlyGraph.track(new
|
|
21017
|
+
const kvService = new import_sdk_core9.KVService({ prefix });
|
|
21018
|
+
const kvContext = receiveOnlyGraph.track(new import_sdk_core9.ServiceContext({
|
|
20344
21019
|
invoke: config2.invoke,
|
|
20345
21020
|
fetch: config2.fetch ?? globalThis.fetch.bind(globalThis),
|
|
20346
21021
|
hosts: config2.hosts,
|
|
@@ -20413,10 +21088,17 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20413
21088
|
nonce: config.nonce,
|
|
20414
21089
|
siweConfig: config.siweConfig,
|
|
20415
21090
|
manifest: useBootstrapSignInRequest ? void 0 : config.manifest,
|
|
20416
|
-
capabilityRequest: useBootstrapSignInRequest ? config.includeAccountRegistryPermissions === false ?
|
|
20417
|
-
includeAccountRegistryPermissions: useBootstrapSignInRequest ? false : config.includeAccountRegistryPermissions
|
|
21091
|
+
capabilityRequest: useBootstrapSignInRequest ? config.includeAccountRegistryPermissions === false ? import_sdk_core9.BOOTSTRAP_DEFAULT_ONLY_SESSION_REQUEST : import_sdk_core9.BOOTSTRAP_SESSION_REQUESTS.default : config.capabilityRequest,
|
|
21092
|
+
includeAccountRegistryPermissions: useBootstrapSignInRequest ? false : config.includeAccountRegistryPermissions,
|
|
21093
|
+
// Sign-in needs only the entry inputs (prefixes + secrets opt-in);
|
|
21094
|
+
// storage and scheduling never leave TinyCloudNode.
|
|
21095
|
+
replication: config.replication?.enabled === true ? {
|
|
21096
|
+
enabled: true,
|
|
21097
|
+
prefixes: config.replication.prefixes,
|
|
21098
|
+
allowSecrets: config.replication.allowSecrets === true
|
|
21099
|
+
} : void 0
|
|
20418
21100
|
});
|
|
20419
|
-
this.tc = new
|
|
21101
|
+
this.tc = new import_sdk_core9.TinyCloud(this.auth, {
|
|
20420
21102
|
invokeAny: this.invokeAnyWithRuntimePermissions,
|
|
20421
21103
|
telemetry: config.telemetry
|
|
20422
21104
|
});
|
|
@@ -20496,7 +21178,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20496
21178
|
/** Publish the active owner Node as a session-signed registry record. */
|
|
20497
21179
|
async publishActiveNodeLocation(registryUrl, fetchFn = globalThis.fetch.bind(globalThis)) {
|
|
20498
21180
|
const node = await this.activeNodeIdentity();
|
|
20499
|
-
return (0,
|
|
21181
|
+
return (0, import_sdk_core9.publishLocationRecord)({
|
|
20500
21182
|
registryUrl,
|
|
20501
21183
|
subject: this.credentialHolderDid,
|
|
20502
21184
|
nodeOrigin: node.origin,
|
|
@@ -20513,7 +21195,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20513
21195
|
*/
|
|
20514
21196
|
get did() {
|
|
20515
21197
|
if (this._address) {
|
|
20516
|
-
return (0,
|
|
21198
|
+
return (0, import_sdk_core9.pkhDid)(this._address, this._chainId);
|
|
20517
21199
|
}
|
|
20518
21200
|
return this.sessionManager.getDID(this.sessionKeyId);
|
|
20519
21201
|
}
|
|
@@ -20550,7 +21232,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20550
21232
|
/** Normalize signed capabilities without collapsing nested encryption into raw authority. */
|
|
20551
21233
|
projectSignedRecapCapabilities(siwe) {
|
|
20552
21234
|
const projected = this.parseRecapWithCaveats(siwe).map((entry) => {
|
|
20553
|
-
const normalized = (0,
|
|
21235
|
+
const normalized = (0, import_sdk_core9.parseRecapCapabilities)(() => [entry], siwe)[0];
|
|
20554
21236
|
if (normalized.service !== "tinycloud.encryption") return normalized;
|
|
20555
21237
|
if (!this.isEncryptionNetworkOperation("encryption", entry.path, entry.space)) {
|
|
20556
21238
|
return { ...normalized, space: entry.space };
|
|
@@ -20595,14 +21277,14 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20595
21277
|
if (!this._address) {
|
|
20596
21278
|
return void 0;
|
|
20597
21279
|
}
|
|
20598
|
-
return this.wasmBindings.makeSpaceId(this._address, this._chainId,
|
|
21280
|
+
return this.wasmBindings.makeSpaceId(this._address, this._chainId, import_sdk_core9.ACCOUNT_REGISTRY_SPACE);
|
|
20599
21281
|
}
|
|
20600
21282
|
/**
|
|
20601
21283
|
* Account-level application and delegation helpers.
|
|
20602
21284
|
*/
|
|
20603
21285
|
get account() {
|
|
20604
21286
|
if (!this._account) {
|
|
20605
|
-
this._account = new
|
|
21287
|
+
this._account = new import_sdk_core5.AccountService({
|
|
20606
21288
|
getDid: () => this.did,
|
|
20607
21289
|
getHost: () => this.hosts[0] ?? this.config.host,
|
|
20608
21290
|
getPrimarySpaceId: () => this.spaceId,
|
|
@@ -20648,7 +21330,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20648
21330
|
}
|
|
20649
21331
|
await this.accountRegistryTail;
|
|
20650
21332
|
await this.wasmBindings.ensureInitialized?.();
|
|
20651
|
-
this._address = (0,
|
|
21333
|
+
this._address = (0, import_sdk_core9.canonicalizeAddress)(await this.signer.getAddress());
|
|
20652
21334
|
this._chainId = await this.signer.getChainId();
|
|
20653
21335
|
this._kv = void 0;
|
|
20654
21336
|
this._sql = void 0;
|
|
@@ -20665,6 +21347,9 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20665
21347
|
this.confirmedHostedSpaceIds.clear();
|
|
20666
21348
|
await this.tc.signIn(options);
|
|
20667
21349
|
this.syncResolvedHostFromAuth();
|
|
21350
|
+
this.replicationDelegateSession = void 0;
|
|
21351
|
+
this.replicationScopeError = void 0;
|
|
21352
|
+
if (this.replicationRuntime) await (await this.replicationRuntime).unbind();
|
|
20668
21353
|
const oldGraph = this._serviceGraph;
|
|
20669
21354
|
this._serviceGraph = this.createServiceGraphLifetime();
|
|
20670
21355
|
oldGraph.retire();
|
|
@@ -20674,7 +21359,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20674
21359
|
this.sessionKeyId = signedInSession.sessionKey;
|
|
20675
21360
|
this.sessionKeyJwk = signedInSession.jwk;
|
|
20676
21361
|
}
|
|
20677
|
-
this.initializeServices();
|
|
21362
|
+
await this.initializeServices();
|
|
20678
21363
|
const primarySession = this.currentTinyCloudSession();
|
|
20679
21364
|
if (primarySession) {
|
|
20680
21365
|
this.registerPrimarySessionGrant(primarySession);
|
|
@@ -20682,10 +21367,11 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20682
21367
|
const bootstrapped = await this.bootstrapAccountIfNeeded();
|
|
20683
21368
|
await this.ensureRequestedEncryptionNetworks();
|
|
20684
21369
|
if (!bootstrapped && this.config.manifest === void 0 && this.config.capabilityRequest === void 0) {
|
|
20685
|
-
await this.ensureOwnedSpaceHostedById(this.ownedSpaceId(
|
|
21370
|
+
await this.ensureOwnedSpaceHostedById(this.ownedSpaceId(import_sdk_core9.SECRETS_SPACE));
|
|
20686
21371
|
}
|
|
20687
21372
|
if (!bootstrapped) {
|
|
20688
21373
|
this.scheduleAccountRegistrySync();
|
|
21374
|
+
await this.accountRegistryTail;
|
|
20689
21375
|
}
|
|
20690
21376
|
this.notificationHandler.success("Successfully signed in");
|
|
20691
21377
|
}
|
|
@@ -20713,7 +21399,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20713
21399
|
this._bootstrapStatus = { skipped: true, reason: "interactive-signer" };
|
|
20714
21400
|
return false;
|
|
20715
21401
|
}
|
|
20716
|
-
const steps = (0,
|
|
21402
|
+
const steps = (0, import_sdk_core9.bootstrapSteps)(this._address, this._chainId);
|
|
20717
21403
|
try {
|
|
20718
21404
|
const decision = await this.resolveBootstrapDecision(steps);
|
|
20719
21405
|
if (decision.action === "skip") {
|
|
@@ -20751,7 +21437,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20751
21437
|
if (!auth) {
|
|
20752
21438
|
throw new Error("Account bootstrap requires an active wallet session");
|
|
20753
21439
|
}
|
|
20754
|
-
const accountSpaceId = this.ownedSpaceId(
|
|
21440
|
+
const accountSpaceId = this.ownedSpaceId(import_sdk_core9.ACCOUNT_REGISTRY_SPACE);
|
|
20755
21441
|
const skipped = auth.lastActivationSkippedSpaceIds;
|
|
20756
21442
|
if (skipped.includes(accountSpaceId)) return { action: "run", mode: "fresh" };
|
|
20757
21443
|
if (skipped.some((spaceId) => enshrinedSpaceIds.has(spaceId))) {
|
|
@@ -20774,7 +21460,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20774
21460
|
}
|
|
20775
21461
|
return { action: "run", mode: "repair" };
|
|
20776
21462
|
}
|
|
20777
|
-
if (marker.error.code ===
|
|
21463
|
+
if (marker.error.code === import_sdk_core9.ErrorCodes.KV_NOT_FOUND && this.markerReadIsUnhostedSpace(marker.error.meta)) {
|
|
20778
21464
|
return { action: "run", mode: "fresh" };
|
|
20779
21465
|
}
|
|
20780
21466
|
} catch (err) {
|
|
@@ -20788,7 +21474,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20788
21474
|
return { action: "run", mode: "repair" };
|
|
20789
21475
|
}
|
|
20790
21476
|
async readBootstrapCompletionMarker() {
|
|
20791
|
-
return this.kvForSpace(this.ownedSpaceId(
|
|
21477
|
+
return this.kvForSpace(this.ownedSpaceId(import_sdk_core9.ACCOUNT_REGISTRY_SPACE)).get(
|
|
20792
21478
|
BOOTSTRAP_COMPLETION_MARKER_KEY
|
|
20793
21479
|
);
|
|
20794
21480
|
}
|
|
@@ -20797,7 +21483,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20797
21483
|
throw new Error("Bootstrap completion marker requires an active wallet session");
|
|
20798
21484
|
}
|
|
20799
21485
|
const canonicalStepIds = new Set(
|
|
20800
|
-
(0,
|
|
21486
|
+
(0, import_sdk_core9.bootstrapSteps)(this._address, this._chainId).map((step) => step.id)
|
|
20801
21487
|
);
|
|
20802
21488
|
const providedStepIds = new Set(steps.map((step) => step.id));
|
|
20803
21489
|
if (canonicalStepIds.size !== providedStepIds.size || [...canonicalStepIds].some((stepId) => !providedStepIds.has(stepId))) {
|
|
@@ -20808,7 +21494,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20808
21494
|
stepIds: [...canonicalStepIds],
|
|
20809
21495
|
completedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
20810
21496
|
};
|
|
20811
|
-
const written = await this.kvForSpace(this.ownedSpaceId(
|
|
21497
|
+
const written = await this.kvForSpace(this.ownedSpaceId(import_sdk_core9.ACCOUNT_REGISTRY_SPACE)).put(
|
|
20812
21498
|
BOOTSTRAP_COMPLETION_MARKER_KEY,
|
|
20813
21499
|
marker
|
|
20814
21500
|
);
|
|
@@ -20847,7 +21533,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20847
21533
|
const warnings = [];
|
|
20848
21534
|
const primarySession = auth.tinyCloudSession;
|
|
20849
21535
|
const defaultSpaceId = this.ownedSpaceId("default");
|
|
20850
|
-
const canReusePrimaryBootstrapSession = primarySession?.spaceId === defaultSpaceId && auth.capabilityRequest ===
|
|
21536
|
+
const canReusePrimaryBootstrapSession = primarySession?.spaceId === defaultSpaceId && auth.capabilityRequest === import_sdk_core9.BOOTSTRAP_SESSION_REQUESTS.default;
|
|
20851
21537
|
for (const step of steps) {
|
|
20852
21538
|
if (step.kind !== "session") continue;
|
|
20853
21539
|
if (step.space === "default" && canReusePrimaryBootstrapSession && primarySession) {
|
|
@@ -20862,7 +21548,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20862
21548
|
try {
|
|
20863
21549
|
session = await auth.createBootstrapSession({
|
|
20864
21550
|
spaceId: step.spaceId,
|
|
20865
|
-
capabilityRequest: step.request ??
|
|
21551
|
+
capabilityRequest: step.request ?? import_sdk_core9.BOOTSTRAP_SESSION_REQUESTS[step.space],
|
|
20866
21552
|
rawAbilities
|
|
20867
21553
|
});
|
|
20868
21554
|
} catch (err) {
|
|
@@ -20892,7 +21578,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20892
21578
|
if (!session) {
|
|
20893
21579
|
throw new Error(`Missing bootstrap session for ${step.space}`);
|
|
20894
21580
|
}
|
|
20895
|
-
const activated = await (0,
|
|
21581
|
+
const activated = await (0, import_sdk_core9.activateSessionWithHost)(host, session.delegationHeader);
|
|
20896
21582
|
if (!activated.success || activated.skipped?.includes(step.spaceId)) {
|
|
20897
21583
|
throw Object.assign(
|
|
20898
21584
|
new Error(
|
|
@@ -20903,7 +21589,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20903
21589
|
}
|
|
20904
21590
|
this.registerBootstrapRuntimeGrant(
|
|
20905
21591
|
session,
|
|
20906
|
-
|
|
21592
|
+
import_sdk_core9.BOOTSTRAP_SESSION_REQUESTS[step.space],
|
|
20907
21593
|
rawAbilitiesBySpace.get(step.space)
|
|
20908
21594
|
);
|
|
20909
21595
|
}
|
|
@@ -20952,7 +21638,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20952
21638
|
}
|
|
20953
21639
|
if (step.kind === "seed-applications") {
|
|
20954
21640
|
const registered = await this.account.applications.register(
|
|
20955
|
-
step.manifests.length > 0 ? [...step.manifests] :
|
|
21641
|
+
step.manifests.length > 0 ? [...step.manifests] : import_sdk_core9.TINYCLOUD_SECRETS_BOOTSTRAP_MANIFEST,
|
|
20956
21642
|
// The write is an INSERT OR REPLACE and is safe to repeat during a
|
|
20957
21643
|
// repair, so skip the manifest-hash pre-read.
|
|
20958
21644
|
{ assumeUnregistered: true }
|
|
@@ -20971,7 +21657,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20971
21657
|
migrations: [
|
|
20972
21658
|
{
|
|
20973
21659
|
id: "001_initial",
|
|
20974
|
-
sql: [...
|
|
21660
|
+
sql: [...import_sdk_core9.SECRET_RECORDS_SCHEMA]
|
|
20975
21661
|
}
|
|
20976
21662
|
]
|
|
20977
21663
|
});
|
|
@@ -21138,7 +21824,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21138
21824
|
provenance: "primary"
|
|
21139
21825
|
});
|
|
21140
21826
|
}
|
|
21141
|
-
async writeManifestRegistryRecords() {
|
|
21827
|
+
async writeManifestRegistryRecords(account, signal) {
|
|
21142
21828
|
const request = this.capabilityRequest;
|
|
21143
21829
|
if (!request || request.registryRecords.length === 0) {
|
|
21144
21830
|
return;
|
|
@@ -21146,9 +21832,10 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21146
21832
|
if (!this.auth || !this.signer) {
|
|
21147
21833
|
throw new Error("Manifest registry write requires wallet mode");
|
|
21148
21834
|
}
|
|
21149
|
-
const accountSpaceId = this.ownedSpaceId(
|
|
21150
|
-
await this.ensureOwnedSpaceHostedById(accountSpaceId);
|
|
21151
|
-
|
|
21835
|
+
const accountSpaceId = this.ownedSpaceId(import_sdk_core9.ACCOUNT_REGISTRY_SPACE);
|
|
21836
|
+
await this.ensureOwnedSpaceHostedById(accountSpaceId, signal);
|
|
21837
|
+
if (signal.aborted) throw signal.reason;
|
|
21838
|
+
const result = await account.applications.register(request.manifests);
|
|
21152
21839
|
if (!result.ok) {
|
|
21153
21840
|
throw Object.assign(
|
|
21154
21841
|
new Error(`Failed to write manifest registry records: ${result.error.message}`),
|
|
@@ -21156,34 +21843,113 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21156
21843
|
);
|
|
21157
21844
|
}
|
|
21158
21845
|
}
|
|
21846
|
+
createAccountRegistryServices(context, signal) {
|
|
21847
|
+
const session = context.session;
|
|
21848
|
+
if (!session) throw new Error("Account registry requires an active service session");
|
|
21849
|
+
const contexts = [context];
|
|
21850
|
+
const accountSpaceId = this.ownedSpaceId(import_sdk_core9.ACCOUNT_REGISTRY_SPACE);
|
|
21851
|
+
const createScopedContext = (spaceId) => {
|
|
21852
|
+
const scoped = this._serviceGraph.track(new import_sdk_core9.ServiceContext({
|
|
21853
|
+
invoke: context.invoke,
|
|
21854
|
+
invokeAny: context.invokeAny,
|
|
21855
|
+
fetch: context.fetch,
|
|
21856
|
+
hosts: context.hosts,
|
|
21857
|
+
telemetry: this.config.telemetry
|
|
21858
|
+
}));
|
|
21859
|
+
scoped.setOperationAbortSignal(signal);
|
|
21860
|
+
scoped.setSession({ ...session, spaceId });
|
|
21861
|
+
contexts.push(scoped);
|
|
21862
|
+
return scoped;
|
|
21863
|
+
};
|
|
21864
|
+
const sql = new import_sdk_core9.SQLService({});
|
|
21865
|
+
const sqlContext = createScopedContext(accountSpaceId);
|
|
21866
|
+
sql.initialize(sqlContext);
|
|
21867
|
+
const spaces = new import_sdk_core9.SpaceService({
|
|
21868
|
+
hosts: context.hosts,
|
|
21869
|
+
session,
|
|
21870
|
+
invoke: context.invoke,
|
|
21871
|
+
fetch: (url, init2) => context.fetch(url, {
|
|
21872
|
+
...init2,
|
|
21873
|
+
signal: init2?.signal ? AbortSignal.any([init2.signal, signal]) : signal
|
|
21874
|
+
}),
|
|
21875
|
+
userDid: this.did,
|
|
21876
|
+
createKVService: (spaceId) => {
|
|
21877
|
+
const kv = new import_sdk_core9.KVService({});
|
|
21878
|
+
kv.initialize(createScopedContext(spaceId));
|
|
21879
|
+
return kv;
|
|
21880
|
+
}
|
|
21881
|
+
});
|
|
21882
|
+
return {
|
|
21883
|
+
contexts,
|
|
21884
|
+
account: new import_sdk_core5.AccountService({
|
|
21885
|
+
getDid: () => this.did,
|
|
21886
|
+
getHost: () => context.hosts[0] ?? this.config.host,
|
|
21887
|
+
getPrimarySpaceId: () => session.spaceId,
|
|
21888
|
+
getAccountSpaceId: () => accountSpaceId,
|
|
21889
|
+
getSpaces: () => spaces,
|
|
21890
|
+
getAccountDb: () => sql.db("account"),
|
|
21891
|
+
ensureAccountSpaceHosted: () => this.ensureOwnedSpaceHostedById(accountSpaceId, signal)
|
|
21892
|
+
})
|
|
21893
|
+
};
|
|
21894
|
+
}
|
|
21159
21895
|
scheduleAccountRegistrySync() {
|
|
21160
21896
|
const session = this.currentTinyCloudSession();
|
|
21161
21897
|
if (!session || this.pendingAccountRegistrySync?.session === session) {
|
|
21162
21898
|
return;
|
|
21163
21899
|
}
|
|
21900
|
+
const controller = new AbortController();
|
|
21901
|
+
const deadline = setTimeout(
|
|
21902
|
+
() => controller.abort(new DOMException("Account registry deadline exceeded", "TimeoutError")),
|
|
21903
|
+
this.accountRegistryDeadlineMs
|
|
21904
|
+
);
|
|
21164
21905
|
const promise = this.enqueueAccountRegistryOperation(session, async () => {
|
|
21165
|
-
|
|
21166
|
-
|
|
21167
|
-
|
|
21168
|
-
|
|
21169
|
-
|
|
21170
|
-
|
|
21171
|
-
|
|
21172
|
-
|
|
21173
|
-
|
|
21174
|
-
|
|
21175
|
-
|
|
21176
|
-
|
|
21177
|
-
|
|
21178
|
-
|
|
21179
|
-
|
|
21180
|
-
|
|
21181
|
-
|
|
21182
|
-
|
|
21183
|
-
|
|
21906
|
+
const sharedContext = this._serviceContext;
|
|
21907
|
+
if (!sharedContext) return;
|
|
21908
|
+
const context = this._serviceGraph.track(new import_sdk_core9.ServiceContext({
|
|
21909
|
+
invoke: sharedContext.invoke,
|
|
21910
|
+
invokeAny: sharedContext.invokeAny,
|
|
21911
|
+
fetch: sharedContext.fetch,
|
|
21912
|
+
hosts: sharedContext.hosts,
|
|
21913
|
+
telemetry: this.config.telemetry
|
|
21914
|
+
}));
|
|
21915
|
+
context.setOperationAbortSignal(controller.signal);
|
|
21916
|
+
const current = this.currentTinyCloudSession();
|
|
21917
|
+
if (!current) return;
|
|
21918
|
+
context.setSession({
|
|
21919
|
+
delegationHeader: current.delegationHeader,
|
|
21920
|
+
delegationCid: current.delegationCid,
|
|
21921
|
+
spaceId: current.spaceId,
|
|
21922
|
+
verificationMethod: current.verificationMethod,
|
|
21923
|
+
jwk: current.jwk
|
|
21924
|
+
});
|
|
21925
|
+
const registry = this.createAccountRegistryServices(context, controller.signal);
|
|
21926
|
+
try {
|
|
21927
|
+
await this.withAccountRegistryRetry(async () => {
|
|
21928
|
+
if (controller.signal.aborted) throw controller.signal.reason;
|
|
21929
|
+
if (this.currentTinyCloudSession() !== session) return;
|
|
21930
|
+
await registry.account.index.ensure();
|
|
21931
|
+
if (controller.signal.aborted) throw controller.signal.reason;
|
|
21932
|
+
if (this.currentTinyCloudSession() !== session) return;
|
|
21933
|
+
await this.writeManifestRegistryRecords(registry.account, controller.signal);
|
|
21934
|
+
if (controller.signal.aborted) throw controller.signal.reason;
|
|
21935
|
+
if (this.currentTinyCloudSession() !== session) return;
|
|
21936
|
+
if (this.currentSessionCanListSpaces()) {
|
|
21937
|
+
const result = await registry.account.spaces.syncAccessible();
|
|
21938
|
+
if (controller.signal.aborted) throw controller.signal.reason;
|
|
21939
|
+
if (!result.ok) {
|
|
21940
|
+
throw Object.assign(
|
|
21941
|
+
new Error(`Failed to sync account spaces: ${result.error.message}`),
|
|
21942
|
+
{ cause: result.error }
|
|
21943
|
+
);
|
|
21944
|
+
}
|
|
21184
21945
|
}
|
|
21946
|
+
}, controller.signal);
|
|
21947
|
+
} finally {
|
|
21948
|
+
for (const operationContext of registry.contexts) {
|
|
21949
|
+
operationContext.retire();
|
|
21185
21950
|
}
|
|
21186
|
-
|
|
21951
|
+
clearTimeout(deadline);
|
|
21952
|
+
}
|
|
21187
21953
|
});
|
|
21188
21954
|
this.pendingAccountRegistrySync = { session, promise };
|
|
21189
21955
|
const clearPendingSync = () => {
|
|
@@ -21192,6 +21958,10 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21192
21958
|
}
|
|
21193
21959
|
};
|
|
21194
21960
|
void promise.then(clearPendingSync, clearPendingSync);
|
|
21961
|
+
void promise.then(
|
|
21962
|
+
() => clearTimeout(deadline),
|
|
21963
|
+
() => clearTimeout(deadline)
|
|
21964
|
+
);
|
|
21195
21965
|
}
|
|
21196
21966
|
enqueueAccountRegistryOperation(session, task) {
|
|
21197
21967
|
const operation = this.accountRegistryTail.then(async () => {
|
|
@@ -21227,15 +21997,23 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21227
21997
|
(operation) => operation.service === "space" && this.actionContains(operation.action, "tinycloud.space/list")
|
|
21228
21998
|
);
|
|
21229
21999
|
}
|
|
21230
|
-
async withAccountRegistryRetry(task) {
|
|
22000
|
+
async withAccountRegistryRetry(task, signal) {
|
|
21231
22001
|
const delays = [250, 1e3, 3e3];
|
|
21232
22002
|
let lastError;
|
|
21233
22003
|
for (let attempt = 0; attempt < delays.length; attempt += 1) {
|
|
22004
|
+
if (signal.aborted) {
|
|
22005
|
+
console.warn("TinyCloud account registry sync stopped: deadline exceeded", signal.reason);
|
|
22006
|
+
return;
|
|
22007
|
+
}
|
|
21234
22008
|
try {
|
|
21235
22009
|
await task();
|
|
21236
22010
|
return;
|
|
21237
22011
|
} catch (error) {
|
|
21238
|
-
|
|
22012
|
+
if (signal.aborted) {
|
|
22013
|
+
console.warn("TinyCloud account registry sync stopped: deadline exceeded", error);
|
|
22014
|
+
return;
|
|
22015
|
+
}
|
|
22016
|
+
const verdict = (0, import_sdk_core9.authorizationVerdictOf)(error);
|
|
21239
22017
|
const message = error instanceof Error ? error.message : String(error);
|
|
21240
22018
|
const isAuthorizationVerdict = verdict === void 0 ? /Unauthorized Action|\b(?:401|403)\b/.test(message) : verdict !== "other";
|
|
21241
22019
|
if (isAuthorizationVerdict) {
|
|
@@ -21245,13 +22023,29 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21245
22023
|
);
|
|
21246
22024
|
return;
|
|
21247
22025
|
}
|
|
21248
|
-
if ((0,
|
|
21249
|
-
console.warn(
|
|
22026
|
+
if ((0, import_sdk_core9.isStorageFullError)(error) || (0, import_sdk_core9.isStorageFullError)(error?.cause) || message.includes(import_sdk_core9.STORAGE_FULL_MESSAGE) || message.includes(import_sdk_core9.STORAGE_WRITE_TOO_LARGE_MESSAGE)) {
|
|
22027
|
+
console.warn(
|
|
22028
|
+
"TinyCloud account registry sync stopped: storage is full",
|
|
22029
|
+
error
|
|
22030
|
+
);
|
|
21250
22031
|
return;
|
|
21251
22032
|
}
|
|
21252
22033
|
lastError = error;
|
|
21253
22034
|
if (attempt < delays.length - 1) {
|
|
21254
|
-
await new Promise((resolve) =>
|
|
22035
|
+
await new Promise((resolve, reject2) => {
|
|
22036
|
+
const timer = setTimeout(() => {
|
|
22037
|
+
signal.removeEventListener("abort", onAbort);
|
|
22038
|
+
resolve();
|
|
22039
|
+
}, delays[attempt]);
|
|
22040
|
+
const onAbort = () => {
|
|
22041
|
+
clearTimeout(timer);
|
|
22042
|
+
signal.removeEventListener("abort", onAbort);
|
|
22043
|
+
reject2(signal.reason);
|
|
22044
|
+
};
|
|
22045
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
22046
|
+
}).catch((error2) => {
|
|
22047
|
+
if (!signal.aborted) throw error2;
|
|
22048
|
+
});
|
|
21255
22049
|
}
|
|
21256
22050
|
}
|
|
21257
22051
|
}
|
|
@@ -21267,7 +22061,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21267
22061
|
}
|
|
21268
22062
|
const networkIds = /* @__PURE__ */ new Set();
|
|
21269
22063
|
for (const resource of request.resources) {
|
|
21270
|
-
if (resource.service ===
|
|
22064
|
+
if (resource.service === import_sdk_core9.ENCRYPTION_PERMISSION_SERVICE && resource.path.startsWith("urn:tinycloud:encryption:") && resource.actions.includes(DECRYPT_ACTION2)) {
|
|
21271
22065
|
networkIds.add(resource.path);
|
|
21272
22066
|
}
|
|
21273
22067
|
}
|
|
@@ -21278,7 +22072,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21278
22072
|
return;
|
|
21279
22073
|
}
|
|
21280
22074
|
for (const networkId of this.requestedEncryptionNetworkIds()) {
|
|
21281
|
-
const parsed = (0,
|
|
22075
|
+
const parsed = (0, import_sdk_core9.parseNetworkId)(networkId);
|
|
21282
22076
|
if (!didPrincipalMatches2(parsed.ownerDid, this.did)) {
|
|
21283
22077
|
continue;
|
|
21284
22078
|
}
|
|
@@ -21301,7 +22095,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21301
22095
|
* self-revealing: the next write to the space fails immediately and loudly
|
|
21302
22096
|
* with `404 Space not found`.
|
|
21303
22097
|
*/
|
|
21304
|
-
async ensureOwnedSpaceHostedById(spaceId) {
|
|
22098
|
+
async ensureOwnedSpaceHostedById(spaceId, signal) {
|
|
21305
22099
|
if (!this.auth) {
|
|
21306
22100
|
throw new Error("Owned space hosting requires wallet mode");
|
|
21307
22101
|
}
|
|
@@ -21316,7 +22110,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21316
22110
|
if (!host) {
|
|
21317
22111
|
throw new Error("Owned space hosting requires a TinyCloud host");
|
|
21318
22112
|
}
|
|
21319
|
-
const activation = await (0,
|
|
22113
|
+
const activation = await (0, import_sdk_core9.activateSessionWithHost)(host, session.delegationHeader, signal);
|
|
21320
22114
|
if (activation.success && !activation.skipped?.includes(spaceId)) {
|
|
21321
22115
|
this.confirmedHostedSpaceIds.add(spaceId);
|
|
21322
22116
|
return;
|
|
@@ -21327,15 +22121,16 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21327
22121
|
{ cause: activation }
|
|
21328
22122
|
);
|
|
21329
22123
|
}
|
|
21330
|
-
const
|
|
22124
|
+
const authorization = this.auth;
|
|
22125
|
+
const created = signal ? await authorization.hostOwnedSpaceResult(spaceId, void 0, signal) : await authorization.hostOwnedSpaceResult(spaceId);
|
|
21331
22126
|
if (!created.success) {
|
|
21332
22127
|
throw Object.assign(
|
|
21333
22128
|
new Error(`Failed to create owned space ${spaceId}: ${describeHostFailure2(created)}`),
|
|
21334
22129
|
{ cause: created }
|
|
21335
22130
|
);
|
|
21336
22131
|
}
|
|
21337
|
-
|
|
21338
|
-
const retry = await (0,
|
|
22132
|
+
if (signal?.aborted) throw signal.reason;
|
|
22133
|
+
const retry = await (0, import_sdk_core9.activateSessionWithHost)(host, session.delegationHeader, signal);
|
|
21339
22134
|
if (!retry.success || retry.skipped?.includes(spaceId)) {
|
|
21340
22135
|
throw Object.assign(
|
|
21341
22136
|
new Error(
|
|
@@ -21383,7 +22178,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21383
22178
|
{ cause: hosted }
|
|
21384
22179
|
);
|
|
21385
22180
|
}
|
|
21386
|
-
const activation = await (0,
|
|
22181
|
+
const activation = await (0, import_sdk_core9.activateSessionWithHost)(
|
|
21387
22182
|
host,
|
|
21388
22183
|
session.delegationHeader
|
|
21389
22184
|
);
|
|
@@ -21571,7 +22366,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21571
22366
|
}
|
|
21572
22367
|
let restoredAddress;
|
|
21573
22368
|
try {
|
|
21574
|
-
restoredAddress = hasPersistedProof ? (0,
|
|
22369
|
+
restoredAddress = hasPersistedProof ? (0, import_sdk_core9.canonicalizeAddress)(sessionData.address) : void 0;
|
|
21575
22370
|
} catch {
|
|
21576
22371
|
throw new InvalidRestoredSessionError("Persisted session has an invalid wallet address.");
|
|
21577
22372
|
}
|
|
@@ -21613,8 +22408,36 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21613
22408
|
const stagedHost = resolvedHost ?? this.config.host;
|
|
21614
22409
|
const stagedAddress = restoredAddress;
|
|
21615
22410
|
const stagedChainId = sessionData.chainId ?? 1;
|
|
21616
|
-
|
|
21617
|
-
|
|
22411
|
+
let replicationPrincipal;
|
|
22412
|
+
let compactReplicationSession;
|
|
22413
|
+
let replicationScopeError;
|
|
22414
|
+
if (this.config.replication?.enabled) {
|
|
22415
|
+
if (stagedAddress !== void 0) {
|
|
22416
|
+
replicationPrincipal = (0, import_sdk_core9.pkhDid)(stagedAddress, stagedChainId);
|
|
22417
|
+
} else {
|
|
22418
|
+
const { replicationScopeFromSignedSession: replicationScopeFromSignedSession2 } = await getNodeReplicationLoaders().authority();
|
|
22419
|
+
const signedScope = replicationScopeFromSignedSession2({
|
|
22420
|
+
delegationHeader: sessionData.delegationHeader,
|
|
22421
|
+
delegationCid: sessionData.delegationCid,
|
|
22422
|
+
verificationMethod: restoredVerificationMethod,
|
|
22423
|
+
persistedSpace: sessionData.spaceId
|
|
22424
|
+
});
|
|
22425
|
+
if (!signedScope) {
|
|
22426
|
+
replicationScopeError = "Persisted space does not match the locally verified delegation scope.";
|
|
22427
|
+
} else {
|
|
22428
|
+
replicationPrincipal = signedScope.principal;
|
|
22429
|
+
compactReplicationSession = {
|
|
22430
|
+
delegationHeader: sessionData.delegationHeader,
|
|
22431
|
+
delegationCid: sessionData.delegationCid,
|
|
22432
|
+
spaceId: signedScope.space,
|
|
22433
|
+
verificationMethod: restoredVerificationMethod,
|
|
22434
|
+
jwk: stagedJwk
|
|
22435
|
+
};
|
|
22436
|
+
}
|
|
22437
|
+
}
|
|
22438
|
+
}
|
|
22439
|
+
const stagedNodeDid = stagedAddress ? (0, import_sdk_core9.pkhDid)(stagedAddress, stagedChainId) : canonicalVerificationMethod;
|
|
22440
|
+
const serviceSession = {
|
|
21618
22441
|
delegationHeader: sessionData.delegationHeader,
|
|
21619
22442
|
delegationCid: sessionData.delegationCid,
|
|
21620
22443
|
spaceId: sessionData.spaceId,
|
|
@@ -21641,7 +22464,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21641
22464
|
stagedSessionExpiry,
|
|
21642
22465
|
stagedRecap
|
|
21643
22466
|
);
|
|
21644
|
-
const stagedAccountSpaceId = stagedAddress ? this.wasmBindings.makeSpaceId(stagedAddress, stagedChainId,
|
|
22467
|
+
const stagedAccountSpaceId = stagedAddress ? this.wasmBindings.makeSpaceId(stagedAddress, stagedChainId, import_sdk_core9.ACCOUNT_REGISTRY_SPACE) : void 0;
|
|
21645
22468
|
const stagedGraph = this.stageRestoredServiceGraph({
|
|
21646
22469
|
host: stagedHost,
|
|
21647
22470
|
manager: stagedManager,
|
|
@@ -21691,7 +22514,18 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21691
22514
|
} else {
|
|
21692
22515
|
this._restoredTcSession = stagedTcSession;
|
|
21693
22516
|
}
|
|
22517
|
+
this.replicationDelegateSession = compactReplicationSession;
|
|
22518
|
+
this.replicationScopeError = replicationScopeError;
|
|
22519
|
+
if (this.replicationRuntime) await (await this.replicationRuntime).unbind();
|
|
21694
22520
|
oldGraph.retire();
|
|
22521
|
+
if (replicationScopeError) {
|
|
22522
|
+
stagedGraph.serviceContext.emit("replication.state", {
|
|
22523
|
+
state: "unavailable",
|
|
22524
|
+
code: "SESSION_SCOPE_MISMATCH",
|
|
22525
|
+
detail: replicationScopeError
|
|
22526
|
+
});
|
|
22527
|
+
}
|
|
22528
|
+
await this.bindReplicationRuntime(stagedGraph.serviceContext, serviceSession, stagedGraph.kv, replicationPrincipal);
|
|
21695
22529
|
oldCore?.retireServices?.();
|
|
21696
22530
|
}
|
|
21697
22531
|
stagePrimarySessionState(session, verificationMethod, host, sessionExpiry, recap) {
|
|
@@ -21742,7 +22576,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21742
22576
|
}
|
|
21743
22577
|
stageRestoredServiceGraph(input) {
|
|
21744
22578
|
const graph = this.createServiceGraphLifetime();
|
|
21745
|
-
const core = this.auth ? new
|
|
22579
|
+
const core = this.auth ? new import_sdk_core9.TinyCloud(this.auth, {
|
|
21746
22580
|
invokeAny: graph.invokeAny,
|
|
21747
22581
|
telemetry: this.config.telemetry
|
|
21748
22582
|
}) : null;
|
|
@@ -21751,23 +22585,23 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21751
22585
|
const coreContext = graph.track(core.serviceContext);
|
|
21752
22586
|
coreContext.setSession(input.serviceSession);
|
|
21753
22587
|
}
|
|
21754
|
-
const serviceContext = graph.track(new
|
|
22588
|
+
const serviceContext = graph.track(new import_sdk_core9.ServiceContext({
|
|
21755
22589
|
invoke: graph.invoke,
|
|
21756
22590
|
invokeAny: graph.invokeAny,
|
|
21757
22591
|
fetch: graph.fetch,
|
|
21758
22592
|
hosts: [input.host],
|
|
21759
22593
|
telemetry: this.config.telemetry
|
|
21760
22594
|
}));
|
|
21761
|
-
const kv = new
|
|
22595
|
+
const kv = new import_sdk_core9.KVService({});
|
|
21762
22596
|
kv.initialize(serviceContext);
|
|
21763
22597
|
serviceContext.registerService("kv", kv);
|
|
21764
|
-
const sql = new
|
|
22598
|
+
const sql = new import_sdk_core9.SQLService({});
|
|
21765
22599
|
sql.initialize(serviceContext);
|
|
21766
22600
|
serviceContext.registerService("sql", sql);
|
|
21767
|
-
const duckdb = new
|
|
22601
|
+
const duckdb = new import_sdk_core9.DuckDbService({});
|
|
21768
22602
|
duckdb.initialize(serviceContext);
|
|
21769
22603
|
serviceContext.registerService("duckdb", duckdb);
|
|
21770
|
-
const hooks = new
|
|
22604
|
+
const hooks = new import_sdk_core9.HooksService({});
|
|
21771
22605
|
hooks.initialize(serviceContext);
|
|
21772
22606
|
serviceContext.registerService("hooks", hooks);
|
|
21773
22607
|
serviceContext.setSession(input.serviceSession);
|
|
@@ -21790,7 +22624,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21790
22624
|
});
|
|
21791
22625
|
vault.initialize(serviceContext);
|
|
21792
22626
|
serviceContext.registerService("vault", vault);
|
|
21793
|
-
const capabilityRegistry = new
|
|
22627
|
+
const capabilityRegistry = new import_sdk_core9.CapabilityKeyRegistry();
|
|
21794
22628
|
if (input.tinyCloudSession) {
|
|
21795
22629
|
const session = input.tinyCloudSession;
|
|
21796
22630
|
const delegations = input.recap.map((entry) => ({
|
|
@@ -21814,7 +22648,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21814
22648
|
}, delegations);
|
|
21815
22649
|
}
|
|
21816
22650
|
}
|
|
21817
|
-
const delegationManager = new
|
|
22651
|
+
const delegationManager = new import_sdk_core9.DelegationManager({
|
|
21818
22652
|
hosts: [input.host],
|
|
21819
22653
|
accountSpaceId: input.accountSpaceId,
|
|
21820
22654
|
session: input.serviceSession,
|
|
@@ -21823,7 +22657,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21823
22657
|
fetch: graph.fetch
|
|
21824
22658
|
});
|
|
21825
22659
|
const keyProvider = new WasmKeyProvider({ sessionManager: input.manager });
|
|
21826
|
-
const sharingService = new
|
|
22660
|
+
const sharingService = new import_sdk_core9.SharingService({
|
|
21827
22661
|
hosts: [input.host],
|
|
21828
22662
|
invoke: graph.invoke,
|
|
21829
22663
|
fetch: graph.fetch,
|
|
@@ -21836,8 +22670,8 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21836
22670
|
return this.wasmBindings.computeCid(data, codec);
|
|
21837
22671
|
},
|
|
21838
22672
|
createKVService: (config) => {
|
|
21839
|
-
const service = new
|
|
21840
|
-
const context = graph.track(new
|
|
22673
|
+
const service = new import_sdk_core9.KVService({ prefix: config.pathPrefix?.replace(/\/$/, "") });
|
|
22674
|
+
const context = graph.track(new import_sdk_core9.ServiceContext({
|
|
21841
22675
|
invoke: config.invoke,
|
|
21842
22676
|
fetch: config.fetch ?? globalThis.fetch.bind(globalThis),
|
|
21843
22677
|
hosts: config.hosts,
|
|
@@ -21845,6 +22679,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21845
22679
|
}));
|
|
21846
22680
|
context.setSession(config.session);
|
|
21847
22681
|
service.initialize(context);
|
|
22682
|
+
this.attachReplicationKV(config.session.spaceId, service);
|
|
21848
22683
|
return service;
|
|
21849
22684
|
}
|
|
21850
22685
|
});
|
|
@@ -21866,7 +22701,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21866
22701
|
return delegation;
|
|
21867
22702
|
} : void 0
|
|
21868
22703
|
});
|
|
21869
|
-
const spaceService = new
|
|
22704
|
+
const spaceService = new import_sdk_core9.SpaceService({
|
|
21870
22705
|
hosts: [input.host],
|
|
21871
22706
|
session: input.serviceSession,
|
|
21872
22707
|
invoke: graph.invoke,
|
|
@@ -21875,8 +22710,8 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21875
22710
|
userDid: input.nodeDid,
|
|
21876
22711
|
createKVService: (spaceId) => {
|
|
21877
22712
|
graph.assertActive();
|
|
21878
|
-
const scopedKv = new
|
|
21879
|
-
const context = graph.track(new
|
|
22713
|
+
const scopedKv = new import_sdk_core9.KVService({});
|
|
22714
|
+
const context = graph.track(new import_sdk_core9.ServiceContext({
|
|
21880
22715
|
invoke: graph.invoke,
|
|
21881
22716
|
invokeAny: graph.invokeAny,
|
|
21882
22717
|
fetch: graph.fetch,
|
|
@@ -21885,12 +22720,13 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21885
22720
|
}));
|
|
21886
22721
|
context.setSession({ ...input.serviceSession, spaceId });
|
|
21887
22722
|
scopedKv.initialize(context);
|
|
22723
|
+
this.attachReplicationKV(spaceId, scopedKv);
|
|
21888
22724
|
return scopedKv;
|
|
21889
22725
|
},
|
|
21890
22726
|
createVaultService: (spaceId) => {
|
|
21891
22727
|
graph.assertActive();
|
|
21892
|
-
const scopedKv = new
|
|
21893
|
-
const context = graph.track(new
|
|
22728
|
+
const scopedKv = new import_sdk_core9.KVService({});
|
|
22729
|
+
const context = graph.track(new import_sdk_core9.ServiceContext({
|
|
21894
22730
|
invoke: graph.invoke,
|
|
21895
22731
|
invokeAny: graph.invokeAny,
|
|
21896
22732
|
fetch: graph.fetch,
|
|
@@ -21899,6 +22735,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21899
22735
|
}));
|
|
21900
22736
|
context.setSession({ ...input.serviceSession, spaceId });
|
|
21901
22737
|
scopedKv.initialize(context);
|
|
22738
|
+
this.attachReplicationKV(spaceId, scopedKv);
|
|
21902
22739
|
const scopedVault = this.createVaultService(spaceId, scopedKv, encryption, {
|
|
21903
22740
|
host: input.host,
|
|
21904
22741
|
did: input.nodeDid,
|
|
@@ -21976,7 +22813,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21976
22813
|
if (address === void 0 || chainId === void 0) {
|
|
21977
22814
|
return void 0;
|
|
21978
22815
|
}
|
|
21979
|
-
const resolved = await (0,
|
|
22816
|
+
const resolved = await (0, import_sdk_core9.resolveTinyCloudHosts)((0, import_sdk_core9.pkhDid)(address, chainId), {
|
|
21980
22817
|
registryUrl: this.config.tinycloudRegistryUrl,
|
|
21981
22818
|
fallbackHosts: this.config.tinycloudFallbackHosts,
|
|
21982
22819
|
autoDiscoverLocalNode: this.config.autoDiscoverLocalNode,
|
|
@@ -22028,7 +22865,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22028
22865
|
nodeAudience: input.nodeAudience,
|
|
22029
22866
|
...input.role === "policy-enforcement" ? { enforcerDid: input.audienceDid } : {}
|
|
22030
22867
|
};
|
|
22031
|
-
const root = await (0,
|
|
22868
|
+
const root = await (0, import_sdk_core9.signCompactUcanRootAuthorization)({
|
|
22032
22869
|
issuerDid: ownerDid,
|
|
22033
22870
|
audienceDid: input.audienceDid,
|
|
22034
22871
|
attenuation: unifiedRootAttenuation(input.capabilities),
|
|
@@ -22070,7 +22907,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22070
22907
|
if (decision.needsApproval) return void 0;
|
|
22071
22908
|
throw new Error(decision.reason ?? "OpenKey automatic credential signing was rejected");
|
|
22072
22909
|
}
|
|
22073
|
-
if (typeof decision.signature !== "string" || !await (0,
|
|
22910
|
+
if (typeof decision.signature !== "string" || !await (0, import_sdk_core9.verifyEip191MessageSignature)(
|
|
22074
22911
|
request.message,
|
|
22075
22912
|
decision.signature,
|
|
22076
22913
|
request.address
|
|
@@ -22095,7 +22932,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22095
22932
|
if (approval) {
|
|
22096
22933
|
const decision = await approval(request);
|
|
22097
22934
|
if (!decision.approved) throw new Error(decision.reason ?? "Credential signing was rejected");
|
|
22098
|
-
if (decision.signature !== void 0 && !await (0,
|
|
22935
|
+
if (decision.signature !== void 0 && !await (0, import_sdk_core9.verifyEip191MessageSignature)(
|
|
22099
22936
|
request.message,
|
|
22100
22937
|
decision.signature,
|
|
22101
22938
|
request.address
|
|
@@ -22178,10 +23015,15 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22178
23015
|
nonce: this.config.nonce,
|
|
22179
23016
|
siweConfig: this.config.siweConfig,
|
|
22180
23017
|
manifest: useBootstrapSignInRequest ? void 0 : this.config.manifest,
|
|
22181
|
-
capabilityRequest: useBootstrapSignInRequest ? this.config.includeAccountRegistryPermissions === false ?
|
|
22182
|
-
includeAccountRegistryPermissions: useBootstrapSignInRequest ? false : this.config.includeAccountRegistryPermissions
|
|
23018
|
+
capabilityRequest: useBootstrapSignInRequest ? this.config.includeAccountRegistryPermissions === false ? import_sdk_core9.BOOTSTRAP_DEFAULT_ONLY_SESSION_REQUEST : import_sdk_core9.BOOTSTRAP_SESSION_REQUESTS.default : this.config.capabilityRequest,
|
|
23019
|
+
includeAccountRegistryPermissions: useBootstrapSignInRequest ? false : this.config.includeAccountRegistryPermissions,
|
|
23020
|
+
replication: this.config.replication?.enabled === true ? {
|
|
23021
|
+
enabled: true,
|
|
23022
|
+
prefixes: this.config.replication.prefixes,
|
|
23023
|
+
allowSecrets: this.config.replication.allowSecrets === true
|
|
23024
|
+
} : void 0
|
|
22183
23025
|
});
|
|
22184
|
-
this.tc = new
|
|
23026
|
+
this.tc = new import_sdk_core9.TinyCloud(this.auth, {
|
|
22185
23027
|
invokeAny: this.invokeAnyWithRuntimePermissions,
|
|
22186
23028
|
telemetry: this.config.telemetry
|
|
22187
23029
|
});
|
|
@@ -22231,10 +23073,15 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22231
23073
|
nonce: this.config.nonce,
|
|
22232
23074
|
siweConfig: this.config.siweConfig,
|
|
22233
23075
|
manifest: useBootstrapSignInRequest ? void 0 : this.config.manifest,
|
|
22234
|
-
capabilityRequest: useBootstrapSignInRequest ? this.config.includeAccountRegistryPermissions === false ?
|
|
22235
|
-
includeAccountRegistryPermissions: useBootstrapSignInRequest ? false : this.config.includeAccountRegistryPermissions
|
|
23076
|
+
capabilityRequest: useBootstrapSignInRequest ? this.config.includeAccountRegistryPermissions === false ? import_sdk_core9.BOOTSTRAP_DEFAULT_ONLY_SESSION_REQUEST : import_sdk_core9.BOOTSTRAP_SESSION_REQUESTS.default : this.config.capabilityRequest,
|
|
23077
|
+
includeAccountRegistryPermissions: useBootstrapSignInRequest ? false : this.config.includeAccountRegistryPermissions,
|
|
23078
|
+
replication: this.config.replication?.enabled === true ? {
|
|
23079
|
+
enabled: true,
|
|
23080
|
+
prefixes: this.config.replication.prefixes,
|
|
23081
|
+
allowSecrets: this.config.replication.allowSecrets === true
|
|
23082
|
+
} : void 0
|
|
22236
23083
|
});
|
|
22237
|
-
this.tc = new
|
|
23084
|
+
this.tc = new import_sdk_core9.TinyCloud(this.auth, {
|
|
22238
23085
|
invokeAny: this.invokeAnyWithRuntimePermissions,
|
|
22239
23086
|
telemetry: this.config.telemetry
|
|
22240
23087
|
});
|
|
@@ -22244,7 +23091,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22244
23091
|
* Initialize the service context and KV service after sign-in.
|
|
22245
23092
|
* @internal
|
|
22246
23093
|
*/
|
|
22247
|
-
initializeServices() {
|
|
23094
|
+
async initializeServices() {
|
|
22248
23095
|
const session = this.currentTinyCloudSession();
|
|
22249
23096
|
if (!session) {
|
|
22250
23097
|
return;
|
|
@@ -22255,28 +23102,28 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22255
23102
|
this._serviceGraph.fetch
|
|
22256
23103
|
);
|
|
22257
23104
|
this._serviceGraph.track(this.tc.serviceContext);
|
|
22258
|
-
this._serviceContext = this._serviceGraph.track(new
|
|
23105
|
+
this._serviceContext = this._serviceGraph.track(new import_sdk_core9.ServiceContext({
|
|
22259
23106
|
invoke: this._serviceGraph.invoke,
|
|
22260
23107
|
invokeAny: this._serviceGraph.invokeAny,
|
|
22261
23108
|
fetch: this._serviceGraph.fetch,
|
|
22262
23109
|
hosts: [this.config.host],
|
|
22263
23110
|
telemetry: this.config.telemetry
|
|
22264
23111
|
}));
|
|
22265
|
-
this._kv = new
|
|
23112
|
+
this._kv = new import_sdk_core9.KVService({});
|
|
22266
23113
|
this._kv.initialize(this._serviceContext);
|
|
22267
23114
|
this._serviceContext.registerService("kv", this._kv);
|
|
22268
23115
|
const features = this.nodeFeatures;
|
|
22269
23116
|
if (features.length === 0 || features.includes("sql")) {
|
|
22270
|
-
this._sql = new
|
|
23117
|
+
this._sql = new import_sdk_core9.SQLService({});
|
|
22271
23118
|
this._sql.initialize(this._serviceContext);
|
|
22272
23119
|
this._serviceContext.registerService("sql", this._sql);
|
|
22273
23120
|
}
|
|
22274
23121
|
if (features.length === 0 || features.includes("duckdb")) {
|
|
22275
|
-
this._duckdb = new
|
|
23122
|
+
this._duckdb = new import_sdk_core9.DuckDbService({});
|
|
22276
23123
|
this._duckdb.initialize(this._serviceContext);
|
|
22277
23124
|
this._serviceContext.registerService("duckdb", this._duckdb);
|
|
22278
23125
|
}
|
|
22279
|
-
this._hooks = new
|
|
23126
|
+
this._hooks = new import_sdk_core9.HooksService({});
|
|
22280
23127
|
this._hooks.initialize(this._serviceContext);
|
|
22281
23128
|
this._serviceContext.registerService("hooks", this._hooks);
|
|
22282
23129
|
const serviceSession = {
|
|
@@ -22287,16 +23134,22 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22287
23134
|
jwk: session.jwk
|
|
22288
23135
|
};
|
|
22289
23136
|
this._serviceContext.setSession(serviceSession);
|
|
23137
|
+
await this.bindReplicationRuntime(this._serviceContext, serviceSession, this._kv);
|
|
22290
23138
|
this.tc.serviceContext.setSession(serviceSession);
|
|
22291
23139
|
this._vault = this.createVaultService(session.spaceId, this._kv);
|
|
22292
23140
|
this._vault.initialize(this._serviceContext);
|
|
22293
23141
|
this._serviceContext.registerService("vault", this._vault);
|
|
22294
23142
|
this.initializeV2Services(serviceSession);
|
|
22295
23143
|
}
|
|
23144
|
+
attachReplicationKV(spaceId, kvService) {
|
|
23145
|
+
if (!this.replicationRuntime) return;
|
|
23146
|
+
const attached = this.replicationRuntime.then((runtime) => runtime.attach(spaceId, kvService));
|
|
23147
|
+
kvService.setReadThroughReady(attached);
|
|
23148
|
+
}
|
|
22296
23149
|
createSpaceScopedKVService(spaceId) {
|
|
22297
|
-
const kvService = new
|
|
23150
|
+
const kvService = new import_sdk_core9.KVService({});
|
|
22298
23151
|
if (this._serviceContext) {
|
|
22299
|
-
const spaceScopedContext = this._serviceGraph.track(new
|
|
23152
|
+
const spaceScopedContext = this._serviceGraph.track(new import_sdk_core9.ServiceContext({
|
|
22300
23153
|
invoke: this._serviceContext.invoke,
|
|
22301
23154
|
invokeAny: this._serviceContext.invokeAny,
|
|
22302
23155
|
fetch: this._serviceContext.fetch,
|
|
@@ -22308,6 +23161,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22308
23161
|
spaceScopedContext.setSession({ ...session, spaceId });
|
|
22309
23162
|
}
|
|
22310
23163
|
kvService.initialize(spaceScopedContext);
|
|
23164
|
+
this.attachReplicationKV(spaceId, kvService);
|
|
22311
23165
|
}
|
|
22312
23166
|
return kvService;
|
|
22313
23167
|
}
|
|
@@ -22388,7 +23242,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22388
23242
|
const shared = wasm.vault_x25519_dh(receiverPrivateKey, peerPublic);
|
|
22389
23243
|
return columnDecrypt(shared, ciphertext);
|
|
22390
23244
|
},
|
|
22391
|
-
verifyNodeSignature: (nodeId, message, signature2) => (0,
|
|
23245
|
+
verifyNodeSignature: (nodeId, message, signature2) => (0, import_sdk_core9.verifyDidKeyEd25519Signature)(nodeId, message, signature2)
|
|
22392
23246
|
};
|
|
22393
23247
|
}
|
|
22394
23248
|
/**
|
|
@@ -22404,7 +23258,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22404
23258
|
if (cached) return cached;
|
|
22405
23259
|
const response = await fetch(`${this.config.host}/info`);
|
|
22406
23260
|
if (!response.ok) {
|
|
22407
|
-
throw await (0,
|
|
23261
|
+
throw await (0, import_sdk_core9.httpResponseError)(response, "Failed to fetch node info");
|
|
22408
23262
|
}
|
|
22409
23263
|
const info = await response.json();
|
|
22410
23264
|
if (typeof info.nodeId !== "string" || info.nodeId.length === 0) {
|
|
@@ -22454,7 +23308,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22454
23308
|
);
|
|
22455
23309
|
if (response.status === 404) return null;
|
|
22456
23310
|
if (!response.ok) {
|
|
22457
|
-
throw await (0,
|
|
23311
|
+
throw await (0, import_sdk_core9.httpResponseError)(response, `Failed to fetch encryption network ${networkId}`);
|
|
22458
23312
|
}
|
|
22459
23313
|
const body = await response.json();
|
|
22460
23314
|
return "descriptor" in body && body.descriptor ? body.descriptor : body;
|
|
@@ -22485,17 +23339,17 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22485
23339
|
);
|
|
22486
23340
|
graph.assertActive();
|
|
22487
23341
|
if (!response.ok) {
|
|
22488
|
-
const permissionHint = response.status === 401 || response.status === 403 ? (0,
|
|
23342
|
+
const permissionHint = response.status === 401 || response.status === 403 ? (0, import_sdk_services3.parsePermissionHint)({
|
|
22489
23343
|
service: "tinycloud.encryption",
|
|
22490
23344
|
path: networkId,
|
|
22491
23345
|
actions: ["tinycloud.encryption/decrypt"]
|
|
22492
23346
|
}) : void 0;
|
|
22493
|
-
throw new
|
|
23347
|
+
throw new import_sdk_core9.DecryptTransportResponseError(response.status, permissionHint);
|
|
22494
23348
|
}
|
|
22495
23349
|
return await response.json();
|
|
22496
23350
|
}
|
|
22497
23351
|
};
|
|
22498
|
-
return new
|
|
23352
|
+
return new import_sdk_core9.EncryptionService({
|
|
22499
23353
|
crypto: crypto3,
|
|
22500
23354
|
signer: {
|
|
22501
23355
|
signDecryptInvocation: async (input) => {
|
|
@@ -22509,7 +23363,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22509
23363
|
graph.assertActive();
|
|
22510
23364
|
return {
|
|
22511
23365
|
...signed2,
|
|
22512
|
-
canonicalBody: (0,
|
|
23366
|
+
canonicalBody: (0, import_sdk_core9.canonicalizeEncryptionJson)(
|
|
22513
23367
|
input.body
|
|
22514
23368
|
)
|
|
22515
23369
|
};
|
|
@@ -22541,7 +23395,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22541
23395
|
if (!address || !didPrincipalMatches2(principal, did)) {
|
|
22542
23396
|
return null;
|
|
22543
23397
|
}
|
|
22544
|
-
const publicSpaceId = (0,
|
|
23398
|
+
const publicSpaceId = (0, import_sdk_core9.makePublicSpaceId)(address, chainId);
|
|
22545
23399
|
const encodedKey = discoveryKey.split("/").map(encodeURIComponent).join("/");
|
|
22546
23400
|
const response = await graph.fetch(
|
|
22547
23401
|
`${host}/public/${encodeURIComponent(publicSpaceId)}/kv/${encodedKey}`,
|
|
@@ -22573,7 +23427,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22573
23427
|
createVaultService(spaceId, kv, encryptionService = this.getEncryptionService(), nodeContext) {
|
|
22574
23428
|
const wasm = this.wasmBindings;
|
|
22575
23429
|
const serviceGraph = nodeContext?.serviceGraph ?? this._serviceGraph;
|
|
22576
|
-
const vaultCrypto = (0,
|
|
23430
|
+
const vaultCrypto = (0, import_sdk_core9.createVaultCrypto)({
|
|
22577
23431
|
vault_encrypt: wasm.vault_encrypt,
|
|
22578
23432
|
vault_decrypt: wasm.vault_decrypt,
|
|
22579
23433
|
vault_derive_key: wasm.vault_derive_key,
|
|
@@ -22588,7 +23442,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22588
23442
|
const chainId = nodeContext?.chainId ?? this._chainId;
|
|
22589
23443
|
const host = nodeContext?.host ?? this.config.host;
|
|
22590
23444
|
const ownerDid = this.ownerDidFromSpaceId(spaceId) ?? did;
|
|
22591
|
-
return new
|
|
23445
|
+
return new import_sdk_core9.DataVaultService({
|
|
22592
23446
|
spaceId,
|
|
22593
23447
|
crypto: vaultCrypto,
|
|
22594
23448
|
encryption: {
|
|
@@ -22613,8 +23467,8 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22613
23467
|
serviceGraph.assertActive();
|
|
22614
23468
|
return self2._publicKV ?? self2.tc.publicKV;
|
|
22615
23469
|
},
|
|
22616
|
-
readPublicSpace: (host2, targetSpaceId, key2) =>
|
|
22617
|
-
makePublicSpaceId:
|
|
23470
|
+
readPublicSpace: (host2, targetSpaceId, key2) => import_sdk_core9.TinyCloud.readPublicSpace(host2, targetSpaceId, key2),
|
|
23471
|
+
makePublicSpaceId: import_sdk_core9.TinyCloud.makePublicSpaceId,
|
|
22618
23472
|
did,
|
|
22619
23473
|
address: address ?? "",
|
|
22620
23474
|
chainId,
|
|
@@ -22628,7 +23482,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22628
23482
|
*/
|
|
22629
23483
|
initializeV2Services(serviceSession) {
|
|
22630
23484
|
const graph = this._serviceGraph;
|
|
22631
|
-
this._capabilityRegistry = new
|
|
23485
|
+
this._capabilityRegistry = new import_sdk_core9.CapabilityKeyRegistry();
|
|
22632
23486
|
const tcSession = this.auth?.tinyCloudSession;
|
|
22633
23487
|
if (tcSession && this._address) {
|
|
22634
23488
|
const sessionKey = {
|
|
@@ -22668,7 +23522,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22668
23522
|
}
|
|
22669
23523
|
this._capabilityRegistry.registerKey(sessionKey, delegations);
|
|
22670
23524
|
}
|
|
22671
|
-
this._delegationManager = new
|
|
23525
|
+
this._delegationManager = new import_sdk_core9.DelegationManager({
|
|
22672
23526
|
hosts: [this.config.host],
|
|
22673
23527
|
accountSpaceId: this.accountSpaceId,
|
|
22674
23528
|
session: serviceSession,
|
|
@@ -22676,7 +23530,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22676
23530
|
invokeAny: graph.invokeAny,
|
|
22677
23531
|
fetch: graph.fetch
|
|
22678
23532
|
});
|
|
22679
|
-
this._spaceService = new
|
|
23533
|
+
this._spaceService = new import_sdk_core9.SpaceService({
|
|
22680
23534
|
hosts: [this.config.host],
|
|
22681
23535
|
session: serviceSession,
|
|
22682
23536
|
invoke: graph.invoke,
|
|
@@ -22741,7 +23595,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22741
23595
|
await this.account.spaces.register(space);
|
|
22742
23596
|
}
|
|
22743
23597
|
});
|
|
22744
|
-
this._sharingService = new
|
|
23598
|
+
this._sharingService = new import_sdk_core9.SharingService({
|
|
22745
23599
|
hosts: [this.config.host],
|
|
22746
23600
|
session: serviceSession,
|
|
22747
23601
|
invoke: graph.invoke,
|
|
@@ -22761,8 +23615,8 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22761
23615
|
},
|
|
22762
23616
|
createKVService: (config) => {
|
|
22763
23617
|
graph.assertActive();
|
|
22764
|
-
const service = new
|
|
22765
|
-
const context = graph.track(new
|
|
23618
|
+
const service = new import_sdk_core9.KVService({ prefix: config.pathPrefix?.replace(/\/$/, "") });
|
|
23619
|
+
const context = graph.track(new import_sdk_core9.ServiceContext({
|
|
22766
23620
|
invoke: config.invoke,
|
|
22767
23621
|
fetch: config.fetch ?? graph.fetch,
|
|
22768
23622
|
hosts: config.hosts,
|
|
@@ -22770,6 +23624,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22770
23624
|
}));
|
|
22771
23625
|
context.setSession(config.session);
|
|
22772
23626
|
service.initialize(context);
|
|
23627
|
+
this.attachReplicationKV(config.session.spaceId, service);
|
|
22773
23628
|
return service;
|
|
22774
23629
|
},
|
|
22775
23630
|
onRootDelegationNeeded: this.signer ? async (params) => {
|
|
@@ -22855,15 +23710,15 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22855
23710
|
}
|
|
22856
23711
|
const permissions = ownerDelegationPermissions(params);
|
|
22857
23712
|
const now = /* @__PURE__ */ new Date();
|
|
22858
|
-
if (!(params.expiresAt instanceof Date) || params.expiresAt.getTime() <= now.getTime() || params.expiresAt.getTime() - now.getTime() >
|
|
23713
|
+
if (!(params.expiresAt instanceof Date) || params.expiresAt.getTime() <= now.getTime() || params.expiresAt.getTime() - now.getTime() > import_sdk_core9.EXPIRY.MAX_MS) {
|
|
22859
23714
|
throw new Error("Owner delegation expiry must be explicit, future, and within EXPIRY.MAX_MS");
|
|
22860
23715
|
}
|
|
22861
23716
|
if (!this.signer) throw new Error("Owner wallet signer is required");
|
|
22862
23717
|
const session = this.currentTinyCloudSession();
|
|
22863
23718
|
if (!session) throw new Error("Owner session is required");
|
|
22864
|
-
const ownerDid = (0,
|
|
23719
|
+
const ownerDid = (0, import_sdk_core9.pkhDid)(session.address, session.chainId);
|
|
22865
23720
|
for (const permission of permissions) {
|
|
22866
|
-
if (permission.service ===
|
|
23721
|
+
if (permission.service === import_sdk_core9.ENCRYPTION_PERMISSION_SERVICE && !(0, import_sdk_core9.principalDidEquals)((0, import_sdk_core9.parseNetworkId)(permission.path).ownerDid, ownerDid)) {
|
|
22867
23722
|
throw new Error("Owner delegation cannot grant a foreign encryption network");
|
|
22868
23723
|
}
|
|
22869
23724
|
}
|
|
@@ -22884,7 +23739,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22884
23739
|
const signature2 = await this.signer.signMessage(prepared.siwe);
|
|
22885
23740
|
assertOwnerGraphActive();
|
|
22886
23741
|
const delegationSession = this.wasmBindings.completeSessionSetup({ ...prepared, signature: signature2 });
|
|
22887
|
-
const activation = await (0,
|
|
23742
|
+
const activation = await (0, import_sdk_core9.activateSessionWithHost)(host, delegationSession.delegationHeader);
|
|
22888
23743
|
assertOwnerGraphActive();
|
|
22889
23744
|
if (!activation.success) {
|
|
22890
23745
|
throw Object.assign(
|
|
@@ -22920,7 +23775,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22920
23775
|
/** Register a signed policy and sibling roots with this Node's Policy/v3 runtime. */
|
|
22921
23776
|
async registerPolicy(params) {
|
|
22922
23777
|
this._serviceGraph.assertActive();
|
|
22923
|
-
return (0,
|
|
23778
|
+
return (0, import_sdk_core9.registerPolicyV3)({
|
|
22924
23779
|
...params,
|
|
22925
23780
|
nodeOrigin: this.config.host,
|
|
22926
23781
|
fetch: globalThis.fetch.bind(globalThis)
|
|
@@ -22947,23 +23802,23 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22947
23802
|
jti: base64UrlEncode(jtiDigest.slice(0, 16)),
|
|
22948
23803
|
expiresAt: new Date(input.expiresAt).toISOString().replace(/\.\d{3}Z$/, "Z")
|
|
22949
23804
|
};
|
|
22950
|
-
const requestBodyDigest = base64UrlEncode(new Uint8Array(await crypto.subtle.digest("SHA-256", new TextEncoder().encode((0,
|
|
23805
|
+
const requestBodyDigest = base64UrlEncode(new Uint8Array(await crypto.subtle.digest("SHA-256", new TextEncoder().encode((0, import_sdk_core9.canonicalizeEncryptionJson)(body)))));
|
|
22951
23806
|
const request = { ...body, requestBodyDigest };
|
|
22952
23807
|
const authorization = authorizationHeader(this.invokeAnyWithRuntimePermissions(serviceSession, [{ spaceId: session.spaceId, service: "kv", path: input.resourcePath, action: "tinycloud.kv/get" }]));
|
|
22953
23808
|
const response = await fetch(`${this.config.host}/policy/v3/deliveries/authorize`, {
|
|
22954
23809
|
method: "POST",
|
|
22955
23810
|
headers: { accept: "application/json", "content-type": "application/json", authorization },
|
|
22956
|
-
body: (0,
|
|
23811
|
+
body: (0, import_sdk_core9.canonicalizeEncryptionJson)(request)
|
|
22957
23812
|
});
|
|
22958
|
-
if (!response.ok) throw await (0,
|
|
22959
|
-
const verified = (0,
|
|
23813
|
+
if (!response.ok) throw await (0, import_sdk_core9.httpResponseError)(response, "V3 share delivery authorization failed");
|
|
23814
|
+
const verified = (0, import_sdk_core9.validateShareDeliveryAuthorizationV3Bytes)(new Uint8Array(await response.arrayBuffer()), {
|
|
22960
23815
|
request,
|
|
22961
23816
|
senderKeyDid: this.credentialHolderDid,
|
|
22962
23817
|
deliveryAudience: input.deliveryAudience
|
|
22963
23818
|
});
|
|
22964
23819
|
const requestDigest = new Uint8Array(await crypto.subtle.digest(
|
|
22965
23820
|
"SHA-256",
|
|
22966
|
-
new TextEncoder().encode(`${
|
|
23821
|
+
new TextEncoder().encode(`${import_sdk_core9.CREDENTIAL_INVITATION_REQUEST_DOMAIN}${(0, import_sdk_core9.canonicalizeEncryptionJson)(verified.request)}`)
|
|
22967
23822
|
));
|
|
22968
23823
|
return {
|
|
22969
23824
|
...verified,
|
|
@@ -23031,7 +23886,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
23031
23886
|
if (!this._sql) {
|
|
23032
23887
|
const features = this.nodeFeatures;
|
|
23033
23888
|
if (features.length > 0 && !features.includes("sql")) {
|
|
23034
|
-
throw new
|
|
23889
|
+
throw new import_sdk_core9.UnsupportedFeatureError("sql", this.config.host, features);
|
|
23035
23890
|
}
|
|
23036
23891
|
throw new Error("Not signed in. Call signIn() first.");
|
|
23037
23892
|
}
|
|
@@ -23055,8 +23910,8 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
23055
23910
|
if (!this._serviceContext || !this._serviceContext.session) {
|
|
23056
23911
|
throw new Error("Not signed in. Call signIn() first.");
|
|
23057
23912
|
}
|
|
23058
|
-
const sql = new
|
|
23059
|
-
const spaceScopedContext = this._serviceGraph.track(new
|
|
23913
|
+
const sql = new import_sdk_core9.SQLService({});
|
|
23914
|
+
const spaceScopedContext = this._serviceGraph.track(new import_sdk_core9.ServiceContext({
|
|
23060
23915
|
invoke: this._serviceContext.invoke,
|
|
23061
23916
|
invokeAny: this._serviceContext.invokeAny,
|
|
23062
23917
|
fetch: this._serviceContext.fetch,
|
|
@@ -23085,8 +23940,8 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
23085
23940
|
if (!this._serviceContext || !this._serviceContext.session) {
|
|
23086
23941
|
throw new Error("Not signed in. Call signIn() first.");
|
|
23087
23942
|
}
|
|
23088
|
-
const kv = new
|
|
23089
|
-
const spaceScopedContext = this._serviceGraph.track(new
|
|
23943
|
+
const kv = new import_sdk_core9.KVService({});
|
|
23944
|
+
const spaceScopedContext = this._serviceGraph.track(new import_sdk_core9.ServiceContext({
|
|
23090
23945
|
invoke: this._serviceContext.invoke,
|
|
23091
23946
|
invokeAny: this._serviceContext.invokeAny,
|
|
23092
23947
|
fetch: this._serviceContext.fetch,
|
|
@@ -23094,6 +23949,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
23094
23949
|
}));
|
|
23095
23950
|
spaceScopedContext.setSession({ ...this._serviceContext.session, spaceId });
|
|
23096
23951
|
kv.initialize(spaceScopedContext);
|
|
23952
|
+
this.attachReplicationKV(spaceId, kv);
|
|
23097
23953
|
return kv;
|
|
23098
23954
|
}
|
|
23099
23955
|
/**
|
|
@@ -23103,7 +23959,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
23103
23959
|
if (!this._duckdb) {
|
|
23104
23960
|
const features = this.nodeFeatures;
|
|
23105
23961
|
if (features.length > 0 && !features.includes("duckdb")) {
|
|
23106
|
-
throw new
|
|
23962
|
+
throw new import_sdk_core9.UnsupportedFeatureError("duckdb", this.config.host, features);
|
|
23107
23963
|
}
|
|
23108
23964
|
throw new Error("Not signed in. Call signIn() first.");
|
|
23109
23965
|
}
|
|
@@ -23147,7 +24003,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
23147
24003
|
type: NETWORK_ADMIN_TYPE,
|
|
23148
24004
|
targetNode,
|
|
23149
24005
|
networkId,
|
|
23150
|
-
bodyHash: (0,
|
|
24006
|
+
bodyHash: (0, import_sdk_core9.canonicalHashHex)(
|
|
23151
24007
|
crypto3.sha256,
|
|
23152
24008
|
body
|
|
23153
24009
|
),
|
|
@@ -23165,7 +24021,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
23165
24021
|
Authorization: signed2.authorization,
|
|
23166
24022
|
"Content-Type": "application/json"
|
|
23167
24023
|
},
|
|
23168
|
-
body: (0,
|
|
24024
|
+
body: (0, import_sdk_core9.canonicalizeEncryptionJson)(
|
|
23169
24025
|
body
|
|
23170
24026
|
)
|
|
23171
24027
|
});
|
|
@@ -23177,7 +24033,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
23177
24033
|
);
|
|
23178
24034
|
}
|
|
23179
24035
|
if (!response.ok) {
|
|
23180
|
-
throw await (0,
|
|
24036
|
+
throw await (0, import_sdk_core9.httpResponseError)(response, `Failed to create encryption network ${networkId}`);
|
|
23181
24037
|
}
|
|
23182
24038
|
const created = await response.json();
|
|
23183
24039
|
return created.descriptor;
|
|
@@ -23196,7 +24052,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
23196
24052
|
return existing;
|
|
23197
24053
|
}
|
|
23198
24054
|
}
|
|
23199
|
-
const parsed = (0,
|
|
24055
|
+
const parsed = (0, import_sdk_core9.parseNetworkId)(networkId);
|
|
23200
24056
|
if (!didPrincipalMatches2(parsed.ownerDid, this.did)) {
|
|
23201
24057
|
throw new Error(
|
|
23202
24058
|
`Cannot create encryption network ${networkId}: owner ${parsed.ownerDid} does not match signed-in DID ${this.did}`
|
|
@@ -23244,14 +24100,14 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
23244
24100
|
* normal KV and encryption invocation paths.
|
|
23245
24101
|
*/
|
|
23246
24102
|
async readSecret(input) {
|
|
23247
|
-
const resolved = (0,
|
|
24103
|
+
const resolved = (0, import_sdk_core9.resolveSecretPath)(input.name, { scope: input.scope });
|
|
23248
24104
|
const targetSpace = input.space.startsWith("tinycloud:") ? input.space : this.ownedSpaceId(input.space);
|
|
23249
24105
|
const result = await this.getBaseVault(targetSpace).readNetworkEncrypted(
|
|
23250
24106
|
resolved.vaultKey
|
|
23251
24107
|
);
|
|
23252
24108
|
if (result.status !== "ok") {
|
|
23253
24109
|
if (result.status === "permission_required") {
|
|
23254
|
-
const hint = (0,
|
|
24110
|
+
const hint = (0, import_sdk_services3.parsePermissionHint)(result.hint);
|
|
23255
24111
|
if (hint === void 0) return { status: "read_failed" };
|
|
23256
24112
|
return {
|
|
23257
24113
|
status: "permission_required",
|
|
@@ -23277,7 +24133,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
23277
24133
|
const resolvedSpace = spaceId.startsWith("tinycloud:") ? spaceId : this.ownedSpaceId(spaceId);
|
|
23278
24134
|
let secrets = this._baseSecrets.get(resolvedSpace);
|
|
23279
24135
|
if (!secrets) {
|
|
23280
|
-
secrets = new
|
|
24136
|
+
secrets = new import_sdk_core9.SecretsService(() => this.getBaseVault(resolvedSpace));
|
|
23281
24137
|
this._baseSecrets.set(resolvedSpace, secrets);
|
|
23282
24138
|
}
|
|
23283
24139
|
return secrets;
|
|
@@ -23420,7 +24276,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
23420
24276
|
for (const grant of this.runtimePermissionGrants) {
|
|
23421
24277
|
if (grant.provenance === "primary") continue;
|
|
23422
24278
|
for (const operation of grant.operations) {
|
|
23423
|
-
const service =
|
|
24279
|
+
const service = import_sdk_core9.SERVICE_SHORT_TO_LONG[operation.service];
|
|
23424
24280
|
if (service === void 0 || typeof operation.path !== "string" || typeof operation.action !== "string") {
|
|
23425
24281
|
continue;
|
|
23426
24282
|
}
|
|
@@ -23438,7 +24294,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
23438
24294
|
service,
|
|
23439
24295
|
...space === void 0 ? {} : { space },
|
|
23440
24296
|
path: operation.path,
|
|
23441
|
-
caveats: (0,
|
|
24297
|
+
caveats: (0, import_sdk_core9.canonicalizeRecapCaveats)(caveats)
|
|
23442
24298
|
});
|
|
23443
24299
|
const existing = grouped.get(identity);
|
|
23444
24300
|
if (existing === void 0) {
|
|
@@ -23483,7 +24339,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
23483
24339
|
delegationCid: grant.delegationCid,
|
|
23484
24340
|
spaceId: grant.spaceId,
|
|
23485
24341
|
jwk: this.sessionKeyJwk,
|
|
23486
|
-
address: (0,
|
|
24342
|
+
address: (0, import_sdk_core9.canonicalizeAddress)(grant.address),
|
|
23487
24343
|
chainId: grant.chainId,
|
|
23488
24344
|
siwe: grant.siwe,
|
|
23489
24345
|
signature: grant.signature
|
|
@@ -23504,10 +24360,10 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
23504
24360
|
async useRuntimeDelegation(delegation) {
|
|
23505
24361
|
const session = this.currentTinyCloudSession();
|
|
23506
24362
|
if (!session) {
|
|
23507
|
-
throw new
|
|
24363
|
+
throw new import_sdk_core9.SessionExpiredError(/* @__PURE__ */ new Date(0));
|
|
23508
24364
|
}
|
|
23509
24365
|
if (delegation.expiry.getTime() <= Date.now()) {
|
|
23510
|
-
throw new
|
|
24366
|
+
throw new import_sdk_core9.SessionExpiredError(delegation.expiry);
|
|
23511
24367
|
}
|
|
23512
24368
|
const expectedDids = [session.verificationMethod, this.sessionDid];
|
|
23513
24369
|
if (!expectedDids.some((did) => didPrincipalMatches2(delegation.delegateDID, did))) {
|
|
@@ -23518,7 +24374,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
23518
24374
|
const targetHost = delegation.host ?? this.config.host;
|
|
23519
24375
|
let activateResult;
|
|
23520
24376
|
try {
|
|
23521
|
-
activateResult = await (0,
|
|
24377
|
+
activateResult = await (0, import_sdk_core9.activateSessionWithHost)(
|
|
23522
24378
|
targetHost,
|
|
23523
24379
|
delegation.delegationHeader
|
|
23524
24380
|
);
|
|
@@ -23560,13 +24416,13 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
23560
24416
|
}
|
|
23561
24417
|
const session = this.currentTinyCloudSession();
|
|
23562
24418
|
if (!session) {
|
|
23563
|
-
throw new
|
|
24419
|
+
throw new import_sdk_core9.SessionExpiredError(/* @__PURE__ */ new Date(0));
|
|
23564
24420
|
}
|
|
23565
24421
|
const sessionExpiry = extractSiweExpiration(session.siwe);
|
|
23566
24422
|
if (sessionExpiry !== void 0) {
|
|
23567
24423
|
const marginMs = _TinyCloudNode.SESSION_EXPIRY_SAFETY_MARGIN_MS;
|
|
23568
24424
|
if (sessionExpiry.getTime() <= Date.now() + marginMs) {
|
|
23569
|
-
throw new
|
|
24425
|
+
throw new import_sdk_core9.SessionExpiredError(sessionExpiry);
|
|
23570
24426
|
}
|
|
23571
24427
|
}
|
|
23572
24428
|
const expanded = this.expandPermissionEntries(permissions);
|
|
@@ -23642,7 +24498,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
23642
24498
|
...prepared,
|
|
23643
24499
|
signature: signature2
|
|
23644
24500
|
});
|
|
23645
|
-
const activateResult = await (0,
|
|
24501
|
+
const activateResult = await (0, import_sdk_core9.activateSessionWithHost)(
|
|
23646
24502
|
this.config.host,
|
|
23647
24503
|
delegatedSession.delegationHeader
|
|
23648
24504
|
);
|
|
@@ -23815,10 +24671,10 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
23815
24671
|
throw new Error("Public space not enabled. Set enablePublicSpace: true in config.");
|
|
23816
24672
|
}
|
|
23817
24673
|
await this.auth.hostPublicSpace(publicSpaceId);
|
|
23818
|
-
const kvActions = [
|
|
24674
|
+
const kvActions = [import_sdk_core9.KV.PUT, import_sdk_core9.KV.GET, import_sdk_core9.KV.DEL, import_sdk_core9.KV.LIST, import_sdk_core9.KV.METADATA];
|
|
23819
24675
|
const abilities = { kv: { "": kvActions } };
|
|
23820
24676
|
const now = /* @__PURE__ */ new Date();
|
|
23821
|
-
const expiryMs =
|
|
24677
|
+
const expiryMs = import_sdk_core9.EXPIRY.EPHEMERAL_MS;
|
|
23822
24678
|
const expirationTime = new Date(now.getTime() + expiryMs);
|
|
23823
24679
|
const prepared = this.wasmBindings.prepareSession({
|
|
23824
24680
|
abilities,
|
|
@@ -23836,7 +24692,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
23836
24692
|
...prepared,
|
|
23837
24693
|
signature: signature2
|
|
23838
24694
|
});
|
|
23839
|
-
const activateResult = await (0,
|
|
24695
|
+
const activateResult = await (0, import_sdk_core9.activateSessionWithHost)(
|
|
23840
24696
|
this.config.host,
|
|
23841
24697
|
delegationSession.delegationHeader
|
|
23842
24698
|
);
|
|
@@ -23866,8 +24722,8 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
23866
24722
|
}]);
|
|
23867
24723
|
}
|
|
23868
24724
|
if (this._serviceContext) {
|
|
23869
|
-
const publicKV = new
|
|
23870
|
-
const publicContext = this._serviceGraph.track(new
|
|
24725
|
+
const publicKV = new import_sdk_core9.KVService({ prefix: "" });
|
|
24726
|
+
const publicContext = this._serviceGraph.track(new import_sdk_core9.ServiceContext({
|
|
23871
24727
|
invoke: this._serviceGraph.invoke,
|
|
23872
24728
|
fetch: this._serviceGraph.fetch,
|
|
23873
24729
|
hosts: this._serviceContext.hosts,
|
|
@@ -24019,14 +24875,14 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24019
24875
|
}
|
|
24020
24876
|
const session = this.currentTinyCloudSession();
|
|
24021
24877
|
if (!session) {
|
|
24022
|
-
throw new
|
|
24878
|
+
throw new import_sdk_core9.SessionExpiredError(/* @__PURE__ */ new Date(0));
|
|
24023
24879
|
}
|
|
24024
24880
|
const sessionExpiry = extractSiweExpiration(session.siwe);
|
|
24025
24881
|
if (sessionExpiry !== void 0) {
|
|
24026
24882
|
const now2 = Date.now();
|
|
24027
24883
|
const marginMs = _TinyCloudNode.SESSION_EXPIRY_SAFETY_MARGIN_MS;
|
|
24028
24884
|
if (sessionExpiry.getTime() <= now2 + marginMs) {
|
|
24029
|
-
throw new
|
|
24885
|
+
throw new import_sdk_core9.SessionExpiredError(sessionExpiry);
|
|
24030
24886
|
}
|
|
24031
24887
|
}
|
|
24032
24888
|
if (!Array.isArray(permissions) || permissions.length === 0) {
|
|
@@ -24056,31 +24912,31 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24056
24912
|
);
|
|
24057
24913
|
return { delegation: delegation2, prompted: true };
|
|
24058
24914
|
}
|
|
24059
|
-
const
|
|
24060
|
-
|
|
24061
|
-
|
|
24062
|
-
|
|
24063
|
-
|
|
24064
|
-
|
|
24065
|
-
|
|
24066
|
-
)
|
|
24067
|
-
|
|
24068
|
-
|
|
24069
|
-
|
|
24070
|
-
|
|
24071
|
-
}
|
|
24072
|
-
const runtimeExpiration = runtimeGrant.expiresAt < effectiveExpiration ? runtimeGrant.expiresAt : effectiveExpiration;
|
|
24073
|
-
const delegation2 = await this.createDelegationViaRuntimeGrant(
|
|
24074
|
-
did,
|
|
24075
|
-
expandedEntries,
|
|
24076
|
-
runtimeExpiration,
|
|
24077
|
-
runtimeGrant,
|
|
24078
|
-
runtimeOperations,
|
|
24079
|
-
onPrepared
|
|
24080
|
-
);
|
|
24081
|
-
return { delegation: delegation2, prompted: false };
|
|
24915
|
+
const plan = this.planDerivation(
|
|
24916
|
+
expandedEntries,
|
|
24917
|
+
session,
|
|
24918
|
+
effectiveExpiration,
|
|
24919
|
+
Date.now()
|
|
24920
|
+
);
|
|
24921
|
+
if ("refused" in plan) {
|
|
24922
|
+
if (plan.refused === "SESSION_EXPIRING") {
|
|
24923
|
+
throw new import_sdk_core9.SessionExpiredError(plan.expiredAt ?? sessionExpiry ?? /* @__PURE__ */ new Date(0));
|
|
24924
|
+
}
|
|
24925
|
+
if (plan.refused === "CAVEATED_AUTHORITY") {
|
|
24926
|
+
throw new import_sdk_core9.CaveatedDelegationUnsupportedError(plan.caveated ?? []);
|
|
24082
24927
|
}
|
|
24083
|
-
throw new
|
|
24928
|
+
throw new import_sdk_core9.PermissionNotInManifestError(plan.missing ?? [], plan.granted ?? []);
|
|
24929
|
+
}
|
|
24930
|
+
if (plan.path === "runtime") {
|
|
24931
|
+
const delegation2 = await this.createDelegationViaRuntimeGrant(
|
|
24932
|
+
did,
|
|
24933
|
+
expandedEntries,
|
|
24934
|
+
plan.effectiveExpiration,
|
|
24935
|
+
plan.grant,
|
|
24936
|
+
plan.operations,
|
|
24937
|
+
onPrepared
|
|
24938
|
+
);
|
|
24939
|
+
return { delegation: delegation2, prompted: false };
|
|
24084
24940
|
}
|
|
24085
24941
|
const delegation = await this.createDelegationViaWasmPath(
|
|
24086
24942
|
did,
|
|
@@ -24091,6 +24947,149 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24091
24947
|
);
|
|
24092
24948
|
return { delegation, prompted: false };
|
|
24093
24949
|
}
|
|
24950
|
+
/**
|
|
24951
|
+
* What `delegateTo` would select for `entries`, without signing or any
|
|
24952
|
+
* network call (TC-858 plan v3 §4.3): the session path when the signed
|
|
24953
|
+
* recap covers every entry, the runtime-grant path otherwise, or a
|
|
24954
|
+
* refusal. A refusal of `CAVEATED_AUTHORITY` means coverage exists only
|
|
24955
|
+
* through caveated branches, which the action-only WASM child-delegation
|
|
24956
|
+
* boundary cannot preserve — replication never derives authority through
|
|
24957
|
+
* them. `expiredAt`/`missing`/`granted`/`caveated` carry the payload
|
|
24958
|
+
* `delegateTo` turns back into its typed errors.
|
|
24959
|
+
* @internal
|
|
24960
|
+
*/
|
|
24961
|
+
planDerivation(expandedEntries, session, effectiveExpiration, nowMs) {
|
|
24962
|
+
const caveatedRequest = expandedEntries.filter(
|
|
24963
|
+
(entry) => !(0, import_sdk_core9.recapCaveatsEqual)(entry.caveats, void 0)
|
|
24964
|
+
);
|
|
24965
|
+
if (caveatedRequest.length > 0) {
|
|
24966
|
+
return { refused: "CAVEATED_AUTHORITY", caveated: caveatedRequest };
|
|
24967
|
+
}
|
|
24968
|
+
const granted = this.projectSignedRecapCapabilities(session.siwe);
|
|
24969
|
+
const { subset, missing } = this.signedCapabilitySubset(expandedEntries, granted);
|
|
24970
|
+
if (subset) {
|
|
24971
|
+
return {
|
|
24972
|
+
path: "session",
|
|
24973
|
+
parentCid: session.delegationCid,
|
|
24974
|
+
expiresAt: effectiveExpiration.getTime(),
|
|
24975
|
+
effectiveExpiration
|
|
24976
|
+
};
|
|
24977
|
+
}
|
|
24978
|
+
const runtimeOperations = this.permissionEntriesToOperations(expandedEntries, session);
|
|
24979
|
+
const runtimeGrant = this.findGrantForOperations(
|
|
24980
|
+
runtimeOperations,
|
|
24981
|
+
{ excludePrimary: true }
|
|
24982
|
+
);
|
|
24983
|
+
if (runtimeGrant) {
|
|
24984
|
+
const marginMs = _TinyCloudNode.SESSION_EXPIRY_SAFETY_MARGIN_MS;
|
|
24985
|
+
if (runtimeGrant.expiresAt.getTime() <= nowMs + marginMs) {
|
|
24986
|
+
return { refused: "SESSION_EXPIRING", expiredAt: runtimeGrant.expiresAt };
|
|
24987
|
+
}
|
|
24988
|
+
const caveated = this.caveatedRuntimeGrantEntries(
|
|
24989
|
+
expandedEntries,
|
|
24990
|
+
runtimeOperations,
|
|
24991
|
+
runtimeGrant
|
|
24992
|
+
);
|
|
24993
|
+
if (caveated.length > 0) {
|
|
24994
|
+
return { refused: "CAVEATED_AUTHORITY", caveated };
|
|
24995
|
+
}
|
|
24996
|
+
const runtimeExpiration = runtimeGrant.expiresAt < effectiveExpiration ? runtimeGrant.expiresAt : effectiveExpiration;
|
|
24997
|
+
return {
|
|
24998
|
+
path: "runtime",
|
|
24999
|
+
parentCid: runtimeGrant.session.delegationCid,
|
|
25000
|
+
expiresAt: runtimeExpiration.getTime(),
|
|
25001
|
+
effectiveExpiration: runtimeExpiration,
|
|
25002
|
+
grant: runtimeGrant,
|
|
25003
|
+
operations: runtimeOperations
|
|
25004
|
+
};
|
|
25005
|
+
}
|
|
25006
|
+
const relaxedGranted = granted.map((entry) => ({ ...entry, caveats: void 0 }));
|
|
25007
|
+
const relaxedRequested = expandedEntries.map((entry) => ({ ...entry, caveats: void 0 }));
|
|
25008
|
+
const relaxed = this.signedCapabilitySubset(relaxedRequested, relaxedGranted);
|
|
25009
|
+
if (relaxed.subset) {
|
|
25010
|
+
return {
|
|
25011
|
+
refused: "CAVEATED_AUTHORITY",
|
|
25012
|
+
caveated: missing.map((entry) => ({ ...entry, caveats: [{ via: "session-recap" }] }))
|
|
25013
|
+
};
|
|
25014
|
+
}
|
|
25015
|
+
return { refused: "NOT_COVERED", missing, granted };
|
|
25016
|
+
}
|
|
25017
|
+
/**
|
|
25018
|
+
* The plan `delegateTo(device, entries)` would follow, as a pure lookup:
|
|
25019
|
+
* no WASM sign and no `POST /delegate`. Backs
|
|
25020
|
+
* `ReplicationAuthority.plan` (and `mint` inside it) so a predicted
|
|
25021
|
+
* parent and expiry can never disagree with what a mint would use (§4.3,
|
|
25022
|
+
* §4.4). Session expiry inside the 60 s margin refuses with
|
|
25023
|
+
* `SESSION_EXPIRING`; the same check delegateTo performs.
|
|
25024
|
+
* @internal
|
|
25025
|
+
*/
|
|
25026
|
+
planDelegation(entries, options) {
|
|
25027
|
+
if (!Array.isArray(entries) || entries.length === 0) {
|
|
25028
|
+
throw new Error("planDelegation requires a non-empty permissions array");
|
|
25029
|
+
}
|
|
25030
|
+
const session = this.currentTinyCloudSession();
|
|
25031
|
+
if (!session) {
|
|
25032
|
+
return { refused: "SESSION_EXPIRING", expiredAt: /* @__PURE__ */ new Date(0) };
|
|
25033
|
+
}
|
|
25034
|
+
const nowMs = Date.now();
|
|
25035
|
+
const sessionExpiry = extractSiweExpiration(session.siwe);
|
|
25036
|
+
if (sessionExpiry !== void 0 && sessionExpiry.getTime() <= nowMs + _TinyCloudNode.SESSION_EXPIRY_SAFETY_MARGIN_MS) {
|
|
25037
|
+
return { refused: "SESSION_EXPIRING", expiredAt: sessionExpiry };
|
|
25038
|
+
}
|
|
25039
|
+
const expandedEntries = this.expandPermissionEntries(entries);
|
|
25040
|
+
const expiryMs = resolveExpiryMs(options?.expiry);
|
|
25041
|
+
const expirationTime = new Date(nowMs + expiryMs);
|
|
25042
|
+
const effectiveExpiration = sessionExpiry !== void 0 && sessionExpiry < expirationTime ? sessionExpiry : expirationTime;
|
|
25043
|
+
return this.planDerivation(expandedEntries, session, effectiveExpiration, nowMs);
|
|
25044
|
+
}
|
|
25045
|
+
/**
|
|
25046
|
+
* The replication entries this node's sign-in request carries for the
|
|
25047
|
+
* current replication config and the signed-in or restored address: the
|
|
25048
|
+
* output of the same augmentation step `resolveSignInCapabilities` runs,
|
|
25049
|
+
* with the unrestricted-get and secrets gates applied (§4.1, §4.6).
|
|
25050
|
+
* Empty when replication is off or no address is known. Pure.
|
|
25051
|
+
*/
|
|
25052
|
+
replicationSignInEntries() {
|
|
25053
|
+
if (this.config.replication?.enabled !== true) return [];
|
|
25054
|
+
const auth = this.auth;
|
|
25055
|
+
if (auth === void 0 || typeof auth.replicationSignInEntries !== "function") {
|
|
25056
|
+
return [];
|
|
25057
|
+
}
|
|
25058
|
+
return auth.replicationSignInEntries();
|
|
25059
|
+
}
|
|
25060
|
+
async replicationAuthority() {
|
|
25061
|
+
const { createReplicationAuthority: createReplicationAuthority2 } = await getNodeReplicationLoaders().authority();
|
|
25062
|
+
return createReplicationAuthority2({
|
|
25063
|
+
replicationSession: () => this.currentTinyCloudSession() ?? this.replicationDelegateSession,
|
|
25064
|
+
siweExpiration: (siwe) => extractSiweExpiration(siwe),
|
|
25065
|
+
planDelegation: (entries, options) => this.planDelegation(entries, options),
|
|
25066
|
+
mintDelegation: async (deviceDid, entries) => {
|
|
25067
|
+
const result = await this.delegateTo((0, import_sdk_core9.principalDid)(deviceDid), entries);
|
|
25068
|
+
return {
|
|
25069
|
+
ucan: result.delegation.delegationHeader.Authorization,
|
|
25070
|
+
expiresAt: result.delegation.expiry.getTime()
|
|
25071
|
+
};
|
|
25072
|
+
}
|
|
25073
|
+
});
|
|
25074
|
+
}
|
|
25075
|
+
async bindReplicationRuntime(context, session, kv, principal) {
|
|
25076
|
+
if (!this.replicationRuntime) return;
|
|
25077
|
+
const identityPrincipal = principal ?? (this._address === void 0 ? void 0 : (0, import_sdk_core9.pkhDid)(this._address, this._chainId));
|
|
25078
|
+
if (identityPrincipal === void 0) return;
|
|
25079
|
+
const runtime = await this.replicationRuntime;
|
|
25080
|
+
const authority = await this.replicationAuthority();
|
|
25081
|
+
await runtime.bind({
|
|
25082
|
+
context,
|
|
25083
|
+
session,
|
|
25084
|
+
principal: identityPrincipal,
|
|
25085
|
+
authority,
|
|
25086
|
+
primaryKV: [{ space: session.spaceId, kv }]
|
|
25087
|
+
});
|
|
25088
|
+
}
|
|
25089
|
+
/** Stable control facade for this node's optional replication runtime. */
|
|
25090
|
+
get replication() {
|
|
25091
|
+
return this.replicationControl;
|
|
25092
|
+
}
|
|
24094
25093
|
/**
|
|
24095
25094
|
* Materialize one manifest-declared delegation using the current session key.
|
|
24096
25095
|
* Delivery is intentionally out of band; callers decide how to transmit the
|
|
@@ -24164,7 +25163,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24164
25163
|
const spaceId = resolvedSpaces.size === 1 ? [...resolvedSpaces][0] : session.spaceId;
|
|
24165
25164
|
const abilities = {};
|
|
24166
25165
|
for (const entry of entries) {
|
|
24167
|
-
const shortService =
|
|
25166
|
+
const shortService = import_sdk_core9.SERVICE_LONG_TO_SHORT[entry.service];
|
|
24168
25167
|
if (shortService === void 0) {
|
|
24169
25168
|
throw new Error(
|
|
24170
25169
|
`delegateTo: unknown service '${entry.service}' \u2014 no short-form mapping`
|
|
@@ -24221,7 +25220,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24221
25220
|
if (onPrepared) {
|
|
24222
25221
|
await onPrepared(delegation);
|
|
24223
25222
|
}
|
|
24224
|
-
const activateResult = await (0,
|
|
25223
|
+
const activateResult = await (0, import_sdk_core9.activateSessionWithHost)(
|
|
24225
25224
|
this.config.host,
|
|
24226
25225
|
delegationHeader
|
|
24227
25226
|
);
|
|
@@ -24263,7 +25262,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24263
25262
|
if (onPrepared) {
|
|
24264
25263
|
await onPrepared(delegation);
|
|
24265
25264
|
}
|
|
24266
|
-
const activateResult = await (0,
|
|
25265
|
+
const activateResult = await (0, import_sdk_core9.activateSessionWithHost)(
|
|
24267
25266
|
targetHost,
|
|
24268
25267
|
delegationHeader
|
|
24269
25268
|
);
|
|
@@ -24292,7 +25291,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24292
25291
|
return this.wasmBindings.makeSpaceId(session.address, session.chainId, space);
|
|
24293
25292
|
}
|
|
24294
25293
|
expandPermissionEntries(permissions) {
|
|
24295
|
-
return (0,
|
|
25294
|
+
return (0, import_sdk_core9.expandPermissionEntries)(permissions);
|
|
24296
25295
|
}
|
|
24297
25296
|
/**
|
|
24298
25297
|
* The current WASM child-delegation APIs accept action-only maps. Refuse any
|
|
@@ -24300,10 +25299,10 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24300
25299
|
*/
|
|
24301
25300
|
assertDelegationCaveatsPreservable(entries) {
|
|
24302
25301
|
const caveated = entries.filter(
|
|
24303
|
-
(entry) => !(0,
|
|
25302
|
+
(entry) => !(0, import_sdk_core9.recapCaveatsEqual)(entry.caveats, void 0)
|
|
24304
25303
|
);
|
|
24305
25304
|
if (caveated.length > 0) {
|
|
24306
|
-
throw new
|
|
25305
|
+
throw new import_sdk_core9.CaveatedDelegationUnsupportedError(caveated);
|
|
24307
25306
|
}
|
|
24308
25307
|
}
|
|
24309
25308
|
/**
|
|
@@ -24313,6 +25312,18 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24313
25312
|
* it only accepts action maps, so reject the selected constrained branch.
|
|
24314
25313
|
*/
|
|
24315
25314
|
assertRuntimeGrantCaveatsPreservable(entries, requestedOperations, grant) {
|
|
25315
|
+
const caveated = this.caveatedRuntimeGrantEntries(entries, requestedOperations, grant);
|
|
25316
|
+
if (caveated.length > 0) {
|
|
25317
|
+
throw new import_sdk_core9.CaveatedDelegationUnsupportedError(caveated);
|
|
25318
|
+
}
|
|
25319
|
+
}
|
|
25320
|
+
/**
|
|
25321
|
+
* The entries of `grant` that cover a requested operation while carrying
|
|
25322
|
+
* caveats — the branches {@link assertRuntimeGrantCaveatsPreservable}
|
|
25323
|
+
* rejects and {@link planDerivation} classifies as `CAVEATED_AUTHORITY`.
|
|
25324
|
+
* Shared so the pure plan and the mint path can't disagree.
|
|
25325
|
+
*/
|
|
25326
|
+
caveatedRuntimeGrantEntries(entries, requestedOperations, grant) {
|
|
24316
25327
|
let operationIndex = 0;
|
|
24317
25328
|
const caveated = [];
|
|
24318
25329
|
for (const entry of entries) {
|
|
@@ -24320,7 +25331,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24320
25331
|
const requested = requestedOperations[operationIndex++];
|
|
24321
25332
|
if (!requested) continue;
|
|
24322
25333
|
const constrained = grant.operations.find(
|
|
24323
|
-
(granted) => this.operationCovers(granted, requested) && !(0,
|
|
25334
|
+
(granted) => this.operationCovers(granted, requested) && !(0, import_sdk_core9.recapCaveatsEqual)(granted.caveats, void 0)
|
|
24324
25335
|
);
|
|
24325
25336
|
if (constrained) {
|
|
24326
25337
|
caveated.push({
|
|
@@ -24331,15 +25342,13 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24331
25342
|
}
|
|
24332
25343
|
}
|
|
24333
25344
|
}
|
|
24334
|
-
|
|
24335
|
-
throw new import_sdk_core8.CaveatedDelegationUnsupportedError(caveated);
|
|
24336
|
-
}
|
|
25345
|
+
return caveated;
|
|
24337
25346
|
}
|
|
24338
25347
|
/** Reject caveated parent branches before action-only child signing. */
|
|
24339
25348
|
assertPortableDelegationCaveatsPreservable(delegation) {
|
|
24340
25349
|
const entries = [];
|
|
24341
25350
|
const add3 = (service, space, path, actions, caveats) => {
|
|
24342
|
-
if ((0,
|
|
25351
|
+
if ((0, import_sdk_core9.recapCaveatsEqual)(caveats, void 0)) return;
|
|
24343
25352
|
entries.push({
|
|
24344
25353
|
service: service.startsWith("tinycloud.") ? service : `tinycloud.${service}`,
|
|
24345
25354
|
space,
|
|
@@ -24359,11 +25368,11 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24359
25368
|
add3(resource.service, resource.space, resource.path, resource.actions, resource.caveats);
|
|
24360
25369
|
}
|
|
24361
25370
|
if (entries.length > 0) {
|
|
24362
|
-
throw new
|
|
25371
|
+
throw new import_sdk_core9.CaveatedDelegationUnsupportedError(entries);
|
|
24363
25372
|
}
|
|
24364
25373
|
}
|
|
24365
25374
|
shortServiceName(service) {
|
|
24366
|
-
const short =
|
|
25375
|
+
const short = import_sdk_core9.SERVICE_LONG_TO_SHORT[service];
|
|
24367
25376
|
if (short === void 0) {
|
|
24368
25377
|
throw new Error(
|
|
24369
25378
|
`unknown service '${service}' \u2014 no short-form mapping`
|
|
@@ -24390,7 +25399,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24390
25399
|
return abilities;
|
|
24391
25400
|
}
|
|
24392
25401
|
isEncryptionPermissionEntry(entry) {
|
|
24393
|
-
return entry.service ===
|
|
25402
|
+
return entry.service === import_sdk_core9.ENCRYPTION_PERMISSION_SERVICE && this.isEncryptionNetworkOperation("encryption", entry.path, entry.space);
|
|
24394
25403
|
}
|
|
24395
25404
|
isRawRevocationPermissionEntry(entry) {
|
|
24396
25405
|
return entry.service === "tinycloud.delegation" && entry.path === "" && entry.space?.startsWith("urn:cid:") === true && entry.actions.includes("tinycloud.delegation/revoke");
|
|
@@ -24438,7 +25447,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24438
25447
|
const missing = requested.filter((entry) => {
|
|
24439
25448
|
const raw = this.isEncryptionPermissionEntry(entry) || this.isRawRevocationPermissionEntry(entry);
|
|
24440
25449
|
const comparable = raw && this.isEncryptionPermissionEntry(entry) ? { ...entry, space: "encryption" } : entry;
|
|
24441
|
-
return !(0,
|
|
25450
|
+
return !(0, import_sdk_core9.isCapabilitySubset)([comparable], raw ? rawGranted : spaceGranted).subset;
|
|
24442
25451
|
});
|
|
24443
25452
|
return { subset: missing.length === 0, missing };
|
|
24444
25453
|
}
|
|
@@ -24674,7 +25683,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24674
25683
|
if (granted.service !== requested.service || !this.actionContains(granted.action, requested.action)) {
|
|
24675
25684
|
return false;
|
|
24676
25685
|
}
|
|
24677
|
-
if (requested.caveats !== void 0 && !(0,
|
|
25686
|
+
if (requested.caveats !== void 0 && !(0, import_sdk_core9.recapCaveatsEqual)(granted.caveats, requested.caveats)) {
|
|
24678
25687
|
return false;
|
|
24679
25688
|
}
|
|
24680
25689
|
if (granted.resource !== void 0 || requested.resource !== void 0) {
|
|
@@ -24696,7 +25705,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24696
25705
|
if (grantedAction === requestedAction) {
|
|
24697
25706
|
return true;
|
|
24698
25707
|
}
|
|
24699
|
-
if ((0,
|
|
25708
|
+
if ((0, import_sdk_core9.isExplicitOnlyAction)(requestedAction)) {
|
|
24700
25709
|
return false;
|
|
24701
25710
|
}
|
|
24702
25711
|
if (grantedAction.endsWith("/*")) {
|
|
@@ -24808,7 +25817,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24808
25817
|
if (resolvedDelegateDID.endsWith(".eth") && this.config.ensResolver) {
|
|
24809
25818
|
const address = await this.config.ensResolver.resolveAddress(resolvedDelegateDID);
|
|
24810
25819
|
if (!address) throw new Error(`Could not resolve ENS name: ${resolvedDelegateDID}`);
|
|
24811
|
-
resolvedDelegateDID = (0,
|
|
25820
|
+
resolvedDelegateDID = (0, import_sdk_core9.pkhDid)(address, 1);
|
|
24812
25821
|
}
|
|
24813
25822
|
const entries = legacyParamsToPermissionEntries(
|
|
24814
25823
|
params.actions,
|
|
@@ -24823,7 +25832,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24823
25832
|
);
|
|
24824
25833
|
return result.delegation;
|
|
24825
25834
|
} catch (err) {
|
|
24826
|
-
if (err instanceof
|
|
25835
|
+
if (err instanceof import_sdk_core9.PermissionNotInManifestError) {
|
|
24827
25836
|
} else {
|
|
24828
25837
|
throw err;
|
|
24829
25838
|
}
|
|
@@ -24880,7 +25889,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24880
25889
|
...prepared,
|
|
24881
25890
|
signature: signature2
|
|
24882
25891
|
});
|
|
24883
|
-
const activateResult = await (0,
|
|
25892
|
+
const activateResult = await (0, import_sdk_core9.activateSessionWithHost)(
|
|
24884
25893
|
this.config.host,
|
|
24885
25894
|
delegationSession.delegationHeader
|
|
24886
25895
|
);
|
|
@@ -24905,12 +25914,12 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24905
25914
|
};
|
|
24906
25915
|
const hasKvActions = params.actions.some((a) => a.startsWith("tinycloud.kv/"));
|
|
24907
25916
|
if (hasKvActions && params.includePublicSpace !== false) {
|
|
24908
|
-
const publicSpaceId = (0,
|
|
25917
|
+
const publicSpaceId = (0, import_sdk_core9.makePublicSpaceId)(
|
|
24909
25918
|
this.wasmBindings.ensureEip55(session.address),
|
|
24910
25919
|
session.chainId
|
|
24911
25920
|
);
|
|
24912
25921
|
const publicAbilities = {
|
|
24913
|
-
kv: { "": [
|
|
25922
|
+
kv: { "": [import_sdk_core9.KV.GET, import_sdk_core9.KV.PUT, import_sdk_core9.KV.METADATA] }
|
|
24914
25923
|
};
|
|
24915
25924
|
const publicPrepared = this.wasmBindings.prepareSession({
|
|
24916
25925
|
abilities: publicAbilities,
|
|
@@ -24928,7 +25937,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24928
25937
|
...publicPrepared,
|
|
24929
25938
|
signature: publicSignature
|
|
24930
25939
|
});
|
|
24931
|
-
const publicActivateResult = await (0,
|
|
25940
|
+
const publicActivateResult = await (0, import_sdk_core9.activateSessionWithHost)(
|
|
24932
25941
|
this.config.host,
|
|
24933
25942
|
publicSession.delegationHeader
|
|
24934
25943
|
);
|
|
@@ -24938,7 +25947,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24938
25947
|
delegationHeader: publicSession.delegationHeader,
|
|
24939
25948
|
spaceId: publicSpaceId,
|
|
24940
25949
|
path: "",
|
|
24941
|
-
actions: [
|
|
25950
|
+
actions: [import_sdk_core9.KV.GET, import_sdk_core9.KV.PUT, import_sdk_core9.KV.METADATA],
|
|
24942
25951
|
disableSubDelegation: params.disableSubDelegation ?? false,
|
|
24943
25952
|
expiry: expirationTime,
|
|
24944
25953
|
delegateDID: params.delegateDID,
|
|
@@ -25033,7 +26042,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
25033
26042
|
...prepared,
|
|
25034
26043
|
signature: signature2
|
|
25035
26044
|
});
|
|
25036
|
-
const activateResult = await (0,
|
|
26045
|
+
const activateResult = await (0, import_sdk_core9.activateSessionWithHost)(
|
|
25037
26046
|
targetHost,
|
|
25038
26047
|
invokerSession.delegationHeader
|
|
25039
26048
|
);
|
|
@@ -25153,7 +26162,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
25153
26162
|
...prepared,
|
|
25154
26163
|
signature: signature2
|
|
25155
26164
|
});
|
|
25156
|
-
const activateResult = await (0,
|
|
26165
|
+
const activateResult = await (0, import_sdk_core9.activateSessionWithHost)(
|
|
25157
26166
|
targetHost,
|
|
25158
26167
|
subDelegationSession.delegationHeader
|
|
25159
26168
|
);
|
|
@@ -25203,12 +26212,18 @@ TinyCloudNode.registerNodeDefaults({
|
|
|
25203
26212
|
createSigner: (privateKey, chainId) => new PrivateKeySigner(privateKey, chainId)
|
|
25204
26213
|
});
|
|
25205
26214
|
|
|
26215
|
+
// src/replication/node-loader.ts
|
|
26216
|
+
registerReplicationLoaders({
|
|
26217
|
+
runtime: () => Promise.resolve().then(() => (init_runtime(), runtime_exports)),
|
|
26218
|
+
authority: () => Promise.resolve().then(() => (init_authority(), authority_exports))
|
|
26219
|
+
});
|
|
26220
|
+
|
|
25206
26221
|
// src/index.ts
|
|
25207
|
-
var
|
|
25208
|
-
var
|
|
26222
|
+
var import_sdk_core14 = require("@tinycloud/sdk-core");
|
|
26223
|
+
var import_sdk_core15 = require("@tinycloud/sdk-core");
|
|
25209
26224
|
|
|
25210
26225
|
// src/storage/FileSessionStorage.ts
|
|
25211
|
-
var
|
|
26226
|
+
var import_sdk_core12 = require("@tinycloud/sdk-core");
|
|
25212
26227
|
var import_fs = require("fs");
|
|
25213
26228
|
var import_path = require("path");
|
|
25214
26229
|
var FileSessionStorage = class {
|
|
@@ -25263,7 +26278,7 @@ var FileSessionStorage = class {
|
|
|
25263
26278
|
try {
|
|
25264
26279
|
const data = (0, import_fs.readFileSync)(filePath, "utf-8");
|
|
25265
26280
|
const parsed = JSON.parse(data);
|
|
25266
|
-
const validation = (0,
|
|
26281
|
+
const validation = (0, import_sdk_core12.validatePersistedSessionData)(parsed);
|
|
25267
26282
|
if (!validation.ok) {
|
|
25268
26283
|
console.warn(`Invalid session data for ${address}:`, validation.error.message);
|
|
25269
26284
|
(0, import_fs.unlinkSync)(filePath);
|
|
@@ -25372,10 +26387,6 @@ function wireOpenKeyAuthorize(openkey) {
|
|
|
25372
26387
|
}
|
|
25373
26388
|
|
|
25374
26389
|
// src/index.ts
|
|
25375
|
-
var import_sdk_core12 = require("@tinycloud/sdk-core");
|
|
25376
|
-
var import_sdk_core13 = require("@tinycloud/sdk-core");
|
|
25377
|
-
var import_sdk_core14 = require("@tinycloud/sdk-core");
|
|
25378
|
-
var import_sdk_core15 = require("@tinycloud/sdk-core");
|
|
25379
26390
|
var import_sdk_core16 = require("@tinycloud/sdk-core");
|
|
25380
26391
|
var import_sdk_core17 = require("@tinycloud/sdk-core");
|
|
25381
26392
|
var import_sdk_core18 = require("@tinycloud/sdk-core");
|
|
@@ -25384,6 +26395,848 @@ var import_sdk_core20 = require("@tinycloud/sdk-core");
|
|
|
25384
26395
|
var import_sdk_core21 = require("@tinycloud/sdk-core");
|
|
25385
26396
|
var import_sdk_core22 = require("@tinycloud/sdk-core");
|
|
25386
26397
|
var import_sdk_core23 = require("@tinycloud/sdk-core");
|
|
26398
|
+
var import_sdk_core24 = require("@tinycloud/sdk-core");
|
|
26399
|
+
var import_sdk_core25 = require("@tinycloud/sdk-core");
|
|
26400
|
+
var import_sdk_core26 = require("@tinycloud/sdk-core");
|
|
26401
|
+
var import_sdk_core27 = require("@tinycloud/sdk-core");
|
|
26402
|
+
|
|
26403
|
+
// src/replication/sqlite.ts
|
|
26404
|
+
var import_node_crypto2 = require("crypto");
|
|
26405
|
+
var import_promises = require("fs/promises");
|
|
26406
|
+
var import_node_path = require("path");
|
|
26407
|
+
var import_sdk_core13 = require("@tinycloud/sdk-core");
|
|
26408
|
+
var import_sdk_services4 = require("@tinycloud/sdk-services");
|
|
26409
|
+
init_authority();
|
|
26410
|
+
var ReplicaStorageError = class extends Error {
|
|
26411
|
+
constructor(code, message, options) {
|
|
26412
|
+
super(message);
|
|
26413
|
+
this.name = "ReplicaStorageError";
|
|
26414
|
+
this.code = code;
|
|
26415
|
+
this.cause = options?.cause;
|
|
26416
|
+
}
|
|
26417
|
+
};
|
|
26418
|
+
function storageError(code, action, error) {
|
|
26419
|
+
if (error instanceof ReplicaStorageError) return error;
|
|
26420
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
26421
|
+
return new ReplicaStorageError(code, `${action} failed: ${detail}`, { cause: error });
|
|
26422
|
+
}
|
|
26423
|
+
function isNotFound(error) {
|
|
26424
|
+
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
26425
|
+
}
|
|
26426
|
+
async function pathExists(path) {
|
|
26427
|
+
try {
|
|
26428
|
+
await (0, import_promises.stat)(path);
|
|
26429
|
+
return true;
|
|
26430
|
+
} catch (error) {
|
|
26431
|
+
if (isNotFound(error)) return false;
|
|
26432
|
+
throw storageError("STORAGE_ERROR", `Reading ${path}`, error);
|
|
26433
|
+
}
|
|
26434
|
+
}
|
|
26435
|
+
function principalOf(did) {
|
|
26436
|
+
return (0, import_sdk_core13.principalDid)(did);
|
|
26437
|
+
}
|
|
26438
|
+
var BASE32 = "abcdefghijklmnopqrstuvwxyz234567";
|
|
26439
|
+
function sha256Base32(material) {
|
|
26440
|
+
const digest = (0, import_node_crypto2.createHash)("sha256").update(material, "utf8").digest();
|
|
26441
|
+
let out = "";
|
|
26442
|
+
let buffer = 0;
|
|
26443
|
+
let bits = 0;
|
|
26444
|
+
for (const byte of digest) {
|
|
26445
|
+
buffer = buffer << 8 | byte;
|
|
26446
|
+
bits += 8;
|
|
26447
|
+
while (bits >= 5) {
|
|
26448
|
+
out += BASE32[buffer >>> bits - 5 & 31];
|
|
26449
|
+
bits -= 5;
|
|
26450
|
+
}
|
|
26451
|
+
}
|
|
26452
|
+
if (bits > 0) out += BASE32[buffer << 5 - bits & 31];
|
|
26453
|
+
return out.slice(0, 26);
|
|
26454
|
+
}
|
|
26455
|
+
function partitionDirOf(root, identity) {
|
|
26456
|
+
return (0, import_node_path.join)(root, sha256Base32((0, import_sdk_services4.replicationIdentityKey)(identity)));
|
|
26457
|
+
}
|
|
26458
|
+
function replicaHashOf(prefix, deviceDid) {
|
|
26459
|
+
return sha256Base32(`${prefix}
|
|
26460
|
+
${principalOf(deviceDid)}`);
|
|
26461
|
+
}
|
|
26462
|
+
async function writeJsonAtomic(path, value, dirSync = fsyncDir) {
|
|
26463
|
+
const tmp = `${path}.${(0, import_node_crypto2.randomBytes)(6).toString("hex")}.tmp`;
|
|
26464
|
+
let handle;
|
|
26465
|
+
try {
|
|
26466
|
+
handle = await (0, import_promises.open)(tmp, "w", 384);
|
|
26467
|
+
await handle.writeFile(JSON.stringify(value), "utf8");
|
|
26468
|
+
await handle.sync();
|
|
26469
|
+
await handle.close();
|
|
26470
|
+
await (0, import_promises.rename)(tmp, path);
|
|
26471
|
+
await dirSync((0, import_node_path.dirname)(path));
|
|
26472
|
+
await (0, import_promises.chmod)(path, 384).catch(() => void 0);
|
|
26473
|
+
} catch (error) {
|
|
26474
|
+
try {
|
|
26475
|
+
await handle?.close();
|
|
26476
|
+
} catch {
|
|
26477
|
+
}
|
|
26478
|
+
await (0, import_promises.rm)(tmp, { force: true }).catch(() => void 0);
|
|
26479
|
+
throw storageError("STORAGE_ERROR", `Writing ${path}`, error);
|
|
26480
|
+
}
|
|
26481
|
+
}
|
|
26482
|
+
var DIR_SYNC_UNSUPPORTED = {
|
|
26483
|
+
ENOTSUP: true,
|
|
26484
|
+
ENOSYS: true,
|
|
26485
|
+
EINVAL: true,
|
|
26486
|
+
EISDIR: true,
|
|
26487
|
+
EPERM: true
|
|
26488
|
+
};
|
|
26489
|
+
async function fsyncDir(dir) {
|
|
26490
|
+
let handle;
|
|
26491
|
+
try {
|
|
26492
|
+
handle = await (0, import_promises.open)(dir, "r");
|
|
26493
|
+
await handle.sync();
|
|
26494
|
+
} catch (error) {
|
|
26495
|
+
const code = typeof error === "object" && error !== null && "code" in error ? error.code : void 0;
|
|
26496
|
+
if (typeof code === "string" && DIR_SYNC_UNSUPPORTED[code] === true) return;
|
|
26497
|
+
throw storageError("STORAGE_ERROR", `Syncing ${dir}`, error);
|
|
26498
|
+
} finally {
|
|
26499
|
+
await handle?.close().catch(() => void 0);
|
|
26500
|
+
}
|
|
26501
|
+
}
|
|
26502
|
+
async function readJsonFile(path) {
|
|
26503
|
+
try {
|
|
26504
|
+
return JSON.parse(await (0, import_promises.readFile)(path, "utf8"));
|
|
26505
|
+
} catch (error) {
|
|
26506
|
+
if (isNotFound(error)) return void 0;
|
|
26507
|
+
throw storageError("STORAGE_ERROR", `Reading ${path}`, error);
|
|
26508
|
+
}
|
|
26509
|
+
}
|
|
26510
|
+
function identityRecordOf(value) {
|
|
26511
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
26512
|
+
return void 0;
|
|
26513
|
+
}
|
|
26514
|
+
if (!("host" in value) || !("space" in value) || !("principal" in value) || typeof value.host !== "string" || typeof value.space !== "string" || typeof value.principal !== "string") {
|
|
26515
|
+
return void 0;
|
|
26516
|
+
}
|
|
26517
|
+
return { host: value.host, space: value.space, principal: value.principal };
|
|
26518
|
+
}
|
|
26519
|
+
function deviceRecordOf(value) {
|
|
26520
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
26521
|
+
return void 0;
|
|
26522
|
+
}
|
|
26523
|
+
if (!("did" in value) || !("jwk" in value) || typeof value.did !== "string" || value.jwk === null || typeof value.jwk !== "object") {
|
|
26524
|
+
return void 0;
|
|
26525
|
+
}
|
|
26526
|
+
return { did: value.did, jwk: value.jwk };
|
|
26527
|
+
}
|
|
26528
|
+
function sameIdentity(a, b) {
|
|
26529
|
+
try {
|
|
26530
|
+
const left = (0, import_sdk_services4.canonicalReplicationIdentity)(a);
|
|
26531
|
+
const right = (0, import_sdk_services4.canonicalReplicationIdentity)(b);
|
|
26532
|
+
return left.host === right.host && left.space === right.space && left.principal === right.principal;
|
|
26533
|
+
} catch {
|
|
26534
|
+
return false;
|
|
26535
|
+
}
|
|
26536
|
+
}
|
|
26537
|
+
async function ensurePartitionIdentity(dir, identity, dirSync) {
|
|
26538
|
+
try {
|
|
26539
|
+
await (0, import_promises.mkdir)(dir, { recursive: true, mode: 448 });
|
|
26540
|
+
await (0, import_promises.chmod)(dir, 448);
|
|
26541
|
+
} catch (error) {
|
|
26542
|
+
throw storageError("STORAGE_ERROR", `Creating ${dir}`, error);
|
|
26543
|
+
}
|
|
26544
|
+
const file = (0, import_node_path.join)(dir, "identity.json");
|
|
26545
|
+
const existing = await readJsonFile(file);
|
|
26546
|
+
if (existing === void 0) {
|
|
26547
|
+
await writeJsonAtomic(file, { v: 1, ...(0, import_sdk_services4.canonicalReplicationIdentity)(identity) }, dirSync);
|
|
26548
|
+
return;
|
|
26549
|
+
}
|
|
26550
|
+
const record = identityRecordOf(existing);
|
|
26551
|
+
if (record === void 0 || !sameIdentity(record, identity)) {
|
|
26552
|
+
throw new ReplicaStorageError(
|
|
26553
|
+
"STORAGE_ERROR",
|
|
26554
|
+
`The partition at ${dir} belongs to a different identity.`
|
|
26555
|
+
);
|
|
26556
|
+
}
|
|
26557
|
+
}
|
|
26558
|
+
var PENDING_WRITE_LOCKS = /* @__PURE__ */ new Map();
|
|
26559
|
+
function serializePendingWrite(file, section) {
|
|
26560
|
+
const tail = PENDING_WRITE_LOCKS.get(file) ?? Promise.resolve();
|
|
26561
|
+
const entered = tail.then(section);
|
|
26562
|
+
const next = entered.then(
|
|
26563
|
+
() => void 0,
|
|
26564
|
+
() => void 0
|
|
26565
|
+
);
|
|
26566
|
+
PENDING_WRITE_LOCKS.set(file, next);
|
|
26567
|
+
void next.then(() => {
|
|
26568
|
+
if (PENDING_WRITE_LOCKS.get(file) === next) PENDING_WRITE_LOCKS.delete(file);
|
|
26569
|
+
});
|
|
26570
|
+
return entered;
|
|
26571
|
+
}
|
|
26572
|
+
function parsePendingState(text, file, identity) {
|
|
26573
|
+
let state;
|
|
26574
|
+
try {
|
|
26575
|
+
state = JSON.parse(text);
|
|
26576
|
+
} catch (error) {
|
|
26577
|
+
throw storageError("STORAGE_ERROR", `Parsing ${file}`, error);
|
|
26578
|
+
}
|
|
26579
|
+
if (state === null || typeof state !== "object" || !("v" in state) || state.v !== 2 || !("identity" in state) || !("committedEpoch" in state) || typeof state.committedEpoch !== "number" || !("seq" in state) || typeof state.seq !== "number" || !("records" in state) || !Array.isArray(state.records)) {
|
|
26580
|
+
throw new ReplicaStorageError("STORAGE_ERROR", `Pending-write state at ${file} is corrupt.`);
|
|
26581
|
+
}
|
|
26582
|
+
const storedIdentity = identityRecordOf(state.identity);
|
|
26583
|
+
if (storedIdentity === void 0 || !sameIdentity(storedIdentity, identity)) {
|
|
26584
|
+
throw new ReplicaStorageError("STORAGE_ERROR", `Pending-write state at ${file} belongs to a different identity.`);
|
|
26585
|
+
}
|
|
26586
|
+
return state;
|
|
26587
|
+
}
|
|
26588
|
+
var _dir, _guard, _dirSync, _file, _FilePendingWriteStore_instances, canonicalFile_fn;
|
|
26589
|
+
var FilePendingWriteStore = class {
|
|
26590
|
+
constructor(identity, dir, guard, dirSync) {
|
|
26591
|
+
__privateAdd(this, _FilePendingWriteStore_instances);
|
|
26592
|
+
this.durable = true;
|
|
26593
|
+
__privateAdd(this, _dir);
|
|
26594
|
+
__privateAdd(this, _guard);
|
|
26595
|
+
__privateAdd(this, _dirSync);
|
|
26596
|
+
__privateAdd(this, _file);
|
|
26597
|
+
this.identity = identity;
|
|
26598
|
+
__privateSet(this, _dir, dir);
|
|
26599
|
+
__privateSet(this, _guard, guard);
|
|
26600
|
+
__privateSet(this, _dirSync, dirSync);
|
|
26601
|
+
}
|
|
26602
|
+
async read() {
|
|
26603
|
+
const file = await __privateMethod(this, _FilePendingWriteStore_instances, canonicalFile_fn).call(this);
|
|
26604
|
+
let text;
|
|
26605
|
+
try {
|
|
26606
|
+
text = await (0, import_promises.readFile)(file, "utf8");
|
|
26607
|
+
} catch (error) {
|
|
26608
|
+
if (isNotFound(error)) {
|
|
26609
|
+
return { v: 2, identity: this.identity, committedEpoch: 0, seq: 0, records: [] };
|
|
26610
|
+
}
|
|
26611
|
+
throw storageError("STORAGE_ERROR", `Reading ${file}`, error);
|
|
26612
|
+
}
|
|
26613
|
+
return parsePendingState(text, file, this.identity);
|
|
26614
|
+
}
|
|
26615
|
+
async readExisting() {
|
|
26616
|
+
let file;
|
|
26617
|
+
try {
|
|
26618
|
+
file = (0, import_node_path.join)(await (0, import_promises.realpath)(__privateGet(this, _dir)), "pending.json");
|
|
26619
|
+
} catch (error) {
|
|
26620
|
+
if (isNotFound(error)) return void 0;
|
|
26621
|
+
throw storageError("STORAGE_ERROR", `Resolving pending-write state in ${__privateGet(this, _dir)}`, error);
|
|
26622
|
+
}
|
|
26623
|
+
try {
|
|
26624
|
+
const text = await (0, import_promises.readFile)(file, "utf8");
|
|
26625
|
+
return parsePendingState(text, file, this.identity);
|
|
26626
|
+
} catch (error) {
|
|
26627
|
+
if (isNotFound(error)) return void 0;
|
|
26628
|
+
if (error instanceof ReplicaStorageError) throw error;
|
|
26629
|
+
throw storageError("STORAGE_ERROR", `Reading ${file}`, error);
|
|
26630
|
+
}
|
|
26631
|
+
}
|
|
26632
|
+
async update(mutate) {
|
|
26633
|
+
const file = await __privateMethod(this, _FilePendingWriteStore_instances, canonicalFile_fn).call(this);
|
|
26634
|
+
return serializePendingWrite(file, async () => {
|
|
26635
|
+
let currentFile;
|
|
26636
|
+
try {
|
|
26637
|
+
currentFile = (0, import_node_path.join)(await (0, import_promises.realpath)((0, import_node_path.dirname)(file)), (0, import_node_path.basename)(file));
|
|
26638
|
+
} catch (error) {
|
|
26639
|
+
throw storageError("STORAGE_ERROR", "Resolving the open pending-write partition", error);
|
|
26640
|
+
}
|
|
26641
|
+
if (currentFile !== file) {
|
|
26642
|
+
throw new ReplicaStorageError(
|
|
26643
|
+
"STORAGE_ERROR",
|
|
26644
|
+
`The pending-write partition changed while open: ${(0, import_node_path.dirname)(file)}.`
|
|
26645
|
+
);
|
|
26646
|
+
}
|
|
26647
|
+
return __privateGet(this, _guard).call(this, async () => {
|
|
26648
|
+
const state = await this.read();
|
|
26649
|
+
const result = mutate(state);
|
|
26650
|
+
await writeJsonAtomic(file, state, __privateGet(this, _dirSync));
|
|
26651
|
+
return result;
|
|
26652
|
+
});
|
|
26653
|
+
});
|
|
26654
|
+
}
|
|
26655
|
+
};
|
|
26656
|
+
_dir = new WeakMap();
|
|
26657
|
+
_guard = new WeakMap();
|
|
26658
|
+
_dirSync = new WeakMap();
|
|
26659
|
+
_file = new WeakMap();
|
|
26660
|
+
_FilePendingWriteStore_instances = new WeakSet();
|
|
26661
|
+
canonicalFile_fn = async function() {
|
|
26662
|
+
__privateGet(this, _file) ?? __privateSet(this, _file, (async () => {
|
|
26663
|
+
await ensurePartitionIdentity(__privateGet(this, _dir), this.identity, __privateGet(this, _dirSync));
|
|
26664
|
+
const file = (0, import_node_path.join)(__privateGet(this, _dir), "pending.json");
|
|
26665
|
+
try {
|
|
26666
|
+
return (0, import_node_path.join)(await (0, import_promises.realpath)((0, import_node_path.dirname)(file)), (0, import_node_path.basename)(file));
|
|
26667
|
+
} catch (error) {
|
|
26668
|
+
throw storageError("STORAGE_ERROR", `Resolving ${file}`, error);
|
|
26669
|
+
}
|
|
26670
|
+
})());
|
|
26671
|
+
return __privateGet(this, _file);
|
|
26672
|
+
};
|
|
26673
|
+
async function loadOrCreateDevice(idDir, guard, createDevice, dirSync) {
|
|
26674
|
+
return guard(async () => {
|
|
26675
|
+
try {
|
|
26676
|
+
await (0, import_promises.mkdir)(idDir, { recursive: true, mode: 448 });
|
|
26677
|
+
await (0, import_promises.chmod)(idDir, 448);
|
|
26678
|
+
} catch (error) {
|
|
26679
|
+
throw storageError("STORAGE_ERROR", `Creating ${idDir}`, error);
|
|
26680
|
+
}
|
|
26681
|
+
const file = (0, import_node_path.join)(idDir, "device.jwk");
|
|
26682
|
+
const existing = await readJsonFile(file);
|
|
26683
|
+
if (existing !== void 0) {
|
|
26684
|
+
const device2 = deviceRecordOf(existing);
|
|
26685
|
+
if (device2 === void 0) {
|
|
26686
|
+
throw new ReplicaStorageError(
|
|
26687
|
+
"STORAGE_ERROR",
|
|
26688
|
+
`The replica device key at ${file} is unreadable; remove the partition or restore it.`
|
|
26689
|
+
);
|
|
26690
|
+
}
|
|
26691
|
+
return device2;
|
|
26692
|
+
}
|
|
26693
|
+
const device = await createDevice();
|
|
26694
|
+
await writeJsonAtomic(file, { did: device.did, jwk: device.jwk }, dirSync);
|
|
26695
|
+
return device;
|
|
26696
|
+
});
|
|
26697
|
+
}
|
|
26698
|
+
async function createDeviceKey() {
|
|
26699
|
+
const wasm = await import("@tinycloud/node-sdk-wasm");
|
|
26700
|
+
const manager = new wasm.TCWSessionManager();
|
|
26701
|
+
const keyId = manager.createSessionKey("replica-device") ?? "replica-device";
|
|
26702
|
+
const jwkText = manager.jwk(keyId);
|
|
26703
|
+
if (jwkText === null || jwkText === void 0) {
|
|
26704
|
+
throw new ReplicaStorageError(
|
|
26705
|
+
"STORAGE_ERROR",
|
|
26706
|
+
"The session manager returned no JWK for the replica device key."
|
|
26707
|
+
);
|
|
26708
|
+
}
|
|
26709
|
+
return { did: manager.getDID(keyId), jwk: JSON.parse(jwkText) };
|
|
26710
|
+
}
|
|
26711
|
+
var SYNC_LEASE_TTL_MS = 12e4;
|
|
26712
|
+
var FENCE_FILE = "fence.json";
|
|
26713
|
+
async function readFence(replicaDir) {
|
|
26714
|
+
const fence = await readJsonFile((0, import_node_path.join)(replicaDir, FENCE_FILE));
|
|
26715
|
+
return typeof fence === "object" && fence !== null && "syncedThroughEpoch" in fence && typeof fence.syncedThroughEpoch === "number" ? fence.syncedThroughEpoch : 0;
|
|
26716
|
+
}
|
|
26717
|
+
function newestGrantInfo(replica, record, pending, spec) {
|
|
26718
|
+
if (record === null) return null;
|
|
26719
|
+
const parsed = replica.parseUcanGrant(record.bytes);
|
|
26720
|
+
return {
|
|
26721
|
+
cid: record.cid,
|
|
26722
|
+
parentCid: parsed.prf[0] ?? null,
|
|
26723
|
+
expiresAt: record.expiresAt === null ? null : record.expiresAt * 1e3,
|
|
26724
|
+
state: pending !== null && record === pending ? "pending" : "active",
|
|
26725
|
+
unconstrained: ucanAttUnconstrainedFor(parsed.att, spec.space, spec.prefix)
|
|
26726
|
+
};
|
|
26727
|
+
}
|
|
26728
|
+
var _device, _store, _replicaDir, _replica, _guard2, _dirSync2, _generation, _ino, _transportOverride, _closed, _inFlight, _transportFactory, _SqliteReplicaHandle_instances, assertOpen_fn, assertLive_fn, transports_fn;
|
|
26729
|
+
var SqliteReplicaHandle = class {
|
|
26730
|
+
constructor(input) {
|
|
26731
|
+
__privateAdd(this, _SqliteReplicaHandle_instances);
|
|
26732
|
+
__privateAdd(this, _device);
|
|
26733
|
+
__privateAdd(this, _store);
|
|
26734
|
+
__privateAdd(this, _replicaDir);
|
|
26735
|
+
__privateAdd(this, _replica);
|
|
26736
|
+
__privateAdd(this, _guard2);
|
|
26737
|
+
__privateAdd(this, _dirSync2);
|
|
26738
|
+
/** The replica row generation this handle opened under — the durable fence a purge commits past (browser-parity wipe). */
|
|
26739
|
+
__privateAdd(this, _generation);
|
|
26740
|
+
/** The inode of `replica.db` at open — a directory recreated in place is a different replica. */
|
|
26741
|
+
__privateAdd(this, _ino);
|
|
26742
|
+
__privateAdd(this, _transportOverride);
|
|
26743
|
+
__privateAdd(this, _closed, false);
|
|
26744
|
+
__privateAdd(this, _inFlight, /* @__PURE__ */ new Set());
|
|
26745
|
+
__privateAdd(this, _transportFactory);
|
|
26746
|
+
this.spec = input.spec;
|
|
26747
|
+
__privateSet(this, _device, input.device);
|
|
26748
|
+
this.deviceDid = input.device.did;
|
|
26749
|
+
__privateSet(this, _store, input.store);
|
|
26750
|
+
__privateSet(this, _replicaDir, input.replicaDir);
|
|
26751
|
+
__privateSet(this, _replica, input.replica);
|
|
26752
|
+
__privateSet(this, _guard2, input.guard);
|
|
26753
|
+
__privateSet(this, _transportOverride, input.transportFor);
|
|
26754
|
+
__privateSet(this, _dirSync2, input.dirSync);
|
|
26755
|
+
__privateSet(this, _generation, input.generation);
|
|
26756
|
+
__privateSet(this, _ino, input.ino);
|
|
26757
|
+
}
|
|
26758
|
+
async get(key2) {
|
|
26759
|
+
await __privateMethod(this, _SqliteReplicaHandle_instances, assertLive_fn).call(this);
|
|
26760
|
+
const result = await new (__privateGet(this, _replica)).Replica({ store: __privateGet(this, _store) }).get(key2);
|
|
26761
|
+
const meta = {
|
|
26762
|
+
asOf: result.meta.asOf,
|
|
26763
|
+
coverage: result.meta.coverage,
|
|
26764
|
+
authority: result.meta.authority,
|
|
26765
|
+
syncedThroughEpoch: await readFence(__privateGet(this, _replicaDir))
|
|
26766
|
+
};
|
|
26767
|
+
switch (result.status) {
|
|
26768
|
+
case "present":
|
|
26769
|
+
return {
|
|
26770
|
+
status: "present",
|
|
26771
|
+
key: result.key,
|
|
26772
|
+
value: result.value,
|
|
26773
|
+
etag: result.etag,
|
|
26774
|
+
metadata: result.metadata,
|
|
26775
|
+
meta
|
|
26776
|
+
};
|
|
26777
|
+
case "content_missing":
|
|
26778
|
+
return {
|
|
26779
|
+
status: "content_missing",
|
|
26780
|
+
key: result.key,
|
|
26781
|
+
etag: result.etag,
|
|
26782
|
+
metadata: result.metadata,
|
|
26783
|
+
meta
|
|
26784
|
+
};
|
|
26785
|
+
default:
|
|
26786
|
+
return { status: result.status, key: result.key, meta };
|
|
26787
|
+
}
|
|
26788
|
+
}
|
|
26789
|
+
async list(options) {
|
|
26790
|
+
await __privateMethod(this, _SqliteReplicaHandle_instances, assertLive_fn).call(this);
|
|
26791
|
+
const result = await new (__privateGet(this, _replica)).Replica({ store: __privateGet(this, _store) }).list({
|
|
26792
|
+
prefix: options.prefix,
|
|
26793
|
+
...options.after === void 0 ? {} : { after: options.after },
|
|
26794
|
+
...options.limit === void 0 ? {} : { limit: options.limit }
|
|
26795
|
+
});
|
|
26796
|
+
return {
|
|
26797
|
+
keys: result.entries.map((entry) => entry.key),
|
|
26798
|
+
meta: {
|
|
26799
|
+
asOf: result.meta.asOf,
|
|
26800
|
+
coverage: result.meta.coverage,
|
|
26801
|
+
authority: result.meta.authority,
|
|
26802
|
+
syncedThroughEpoch: await readFence(__privateGet(this, _replicaDir))
|
|
26803
|
+
}
|
|
26804
|
+
};
|
|
26805
|
+
}
|
|
26806
|
+
/**
|
|
26807
|
+
* The newest installed grant — the pending one when a not-yet-promoted
|
|
26808
|
+
* install exists — with `parentCid` = signed `prf[0]` and `unconstrained`
|
|
26809
|
+
* computed from the signed `att` (replica's own grantCovers ignores
|
|
26810
|
+
* caveats, so the adapter computes it, §2.1). A constrained installed
|
|
26811
|
+
* grant is still reported (unconstrained: false) and never reused.
|
|
26812
|
+
*/
|
|
26813
|
+
async grant() {
|
|
26814
|
+
await __privateMethod(this, _SqliteReplicaHandle_instances, assertLive_fn).call(this);
|
|
26815
|
+
const state = await __privateGet(this, _store).open();
|
|
26816
|
+
if (state === null) return null;
|
|
26817
|
+
return newestGrantInfo(
|
|
26818
|
+
__privateGet(this, _replica),
|
|
26819
|
+
state.pendingGrant ?? state.grant,
|
|
26820
|
+
state.pendingGrant,
|
|
26821
|
+
this.spec
|
|
26822
|
+
);
|
|
26823
|
+
}
|
|
26824
|
+
async installGrant(ucan) {
|
|
26825
|
+
await __privateMethod(this, _SqliteReplicaHandle_instances, assertLive_fn).call(this);
|
|
26826
|
+
const parsed = __privateGet(this, _replica).parseUcanGrant(ucan);
|
|
26827
|
+
const state = await __privateGet(this, _store).open();
|
|
26828
|
+
if (state === null) {
|
|
26829
|
+
throw new (__privateGet(this, _replica)).ReplicaError(
|
|
26830
|
+
__privateGet(this, _replica).ReplicaErrorCode.NOT_FOUND,
|
|
26831
|
+
"The replica has not been created."
|
|
26832
|
+
);
|
|
26833
|
+
}
|
|
26834
|
+
__privateGet(this, _replica).assertGrantInstallable(parsed, {
|
|
26835
|
+
deviceDid: principalOf(__privateGet(this, _device).did),
|
|
26836
|
+
space: this.spec.space,
|
|
26837
|
+
prefix: this.spec.prefix,
|
|
26838
|
+
now: Date.now()
|
|
26839
|
+
});
|
|
26840
|
+
if (!ucanAttUnconstrainedFor(parsed.att, this.spec.space, this.spec.prefix)) {
|
|
26841
|
+
throw new (__privateGet(this, _replica)).ReplicaError(
|
|
26842
|
+
__privateGet(this, _replica).ReplicaErrorCode.GRANT_NOT_COVERING,
|
|
26843
|
+
"The grant's get or sync coverage carries caveats; re-mint instead of installing it."
|
|
26844
|
+
);
|
|
26845
|
+
}
|
|
26846
|
+
await __privateGet(this, _store).installGrant(parsed);
|
|
26847
|
+
return newestGrantInfo(__privateGet(this, _replica), parsed, parsed, this.spec);
|
|
26848
|
+
}
|
|
26849
|
+
async sync(options) {
|
|
26850
|
+
await __privateMethod(this, _SqliteReplicaHandle_instances, assertLive_fn).call(this);
|
|
26851
|
+
const transportFor = await __privateMethod(this, _SqliteReplicaHandle_instances, transports_fn).call(this);
|
|
26852
|
+
const abort = new AbortController();
|
|
26853
|
+
options.signal.throwIfAborted();
|
|
26854
|
+
const onAbort = () => abort.abort(options.signal.reason);
|
|
26855
|
+
options.signal.addEventListener("abort", onAbort, { once: true });
|
|
26856
|
+
const engine = new (__privateGet(this, _replica)).Replica({
|
|
26857
|
+
store: __privateGet(this, _store),
|
|
26858
|
+
transportFor
|
|
26859
|
+
});
|
|
26860
|
+
const running = engine.sync({ signal: abort.signal });
|
|
26861
|
+
const registration = { promise: running, abort: () => abort.abort() };
|
|
26862
|
+
__privateGet(this, _inFlight).add(registration);
|
|
26863
|
+
try {
|
|
26864
|
+
const report = await running;
|
|
26865
|
+
await __privateGet(this, _guard2).call(this, () => writeJsonAtomic(
|
|
26866
|
+
(0, import_node_path.join)(__privateGet(this, _replicaDir), FENCE_FILE),
|
|
26867
|
+
{ v: 1, syncedThroughEpoch: options.syncStartEpoch },
|
|
26868
|
+
__privateGet(this, _dirSync2)
|
|
26869
|
+
));
|
|
26870
|
+
return {
|
|
26871
|
+
status: "synced",
|
|
26872
|
+
pages: report.pages,
|
|
26873
|
+
changes: report.changes,
|
|
26874
|
+
deleted: report.deleted,
|
|
26875
|
+
fetched: report.fetched,
|
|
26876
|
+
contentMissing: report.contentMissing,
|
|
26877
|
+
coverage: report.coverage,
|
|
26878
|
+
syncedThroughEpoch: options.syncStartEpoch
|
|
26879
|
+
};
|
|
26880
|
+
} catch (error) {
|
|
26881
|
+
if (__privateGet(this, _replica).isReplicaError(error, __privateGet(this, _replica).ReplicaErrorCode.BUSY)) {
|
|
26882
|
+
return { status: "busy" };
|
|
26883
|
+
}
|
|
26884
|
+
throw error;
|
|
26885
|
+
} finally {
|
|
26886
|
+
__privateGet(this, _inFlight).delete(registration);
|
|
26887
|
+
options.signal.removeEventListener("abort", onAbort);
|
|
26888
|
+
}
|
|
26889
|
+
}
|
|
26890
|
+
async status() {
|
|
26891
|
+
await __privateMethod(this, _SqliteReplicaHandle_instances, assertLive_fn).call(this);
|
|
26892
|
+
const engine = new (__privateGet(this, _replica)).Replica({ store: __privateGet(this, _store) });
|
|
26893
|
+
const status = await engine.status();
|
|
26894
|
+
const syncedThroughEpoch = await readFence(__privateGet(this, _replicaDir));
|
|
26895
|
+
const state = await __privateGet(this, _store).open();
|
|
26896
|
+
const grant = state === null ? null : newestGrantInfo(
|
|
26897
|
+
__privateGet(this, _replica),
|
|
26898
|
+
state.pendingGrant ?? state.grant,
|
|
26899
|
+
state.pendingGrant,
|
|
26900
|
+
this.spec
|
|
26901
|
+
);
|
|
26902
|
+
return {
|
|
26903
|
+
coverage: status.coverage,
|
|
26904
|
+
lastSyncAt: status.lastSyncAt,
|
|
26905
|
+
syncedThroughEpoch,
|
|
26906
|
+
authority: { state: status.authority.state, expiresAt: status.authority.expiresAt },
|
|
26907
|
+
grant,
|
|
26908
|
+
counts: status.counts,
|
|
26909
|
+
bytes: status.bytes,
|
|
26910
|
+
lastError: status.lastError
|
|
26911
|
+
};
|
|
26912
|
+
}
|
|
26913
|
+
async close() {
|
|
26914
|
+
if (__privateGet(this, _closed)) return;
|
|
26915
|
+
__privateSet(this, _closed, true);
|
|
26916
|
+
for (const sync of __privateGet(this, _inFlight)) sync.abort();
|
|
26917
|
+
await Promise.allSettled([...__privateGet(this, _inFlight)].map((sync) => sync.promise));
|
|
26918
|
+
await __privateGet(this, _store).close();
|
|
26919
|
+
}
|
|
26920
|
+
};
|
|
26921
|
+
_device = new WeakMap();
|
|
26922
|
+
_store = new WeakMap();
|
|
26923
|
+
_replicaDir = new WeakMap();
|
|
26924
|
+
_replica = new WeakMap();
|
|
26925
|
+
_guard2 = new WeakMap();
|
|
26926
|
+
_dirSync2 = new WeakMap();
|
|
26927
|
+
_generation = new WeakMap();
|
|
26928
|
+
_ino = new WeakMap();
|
|
26929
|
+
_transportOverride = new WeakMap();
|
|
26930
|
+
_closed = new WeakMap();
|
|
26931
|
+
_inFlight = new WeakMap();
|
|
26932
|
+
_transportFactory = new WeakMap();
|
|
26933
|
+
_SqliteReplicaHandle_instances = new WeakSet();
|
|
26934
|
+
assertOpen_fn = function() {
|
|
26935
|
+
if (__privateGet(this, _closed)) {
|
|
26936
|
+
throw new (__privateGet(this, _replica)).ReplicaError(
|
|
26937
|
+
__privateGet(this, _replica).ReplicaErrorCode.CLOSED,
|
|
26938
|
+
"The replica handle is closed."
|
|
26939
|
+
);
|
|
26940
|
+
}
|
|
26941
|
+
};
|
|
26942
|
+
assertLive_fn = async function() {
|
|
26943
|
+
__privateMethod(this, _SqliteReplicaHandle_instances, assertOpen_fn).call(this);
|
|
26944
|
+
try {
|
|
26945
|
+
const stats = await (0, import_promises.stat)((0, import_node_path.join)(__privateGet(this, _replicaDir), "replica.db"));
|
|
26946
|
+
if (__privateGet(this, _ino) !== void 0 && stats.ino !== __privateGet(this, _ino)) {
|
|
26947
|
+
throw new (__privateGet(this, _replica)).ReplicaError(
|
|
26948
|
+
__privateGet(this, _replica).ReplicaErrorCode.RESET_REQUIRED,
|
|
26949
|
+
"The replica was recreated; open it again to continue."
|
|
26950
|
+
);
|
|
26951
|
+
}
|
|
26952
|
+
} catch (error) {
|
|
26953
|
+
if (isNotFound(error)) {
|
|
26954
|
+
throw new (__privateGet(this, _replica)).ReplicaError(
|
|
26955
|
+
__privateGet(this, _replica).ReplicaErrorCode.RESET_REQUIRED,
|
|
26956
|
+
"The replica was purged; open it again to continue."
|
|
26957
|
+
);
|
|
26958
|
+
}
|
|
26959
|
+
throw error;
|
|
26960
|
+
}
|
|
26961
|
+
const state = await __privateGet(this, _store).open();
|
|
26962
|
+
if (state !== null && state.generation !== __privateGet(this, _generation)) {
|
|
26963
|
+
throw new (__privateGet(this, _replica)).ReplicaError(
|
|
26964
|
+
__privateGet(this, _replica).ReplicaErrorCode.RESET_REQUIRED,
|
|
26965
|
+
"The replica was purged or reopened; open it again to continue."
|
|
26966
|
+
);
|
|
26967
|
+
}
|
|
26968
|
+
};
|
|
26969
|
+
transports_fn = async function() {
|
|
26970
|
+
if (__privateGet(this, _transportOverride) !== void 0) {
|
|
26971
|
+
const override = __privateGet(this, _transportOverride);
|
|
26972
|
+
const spec = this.spec;
|
|
26973
|
+
const device = __privateGet(this, _device);
|
|
26974
|
+
return (grant) => override(grant, spec, device);
|
|
26975
|
+
}
|
|
26976
|
+
__privateGet(this, _transportFactory) ?? __privateSet(this, _transportFactory, (async () => {
|
|
26977
|
+
const wasm = await import("@tinycloud/node-sdk-wasm");
|
|
26978
|
+
const kvSyncTransport = __privateGet(this, _replica).kvSyncTransport;
|
|
26979
|
+
const spec = this.spec;
|
|
26980
|
+
const device = __privateGet(this, _device);
|
|
26981
|
+
const fetch2 = spec.fetch ?? globalThis.fetch.bind(globalThis);
|
|
26982
|
+
return (grant) => {
|
|
26983
|
+
const context = new import_sdk_core13.ServiceContext({
|
|
26984
|
+
invoke: wasm.invoke,
|
|
26985
|
+
invokeAny: wasm.invokeAny,
|
|
26986
|
+
fetch: fetch2,
|
|
26987
|
+
hosts: [spec.identity.host]
|
|
26988
|
+
});
|
|
26989
|
+
const kv = new import_sdk_core13.KVService({});
|
|
26990
|
+
kv.initialize(context);
|
|
26991
|
+
context.registerService("kv", kv);
|
|
26992
|
+
context.setSession({
|
|
26993
|
+
delegationHeader: { Authorization: new TextDecoder().decode(grant.bytes) },
|
|
26994
|
+
delegationCid: grant.cid,
|
|
26995
|
+
spaceId: spec.space,
|
|
26996
|
+
verificationMethod: device.did,
|
|
26997
|
+
jwk: device.jwk
|
|
26998
|
+
});
|
|
26999
|
+
return kvSyncTransport(kv);
|
|
27000
|
+
};
|
|
27001
|
+
})());
|
|
27002
|
+
return __privateGet(this, _transportFactory);
|
|
27003
|
+
};
|
|
27004
|
+
function createSqliteReplicaStorage(options) {
|
|
27005
|
+
const root = options.dir;
|
|
27006
|
+
const guard = options.guard ?? ((section) => section());
|
|
27007
|
+
const createDevice = options.createDevice ?? createDeviceKey;
|
|
27008
|
+
async function openHandle(spec) {
|
|
27009
|
+
const [replica, sqlite] = await Promise.all([
|
|
27010
|
+
// @ts-ignore — TS2307 when replica's dist is absent (CI builds node-sdk first).
|
|
27011
|
+
import("@tinycloud/replica"),
|
|
27012
|
+
// @ts-ignore — same as above.
|
|
27013
|
+
import("@tinycloud/replica/sqlite")
|
|
27014
|
+
]);
|
|
27015
|
+
if ((0, import_sdk_services4.requiresSecretsOptIn)(spec.space, spec.prefix) && spec.allowSecrets !== true) {
|
|
27016
|
+
throw new replica.ReplicaError(
|
|
27017
|
+
replica.ReplicaErrorCode.SECRETS_OPT_IN_REQUIRED,
|
|
27018
|
+
`Replicating ${spec.space}/kv/${spec.prefix} copies secret material to disk; pass allowSecrets to opt in.`
|
|
27019
|
+
);
|
|
27020
|
+
}
|
|
27021
|
+
const idDir = partitionDirOf(root, spec.identity);
|
|
27022
|
+
await ensurePartitionIdentity(idDir, spec.identity, options.dirSync);
|
|
27023
|
+
const createdDevice = spec.device ?? await loadOrCreateDevice(idDir, guard, createDevice, options.dirSync);
|
|
27024
|
+
const device = { ...createdDevice, did: principalOf(createdDevice.did) };
|
|
27025
|
+
const replicaHash = replicaHashOf(spec.prefix, device.did);
|
|
27026
|
+
const replicaDir = (0, import_node_path.join)(idDir, "replicas", replicaHash);
|
|
27027
|
+
const store = await sqlite.SqliteReplicaStore.open(replicaDir, {
|
|
27028
|
+
create: true,
|
|
27029
|
+
guard
|
|
27030
|
+
});
|
|
27031
|
+
let generation;
|
|
27032
|
+
try {
|
|
27033
|
+
try {
|
|
27034
|
+
await store.init({
|
|
27035
|
+
name: spec.prefix.replace(/\/+$/, "") || "replica",
|
|
27036
|
+
replicaId: replicaHash,
|
|
27037
|
+
host: spec.identity.host,
|
|
27038
|
+
space: spec.space,
|
|
27039
|
+
prefix: spec.prefix,
|
|
27040
|
+
deviceDid: device.did,
|
|
27041
|
+
allowSecrets: spec.allowSecrets,
|
|
27042
|
+
localReadPolicy: "whileGrantValid",
|
|
27043
|
+
retentionGrantCid: null
|
|
27044
|
+
});
|
|
27045
|
+
} catch (error) {
|
|
27046
|
+
if (!replica.isReplicaError(error, replica.ReplicaErrorCode.CONFIG_MISMATCH)) {
|
|
27047
|
+
throw error;
|
|
27048
|
+
}
|
|
27049
|
+
}
|
|
27050
|
+
const state = await store.open();
|
|
27051
|
+
if (state === null) {
|
|
27052
|
+
throw new replica.ReplicaError(
|
|
27053
|
+
replica.ReplicaErrorCode.NOT_FOUND,
|
|
27054
|
+
"The replica row vanished during init."
|
|
27055
|
+
);
|
|
27056
|
+
}
|
|
27057
|
+
const config = state.config;
|
|
27058
|
+
if (config.host !== spec.identity.host || config.space !== spec.space || config.prefix !== spec.prefix) {
|
|
27059
|
+
throw new replica.ReplicaError(
|
|
27060
|
+
replica.ReplicaErrorCode.CONFIG_MISMATCH,
|
|
27061
|
+
`This replica follows ${config.host} ${config.space}/kv/${config.prefix}, not ${spec.identity.host} ${spec.space}/kv/${spec.prefix}.`
|
|
27062
|
+
);
|
|
27063
|
+
}
|
|
27064
|
+
if (principalOf(config.deviceDid) !== principalOf(device.did)) {
|
|
27065
|
+
throw new replica.ReplicaError(
|
|
27066
|
+
replica.ReplicaErrorCode.CONFIG_MISMATCH,
|
|
27067
|
+
"The stored replica belongs to a different device key; purge the partition to rekey."
|
|
27068
|
+
);
|
|
27069
|
+
}
|
|
27070
|
+
generation = state.generation;
|
|
27071
|
+
} catch (error) {
|
|
27072
|
+
await store.close().catch(() => void 0);
|
|
27073
|
+
throw error;
|
|
27074
|
+
}
|
|
27075
|
+
let ino;
|
|
27076
|
+
try {
|
|
27077
|
+
ino = (await (0, import_promises.stat)((0, import_node_path.join)(replicaDir, "replica.db"))).ino;
|
|
27078
|
+
} catch (error) {
|
|
27079
|
+
if (!isNotFound(error)) throw error;
|
|
27080
|
+
}
|
|
27081
|
+
return new SqliteReplicaHandle({
|
|
27082
|
+
spec,
|
|
27083
|
+
device,
|
|
27084
|
+
store,
|
|
27085
|
+
replicaDir,
|
|
27086
|
+
replica,
|
|
27087
|
+
guard,
|
|
27088
|
+
transportFor: options.transportFor,
|
|
27089
|
+
dirSync: options.dirSync,
|
|
27090
|
+
generation,
|
|
27091
|
+
ino
|
|
27092
|
+
});
|
|
27093
|
+
}
|
|
27094
|
+
async function inspectStatus(spec, { signal }) {
|
|
27095
|
+
const checkAbort = () => {
|
|
27096
|
+
if (signal.aborted) throw signal.reason ?? Object.assign(new Error("Replica status inspection was aborted"), { code: "ABORTED" });
|
|
27097
|
+
};
|
|
27098
|
+
checkAbort();
|
|
27099
|
+
const idDir = partitionDirOf(root, spec.identity);
|
|
27100
|
+
if (!await pathExists(idDir)) return void 0;
|
|
27101
|
+
checkAbort();
|
|
27102
|
+
const identityFile = (0, import_node_path.join)(idDir, "identity.json");
|
|
27103
|
+
const storedIdentity = identityRecordOf(await readJsonFile(identityFile));
|
|
27104
|
+
if (storedIdentity === void 0 || !sameIdentity(storedIdentity, spec.identity)) {
|
|
27105
|
+
throw new ReplicaStorageError("STORAGE_ERROR", `The partition at ${idDir} belongs to a different identity or has no identity record.`);
|
|
27106
|
+
}
|
|
27107
|
+
checkAbort();
|
|
27108
|
+
let device = spec.device;
|
|
27109
|
+
if (device === void 0) {
|
|
27110
|
+
const deviceFile = (0, import_node_path.join)(idDir, "device.jwk");
|
|
27111
|
+
const storedDevice = await readJsonFile(deviceFile);
|
|
27112
|
+
if (storedDevice === void 0) return void 0;
|
|
27113
|
+
device = deviceRecordOf(storedDevice);
|
|
27114
|
+
if (device === void 0) throw new ReplicaStorageError("STORAGE_ERROR", `The replica device key at ${deviceFile} is unreadable.`);
|
|
27115
|
+
}
|
|
27116
|
+
checkAbort();
|
|
27117
|
+
const replicaDir = (0, import_node_path.join)(idDir, "replicas", replicaHashOf(spec.prefix, device.did));
|
|
27118
|
+
if (!await pathExists(replicaDir)) return void 0;
|
|
27119
|
+
checkAbort();
|
|
27120
|
+
const [replica, sqlite] = await Promise.all([
|
|
27121
|
+
// @ts-ignore — TS2307 when replica's dist is absent (CI builds node-sdk first).
|
|
27122
|
+
import("@tinycloud/replica"),
|
|
27123
|
+
// @ts-ignore — same as above.
|
|
27124
|
+
import("@tinycloud/replica/sqlite")
|
|
27125
|
+
]);
|
|
27126
|
+
checkAbort();
|
|
27127
|
+
const inspected = await sqlite.SqliteReplicaStore.inspect(replicaDir, { signal });
|
|
27128
|
+
checkAbort();
|
|
27129
|
+
if (inspected === null) return void 0;
|
|
27130
|
+
const { state, status } = inspected;
|
|
27131
|
+
if (state.config.host !== spec.identity.host || state.config.space !== spec.space || state.config.prefix !== spec.prefix || principalOf(state.config.deviceDid) !== principalOf(device.did)) {
|
|
27132
|
+
throw new ReplicaStorageError("STORAGE_ERROR", `The replica at ${replicaDir} does not match the requested identity, space, prefix, or device.`);
|
|
27133
|
+
}
|
|
27134
|
+
const syncedThroughEpoch = await readFence(replicaDir);
|
|
27135
|
+
checkAbort();
|
|
27136
|
+
return {
|
|
27137
|
+
coverage: status.coverage,
|
|
27138
|
+
lastSyncAt: status.lastSyncAt,
|
|
27139
|
+
syncedThroughEpoch,
|
|
27140
|
+
authority: { state: status.authority.state, expiresAt: status.authority.expiresAt },
|
|
27141
|
+
grant: newestGrantInfo(replica, state.pendingGrant ?? state.grant, state.pendingGrant, spec),
|
|
27142
|
+
counts: status.counts,
|
|
27143
|
+
bytes: status.bytes,
|
|
27144
|
+
lastError: status.lastError
|
|
27145
|
+
};
|
|
27146
|
+
}
|
|
27147
|
+
async function purgePartition(target) {
|
|
27148
|
+
const [replica, sqlite] = await Promise.all([
|
|
27149
|
+
// @ts-ignore — TS2307 when replica's dist is absent (CI builds node-sdk first).
|
|
27150
|
+
import("@tinycloud/replica"),
|
|
27151
|
+
// @ts-ignore — same as above.
|
|
27152
|
+
import("@tinycloud/replica/sqlite")
|
|
27153
|
+
]);
|
|
27154
|
+
const idDir = partitionDirOf(root, target.identity);
|
|
27155
|
+
if (!await pathExists(idDir)) return;
|
|
27156
|
+
const deviceDids = [];
|
|
27157
|
+
const deviceFile = (0, import_node_path.join)(idDir, "device.jwk");
|
|
27158
|
+
const stored = await readJsonFile(deviceFile);
|
|
27159
|
+
if (stored !== void 0) {
|
|
27160
|
+
const device = deviceRecordOf(stored);
|
|
27161
|
+
if (device === void 0) {
|
|
27162
|
+
throw new ReplicaStorageError(
|
|
27163
|
+
"STORAGE_ERROR",
|
|
27164
|
+
`The replica device key at ${deviceFile} is unreadable.`
|
|
27165
|
+
);
|
|
27166
|
+
}
|
|
27167
|
+
deviceDids.push(device.did);
|
|
27168
|
+
}
|
|
27169
|
+
if (target.sessionDeviceDid !== void 0) deviceDids.push(target.sessionDeviceDid);
|
|
27170
|
+
const devices = [...new Map(deviceDids.map((did) => [principalOf(did), did])).values()];
|
|
27171
|
+
let firstError;
|
|
27172
|
+
for (const deviceDid of devices) {
|
|
27173
|
+
const replicaDir = (0, import_node_path.join)(idDir, "replicas", replicaHashOf(target.prefix, deviceDid));
|
|
27174
|
+
if (!await pathExists(replicaDir)) continue;
|
|
27175
|
+
try {
|
|
27176
|
+
let store;
|
|
27177
|
+
try {
|
|
27178
|
+
store = await sqlite.SqliteReplicaStore.open(replicaDir, { create: false, guard });
|
|
27179
|
+
} catch (error) {
|
|
27180
|
+
if (replica.isReplicaError(error, replica.ReplicaErrorCode.NOT_FOUND)) {
|
|
27181
|
+
await guard(() => (0, import_promises.rm)(replicaDir, { recursive: true, force: true }));
|
|
27182
|
+
continue;
|
|
27183
|
+
}
|
|
27184
|
+
throw error;
|
|
27185
|
+
}
|
|
27186
|
+
try {
|
|
27187
|
+
const state = await store.open();
|
|
27188
|
+
if (state === null) {
|
|
27189
|
+
await store.close().catch(() => void 0);
|
|
27190
|
+
await guard(() => (0, import_promises.rm)(replicaDir, { recursive: true, force: true }));
|
|
27191
|
+
continue;
|
|
27192
|
+
}
|
|
27193
|
+
const lease = await store.acquireSyncLease(SYNC_LEASE_TTL_MS);
|
|
27194
|
+
if (lease === null) {
|
|
27195
|
+
throw new replica.ReplicaError(
|
|
27196
|
+
replica.ReplicaErrorCode.BUSY,
|
|
27197
|
+
"Another process holds this replica's sync lease."
|
|
27198
|
+
);
|
|
27199
|
+
}
|
|
27200
|
+
try {
|
|
27201
|
+
if (state.revoked === null) {
|
|
27202
|
+
await store.reset(lease, "purged");
|
|
27203
|
+
}
|
|
27204
|
+
await store.destroy(lease);
|
|
27205
|
+
} finally {
|
|
27206
|
+
await store.releaseLease(lease).catch(() => void 0);
|
|
27207
|
+
}
|
|
27208
|
+
} finally {
|
|
27209
|
+
await store.close().catch(() => void 0);
|
|
27210
|
+
}
|
|
27211
|
+
} catch (error) {
|
|
27212
|
+
firstError ?? (firstError = error);
|
|
27213
|
+
}
|
|
27214
|
+
}
|
|
27215
|
+
if (firstError !== void 0) throw firstError;
|
|
27216
|
+
}
|
|
27217
|
+
return {
|
|
27218
|
+
kind: "sqlite",
|
|
27219
|
+
open: openHandle,
|
|
27220
|
+
inspectStatus,
|
|
27221
|
+
purge: purgePartition,
|
|
27222
|
+
// Always the durable partitioned file store (review): the runtime
|
|
27223
|
+
// must never fall back to volatile in-memory pending state — a
|
|
27224
|
+
// restart that lost ambiguous write records would serve stale data.
|
|
27225
|
+
// Without a guard the file store still durably serializes each update;
|
|
27226
|
+
// the guard only adds cross-process read-modify-write exclusion.
|
|
27227
|
+
pendingWrites(identity) {
|
|
27228
|
+
return new FilePendingWriteStore(
|
|
27229
|
+
identity,
|
|
27230
|
+
partitionDirOf(root, identity),
|
|
27231
|
+
guard,
|
|
27232
|
+
options.dirSync
|
|
27233
|
+
);
|
|
27234
|
+
}
|
|
27235
|
+
};
|
|
27236
|
+
}
|
|
27237
|
+
function sqliteReplicaStorage(options) {
|
|
27238
|
+
return createSqliteReplicaStorage(options);
|
|
27239
|
+
}
|
|
25387
27240
|
// Annotate the CommonJS export names for ESM import in node:
|
|
25388
27241
|
0 && (module.exports = {
|
|
25389
27242
|
ACCEPTED_MARKER_VERSIONS,
|
|
@@ -25540,6 +27393,7 @@ var import_sdk_core23 = require("@tinycloud/sdk-core");
|
|
|
25540
27393
|
resourceCapabilitiesToSpaceAbilitiesMap,
|
|
25541
27394
|
serializeDelegation,
|
|
25542
27395
|
signedCompactUcanExpiry,
|
|
27396
|
+
sqliteReplicaStorage,
|
|
25543
27397
|
tinyCloudDebugLogger,
|
|
25544
27398
|
validateEnvelope,
|
|
25545
27399
|
validateManifest,
|