@tinycloud/node-sdk 3.2.0-beta.1 → 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-C7-YdUWg.d.cts → WasmKeyProvider-DjfRu9aL.d.cts} +163 -3
- package/dist/{core-C7-YdUWg.d.ts → WasmKeyProvider-DjfRu9aL.d.ts} +163 -3
- package/dist/authority-mTQEgN56.d.cts +97 -0
- package/dist/authority-mTQEgN56.d.ts +97 -0
- package/dist/core.cjs +1076 -447
- 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 +753 -120
- package/dist/core.js.map +1 -1
- package/dist/index.cjs +2382 -495
- 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 +2032 -131
- 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,166 +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
|
-
|
|
17533
|
+
KVService: () => import_sdk_core17.KVService,
|
|
17534
|
+
MAX_SECRET_SCOPE_LENGTH: () => import_sdk_core20.MAX_SECRET_SCOPE_LENGTH,
|
|
17535
|
+
ManifestValidationError: () => import_sdk_core16.ManifestValidationError,
|
|
17066
17536
|
MemorySessionStorage: () => MemorySessionStorage,
|
|
17067
|
-
NETWORK_NAME_PATTERN: () =>
|
|
17068
|
-
NetworkIdError: () =>
|
|
17537
|
+
NETWORK_NAME_PATTERN: () => import_sdk_core21.NETWORK_NAME_PATTERN,
|
|
17538
|
+
NetworkIdError: () => import_sdk_core21.NetworkIdError,
|
|
17069
17539
|
NodeUserAuthorization: () => NodeUserAuthorization,
|
|
17070
17540
|
NodeWasmBindings: () => NodeWasmBindings,
|
|
17071
|
-
PermissionNotInManifestError: () =>
|
|
17072
|
-
PrefixedKVService: () =>
|
|
17541
|
+
PermissionNotInManifestError: () => import_sdk_core16.PermissionNotInManifestError,
|
|
17542
|
+
PrefixedKVService: () => import_sdk_core17.PrefixedKVService,
|
|
17073
17543
|
PrivateKeySigner: () => PrivateKeySigner,
|
|
17074
|
-
ProtocolMismatchError: () =>
|
|
17544
|
+
ProtocolMismatchError: () => import_sdk_core26.ProtocolMismatchError,
|
|
17075
17545
|
RUNTIME_DELEGATION_REJECTIONS: () => RUNTIME_DELEGATION_REJECTIONS,
|
|
17076
17546
|
RuntimeDelegationRejectedError: () => RuntimeDelegationRejectedError,
|
|
17077
|
-
SECRET_NAME_RE: () =>
|
|
17078
|
-
|
|
17079
|
-
|
|
17080
|
-
|
|
17081
|
-
|
|
17082
|
-
|
|
17083
|
-
|
|
17084
|
-
|
|
17085
|
-
|
|
17086
|
-
|
|
17087
|
-
|
|
17088
|
-
|
|
17089
|
-
|
|
17090
|
-
|
|
17091
|
-
|
|
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,
|
|
17092
17564
|
TinyCloudNode: () => TinyCloudNode,
|
|
17093
|
-
UnsupportedFeatureError: () =>
|
|
17565
|
+
UnsupportedFeatureError: () => import_sdk_core26.UnsupportedFeatureError,
|
|
17094
17566
|
UnsupportedSessionRestoreError: () => UnsupportedSessionRestoreError,
|
|
17095
|
-
VAULT_PERMISSION_SERVICE: () =>
|
|
17096
|
-
VaultHeaders: () =>
|
|
17097
|
-
VaultPublicSpaceKVActions: () =>
|
|
17098
|
-
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,
|
|
17099
17571
|
WasmKeyProvider: () => WasmKeyProvider,
|
|
17100
17572
|
activateCompactRuntimeDelegation: () => activateCompactRuntimeDelegation,
|
|
17101
17573
|
activateValidatedRuntimeDelegation: () => activateValidatedRuntimeDelegation,
|
|
17102
|
-
addressStorageKey: () =>
|
|
17103
|
-
|
|
17104
|
-
|
|
17105
|
-
|
|
17106
|
-
|
|
17107
|
-
|
|
17108
|
-
|
|
17109
|
-
|
|
17110
|
-
|
|
17111
|
-
|
|
17112
|
-
|
|
17113
|
-
|
|
17114
|
-
|
|
17115
|
-
|
|
17116
|
-
|
|
17117
|
-
|
|
17118
|
-
|
|
17119
|
-
|
|
17120
|
-
|
|
17121
|
-
|
|
17122
|
-
|
|
17123
|
-
|
|
17124
|
-
|
|
17125
|
-
|
|
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,
|
|
17126
17599
|
createWasmKeyProvider: () => createWasmKeyProvider,
|
|
17127
|
-
decryptEnvelopeWithKey: () =>
|
|
17600
|
+
decryptEnvelopeWithKey: () => import_sdk_core21.decryptEnvelopeWithKey,
|
|
17128
17601
|
defaultSignStrategy: () => defaultSignStrategy,
|
|
17129
|
-
defaultSpaceCreationHandler: () =>
|
|
17130
|
-
deriveSignedReceiverKey: () =>
|
|
17602
|
+
defaultSpaceCreationHandler: () => import_sdk_core15.defaultSpaceCreationHandler,
|
|
17603
|
+
deriveSignedReceiverKey: () => import_sdk_core21.deriveSignedReceiverKey,
|
|
17131
17604
|
deserializeDelegation: () => deserializeDelegation,
|
|
17132
|
-
didCacheKey: () =>
|
|
17133
|
-
didEquals: () =>
|
|
17134
|
-
disableTinyCloudDebug: () =>
|
|
17135
|
-
discoverNetwork: () =>
|
|
17136
|
-
enableTinyCloudDebug: () =>
|
|
17137
|
-
encryptToNetwork: () =>
|
|
17138
|
-
encryptionBase64Decode: () =>
|
|
17139
|
-
encryptionBase64Encode: () =>
|
|
17140
|
-
encryptionError: () =>
|
|
17141
|
-
encryptionUtf8Decode: () =>
|
|
17142
|
-
encryptionUtf8Encode: () =>
|
|
17143
|
-
ensureNetworkUsableForDecrypt: () =>
|
|
17144
|
-
expandActionShortNames: () =>
|
|
17145
|
-
expandPermissionEntries: () =>
|
|
17146
|
-
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,
|
|
17147
17620
|
extractSiweExpiration: () => extractSiweExpiration,
|
|
17148
|
-
generateRandomReceiverKey: () =>
|
|
17149
|
-
getTinyCloudDebugLogs: () =>
|
|
17621
|
+
generateRandomReceiverKey: () => import_sdk_core21.generateRandomReceiverKey,
|
|
17622
|
+
getTinyCloudDebugLogs: () => import_sdk_core15.getTinyCloudDebugLogs,
|
|
17150
17623
|
grantAuthRequest: () => grantAuthRequest,
|
|
17151
|
-
hexDecode: () =>
|
|
17152
|
-
hexEncode: () =>
|
|
17153
|
-
installTinyCloudDebugGlobals: () =>
|
|
17154
|
-
isCapabilitySubset: () =>
|
|
17155
|
-
isEvmAddress: () =>
|
|
17156
|
-
isNetworkId: () =>
|
|
17157
|
-
isStorageFullError: () =>
|
|
17158
|
-
loadManifest: () =>
|
|
17159
|
-
makePkhSpaceId: () =>
|
|
17160
|
-
makePublicSpaceId: () =>
|
|
17161
|
-
networkDiscoveryKey: () =>
|
|
17162
|
-
openWrappedKey: () =>
|
|
17163
|
-
parseCanonicalNetworkId: () =>
|
|
17164
|
-
parseExpiry: () =>
|
|
17165
|
-
parseNetworkId: () =>
|
|
17166
|
-
parsePkhDid: () =>
|
|
17167
|
-
parseSecretCatalogKey: () =>
|
|
17168
|
-
parseSpaceUri: () =>
|
|
17169
|
-
pkhDid: () =>
|
|
17170
|
-
principalDid: () =>
|
|
17171
|
-
principalDidEquals: () =>
|
|
17172
|
-
resolveManifest: () =>
|
|
17173
|
-
resolveSecretListPrefix: () =>
|
|
17174
|
-
resolveSecretPath: () =>
|
|
17175
|
-
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,
|
|
17176
17649
|
serializeDelegation: () => serializeDelegation,
|
|
17177
17650
|
signedCompactUcanExpiry: () => signedCompactUcanExpiry,
|
|
17178
|
-
|
|
17179
|
-
|
|
17180
|
-
|
|
17181
|
-
|
|
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,
|
|
17182
17656
|
wireOpenKeyAuthorize: () => wireOpenKeyAuthorize
|
|
17183
17657
|
});
|
|
17184
|
-
module.exports = __toCommonJS(
|
|
17658
|
+
module.exports = __toCommonJS(src_exports);
|
|
17185
17659
|
|
|
17186
17660
|
// src/NodeWasmBindings.ts
|
|
17187
17661
|
var import_node_sdk_wasm = require("@tinycloud/node-sdk-wasm");
|
|
@@ -17303,7 +17777,9 @@ var RUNTIME_DELEGATION_REJECTIONS = [
|
|
|
17303
17777
|
"audience_mismatch",
|
|
17304
17778
|
"resources_mismatch",
|
|
17305
17779
|
"unsupported",
|
|
17306
|
-
"activation_rejected"
|
|
17780
|
+
"activation_rejected",
|
|
17781
|
+
"activation_unavailable",
|
|
17782
|
+
"activation_unauthenticated"
|
|
17307
17783
|
];
|
|
17308
17784
|
var RuntimeDelegationRejectedError = class extends Error {
|
|
17309
17785
|
constructor(reason, message) {
|
|
@@ -17312,6 +17788,18 @@ var RuntimeDelegationRejectedError = class extends Error {
|
|
|
17312
17788
|
this.reason = reason;
|
|
17313
17789
|
}
|
|
17314
17790
|
};
|
|
17791
|
+
function activationRejectionReason(error) {
|
|
17792
|
+
if (typeof error !== "object" || error === null) return "activation_rejected";
|
|
17793
|
+
if ("code" in error && error.code === "ACTIVATION_TRANSPORT_FAILED") {
|
|
17794
|
+
return "activation_unavailable";
|
|
17795
|
+
}
|
|
17796
|
+
const cause = "cause" in error ? error.cause : void 0;
|
|
17797
|
+
const status = typeof cause === "object" && cause !== null && "status" in cause ? cause.status : void 0;
|
|
17798
|
+
if (typeof status !== "number") return "activation_rejected";
|
|
17799
|
+
if (status === 408 || status === 429 || status >= 500) return "activation_unavailable";
|
|
17800
|
+
if (status === 401) return "activation_unauthenticated";
|
|
17801
|
+
return "activation_rejected";
|
|
17802
|
+
}
|
|
17315
17803
|
function reject(reason, message) {
|
|
17316
17804
|
throw new RuntimeDelegationRejectedError(reason, message);
|
|
17317
17805
|
}
|
|
@@ -17696,7 +18184,10 @@ async function activateValidatedRuntimeDelegation(node, delegation, options) {
|
|
|
17696
18184
|
await node.useRuntimeDelegation(installedCandidate);
|
|
17697
18185
|
}
|
|
17698
18186
|
} catch (error) {
|
|
17699
|
-
reject(
|
|
18187
|
+
reject(
|
|
18188
|
+
activationRejectionReason(error),
|
|
18189
|
+
error instanceof Error ? error.message : String(error)
|
|
18190
|
+
);
|
|
17700
18191
|
}
|
|
17701
18192
|
const installed = node.getRuntimePermissionDelegations().find((candidate) => candidate.cid === cid);
|
|
17702
18193
|
if (!installed) {
|
|
@@ -17796,16 +18287,32 @@ function deserializeDelegation(data) {
|
|
|
17796
18287
|
}
|
|
17797
18288
|
|
|
17798
18289
|
// src/TinyCloudNode.ts
|
|
17799
|
-
|
|
17800
|
-
|
|
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");
|
|
17801
18307
|
|
|
17802
18308
|
// src/authorization/NodeUserAuthorization.ts
|
|
17803
18309
|
var import_node_crypto = require("crypto");
|
|
17804
18310
|
var import_siwe = require("siwe");
|
|
17805
|
-
var
|
|
18311
|
+
var import_sdk_core4 = require("@tinycloud/sdk-core");
|
|
18312
|
+
init_authority_sign_in();
|
|
17806
18313
|
|
|
17807
18314
|
// src/authorization/strategies.ts
|
|
17808
|
-
var
|
|
18315
|
+
var import_sdk_core3 = require("@tinycloud/sdk-core");
|
|
17809
18316
|
var defaultSignStrategy = { type: "auto-sign" };
|
|
17810
18317
|
|
|
17811
18318
|
// src/storage/MemorySessionStorage.ts
|
|
@@ -17880,8 +18387,8 @@ var MemorySessionStorage = class {
|
|
|
17880
18387
|
};
|
|
17881
18388
|
|
|
17882
18389
|
// src/authorization/NodeUserAuthorization.ts
|
|
17883
|
-
var DECRYPT_ACTION =
|
|
17884
|
-
var NETWORK_CREATE_ACTION =
|
|
18390
|
+
var DECRYPT_ACTION = import_sdk_core4.ENCRYPTION.DECRYPT;
|
|
18391
|
+
var NETWORK_CREATE_ACTION = import_sdk_core4.ENCRYPTION.NETWORK_CREATE;
|
|
17885
18392
|
function describeHostFailure(result) {
|
|
17886
18393
|
const text = result.error?.trim();
|
|
17887
18394
|
return text ? `${result.status} - ${text}` : `${result.status}`;
|
|
@@ -17909,7 +18416,7 @@ function canonicalOpenKeyManifestSha256Hex(value) {
|
|
|
17909
18416
|
}
|
|
17910
18417
|
function didPrincipalMatches(actual, expected) {
|
|
17911
18418
|
try {
|
|
17912
|
-
return (0,
|
|
18419
|
+
return (0, import_sdk_core4.principalDidEquals)(actual, expected);
|
|
17913
18420
|
} catch {
|
|
17914
18421
|
return actual === expected;
|
|
17915
18422
|
}
|
|
@@ -17950,30 +18457,30 @@ var NodeUserAuthorization = class {
|
|
|
17950
18457
|
this.spacePrefix = config.spacePrefix ?? "default";
|
|
17951
18458
|
this.defaultActions = config.defaultActions ?? {
|
|
17952
18459
|
kv: {
|
|
17953
|
-
"": [
|
|
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]
|
|
17954
18461
|
},
|
|
17955
18462
|
sql: {
|
|
17956
|
-
"": [
|
|
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]
|
|
17957
18464
|
},
|
|
17958
18465
|
duckdb: {
|
|
17959
18466
|
"": [
|
|
17960
|
-
|
|
17961
|
-
|
|
17962
|
-
|
|
17963
|
-
|
|
17964
|
-
|
|
17965
|
-
|
|
17966
|
-
|
|
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
|
|
17967
18474
|
]
|
|
17968
18475
|
},
|
|
17969
18476
|
capabilities: {
|
|
17970
|
-
"": [
|
|
18477
|
+
"": [import_sdk_core4.CAPABILITIES.READ]
|
|
17971
18478
|
},
|
|
17972
18479
|
hooks: {
|
|
17973
|
-
"": [
|
|
18480
|
+
"": [import_sdk_core4.HOOKS.SUBSCRIBE, import_sdk_core4.HOOKS.REGISTER, import_sdk_core4.HOOKS.LIST, import_sdk_core4.HOOKS.UNREGISTER]
|
|
17974
18481
|
}
|
|
17975
18482
|
};
|
|
17976
|
-
this.sessionExpirationMs = config.sessionExpirationMs ??
|
|
18483
|
+
this.sessionExpirationMs = config.sessionExpirationMs ?? import_sdk_core4.EXPIRY.SESSION_MS;
|
|
17977
18484
|
this.autoCreateSpace = config.autoCreateSpace ?? false;
|
|
17978
18485
|
this.spaceCreationHandler = config.spaceCreationHandler;
|
|
17979
18486
|
this.tinycloudHosts = config.tinycloudHosts;
|
|
@@ -17988,6 +18495,7 @@ var NodeUserAuthorization = class {
|
|
|
17988
18495
|
this.nonce = config.nonce;
|
|
17989
18496
|
this.siweConfig = config.siweConfig;
|
|
17990
18497
|
this.includeAccountRegistryPermissions = config.includeAccountRegistryPermissions ?? true;
|
|
18498
|
+
this.replication = config.replication?.enabled === true ? config.replication : void 0;
|
|
17991
18499
|
this._manifest = config.manifest;
|
|
17992
18500
|
this._capabilityRequest = config.capabilityRequest;
|
|
17993
18501
|
this.sessionManager = config.sessionManager ?? this.wasm.createSessionManager();
|
|
@@ -18052,7 +18560,7 @@ var NodeUserAuthorization = class {
|
|
|
18052
18560
|
* {@link ensureTinyCloudHosts}.
|
|
18053
18561
|
*/
|
|
18054
18562
|
setRestoredTinyCloudSession(session, hosts) {
|
|
18055
|
-
const address = (0,
|
|
18563
|
+
const address = (0, import_sdk_core4.canonicalizeAddress)(session.address);
|
|
18056
18564
|
this._tinyCloudSession = { ...session, address };
|
|
18057
18565
|
this._address = address;
|
|
18058
18566
|
this._chainId = session.chainId;
|
|
@@ -18113,8 +18621,8 @@ var NodeUserAuthorization = class {
|
|
|
18113
18621
|
if (this.tinycloudHosts && this.tinycloudHosts.length > 0) {
|
|
18114
18622
|
return;
|
|
18115
18623
|
}
|
|
18116
|
-
const subject = (0,
|
|
18117
|
-
const resolved = await (0,
|
|
18624
|
+
const subject = (0, import_sdk_core4.pkhDid)(address, chainId);
|
|
18625
|
+
const resolved = await (0, import_sdk_core4.resolveTinyCloudHosts)(subject, {
|
|
18118
18626
|
registryUrl: this.tinycloudRegistryUrl,
|
|
18119
18627
|
fallbackHosts: this.tinycloudFallbackHosts,
|
|
18120
18628
|
autoDiscoverLocalNode: this.autoDiscoverLocalNode,
|
|
@@ -18182,7 +18690,7 @@ var NodeUserAuthorization = class {
|
|
|
18182
18690
|
if (this._manifest === void 0) {
|
|
18183
18691
|
return void 0;
|
|
18184
18692
|
}
|
|
18185
|
-
this._capabilityRequest = (0,
|
|
18693
|
+
this._capabilityRequest = (0, import_sdk_core4.composeManifestRequest)(
|
|
18186
18694
|
Array.isArray(this._manifest) ? this._manifest : [this._manifest],
|
|
18187
18695
|
{
|
|
18188
18696
|
includeAccountRegistryPermissions: this.includeAccountRegistryPermissions
|
|
@@ -18194,50 +18702,173 @@ var NodeUserAuthorization = class {
|
|
|
18194
18702
|
if (space.startsWith("tinycloud:")) {
|
|
18195
18703
|
return space;
|
|
18196
18704
|
}
|
|
18197
|
-
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
|
+
});
|
|
18198
18843
|
}
|
|
18199
18844
|
defaultEncryptionNetworkId(address, chainId) {
|
|
18200
|
-
return `urn:tinycloud:encryption:${(0,
|
|
18845
|
+
return `urn:tinycloud:encryption:${(0, import_sdk_core4.pkhDid)(address, chainId)}:default`;
|
|
18201
18846
|
}
|
|
18202
18847
|
resolveSignInCapabilities(address, chainId) {
|
|
18203
18848
|
const request = this.getCapabilityRequest();
|
|
18204
18849
|
if (request === void 0) {
|
|
18205
18850
|
const defaultNetworkId = this.defaultEncryptionNetworkId(address, chainId);
|
|
18206
|
-
const primarySpaceId2 = (0,
|
|
18207
|
-
const secretsSpaceId = (0,
|
|
18208
|
-
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();
|
|
18209
18854
|
const spaceAbilities2 = {
|
|
18210
18855
|
[primarySpaceId2]: primaryActions,
|
|
18211
|
-
[secretsSpaceId]:
|
|
18212
|
-
kv: {
|
|
18213
|
-
"vault/secrets/": [
|
|
18214
|
-
import_sdk_core3.KV.GET,
|
|
18215
|
-
import_sdk_core3.KV.PUT,
|
|
18216
|
-
import_sdk_core3.KV.DEL,
|
|
18217
|
-
import_sdk_core3.KV.LIST,
|
|
18218
|
-
import_sdk_core3.KV.METADATA
|
|
18219
|
-
]
|
|
18220
|
-
}
|
|
18221
|
-
}
|
|
18856
|
+
[secretsSpaceId]: this.secretsPrimaryAbilities()
|
|
18222
18857
|
};
|
|
18223
|
-
if (this.includeAccountRegistryPermissions && this.spacePrefix !==
|
|
18224
|
-
spaceAbilities2[(0,
|
|
18225
|
-
}
|
|
18226
|
-
|
|
18227
|
-
|
|
18228
|
-
|
|
18229
|
-
|
|
18230
|
-
|
|
18231
|
-
|
|
18232
|
-
|
|
18233
|
-
|
|
18234
|
-
|
|
18235
|
-
}
|
|
18236
|
-
}
|
|
18237
|
-
}
|
|
18238
|
-
}
|
|
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
|
+
);
|
|
18239
18870
|
return {
|
|
18240
|
-
abilities:
|
|
18871
|
+
abilities: mergedPrimary,
|
|
18241
18872
|
spaceId: primarySpaceId2,
|
|
18242
18873
|
spaceAbilities: spaceAbilities2,
|
|
18243
18874
|
rawAbilities: {
|
|
@@ -18246,35 +18877,44 @@ var NodeUserAuthorization = class {
|
|
|
18246
18877
|
};
|
|
18247
18878
|
}
|
|
18248
18879
|
const rawAbilities = {};
|
|
18249
|
-
const currentDid = (0,
|
|
18880
|
+
const currentDid = (0, import_sdk_core4.pkhDid)(address, chainId);
|
|
18250
18881
|
const spaceResources = request.resources.filter((entry) => {
|
|
18251
|
-
if (entry.service !==
|
|
18882
|
+
if (entry.service !== import_sdk_core4.ENCRYPTION_PERMISSION_SERVICE) {
|
|
18252
18883
|
return true;
|
|
18253
18884
|
}
|
|
18254
18885
|
for (const action of entry.actions) {
|
|
18255
18886
|
addRawAbility(rawAbilities, entry.path, action);
|
|
18256
18887
|
}
|
|
18257
18888
|
if (entry.actions.includes(DECRYPT_ACTION)) {
|
|
18258
|
-
const parsed = (0,
|
|
18889
|
+
const parsed = (0, import_sdk_core4.parseNetworkId)(entry.path);
|
|
18259
18890
|
if (didPrincipalMatches(parsed.ownerDid, currentDid)) {
|
|
18260
18891
|
addRawAbility(rawAbilities, entry.path, NETWORK_CREATE_ACTION);
|
|
18261
18892
|
}
|
|
18262
18893
|
}
|
|
18263
18894
|
return false;
|
|
18264
18895
|
});
|
|
18265
|
-
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;
|
|
18266
18897
|
const primarySpaceId = this.resolveSpaceName(
|
|
18267
18898
|
primarySpaceName,
|
|
18268
18899
|
address,
|
|
18269
18900
|
chainId
|
|
18270
18901
|
);
|
|
18271
|
-
const bySpace = (0,
|
|
18902
|
+
const bySpace = (0, import_sdk_core4.resourceCapabilitiesToSpaceAbilitiesMap)(spaceResources);
|
|
18272
18903
|
const spaceAbilities = {};
|
|
18273
18904
|
for (const [space, abilities] of Object.entries(bySpace)) {
|
|
18274
18905
|
spaceAbilities[this.resolveSpaceName(space, address, chainId)] = abilities;
|
|
18275
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
|
+
);
|
|
18276
18916
|
return {
|
|
18277
|
-
abilities:
|
|
18917
|
+
abilities: mergedPrimaryAbilities,
|
|
18278
18918
|
spaceId: primarySpaceId,
|
|
18279
18919
|
spaceAbilities,
|
|
18280
18920
|
rawAbilities: Object.keys(rawAbilities).length > 0 ? rawAbilities : void 0
|
|
@@ -18332,14 +18972,14 @@ var NodeUserAuthorization = class {
|
|
|
18332
18972
|
* Create the space on the TinyCloud server (host delegation).
|
|
18333
18973
|
* This registers the user as the owner of the space.
|
|
18334
18974
|
*/
|
|
18335
|
-
async hostSpace(targetSpaceId, purpose) {
|
|
18975
|
+
async hostSpace(targetSpaceId, purpose, signal) {
|
|
18336
18976
|
if (!this._tinyCloudSession || !this._address || !this._chainId) {
|
|
18337
18977
|
throw new Error("Must be signed in to host space");
|
|
18338
18978
|
}
|
|
18339
18979
|
await this.ensureTinyCloudHosts();
|
|
18340
18980
|
const host = this.primaryTinyCloudHost;
|
|
18341
18981
|
const spaceId = targetSpaceId ?? this._tinyCloudSession.spaceId;
|
|
18342
|
-
const peerId = await (0,
|
|
18982
|
+
const peerId = await (0, import_sdk_core4.fetchPeerId)(host, spaceId, signal);
|
|
18343
18983
|
const siwe = this.wasm.generateHostSIWEMessage({
|
|
18344
18984
|
address: this._address,
|
|
18345
18985
|
chainId: this._chainId,
|
|
@@ -18348,9 +18988,28 @@ var NodeUserAuthorization = class {
|
|
|
18348
18988
|
spaceId,
|
|
18349
18989
|
peerId
|
|
18350
18990
|
});
|
|
18351
|
-
|
|
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;
|
|
18352
19011
|
const headers = this.wasm.siweToDelegationHeaders({ siwe, signature: signature2 });
|
|
18353
|
-
return (0,
|
|
19012
|
+
return (0, import_sdk_core4.submitHostDelegation)(host, headers, signal);
|
|
18354
19013
|
}
|
|
18355
19014
|
/**
|
|
18356
19015
|
* Create a specific space on the server via host delegation.
|
|
@@ -18371,8 +19030,8 @@ var NodeUserAuthorization = class {
|
|
|
18371
19030
|
* keeps its HTTP status (e.g. a typed 401/403) instead of collapsing to
|
|
18372
19031
|
* `false`.
|
|
18373
19032
|
*/
|
|
18374
|
-
async hostOwnedSpaceResult(spaceId, purpose) {
|
|
18375
|
-
return this.hostSpace(spaceId, purpose);
|
|
19033
|
+
async hostOwnedSpaceResult(spaceId, purpose, signal) {
|
|
19034
|
+
return this.hostSpace(spaceId, purpose, signal);
|
|
18376
19035
|
}
|
|
18377
19036
|
/**
|
|
18378
19037
|
* Ensure the user's space exists on the TinyCloud server.
|
|
@@ -18389,12 +19048,12 @@ var NodeUserAuthorization = class {
|
|
|
18389
19048
|
await this.ensureTinyCloudHosts();
|
|
18390
19049
|
const host = this.primaryTinyCloudHost;
|
|
18391
19050
|
const primarySpaceId = this._tinyCloudSession.spaceId;
|
|
18392
|
-
const result = await (0,
|
|
19051
|
+
const result = await (0, import_sdk_core4.activateSessionWithHost)(
|
|
18393
19052
|
host,
|
|
18394
19053
|
this._tinyCloudSession.delegationHeader
|
|
18395
19054
|
);
|
|
18396
19055
|
this.recordActivationSkippedSpaces(result, primarySpaceId);
|
|
18397
|
-
const handler = this.spaceCreationHandler ?? (this.autoCreateSpace ? new
|
|
19056
|
+
const handler = this.spaceCreationHandler ?? (this.autoCreateSpace ? new import_sdk_core4.AutoApproveSpaceCreationHandler() : void 0);
|
|
18398
19057
|
const creationContext = {
|
|
18399
19058
|
spaceId: primarySpaceId,
|
|
18400
19059
|
address: this._address,
|
|
@@ -18430,7 +19089,7 @@ var NodeUserAuthorization = class {
|
|
|
18430
19089
|
throw error;
|
|
18431
19090
|
}
|
|
18432
19091
|
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
18433
|
-
const retryResult = await (0,
|
|
19092
|
+
const retryResult = await (0, import_sdk_core4.activateSessionWithHost)(
|
|
18434
19093
|
host,
|
|
18435
19094
|
this._tinyCloudSession.delegationHeader
|
|
18436
19095
|
);
|
|
@@ -18470,7 +19129,7 @@ var NodeUserAuthorization = class {
|
|
|
18470
19129
|
throw error;
|
|
18471
19130
|
}
|
|
18472
19131
|
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
18473
|
-
const retryResult = await (0,
|
|
19132
|
+
const retryResult = await (0, import_sdk_core4.activateSessionWithHost)(
|
|
18474
19133
|
host,
|
|
18475
19134
|
this._tinyCloudSession.delegationHeader
|
|
18476
19135
|
);
|
|
@@ -18512,7 +19171,7 @@ var NodeUserAuthorization = class {
|
|
|
18512
19171
|
const jwk = JSON.parse(jwkString);
|
|
18513
19172
|
const now = /* @__PURE__ */ new Date();
|
|
18514
19173
|
const expirationTime = new Date(now.getTime() + this.sessionExpirationMs);
|
|
18515
|
-
const abilities = (0,
|
|
19174
|
+
const abilities = (0, import_sdk_core4.resourceCapabilitiesToAbilitiesMap)(
|
|
18516
19175
|
options.capabilityRequest.resources
|
|
18517
19176
|
);
|
|
18518
19177
|
const prepared = this.wasm.prepareSession({
|
|
@@ -18563,7 +19222,7 @@ var NodeUserAuthorization = class {
|
|
|
18563
19222
|
* @param options - Optional per-call SIWE overrides for this sign-in only
|
|
18564
19223
|
*/
|
|
18565
19224
|
async signIn(options) {
|
|
18566
|
-
this._address = (0,
|
|
19225
|
+
this._address = (0, import_sdk_core4.canonicalizeAddress)(await this.signer.getAddress());
|
|
18567
19226
|
this._chainId = await this.signer.getChainId();
|
|
18568
19227
|
const address = this._address;
|
|
18569
19228
|
const chainId = this._chainId;
|
|
@@ -18612,7 +19271,7 @@ var NodeUserAuthorization = class {
|
|
|
18612
19271
|
siwe: prepared.siwe,
|
|
18613
19272
|
signature: signature2
|
|
18614
19273
|
};
|
|
18615
|
-
const spacesMetadata = this.enablePublicSpace ? { public: (0,
|
|
19274
|
+
const spacesMetadata = this.enablePublicSpace ? { public: (0, import_sdk_core4.makePkhSpaceId)(address, chainId, "public") } : void 0;
|
|
18616
19275
|
const tinyCloudSession = {
|
|
18617
19276
|
address,
|
|
18618
19277
|
chainId,
|
|
@@ -18650,7 +19309,7 @@ var NodeUserAuthorization = class {
|
|
|
18650
19309
|
this._address = address;
|
|
18651
19310
|
this._chainId = chainId;
|
|
18652
19311
|
const infoHost = this.primaryTinyCloudHost;
|
|
18653
|
-
const nodeInfo = await (0,
|
|
19312
|
+
const nodeInfo = await (0, import_sdk_core4.checkNodeInfo)(
|
|
18654
19313
|
infoHost,
|
|
18655
19314
|
this.wasm.protocolVersion()
|
|
18656
19315
|
);
|
|
@@ -18690,7 +19349,7 @@ var NodeUserAuthorization = class {
|
|
|
18690
19349
|
*/
|
|
18691
19350
|
async signMessage(message, purpose) {
|
|
18692
19351
|
if (!this._address) {
|
|
18693
|
-
this._address = (0,
|
|
19352
|
+
this._address = (0, import_sdk_core4.canonicalizeAddress)(await this.signer.getAddress());
|
|
18694
19353
|
}
|
|
18695
19354
|
if (!this._chainId) {
|
|
18696
19355
|
this._chainId = await this.signer.getChainId();
|
|
@@ -18718,7 +19377,7 @@ var NodeUserAuthorization = class {
|
|
|
18718
19377
|
* ```
|
|
18719
19378
|
*/
|
|
18720
19379
|
async prepareSessionForSigning() {
|
|
18721
|
-
const address = (0,
|
|
19380
|
+
const address = (0, import_sdk_core4.canonicalizeAddress)(await this.signer.getAddress());
|
|
18722
19381
|
const chainId = await this.signer.getChainId();
|
|
18723
19382
|
const keyId = `session-${Date.now()}`;
|
|
18724
19383
|
this.sessionManager.renameSessionKeyId(this.activeSessionKeyId, keyId);
|
|
@@ -18769,7 +19428,7 @@ var NodeUserAuthorization = class {
|
|
|
18769
19428
|
...prepared,
|
|
18770
19429
|
signature: signature2
|
|
18771
19430
|
});
|
|
18772
|
-
const address = (0,
|
|
19431
|
+
const address = (0, import_sdk_core4.canonicalizeAddress)(await this.signer.getAddress());
|
|
18773
19432
|
const chainId = await this.signer.getChainId();
|
|
18774
19433
|
await this.resolveTinyCloudHostsForSignIn(address, chainId);
|
|
18775
19434
|
const clientSession = {
|
|
@@ -18780,7 +19439,7 @@ var NodeUserAuthorization = class {
|
|
|
18780
19439
|
siwe: prepared.siwe,
|
|
18781
19440
|
signature: signature2
|
|
18782
19441
|
};
|
|
18783
|
-
const spacesMetadata = this.enablePublicSpace ? { public: (0,
|
|
19442
|
+
const spacesMetadata = this.enablePublicSpace ? { public: (0, import_sdk_core4.makePkhSpaceId)(address, chainId, "public") } : void 0;
|
|
18784
19443
|
const tinyCloudSession = {
|
|
18785
19444
|
address,
|
|
18786
19445
|
chainId,
|
|
@@ -18822,7 +19481,7 @@ var NodeUserAuthorization = class {
|
|
|
18822
19481
|
this._address = address;
|
|
18823
19482
|
this._chainId = chainId;
|
|
18824
19483
|
const infoHost = this.primaryTinyCloudHost;
|
|
18825
|
-
const nodeInfo = await (0,
|
|
19484
|
+
const nodeInfo = await (0, import_sdk_core4.checkNodeInfo)(
|
|
18826
19485
|
infoHost,
|
|
18827
19486
|
this.wasm.protocolVersion()
|
|
18828
19487
|
);
|
|
@@ -18878,7 +19537,7 @@ var NodeUserAuthorization = class {
|
|
|
18878
19537
|
}
|
|
18879
19538
|
this.tinycloudHosts = [overrideHost];
|
|
18880
19539
|
}
|
|
18881
|
-
const signingAddress = (0,
|
|
19540
|
+
const signingAddress = (0, import_sdk_core4.canonicalizeAddress)(await this.signer.getAddress());
|
|
18882
19541
|
const signingChainId = await this.signer.getChainId();
|
|
18883
19542
|
await this.resolveTinyCloudHostsForSignIn(signingAddress, signingChainId);
|
|
18884
19543
|
const { prepared, keyId, jwk } = await this.prepareSessionForSigning();
|
|
@@ -18983,8 +19642,8 @@ var NodeUserAuthorization = class {
|
|
|
18983
19642
|
"signInWithOpenKeyResult requires prepared.siwe (the SDK-generated SIWE the sign-in was proposed with)"
|
|
18984
19643
|
);
|
|
18985
19644
|
}
|
|
18986
|
-
const expectedAddress = (0,
|
|
18987
|
-
if ((0,
|
|
19645
|
+
const expectedAddress = (0, import_sdk_core4.canonicalizeAddress)(await this.signer.getAddress());
|
|
19646
|
+
if ((0, import_sdk_core4.canonicalizeAddress)(result.address) !== expectedAddress) {
|
|
18988
19647
|
throw new Error(
|
|
18989
19648
|
`OpenKey returned signature from ${result.address} but expected ${expectedAddress}`
|
|
18990
19649
|
);
|
|
@@ -19009,15 +19668,15 @@ var NodeUserAuthorization = class {
|
|
|
19009
19668
|
`OpenKey signature verification failed${type ? `: ${type}` : ""}${details}`
|
|
19010
19669
|
);
|
|
19011
19670
|
}
|
|
19012
|
-
if ((0,
|
|
19671
|
+
if ((0, import_sdk_core4.canonicalizeAddress)(parsedSignedSiwe.address) !== expectedAddress) {
|
|
19013
19672
|
throw new Error(
|
|
19014
19673
|
`OpenKey signedMessage.address (${parsedSignedSiwe.address}) does not match local signer address (${expectedAddress})`
|
|
19015
19674
|
);
|
|
19016
19675
|
}
|
|
19017
19676
|
const originalHasRecap = /(?:^|\n)-\s+urn:recap:/i.test(prepared.siwe);
|
|
19018
|
-
const originalFields = (0,
|
|
19019
|
-
const signedFields = (0,
|
|
19020
|
-
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, {
|
|
19021
19680
|
originalHasRecap
|
|
19022
19681
|
});
|
|
19023
19682
|
if (changedFields.length > 0) {
|
|
@@ -19028,20 +19687,20 @@ var NodeUserAuthorization = class {
|
|
|
19028
19687
|
let originalCaps;
|
|
19029
19688
|
let signedCaps;
|
|
19030
19689
|
try {
|
|
19031
|
-
originalCaps = (0,
|
|
19690
|
+
originalCaps = (0, import_sdk_core4.extractRecapAttenuations)(prepared.siwe);
|
|
19032
19691
|
} catch (err) {
|
|
19033
19692
|
throw new Error(
|
|
19034
19693
|
`Failed to decode prepared SIWE recap: ${err.message}`
|
|
19035
19694
|
);
|
|
19036
19695
|
}
|
|
19037
19696
|
try {
|
|
19038
|
-
signedCaps = (0,
|
|
19697
|
+
signedCaps = (0, import_sdk_core4.extractRecapAttenuations)(result.signedMessage);
|
|
19039
19698
|
} catch (err) {
|
|
19040
19699
|
throw new Error(
|
|
19041
19700
|
`Failed to decode OpenKey signedMessage recap: ${err.message}`
|
|
19042
19701
|
);
|
|
19043
19702
|
}
|
|
19044
|
-
const unauthorized = (0,
|
|
19703
|
+
const unauthorized = (0, import_sdk_core4.unauthorizedRecapCapabilities)(signedCaps, originalCaps);
|
|
19045
19704
|
if (unauthorized.length > 0) {
|
|
19046
19705
|
const previewLimit = 5;
|
|
19047
19706
|
const preview = unauthorized.slice(0, previewLimit).map((u) => `${u.resource}::${u.action}`).join(", ");
|
|
@@ -19058,7 +19717,7 @@ var NodeUserAuthorization = class {
|
|
|
19058
19717
|
const grantedPairs = /* @__PURE__ */ new Set();
|
|
19059
19718
|
const grantedFourPartIndex = /* @__PURE__ */ new Map();
|
|
19060
19719
|
for (const [resource, actions] of Object.entries(signedCaps)) {
|
|
19061
|
-
const { space, path } = (0,
|
|
19720
|
+
const { space, path } = (0, import_sdk_core4.parseCanonicalRecapResource)(resource);
|
|
19062
19721
|
for (const action of Object.keys(actions)) {
|
|
19063
19722
|
grantedPairs.add(`${resource}\0${action}`);
|
|
19064
19723
|
const slashIdx = action.indexOf("/");
|
|
@@ -19299,16 +19958,16 @@ var NodeUserAuthorization = class {
|
|
|
19299
19958
|
};
|
|
19300
19959
|
|
|
19301
19960
|
// src/account/AccountService.ts
|
|
19302
|
-
var
|
|
19961
|
+
var import_sdk_core5 = require("@tinycloud/sdk-core");
|
|
19303
19962
|
|
|
19304
19963
|
// src/DelegatedAccess.ts
|
|
19305
|
-
var
|
|
19964
|
+
var import_sdk_core6 = require("@tinycloud/sdk-core");
|
|
19306
19965
|
var DelegatedAccess = class {
|
|
19307
19966
|
constructor(session, delegation, host, invoke2, invokeAny2, telemetry) {
|
|
19308
19967
|
this.session = session;
|
|
19309
19968
|
this._delegation = delegation;
|
|
19310
19969
|
this.host = host;
|
|
19311
|
-
this._serviceContext = new
|
|
19970
|
+
this._serviceContext = new import_sdk_core6.ServiceContext({
|
|
19312
19971
|
invoke: invoke2,
|
|
19313
19972
|
invokeAny: invokeAny2,
|
|
19314
19973
|
fetch: globalThis.fetch.bind(globalThis),
|
|
@@ -19316,16 +19975,16 @@ var DelegatedAccess = class {
|
|
|
19316
19975
|
telemetry
|
|
19317
19976
|
});
|
|
19318
19977
|
const prefix = this._delegation.path.replace(/\/$/, "");
|
|
19319
|
-
this._kv = new
|
|
19978
|
+
this._kv = new import_sdk_core6.KVService({ prefix });
|
|
19320
19979
|
this._kv.initialize(this._serviceContext);
|
|
19321
19980
|
this._serviceContext.registerService("kv", this._kv);
|
|
19322
|
-
this._sql = new
|
|
19981
|
+
this._sql = new import_sdk_core6.SQLService({});
|
|
19323
19982
|
this._sql.initialize(this._serviceContext);
|
|
19324
19983
|
this._serviceContext.registerService("sql", this._sql);
|
|
19325
|
-
this._duckdb = new
|
|
19984
|
+
this._duckdb = new import_sdk_core6.DuckDbService({});
|
|
19326
19985
|
this._duckdb.initialize(this._serviceContext);
|
|
19327
19986
|
this._serviceContext.registerService("duckdb", this._duckdb);
|
|
19328
|
-
this._hooks = new
|
|
19987
|
+
this._hooks = new import_sdk_core6.HooksService({});
|
|
19329
19988
|
this._hooks.initialize(this._serviceContext);
|
|
19330
19989
|
this._serviceContext.registerService("hooks", this._hooks);
|
|
19331
19990
|
const serviceSession = {
|
|
@@ -19475,7 +20134,7 @@ function createWasmKeyProvider(sessionManager) {
|
|
|
19475
20134
|
}
|
|
19476
20135
|
|
|
19477
20136
|
// src/delegateToHelpers.ts
|
|
19478
|
-
var
|
|
20137
|
+
var import_sdk_core7 = require("@tinycloud/sdk-core");
|
|
19479
20138
|
function legacyParamsToPermissionEntries(actions, path, spaceIdOverride) {
|
|
19480
20139
|
const byService = /* @__PURE__ */ new Map();
|
|
19481
20140
|
for (const a of actions) {
|
|
@@ -19506,7 +20165,7 @@ function legacyParamsToPermissionEntries(actions, path, spaceIdOverride) {
|
|
|
19506
20165
|
}
|
|
19507
20166
|
return entries;
|
|
19508
20167
|
}
|
|
19509
|
-
var DEFAULT_DELEGATION_EXPIRY_MS =
|
|
20168
|
+
var DEFAULT_DELEGATION_EXPIRY_MS = import_sdk_core7.EXPIRY.SESSION_MS;
|
|
19510
20169
|
function resolveExpiryMs(expiry) {
|
|
19511
20170
|
if (expiry === void 0) {
|
|
19512
20171
|
return DEFAULT_DELEGATION_EXPIRY_MS;
|
|
@@ -19519,10 +20178,10 @@ function resolveExpiryMs(expiry) {
|
|
|
19519
20178
|
}
|
|
19520
20179
|
return expiry;
|
|
19521
20180
|
}
|
|
19522
|
-
return (0,
|
|
20181
|
+
return (0, import_sdk_core7.parseExpiry)(expiry);
|
|
19523
20182
|
}
|
|
19524
20183
|
function extractSiweExpiration(siwe) {
|
|
19525
|
-
const parsed = new
|
|
20184
|
+
const parsed = new import_sdk_core7.SiweMessage(siwe);
|
|
19526
20185
|
if (parsed.expirationTime === void 0 || parsed.expirationTime === null) {
|
|
19527
20186
|
return void 0;
|
|
19528
20187
|
}
|
|
@@ -19536,7 +20195,7 @@ function extractSiweExpiration(siwe) {
|
|
|
19536
20195
|
}
|
|
19537
20196
|
|
|
19538
20197
|
// src/NodeSecretsService.ts
|
|
19539
|
-
var
|
|
20198
|
+
var import_sdk_core8 = require("@tinycloud/sdk-core");
|
|
19540
20199
|
var SECRETS_SPACE = "secrets";
|
|
19541
20200
|
function ok() {
|
|
19542
20201
|
return { ok: true, data: void 0 };
|
|
@@ -19569,7 +20228,7 @@ function secretActionName(action) {
|
|
|
19569
20228
|
}
|
|
19570
20229
|
function secretPermissionEntries(name, options, action, space, encryptionNetworkId) {
|
|
19571
20230
|
const entries = [];
|
|
19572
|
-
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;
|
|
19573
20232
|
entries.push({
|
|
19574
20233
|
service: "tinycloud.kv",
|
|
19575
20234
|
space,
|
|
@@ -19666,7 +20325,7 @@ var NodeSecretsService = class {
|
|
|
19666
20325
|
);
|
|
19667
20326
|
} catch (error) {
|
|
19668
20327
|
return secretsError(
|
|
19669
|
-
|
|
20328
|
+
import_sdk_core8.ErrorCodes.INVALID_INPUT,
|
|
19670
20329
|
error instanceof Error ? error.message : String(error),
|
|
19671
20330
|
error instanceof Error ? error : void 0
|
|
19672
20331
|
);
|
|
@@ -19676,7 +20335,7 @@ var NodeSecretsService = class {
|
|
|
19676
20335
|
}
|
|
19677
20336
|
if (!this.config.canEscalate()) {
|
|
19678
20337
|
return secretsError(
|
|
19679
|
-
|
|
20338
|
+
import_sdk_core8.ErrorCodes.PERMISSION_DENIED,
|
|
19680
20339
|
`Cannot autosign ${displayActionUrn(action)} for ${target}; TinyCloudNode needs wallet mode with a signer or privateKey.`
|
|
19681
20340
|
);
|
|
19682
20341
|
}
|
|
@@ -19685,7 +20344,7 @@ var NodeSecretsService = class {
|
|
|
19685
20344
|
return this.restoreUnlockAfterEscalation();
|
|
19686
20345
|
} catch (error) {
|
|
19687
20346
|
return secretsError(
|
|
19688
|
-
|
|
20347
|
+
import_sdk_core8.ErrorCodes.PERMISSION_DENIED,
|
|
19689
20348
|
error instanceof Error ? error.message : `Autosign escalation for ${displayActionUrn(action)} on ${target} failed.`,
|
|
19690
20349
|
error instanceof Error ? error : void 0
|
|
19691
20350
|
);
|
|
@@ -19706,10 +20365,10 @@ var NodeSecretsService = class {
|
|
|
19706
20365
|
return false;
|
|
19707
20366
|
}
|
|
19708
20367
|
const manifests = Array.isArray(manifest) ? manifest : [manifest];
|
|
19709
|
-
const requestedEntries = (0,
|
|
20368
|
+
const requestedEntries = (0, import_sdk_core8.expandPermissionEntries)(permissionEntries);
|
|
19710
20369
|
return requestedEntries.every(
|
|
19711
20370
|
(entry) => manifests.some((candidate) => {
|
|
19712
|
-
const resolved = (0,
|
|
20371
|
+
const resolved = (0, import_sdk_core8.resolveManifest)(candidate);
|
|
19713
20372
|
return resolved.resources.some(
|
|
19714
20373
|
(resource) => resource.service === entry.service && spaceMatches(
|
|
19715
20374
|
resource.space,
|
|
@@ -19725,8 +20384,8 @@ var NodeSecretsService = class {
|
|
|
19725
20384
|
// src/TinyCloudNode.ts
|
|
19726
20385
|
var DEFAULT_HOST = "https://node.tinycloud.xyz";
|
|
19727
20386
|
var DEFAULT_ENCRYPTION_NETWORK_NAME = "default";
|
|
19728
|
-
var NETWORK_CREATE_ACTION2 =
|
|
19729
|
-
var DECRYPT_ACTION2 =
|
|
20387
|
+
var NETWORK_CREATE_ACTION2 = import_sdk_core9.ENCRYPTION.NETWORK_CREATE;
|
|
20388
|
+
var DECRYPT_ACTION2 = import_sdk_core9.ENCRYPTION.DECRYPT;
|
|
19730
20389
|
var BOOTSTRAP_COMPLETION_MARKER_KEY = "system/bootstrap/complete";
|
|
19731
20390
|
var BOOTSTRAP_COMPLETION_MARKER_VERSION = 1;
|
|
19732
20391
|
var ACCEPTED_MARKER_VERSIONS = [BOOTSTRAP_COMPLETION_MARKER_VERSION];
|
|
@@ -19735,24 +20394,24 @@ function isSecretPayload(value) {
|
|
|
19735
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";
|
|
19736
20395
|
}
|
|
19737
20396
|
var ROOT_DELEGATION_ACTIONS = [
|
|
19738
|
-
|
|
19739
|
-
|
|
19740
|
-
|
|
19741
|
-
|
|
19742
|
-
|
|
19743
|
-
|
|
19744
|
-
|
|
19745
|
-
|
|
19746
|
-
|
|
19747
|
-
|
|
19748
|
-
|
|
19749
|
-
|
|
19750
|
-
|
|
19751
|
-
|
|
19752
|
-
|
|
19753
|
-
|
|
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
|
|
19754
20413
|
];
|
|
19755
|
-
var DEFAULT_SESSION_EXPIRATION_MS =
|
|
20414
|
+
var DEFAULT_SESSION_EXPIRATION_MS = import_sdk_core9.EXPIRY.SESSION_MS;
|
|
19756
20415
|
function unifiedRootAttenuation(capabilities) {
|
|
19757
20416
|
const attenuation = {};
|
|
19758
20417
|
for (const capability of capabilities) {
|
|
@@ -19798,7 +20457,7 @@ function isInteractiveSigner(config) {
|
|
|
19798
20457
|
}
|
|
19799
20458
|
function didPrincipalMatches2(actual, expected) {
|
|
19800
20459
|
try {
|
|
19801
|
-
return (0,
|
|
20460
|
+
return (0, import_sdk_core9.principalDidEquals)(actual, expected);
|
|
19802
20461
|
} catch {
|
|
19803
20462
|
return actual === expected;
|
|
19804
20463
|
}
|
|
@@ -20009,7 +20668,7 @@ function ownerDelegationPermissions(params) {
|
|
|
20009
20668
|
}
|
|
20010
20669
|
const slash = action.indexOf("/");
|
|
20011
20670
|
const service = slash === -1 ? "" : action.slice(0, slash);
|
|
20012
|
-
if (
|
|
20671
|
+
if (import_sdk_core9.SERVICE_LONG_TO_SHORT[service] === void 0) {
|
|
20013
20672
|
throw new Error("Owner delegation capabilities are unsupported");
|
|
20014
20673
|
}
|
|
20015
20674
|
const actions = byService.get(service) ?? [];
|
|
@@ -20025,7 +20684,7 @@ function ownerDelegationPermissions(params) {
|
|
|
20025
20684
|
}
|
|
20026
20685
|
const resources = /* @__PURE__ */ new Set();
|
|
20027
20686
|
for (const permission of permissions) {
|
|
20028
|
-
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) {
|
|
20029
20688
|
throw new Error("Owner delegation requires bounded capabilities");
|
|
20030
20689
|
}
|
|
20031
20690
|
const resourceKey = `${permission.service}\0${permission.path}`;
|
|
@@ -20040,9 +20699,9 @@ function ownerDelegationPermissions(params) {
|
|
|
20040
20699
|
}
|
|
20041
20700
|
actions.add(action);
|
|
20042
20701
|
}
|
|
20043
|
-
if (permission.service ===
|
|
20702
|
+
if (permission.service === import_sdk_core9.ENCRYPTION_PERMISSION_SERVICE) {
|
|
20044
20703
|
try {
|
|
20045
|
-
(0,
|
|
20704
|
+
(0, import_sdk_core9.parseNetworkId)(permission.path);
|
|
20046
20705
|
} catch {
|
|
20047
20706
|
throw new Error("Owner delegation encryption permission requires a canonical network URN");
|
|
20048
20707
|
}
|
|
@@ -20054,11 +20713,11 @@ function ownerPermissionsToAbilities(permissions) {
|
|
|
20054
20713
|
const abilities = {};
|
|
20055
20714
|
const rawAbilities = {};
|
|
20056
20715
|
for (const permission of permissions) {
|
|
20057
|
-
if (permission.service ===
|
|
20716
|
+
if (permission.service === import_sdk_core9.ENCRYPTION_PERMISSION_SERVICE) {
|
|
20058
20717
|
rawAbilities[permission.path] = [...permission.actions];
|
|
20059
20718
|
continue;
|
|
20060
20719
|
}
|
|
20061
|
-
const shortService =
|
|
20720
|
+
const shortService = import_sdk_core9.SERVICE_LONG_TO_SHORT[permission.service];
|
|
20062
20721
|
abilities[shortService] ?? (abilities[shortService] = {});
|
|
20063
20722
|
abilities[shortService][permission.path] = [...permission.actions];
|
|
20064
20723
|
}
|
|
@@ -20190,6 +20849,8 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20190
20849
|
this.confirmedHostedSpaceIds = /* @__PURE__ */ new Set();
|
|
20191
20850
|
/** Serializes account-registry writes for the active node instance. */
|
|
20192
20851
|
this.accountRegistryTail = Promise.resolve();
|
|
20852
|
+
/** Bounds best-effort registry work on the sign-in critical path. */
|
|
20853
|
+
this.accountRegistryDeadlineMs = 4e3;
|
|
20193
20854
|
/**
|
|
20194
20855
|
* True when the last signIn() detected an interactive signer and skipped
|
|
20195
20856
|
* client-side bootstrap. Apps can read this to know whether bootstrap was
|
|
@@ -20261,18 +20922,53 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20261
20922
|
if (!granted?.caveats?.length) {
|
|
20262
20923
|
return entry;
|
|
20263
20924
|
}
|
|
20264
|
-
if (entry.caveats !== void 0 && !(0,
|
|
20925
|
+
if (entry.caveats !== void 0 && !(0, import_sdk_core9.recapCaveatsEqual)(entry.caveats, granted.caveats)) {
|
|
20265
20926
|
throw new Error("Invocation caveats do not match signed ReCap authority.");
|
|
20266
20927
|
}
|
|
20267
20928
|
return { ...entry, caveats: cloneRecapCaveats(granted.caveats) };
|
|
20268
20929
|
});
|
|
20269
20930
|
return this.wasmBindings.invokeAny(invocationSession, caveatPreservingEntries, facts);
|
|
20270
20931
|
};
|
|
20932
|
+
assertValidReplicationConfig(config.replication);
|
|
20271
20933
|
this.explicitHost = config.host;
|
|
20272
20934
|
this.config = {
|
|
20273
20935
|
...config,
|
|
20274
20936
|
host: config.host ?? DEFAULT_HOST
|
|
20275
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
|
+
}
|
|
20276
20972
|
if (config.wasmBindings) {
|
|
20277
20973
|
this.wasmBindings = config.wasmBindings;
|
|
20278
20974
|
} else if (_TinyCloudNode.nodeDefaults) {
|
|
@@ -20296,13 +20992,13 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20296
20992
|
}
|
|
20297
20993
|
this.sessionKeyJwk = JSON.parse(jwkStr);
|
|
20298
20994
|
this._serviceGraph = this.createServiceGraphLifetime();
|
|
20299
|
-
this._capabilityRegistry = new
|
|
20995
|
+
this._capabilityRegistry = new import_sdk_core9.CapabilityKeyRegistry();
|
|
20300
20996
|
this._keyProvider = new WasmKeyProvider({
|
|
20301
20997
|
sessionManager: this.sessionManager
|
|
20302
20998
|
});
|
|
20303
|
-
this.notificationHandler = config.notificationHandler ?? new
|
|
20999
|
+
this.notificationHandler = config.notificationHandler ?? new import_sdk_core9.SilentNotificationHandler();
|
|
20304
21000
|
const receiveOnlyGraph = this._serviceGraph;
|
|
20305
|
-
this._sharingService = new
|
|
21001
|
+
this._sharingService = new import_sdk_core9.SharingService({
|
|
20306
21002
|
hosts: [this.config.host],
|
|
20307
21003
|
// session: undefined - not needed for receive()
|
|
20308
21004
|
invoke: receiveOnlyGraph.invoke,
|
|
@@ -20318,8 +21014,8 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20318
21014
|
// delegationManager: undefined - not needed for receive()
|
|
20319
21015
|
createKVService: (config2) => {
|
|
20320
21016
|
const prefix = config2.pathPrefix?.replace(/\/$/, "");
|
|
20321
|
-
const kvService = new
|
|
20322
|
-
const kvContext = receiveOnlyGraph.track(new
|
|
21017
|
+
const kvService = new import_sdk_core9.KVService({ prefix });
|
|
21018
|
+
const kvContext = receiveOnlyGraph.track(new import_sdk_core9.ServiceContext({
|
|
20323
21019
|
invoke: config2.invoke,
|
|
20324
21020
|
fetch: config2.fetch ?? globalThis.fetch.bind(globalThis),
|
|
20325
21021
|
hosts: config2.hosts,
|
|
@@ -20392,10 +21088,17 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20392
21088
|
nonce: config.nonce,
|
|
20393
21089
|
siweConfig: config.siweConfig,
|
|
20394
21090
|
manifest: useBootstrapSignInRequest ? void 0 : config.manifest,
|
|
20395
|
-
capabilityRequest: useBootstrapSignInRequest ? config.includeAccountRegistryPermissions === false ?
|
|
20396
|
-
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
|
|
20397
21100
|
});
|
|
20398
|
-
this.tc = new
|
|
21101
|
+
this.tc = new import_sdk_core9.TinyCloud(this.auth, {
|
|
20399
21102
|
invokeAny: this.invokeAnyWithRuntimePermissions,
|
|
20400
21103
|
telemetry: config.telemetry
|
|
20401
21104
|
});
|
|
@@ -20475,7 +21178,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20475
21178
|
/** Publish the active owner Node as a session-signed registry record. */
|
|
20476
21179
|
async publishActiveNodeLocation(registryUrl, fetchFn = globalThis.fetch.bind(globalThis)) {
|
|
20477
21180
|
const node = await this.activeNodeIdentity();
|
|
20478
|
-
return (0,
|
|
21181
|
+
return (0, import_sdk_core9.publishLocationRecord)({
|
|
20479
21182
|
registryUrl,
|
|
20480
21183
|
subject: this.credentialHolderDid,
|
|
20481
21184
|
nodeOrigin: node.origin,
|
|
@@ -20492,7 +21195,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20492
21195
|
*/
|
|
20493
21196
|
get did() {
|
|
20494
21197
|
if (this._address) {
|
|
20495
|
-
return (0,
|
|
21198
|
+
return (0, import_sdk_core9.pkhDid)(this._address, this._chainId);
|
|
20496
21199
|
}
|
|
20497
21200
|
return this.sessionManager.getDID(this.sessionKeyId);
|
|
20498
21201
|
}
|
|
@@ -20529,7 +21232,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20529
21232
|
/** Normalize signed capabilities without collapsing nested encryption into raw authority. */
|
|
20530
21233
|
projectSignedRecapCapabilities(siwe) {
|
|
20531
21234
|
const projected = this.parseRecapWithCaveats(siwe).map((entry) => {
|
|
20532
|
-
const normalized = (0,
|
|
21235
|
+
const normalized = (0, import_sdk_core9.parseRecapCapabilities)(() => [entry], siwe)[0];
|
|
20533
21236
|
if (normalized.service !== "tinycloud.encryption") return normalized;
|
|
20534
21237
|
if (!this.isEncryptionNetworkOperation("encryption", entry.path, entry.space)) {
|
|
20535
21238
|
return { ...normalized, space: entry.space };
|
|
@@ -20574,14 +21277,14 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20574
21277
|
if (!this._address) {
|
|
20575
21278
|
return void 0;
|
|
20576
21279
|
}
|
|
20577
|
-
return this.wasmBindings.makeSpaceId(this._address, this._chainId,
|
|
21280
|
+
return this.wasmBindings.makeSpaceId(this._address, this._chainId, import_sdk_core9.ACCOUNT_REGISTRY_SPACE);
|
|
20578
21281
|
}
|
|
20579
21282
|
/**
|
|
20580
21283
|
* Account-level application and delegation helpers.
|
|
20581
21284
|
*/
|
|
20582
21285
|
get account() {
|
|
20583
21286
|
if (!this._account) {
|
|
20584
|
-
this._account = new
|
|
21287
|
+
this._account = new import_sdk_core5.AccountService({
|
|
20585
21288
|
getDid: () => this.did,
|
|
20586
21289
|
getHost: () => this.hosts[0] ?? this.config.host,
|
|
20587
21290
|
getPrimarySpaceId: () => this.spaceId,
|
|
@@ -20627,7 +21330,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20627
21330
|
}
|
|
20628
21331
|
await this.accountRegistryTail;
|
|
20629
21332
|
await this.wasmBindings.ensureInitialized?.();
|
|
20630
|
-
this._address = (0,
|
|
21333
|
+
this._address = (0, import_sdk_core9.canonicalizeAddress)(await this.signer.getAddress());
|
|
20631
21334
|
this._chainId = await this.signer.getChainId();
|
|
20632
21335
|
this._kv = void 0;
|
|
20633
21336
|
this._sql = void 0;
|
|
@@ -20644,6 +21347,9 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20644
21347
|
this.confirmedHostedSpaceIds.clear();
|
|
20645
21348
|
await this.tc.signIn(options);
|
|
20646
21349
|
this.syncResolvedHostFromAuth();
|
|
21350
|
+
this.replicationDelegateSession = void 0;
|
|
21351
|
+
this.replicationScopeError = void 0;
|
|
21352
|
+
if (this.replicationRuntime) await (await this.replicationRuntime).unbind();
|
|
20647
21353
|
const oldGraph = this._serviceGraph;
|
|
20648
21354
|
this._serviceGraph = this.createServiceGraphLifetime();
|
|
20649
21355
|
oldGraph.retire();
|
|
@@ -20653,7 +21359,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20653
21359
|
this.sessionKeyId = signedInSession.sessionKey;
|
|
20654
21360
|
this.sessionKeyJwk = signedInSession.jwk;
|
|
20655
21361
|
}
|
|
20656
|
-
this.initializeServices();
|
|
21362
|
+
await this.initializeServices();
|
|
20657
21363
|
const primarySession = this.currentTinyCloudSession();
|
|
20658
21364
|
if (primarySession) {
|
|
20659
21365
|
this.registerPrimarySessionGrant(primarySession);
|
|
@@ -20661,10 +21367,11 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20661
21367
|
const bootstrapped = await this.bootstrapAccountIfNeeded();
|
|
20662
21368
|
await this.ensureRequestedEncryptionNetworks();
|
|
20663
21369
|
if (!bootstrapped && this.config.manifest === void 0 && this.config.capabilityRequest === void 0) {
|
|
20664
|
-
await this.ensureOwnedSpaceHostedById(this.ownedSpaceId(
|
|
21370
|
+
await this.ensureOwnedSpaceHostedById(this.ownedSpaceId(import_sdk_core9.SECRETS_SPACE));
|
|
20665
21371
|
}
|
|
20666
21372
|
if (!bootstrapped) {
|
|
20667
21373
|
this.scheduleAccountRegistrySync();
|
|
21374
|
+
await this.accountRegistryTail;
|
|
20668
21375
|
}
|
|
20669
21376
|
this.notificationHandler.success("Successfully signed in");
|
|
20670
21377
|
}
|
|
@@ -20692,7 +21399,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20692
21399
|
this._bootstrapStatus = { skipped: true, reason: "interactive-signer" };
|
|
20693
21400
|
return false;
|
|
20694
21401
|
}
|
|
20695
|
-
const steps = (0,
|
|
21402
|
+
const steps = (0, import_sdk_core9.bootstrapSteps)(this._address, this._chainId);
|
|
20696
21403
|
try {
|
|
20697
21404
|
const decision = await this.resolveBootstrapDecision(steps);
|
|
20698
21405
|
if (decision.action === "skip") {
|
|
@@ -20730,7 +21437,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20730
21437
|
if (!auth) {
|
|
20731
21438
|
throw new Error("Account bootstrap requires an active wallet session");
|
|
20732
21439
|
}
|
|
20733
|
-
const accountSpaceId = this.ownedSpaceId(
|
|
21440
|
+
const accountSpaceId = this.ownedSpaceId(import_sdk_core9.ACCOUNT_REGISTRY_SPACE);
|
|
20734
21441
|
const skipped = auth.lastActivationSkippedSpaceIds;
|
|
20735
21442
|
if (skipped.includes(accountSpaceId)) return { action: "run", mode: "fresh" };
|
|
20736
21443
|
if (skipped.some((spaceId) => enshrinedSpaceIds.has(spaceId))) {
|
|
@@ -20753,7 +21460,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20753
21460
|
}
|
|
20754
21461
|
return { action: "run", mode: "repair" };
|
|
20755
21462
|
}
|
|
20756
|
-
if (marker.error.code ===
|
|
21463
|
+
if (marker.error.code === import_sdk_core9.ErrorCodes.KV_NOT_FOUND && this.markerReadIsUnhostedSpace(marker.error.meta)) {
|
|
20757
21464
|
return { action: "run", mode: "fresh" };
|
|
20758
21465
|
}
|
|
20759
21466
|
} catch (err) {
|
|
@@ -20767,7 +21474,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20767
21474
|
return { action: "run", mode: "repair" };
|
|
20768
21475
|
}
|
|
20769
21476
|
async readBootstrapCompletionMarker() {
|
|
20770
|
-
return this.kvForSpace(this.ownedSpaceId(
|
|
21477
|
+
return this.kvForSpace(this.ownedSpaceId(import_sdk_core9.ACCOUNT_REGISTRY_SPACE)).get(
|
|
20771
21478
|
BOOTSTRAP_COMPLETION_MARKER_KEY
|
|
20772
21479
|
);
|
|
20773
21480
|
}
|
|
@@ -20776,7 +21483,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20776
21483
|
throw new Error("Bootstrap completion marker requires an active wallet session");
|
|
20777
21484
|
}
|
|
20778
21485
|
const canonicalStepIds = new Set(
|
|
20779
|
-
(0,
|
|
21486
|
+
(0, import_sdk_core9.bootstrapSteps)(this._address, this._chainId).map((step) => step.id)
|
|
20780
21487
|
);
|
|
20781
21488
|
const providedStepIds = new Set(steps.map((step) => step.id));
|
|
20782
21489
|
if (canonicalStepIds.size !== providedStepIds.size || [...canonicalStepIds].some((stepId) => !providedStepIds.has(stepId))) {
|
|
@@ -20787,7 +21494,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20787
21494
|
stepIds: [...canonicalStepIds],
|
|
20788
21495
|
completedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
20789
21496
|
};
|
|
20790
|
-
const written = await this.kvForSpace(this.ownedSpaceId(
|
|
21497
|
+
const written = await this.kvForSpace(this.ownedSpaceId(import_sdk_core9.ACCOUNT_REGISTRY_SPACE)).put(
|
|
20791
21498
|
BOOTSTRAP_COMPLETION_MARKER_KEY,
|
|
20792
21499
|
marker
|
|
20793
21500
|
);
|
|
@@ -20826,7 +21533,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20826
21533
|
const warnings = [];
|
|
20827
21534
|
const primarySession = auth.tinyCloudSession;
|
|
20828
21535
|
const defaultSpaceId = this.ownedSpaceId("default");
|
|
20829
|
-
const canReusePrimaryBootstrapSession = primarySession?.spaceId === defaultSpaceId && auth.capabilityRequest ===
|
|
21536
|
+
const canReusePrimaryBootstrapSession = primarySession?.spaceId === defaultSpaceId && auth.capabilityRequest === import_sdk_core9.BOOTSTRAP_SESSION_REQUESTS.default;
|
|
20830
21537
|
for (const step of steps) {
|
|
20831
21538
|
if (step.kind !== "session") continue;
|
|
20832
21539
|
if (step.space === "default" && canReusePrimaryBootstrapSession && primarySession) {
|
|
@@ -20841,7 +21548,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20841
21548
|
try {
|
|
20842
21549
|
session = await auth.createBootstrapSession({
|
|
20843
21550
|
spaceId: step.spaceId,
|
|
20844
|
-
capabilityRequest: step.request ??
|
|
21551
|
+
capabilityRequest: step.request ?? import_sdk_core9.BOOTSTRAP_SESSION_REQUESTS[step.space],
|
|
20845
21552
|
rawAbilities
|
|
20846
21553
|
});
|
|
20847
21554
|
} catch (err) {
|
|
@@ -20871,7 +21578,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20871
21578
|
if (!session) {
|
|
20872
21579
|
throw new Error(`Missing bootstrap session for ${step.space}`);
|
|
20873
21580
|
}
|
|
20874
|
-
const activated = await (0,
|
|
21581
|
+
const activated = await (0, import_sdk_core9.activateSessionWithHost)(host, session.delegationHeader);
|
|
20875
21582
|
if (!activated.success || activated.skipped?.includes(step.spaceId)) {
|
|
20876
21583
|
throw Object.assign(
|
|
20877
21584
|
new Error(
|
|
@@ -20882,7 +21589,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20882
21589
|
}
|
|
20883
21590
|
this.registerBootstrapRuntimeGrant(
|
|
20884
21591
|
session,
|
|
20885
|
-
|
|
21592
|
+
import_sdk_core9.BOOTSTRAP_SESSION_REQUESTS[step.space],
|
|
20886
21593
|
rawAbilitiesBySpace.get(step.space)
|
|
20887
21594
|
);
|
|
20888
21595
|
}
|
|
@@ -20931,7 +21638,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20931
21638
|
}
|
|
20932
21639
|
if (step.kind === "seed-applications") {
|
|
20933
21640
|
const registered = await this.account.applications.register(
|
|
20934
|
-
step.manifests.length > 0 ? [...step.manifests] :
|
|
21641
|
+
step.manifests.length > 0 ? [...step.manifests] : import_sdk_core9.TINYCLOUD_SECRETS_BOOTSTRAP_MANIFEST,
|
|
20935
21642
|
// The write is an INSERT OR REPLACE and is safe to repeat during a
|
|
20936
21643
|
// repair, so skip the manifest-hash pre-read.
|
|
20937
21644
|
{ assumeUnregistered: true }
|
|
@@ -20950,7 +21657,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20950
21657
|
migrations: [
|
|
20951
21658
|
{
|
|
20952
21659
|
id: "001_initial",
|
|
20953
|
-
sql: [...
|
|
21660
|
+
sql: [...import_sdk_core9.SECRET_RECORDS_SCHEMA]
|
|
20954
21661
|
}
|
|
20955
21662
|
]
|
|
20956
21663
|
});
|
|
@@ -21117,7 +21824,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21117
21824
|
provenance: "primary"
|
|
21118
21825
|
});
|
|
21119
21826
|
}
|
|
21120
|
-
async writeManifestRegistryRecords() {
|
|
21827
|
+
async writeManifestRegistryRecords(account, signal) {
|
|
21121
21828
|
const request = this.capabilityRequest;
|
|
21122
21829
|
if (!request || request.registryRecords.length === 0) {
|
|
21123
21830
|
return;
|
|
@@ -21125,9 +21832,10 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21125
21832
|
if (!this.auth || !this.signer) {
|
|
21126
21833
|
throw new Error("Manifest registry write requires wallet mode");
|
|
21127
21834
|
}
|
|
21128
|
-
const accountSpaceId = this.ownedSpaceId(
|
|
21129
|
-
await this.ensureOwnedSpaceHostedById(accountSpaceId);
|
|
21130
|
-
|
|
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);
|
|
21131
21839
|
if (!result.ok) {
|
|
21132
21840
|
throw Object.assign(
|
|
21133
21841
|
new Error(`Failed to write manifest registry records: ${result.error.message}`),
|
|
@@ -21135,34 +21843,113 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21135
21843
|
);
|
|
21136
21844
|
}
|
|
21137
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
|
+
}
|
|
21138
21895
|
scheduleAccountRegistrySync() {
|
|
21139
21896
|
const session = this.currentTinyCloudSession();
|
|
21140
21897
|
if (!session || this.pendingAccountRegistrySync?.session === session) {
|
|
21141
21898
|
return;
|
|
21142
21899
|
}
|
|
21900
|
+
const controller = new AbortController();
|
|
21901
|
+
const deadline = setTimeout(
|
|
21902
|
+
() => controller.abort(new DOMException("Account registry deadline exceeded", "TimeoutError")),
|
|
21903
|
+
this.accountRegistryDeadlineMs
|
|
21904
|
+
);
|
|
21143
21905
|
const promise = this.enqueueAccountRegistryOperation(session, async () => {
|
|
21144
|
-
|
|
21145
|
-
|
|
21146
|
-
|
|
21147
|
-
|
|
21148
|
-
|
|
21149
|
-
|
|
21150
|
-
|
|
21151
|
-
|
|
21152
|
-
|
|
21153
|
-
|
|
21154
|
-
|
|
21155
|
-
|
|
21156
|
-
|
|
21157
|
-
|
|
21158
|
-
|
|
21159
|
-
|
|
21160
|
-
|
|
21161
|
-
|
|
21162
|
-
|
|
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
|
+
}
|
|
21163
21945
|
}
|
|
21946
|
+
}, controller.signal);
|
|
21947
|
+
} finally {
|
|
21948
|
+
for (const operationContext of registry.contexts) {
|
|
21949
|
+
operationContext.retire();
|
|
21164
21950
|
}
|
|
21165
|
-
|
|
21951
|
+
clearTimeout(deadline);
|
|
21952
|
+
}
|
|
21166
21953
|
});
|
|
21167
21954
|
this.pendingAccountRegistrySync = { session, promise };
|
|
21168
21955
|
const clearPendingSync = () => {
|
|
@@ -21171,6 +21958,10 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21171
21958
|
}
|
|
21172
21959
|
};
|
|
21173
21960
|
void promise.then(clearPendingSync, clearPendingSync);
|
|
21961
|
+
void promise.then(
|
|
21962
|
+
() => clearTimeout(deadline),
|
|
21963
|
+
() => clearTimeout(deadline)
|
|
21964
|
+
);
|
|
21174
21965
|
}
|
|
21175
21966
|
enqueueAccountRegistryOperation(session, task) {
|
|
21176
21967
|
const operation = this.accountRegistryTail.then(async () => {
|
|
@@ -21206,15 +21997,23 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21206
21997
|
(operation) => operation.service === "space" && this.actionContains(operation.action, "tinycloud.space/list")
|
|
21207
21998
|
);
|
|
21208
21999
|
}
|
|
21209
|
-
async withAccountRegistryRetry(task) {
|
|
22000
|
+
async withAccountRegistryRetry(task, signal) {
|
|
21210
22001
|
const delays = [250, 1e3, 3e3];
|
|
21211
22002
|
let lastError;
|
|
21212
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
|
+
}
|
|
21213
22008
|
try {
|
|
21214
22009
|
await task();
|
|
21215
22010
|
return;
|
|
21216
22011
|
} catch (error) {
|
|
21217
|
-
|
|
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);
|
|
21218
22017
|
const message = error instanceof Error ? error.message : String(error);
|
|
21219
22018
|
const isAuthorizationVerdict = verdict === void 0 ? /Unauthorized Action|\b(?:401|403)\b/.test(message) : verdict !== "other";
|
|
21220
22019
|
if (isAuthorizationVerdict) {
|
|
@@ -21224,14 +22023,30 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21224
22023
|
);
|
|
21225
22024
|
return;
|
|
21226
22025
|
}
|
|
21227
|
-
if ((0,
|
|
21228
|
-
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
|
+
);
|
|
21229
22031
|
return;
|
|
21230
22032
|
}
|
|
21231
22033
|
lastError = error;
|
|
21232
22034
|
if (attempt < delays.length - 1) {
|
|
21233
|
-
await new Promise((resolve) =>
|
|
21234
|
-
|
|
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
|
+
});
|
|
22049
|
+
}
|
|
21235
22050
|
}
|
|
21236
22051
|
}
|
|
21237
22052
|
console.warn(
|
|
@@ -21246,7 +22061,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21246
22061
|
}
|
|
21247
22062
|
const networkIds = /* @__PURE__ */ new Set();
|
|
21248
22063
|
for (const resource of request.resources) {
|
|
21249
|
-
if (resource.service ===
|
|
22064
|
+
if (resource.service === import_sdk_core9.ENCRYPTION_PERMISSION_SERVICE && resource.path.startsWith("urn:tinycloud:encryption:") && resource.actions.includes(DECRYPT_ACTION2)) {
|
|
21250
22065
|
networkIds.add(resource.path);
|
|
21251
22066
|
}
|
|
21252
22067
|
}
|
|
@@ -21257,7 +22072,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21257
22072
|
return;
|
|
21258
22073
|
}
|
|
21259
22074
|
for (const networkId of this.requestedEncryptionNetworkIds()) {
|
|
21260
|
-
const parsed = (0,
|
|
22075
|
+
const parsed = (0, import_sdk_core9.parseNetworkId)(networkId);
|
|
21261
22076
|
if (!didPrincipalMatches2(parsed.ownerDid, this.did)) {
|
|
21262
22077
|
continue;
|
|
21263
22078
|
}
|
|
@@ -21280,7 +22095,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21280
22095
|
* self-revealing: the next write to the space fails immediately and loudly
|
|
21281
22096
|
* with `404 Space not found`.
|
|
21282
22097
|
*/
|
|
21283
|
-
async ensureOwnedSpaceHostedById(spaceId) {
|
|
22098
|
+
async ensureOwnedSpaceHostedById(spaceId, signal) {
|
|
21284
22099
|
if (!this.auth) {
|
|
21285
22100
|
throw new Error("Owned space hosting requires wallet mode");
|
|
21286
22101
|
}
|
|
@@ -21295,7 +22110,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21295
22110
|
if (!host) {
|
|
21296
22111
|
throw new Error("Owned space hosting requires a TinyCloud host");
|
|
21297
22112
|
}
|
|
21298
|
-
const activation = await (0,
|
|
22113
|
+
const activation = await (0, import_sdk_core9.activateSessionWithHost)(host, session.delegationHeader, signal);
|
|
21299
22114
|
if (activation.success && !activation.skipped?.includes(spaceId)) {
|
|
21300
22115
|
this.confirmedHostedSpaceIds.add(spaceId);
|
|
21301
22116
|
return;
|
|
@@ -21306,15 +22121,16 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21306
22121
|
{ cause: activation }
|
|
21307
22122
|
);
|
|
21308
22123
|
}
|
|
21309
|
-
const
|
|
22124
|
+
const authorization = this.auth;
|
|
22125
|
+
const created = signal ? await authorization.hostOwnedSpaceResult(spaceId, void 0, signal) : await authorization.hostOwnedSpaceResult(spaceId);
|
|
21310
22126
|
if (!created.success) {
|
|
21311
22127
|
throw Object.assign(
|
|
21312
22128
|
new Error(`Failed to create owned space ${spaceId}: ${describeHostFailure2(created)}`),
|
|
21313
22129
|
{ cause: created }
|
|
21314
22130
|
);
|
|
21315
22131
|
}
|
|
21316
|
-
|
|
21317
|
-
const retry = await (0,
|
|
22132
|
+
if (signal?.aborted) throw signal.reason;
|
|
22133
|
+
const retry = await (0, import_sdk_core9.activateSessionWithHost)(host, session.delegationHeader, signal);
|
|
21318
22134
|
if (!retry.success || retry.skipped?.includes(spaceId)) {
|
|
21319
22135
|
throw Object.assign(
|
|
21320
22136
|
new Error(
|
|
@@ -21362,7 +22178,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21362
22178
|
{ cause: hosted }
|
|
21363
22179
|
);
|
|
21364
22180
|
}
|
|
21365
|
-
const activation = await (0,
|
|
22181
|
+
const activation = await (0, import_sdk_core9.activateSessionWithHost)(
|
|
21366
22182
|
host,
|
|
21367
22183
|
session.delegationHeader
|
|
21368
22184
|
);
|
|
@@ -21550,7 +22366,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21550
22366
|
}
|
|
21551
22367
|
let restoredAddress;
|
|
21552
22368
|
try {
|
|
21553
|
-
restoredAddress = hasPersistedProof ? (0,
|
|
22369
|
+
restoredAddress = hasPersistedProof ? (0, import_sdk_core9.canonicalizeAddress)(sessionData.address) : void 0;
|
|
21554
22370
|
} catch {
|
|
21555
22371
|
throw new InvalidRestoredSessionError("Persisted session has an invalid wallet address.");
|
|
21556
22372
|
}
|
|
@@ -21592,7 +22408,35 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21592
22408
|
const stagedHost = resolvedHost ?? this.config.host;
|
|
21593
22409
|
const stagedAddress = restoredAddress;
|
|
21594
22410
|
const stagedChainId = sessionData.chainId ?? 1;
|
|
21595
|
-
|
|
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;
|
|
21596
22440
|
const serviceSession = {
|
|
21597
22441
|
delegationHeader: sessionData.delegationHeader,
|
|
21598
22442
|
delegationCid: sessionData.delegationCid,
|
|
@@ -21620,7 +22464,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21620
22464
|
stagedSessionExpiry,
|
|
21621
22465
|
stagedRecap
|
|
21622
22466
|
);
|
|
21623
|
-
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;
|
|
21624
22468
|
const stagedGraph = this.stageRestoredServiceGraph({
|
|
21625
22469
|
host: stagedHost,
|
|
21626
22470
|
manager: stagedManager,
|
|
@@ -21670,7 +22514,18 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21670
22514
|
} else {
|
|
21671
22515
|
this._restoredTcSession = stagedTcSession;
|
|
21672
22516
|
}
|
|
22517
|
+
this.replicationDelegateSession = compactReplicationSession;
|
|
22518
|
+
this.replicationScopeError = replicationScopeError;
|
|
22519
|
+
if (this.replicationRuntime) await (await this.replicationRuntime).unbind();
|
|
21673
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);
|
|
21674
22529
|
oldCore?.retireServices?.();
|
|
21675
22530
|
}
|
|
21676
22531
|
stagePrimarySessionState(session, verificationMethod, host, sessionExpiry, recap) {
|
|
@@ -21721,7 +22576,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21721
22576
|
}
|
|
21722
22577
|
stageRestoredServiceGraph(input) {
|
|
21723
22578
|
const graph = this.createServiceGraphLifetime();
|
|
21724
|
-
const core = this.auth ? new
|
|
22579
|
+
const core = this.auth ? new import_sdk_core9.TinyCloud(this.auth, {
|
|
21725
22580
|
invokeAny: graph.invokeAny,
|
|
21726
22581
|
telemetry: this.config.telemetry
|
|
21727
22582
|
}) : null;
|
|
@@ -21730,23 +22585,23 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21730
22585
|
const coreContext = graph.track(core.serviceContext);
|
|
21731
22586
|
coreContext.setSession(input.serviceSession);
|
|
21732
22587
|
}
|
|
21733
|
-
const serviceContext = graph.track(new
|
|
22588
|
+
const serviceContext = graph.track(new import_sdk_core9.ServiceContext({
|
|
21734
22589
|
invoke: graph.invoke,
|
|
21735
22590
|
invokeAny: graph.invokeAny,
|
|
21736
22591
|
fetch: graph.fetch,
|
|
21737
22592
|
hosts: [input.host],
|
|
21738
22593
|
telemetry: this.config.telemetry
|
|
21739
22594
|
}));
|
|
21740
|
-
const kv = new
|
|
22595
|
+
const kv = new import_sdk_core9.KVService({});
|
|
21741
22596
|
kv.initialize(serviceContext);
|
|
21742
22597
|
serviceContext.registerService("kv", kv);
|
|
21743
|
-
const sql = new
|
|
22598
|
+
const sql = new import_sdk_core9.SQLService({});
|
|
21744
22599
|
sql.initialize(serviceContext);
|
|
21745
22600
|
serviceContext.registerService("sql", sql);
|
|
21746
|
-
const duckdb = new
|
|
22601
|
+
const duckdb = new import_sdk_core9.DuckDbService({});
|
|
21747
22602
|
duckdb.initialize(serviceContext);
|
|
21748
22603
|
serviceContext.registerService("duckdb", duckdb);
|
|
21749
|
-
const hooks = new
|
|
22604
|
+
const hooks = new import_sdk_core9.HooksService({});
|
|
21750
22605
|
hooks.initialize(serviceContext);
|
|
21751
22606
|
serviceContext.registerService("hooks", hooks);
|
|
21752
22607
|
serviceContext.setSession(input.serviceSession);
|
|
@@ -21769,7 +22624,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21769
22624
|
});
|
|
21770
22625
|
vault.initialize(serviceContext);
|
|
21771
22626
|
serviceContext.registerService("vault", vault);
|
|
21772
|
-
const capabilityRegistry = new
|
|
22627
|
+
const capabilityRegistry = new import_sdk_core9.CapabilityKeyRegistry();
|
|
21773
22628
|
if (input.tinyCloudSession) {
|
|
21774
22629
|
const session = input.tinyCloudSession;
|
|
21775
22630
|
const delegations = input.recap.map((entry) => ({
|
|
@@ -21793,7 +22648,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21793
22648
|
}, delegations);
|
|
21794
22649
|
}
|
|
21795
22650
|
}
|
|
21796
|
-
const delegationManager = new
|
|
22651
|
+
const delegationManager = new import_sdk_core9.DelegationManager({
|
|
21797
22652
|
hosts: [input.host],
|
|
21798
22653
|
accountSpaceId: input.accountSpaceId,
|
|
21799
22654
|
session: input.serviceSession,
|
|
@@ -21802,7 +22657,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21802
22657
|
fetch: graph.fetch
|
|
21803
22658
|
});
|
|
21804
22659
|
const keyProvider = new WasmKeyProvider({ sessionManager: input.manager });
|
|
21805
|
-
const sharingService = new
|
|
22660
|
+
const sharingService = new import_sdk_core9.SharingService({
|
|
21806
22661
|
hosts: [input.host],
|
|
21807
22662
|
invoke: graph.invoke,
|
|
21808
22663
|
fetch: graph.fetch,
|
|
@@ -21815,8 +22670,8 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21815
22670
|
return this.wasmBindings.computeCid(data, codec);
|
|
21816
22671
|
},
|
|
21817
22672
|
createKVService: (config) => {
|
|
21818
|
-
const service = new
|
|
21819
|
-
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({
|
|
21820
22675
|
invoke: config.invoke,
|
|
21821
22676
|
fetch: config.fetch ?? globalThis.fetch.bind(globalThis),
|
|
21822
22677
|
hosts: config.hosts,
|
|
@@ -21824,6 +22679,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21824
22679
|
}));
|
|
21825
22680
|
context.setSession(config.session);
|
|
21826
22681
|
service.initialize(context);
|
|
22682
|
+
this.attachReplicationKV(config.session.spaceId, service);
|
|
21827
22683
|
return service;
|
|
21828
22684
|
}
|
|
21829
22685
|
});
|
|
@@ -21845,7 +22701,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21845
22701
|
return delegation;
|
|
21846
22702
|
} : void 0
|
|
21847
22703
|
});
|
|
21848
|
-
const spaceService = new
|
|
22704
|
+
const spaceService = new import_sdk_core9.SpaceService({
|
|
21849
22705
|
hosts: [input.host],
|
|
21850
22706
|
session: input.serviceSession,
|
|
21851
22707
|
invoke: graph.invoke,
|
|
@@ -21854,8 +22710,8 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21854
22710
|
userDid: input.nodeDid,
|
|
21855
22711
|
createKVService: (spaceId) => {
|
|
21856
22712
|
graph.assertActive();
|
|
21857
|
-
const scopedKv = new
|
|
21858
|
-
const context = graph.track(new
|
|
22713
|
+
const scopedKv = new import_sdk_core9.KVService({});
|
|
22714
|
+
const context = graph.track(new import_sdk_core9.ServiceContext({
|
|
21859
22715
|
invoke: graph.invoke,
|
|
21860
22716
|
invokeAny: graph.invokeAny,
|
|
21861
22717
|
fetch: graph.fetch,
|
|
@@ -21864,12 +22720,13 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21864
22720
|
}));
|
|
21865
22721
|
context.setSession({ ...input.serviceSession, spaceId });
|
|
21866
22722
|
scopedKv.initialize(context);
|
|
22723
|
+
this.attachReplicationKV(spaceId, scopedKv);
|
|
21867
22724
|
return scopedKv;
|
|
21868
22725
|
},
|
|
21869
22726
|
createVaultService: (spaceId) => {
|
|
21870
22727
|
graph.assertActive();
|
|
21871
|
-
const scopedKv = new
|
|
21872
|
-
const context = graph.track(new
|
|
22728
|
+
const scopedKv = new import_sdk_core9.KVService({});
|
|
22729
|
+
const context = graph.track(new import_sdk_core9.ServiceContext({
|
|
21873
22730
|
invoke: graph.invoke,
|
|
21874
22731
|
invokeAny: graph.invokeAny,
|
|
21875
22732
|
fetch: graph.fetch,
|
|
@@ -21878,6 +22735,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21878
22735
|
}));
|
|
21879
22736
|
context.setSession({ ...input.serviceSession, spaceId });
|
|
21880
22737
|
scopedKv.initialize(context);
|
|
22738
|
+
this.attachReplicationKV(spaceId, scopedKv);
|
|
21881
22739
|
const scopedVault = this.createVaultService(spaceId, scopedKv, encryption, {
|
|
21882
22740
|
host: input.host,
|
|
21883
22741
|
did: input.nodeDid,
|
|
@@ -21955,7 +22813,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21955
22813
|
if (address === void 0 || chainId === void 0) {
|
|
21956
22814
|
return void 0;
|
|
21957
22815
|
}
|
|
21958
|
-
const resolved = await (0,
|
|
22816
|
+
const resolved = await (0, import_sdk_core9.resolveTinyCloudHosts)((0, import_sdk_core9.pkhDid)(address, chainId), {
|
|
21959
22817
|
registryUrl: this.config.tinycloudRegistryUrl,
|
|
21960
22818
|
fallbackHosts: this.config.tinycloudFallbackHosts,
|
|
21961
22819
|
autoDiscoverLocalNode: this.config.autoDiscoverLocalNode,
|
|
@@ -22007,7 +22865,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22007
22865
|
nodeAudience: input.nodeAudience,
|
|
22008
22866
|
...input.role === "policy-enforcement" ? { enforcerDid: input.audienceDid } : {}
|
|
22009
22867
|
};
|
|
22010
|
-
const root = await (0,
|
|
22868
|
+
const root = await (0, import_sdk_core9.signCompactUcanRootAuthorization)({
|
|
22011
22869
|
issuerDid: ownerDid,
|
|
22012
22870
|
audienceDid: input.audienceDid,
|
|
22013
22871
|
attenuation: unifiedRootAttenuation(input.capabilities),
|
|
@@ -22049,7 +22907,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22049
22907
|
if (decision.needsApproval) return void 0;
|
|
22050
22908
|
throw new Error(decision.reason ?? "OpenKey automatic credential signing was rejected");
|
|
22051
22909
|
}
|
|
22052
|
-
if (typeof decision.signature !== "string" || !await (0,
|
|
22910
|
+
if (typeof decision.signature !== "string" || !await (0, import_sdk_core9.verifyEip191MessageSignature)(
|
|
22053
22911
|
request.message,
|
|
22054
22912
|
decision.signature,
|
|
22055
22913
|
request.address
|
|
@@ -22074,7 +22932,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22074
22932
|
if (approval) {
|
|
22075
22933
|
const decision = await approval(request);
|
|
22076
22934
|
if (!decision.approved) throw new Error(decision.reason ?? "Credential signing was rejected");
|
|
22077
|
-
if (decision.signature !== void 0 && !await (0,
|
|
22935
|
+
if (decision.signature !== void 0 && !await (0, import_sdk_core9.verifyEip191MessageSignature)(
|
|
22078
22936
|
request.message,
|
|
22079
22937
|
decision.signature,
|
|
22080
22938
|
request.address
|
|
@@ -22157,10 +23015,15 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22157
23015
|
nonce: this.config.nonce,
|
|
22158
23016
|
siweConfig: this.config.siweConfig,
|
|
22159
23017
|
manifest: useBootstrapSignInRequest ? void 0 : this.config.manifest,
|
|
22160
|
-
capabilityRequest: useBootstrapSignInRequest ? this.config.includeAccountRegistryPermissions === false ?
|
|
22161
|
-
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
|
|
22162
23025
|
});
|
|
22163
|
-
this.tc = new
|
|
23026
|
+
this.tc = new import_sdk_core9.TinyCloud(this.auth, {
|
|
22164
23027
|
invokeAny: this.invokeAnyWithRuntimePermissions,
|
|
22165
23028
|
telemetry: this.config.telemetry
|
|
22166
23029
|
});
|
|
@@ -22210,10 +23073,15 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22210
23073
|
nonce: this.config.nonce,
|
|
22211
23074
|
siweConfig: this.config.siweConfig,
|
|
22212
23075
|
manifest: useBootstrapSignInRequest ? void 0 : this.config.manifest,
|
|
22213
|
-
capabilityRequest: useBootstrapSignInRequest ? this.config.includeAccountRegistryPermissions === false ?
|
|
22214
|
-
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
|
|
22215
23083
|
});
|
|
22216
|
-
this.tc = new
|
|
23084
|
+
this.tc = new import_sdk_core9.TinyCloud(this.auth, {
|
|
22217
23085
|
invokeAny: this.invokeAnyWithRuntimePermissions,
|
|
22218
23086
|
telemetry: this.config.telemetry
|
|
22219
23087
|
});
|
|
@@ -22223,7 +23091,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22223
23091
|
* Initialize the service context and KV service after sign-in.
|
|
22224
23092
|
* @internal
|
|
22225
23093
|
*/
|
|
22226
|
-
initializeServices() {
|
|
23094
|
+
async initializeServices() {
|
|
22227
23095
|
const session = this.currentTinyCloudSession();
|
|
22228
23096
|
if (!session) {
|
|
22229
23097
|
return;
|
|
@@ -22234,28 +23102,28 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22234
23102
|
this._serviceGraph.fetch
|
|
22235
23103
|
);
|
|
22236
23104
|
this._serviceGraph.track(this.tc.serviceContext);
|
|
22237
|
-
this._serviceContext = this._serviceGraph.track(new
|
|
23105
|
+
this._serviceContext = this._serviceGraph.track(new import_sdk_core9.ServiceContext({
|
|
22238
23106
|
invoke: this._serviceGraph.invoke,
|
|
22239
23107
|
invokeAny: this._serviceGraph.invokeAny,
|
|
22240
23108
|
fetch: this._serviceGraph.fetch,
|
|
22241
23109
|
hosts: [this.config.host],
|
|
22242
23110
|
telemetry: this.config.telemetry
|
|
22243
23111
|
}));
|
|
22244
|
-
this._kv = new
|
|
23112
|
+
this._kv = new import_sdk_core9.KVService({});
|
|
22245
23113
|
this._kv.initialize(this._serviceContext);
|
|
22246
23114
|
this._serviceContext.registerService("kv", this._kv);
|
|
22247
23115
|
const features = this.nodeFeatures;
|
|
22248
23116
|
if (features.length === 0 || features.includes("sql")) {
|
|
22249
|
-
this._sql = new
|
|
23117
|
+
this._sql = new import_sdk_core9.SQLService({});
|
|
22250
23118
|
this._sql.initialize(this._serviceContext);
|
|
22251
23119
|
this._serviceContext.registerService("sql", this._sql);
|
|
22252
23120
|
}
|
|
22253
23121
|
if (features.length === 0 || features.includes("duckdb")) {
|
|
22254
|
-
this._duckdb = new
|
|
23122
|
+
this._duckdb = new import_sdk_core9.DuckDbService({});
|
|
22255
23123
|
this._duckdb.initialize(this._serviceContext);
|
|
22256
23124
|
this._serviceContext.registerService("duckdb", this._duckdb);
|
|
22257
23125
|
}
|
|
22258
|
-
this._hooks = new
|
|
23126
|
+
this._hooks = new import_sdk_core9.HooksService({});
|
|
22259
23127
|
this._hooks.initialize(this._serviceContext);
|
|
22260
23128
|
this._serviceContext.registerService("hooks", this._hooks);
|
|
22261
23129
|
const serviceSession = {
|
|
@@ -22266,16 +23134,22 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22266
23134
|
jwk: session.jwk
|
|
22267
23135
|
};
|
|
22268
23136
|
this._serviceContext.setSession(serviceSession);
|
|
23137
|
+
await this.bindReplicationRuntime(this._serviceContext, serviceSession, this._kv);
|
|
22269
23138
|
this.tc.serviceContext.setSession(serviceSession);
|
|
22270
23139
|
this._vault = this.createVaultService(session.spaceId, this._kv);
|
|
22271
23140
|
this._vault.initialize(this._serviceContext);
|
|
22272
23141
|
this._serviceContext.registerService("vault", this._vault);
|
|
22273
23142
|
this.initializeV2Services(serviceSession);
|
|
22274
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
|
+
}
|
|
22275
23149
|
createSpaceScopedKVService(spaceId) {
|
|
22276
|
-
const kvService = new
|
|
23150
|
+
const kvService = new import_sdk_core9.KVService({});
|
|
22277
23151
|
if (this._serviceContext) {
|
|
22278
|
-
const spaceScopedContext = this._serviceGraph.track(new
|
|
23152
|
+
const spaceScopedContext = this._serviceGraph.track(new import_sdk_core9.ServiceContext({
|
|
22279
23153
|
invoke: this._serviceContext.invoke,
|
|
22280
23154
|
invokeAny: this._serviceContext.invokeAny,
|
|
22281
23155
|
fetch: this._serviceContext.fetch,
|
|
@@ -22287,6 +23161,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22287
23161
|
spaceScopedContext.setSession({ ...session, spaceId });
|
|
22288
23162
|
}
|
|
22289
23163
|
kvService.initialize(spaceScopedContext);
|
|
23164
|
+
this.attachReplicationKV(spaceId, kvService);
|
|
22290
23165
|
}
|
|
22291
23166
|
return kvService;
|
|
22292
23167
|
}
|
|
@@ -22367,7 +23242,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22367
23242
|
const shared = wasm.vault_x25519_dh(receiverPrivateKey, peerPublic);
|
|
22368
23243
|
return columnDecrypt(shared, ciphertext);
|
|
22369
23244
|
},
|
|
22370
|
-
verifyNodeSignature: (nodeId, message, signature2) => (0,
|
|
23245
|
+
verifyNodeSignature: (nodeId, message, signature2) => (0, import_sdk_core9.verifyDidKeyEd25519Signature)(nodeId, message, signature2)
|
|
22371
23246
|
};
|
|
22372
23247
|
}
|
|
22373
23248
|
/**
|
|
@@ -22383,7 +23258,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22383
23258
|
if (cached) return cached;
|
|
22384
23259
|
const response = await fetch(`${this.config.host}/info`);
|
|
22385
23260
|
if (!response.ok) {
|
|
22386
|
-
throw await (0,
|
|
23261
|
+
throw await (0, import_sdk_core9.httpResponseError)(response, "Failed to fetch node info");
|
|
22387
23262
|
}
|
|
22388
23263
|
const info = await response.json();
|
|
22389
23264
|
if (typeof info.nodeId !== "string" || info.nodeId.length === 0) {
|
|
@@ -22433,7 +23308,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22433
23308
|
);
|
|
22434
23309
|
if (response.status === 404) return null;
|
|
22435
23310
|
if (!response.ok) {
|
|
22436
|
-
throw await (0,
|
|
23311
|
+
throw await (0, import_sdk_core9.httpResponseError)(response, `Failed to fetch encryption network ${networkId}`);
|
|
22437
23312
|
}
|
|
22438
23313
|
const body = await response.json();
|
|
22439
23314
|
return "descriptor" in body && body.descriptor ? body.descriptor : body;
|
|
@@ -22464,17 +23339,17 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22464
23339
|
);
|
|
22465
23340
|
graph.assertActive();
|
|
22466
23341
|
if (!response.ok) {
|
|
22467
|
-
const permissionHint = response.status === 401 || response.status === 403 ? (0,
|
|
23342
|
+
const permissionHint = response.status === 401 || response.status === 403 ? (0, import_sdk_services3.parsePermissionHint)({
|
|
22468
23343
|
service: "tinycloud.encryption",
|
|
22469
23344
|
path: networkId,
|
|
22470
23345
|
actions: ["tinycloud.encryption/decrypt"]
|
|
22471
23346
|
}) : void 0;
|
|
22472
|
-
throw new
|
|
23347
|
+
throw new import_sdk_core9.DecryptTransportResponseError(response.status, permissionHint);
|
|
22473
23348
|
}
|
|
22474
23349
|
return await response.json();
|
|
22475
23350
|
}
|
|
22476
23351
|
};
|
|
22477
|
-
return new
|
|
23352
|
+
return new import_sdk_core9.EncryptionService({
|
|
22478
23353
|
crypto: crypto3,
|
|
22479
23354
|
signer: {
|
|
22480
23355
|
signDecryptInvocation: async (input) => {
|
|
@@ -22488,7 +23363,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22488
23363
|
graph.assertActive();
|
|
22489
23364
|
return {
|
|
22490
23365
|
...signed2,
|
|
22491
|
-
canonicalBody: (0,
|
|
23366
|
+
canonicalBody: (0, import_sdk_core9.canonicalizeEncryptionJson)(
|
|
22492
23367
|
input.body
|
|
22493
23368
|
)
|
|
22494
23369
|
};
|
|
@@ -22520,7 +23395,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22520
23395
|
if (!address || !didPrincipalMatches2(principal, did)) {
|
|
22521
23396
|
return null;
|
|
22522
23397
|
}
|
|
22523
|
-
const publicSpaceId = (0,
|
|
23398
|
+
const publicSpaceId = (0, import_sdk_core9.makePublicSpaceId)(address, chainId);
|
|
22524
23399
|
const encodedKey = discoveryKey.split("/").map(encodeURIComponent).join("/");
|
|
22525
23400
|
const response = await graph.fetch(
|
|
22526
23401
|
`${host}/public/${encodeURIComponent(publicSpaceId)}/kv/${encodedKey}`,
|
|
@@ -22552,7 +23427,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22552
23427
|
createVaultService(spaceId, kv, encryptionService = this.getEncryptionService(), nodeContext) {
|
|
22553
23428
|
const wasm = this.wasmBindings;
|
|
22554
23429
|
const serviceGraph = nodeContext?.serviceGraph ?? this._serviceGraph;
|
|
22555
|
-
const vaultCrypto = (0,
|
|
23430
|
+
const vaultCrypto = (0, import_sdk_core9.createVaultCrypto)({
|
|
22556
23431
|
vault_encrypt: wasm.vault_encrypt,
|
|
22557
23432
|
vault_decrypt: wasm.vault_decrypt,
|
|
22558
23433
|
vault_derive_key: wasm.vault_derive_key,
|
|
@@ -22567,7 +23442,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22567
23442
|
const chainId = nodeContext?.chainId ?? this._chainId;
|
|
22568
23443
|
const host = nodeContext?.host ?? this.config.host;
|
|
22569
23444
|
const ownerDid = this.ownerDidFromSpaceId(spaceId) ?? did;
|
|
22570
|
-
return new
|
|
23445
|
+
return new import_sdk_core9.DataVaultService({
|
|
22571
23446
|
spaceId,
|
|
22572
23447
|
crypto: vaultCrypto,
|
|
22573
23448
|
encryption: {
|
|
@@ -22592,8 +23467,8 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22592
23467
|
serviceGraph.assertActive();
|
|
22593
23468
|
return self2._publicKV ?? self2.tc.publicKV;
|
|
22594
23469
|
},
|
|
22595
|
-
readPublicSpace: (host2, targetSpaceId, key2) =>
|
|
22596
|
-
makePublicSpaceId:
|
|
23470
|
+
readPublicSpace: (host2, targetSpaceId, key2) => import_sdk_core9.TinyCloud.readPublicSpace(host2, targetSpaceId, key2),
|
|
23471
|
+
makePublicSpaceId: import_sdk_core9.TinyCloud.makePublicSpaceId,
|
|
22597
23472
|
did,
|
|
22598
23473
|
address: address ?? "",
|
|
22599
23474
|
chainId,
|
|
@@ -22607,7 +23482,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22607
23482
|
*/
|
|
22608
23483
|
initializeV2Services(serviceSession) {
|
|
22609
23484
|
const graph = this._serviceGraph;
|
|
22610
|
-
this._capabilityRegistry = new
|
|
23485
|
+
this._capabilityRegistry = new import_sdk_core9.CapabilityKeyRegistry();
|
|
22611
23486
|
const tcSession = this.auth?.tinyCloudSession;
|
|
22612
23487
|
if (tcSession && this._address) {
|
|
22613
23488
|
const sessionKey = {
|
|
@@ -22647,7 +23522,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22647
23522
|
}
|
|
22648
23523
|
this._capabilityRegistry.registerKey(sessionKey, delegations);
|
|
22649
23524
|
}
|
|
22650
|
-
this._delegationManager = new
|
|
23525
|
+
this._delegationManager = new import_sdk_core9.DelegationManager({
|
|
22651
23526
|
hosts: [this.config.host],
|
|
22652
23527
|
accountSpaceId: this.accountSpaceId,
|
|
22653
23528
|
session: serviceSession,
|
|
@@ -22655,7 +23530,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22655
23530
|
invokeAny: graph.invokeAny,
|
|
22656
23531
|
fetch: graph.fetch
|
|
22657
23532
|
});
|
|
22658
|
-
this._spaceService = new
|
|
23533
|
+
this._spaceService = new import_sdk_core9.SpaceService({
|
|
22659
23534
|
hosts: [this.config.host],
|
|
22660
23535
|
session: serviceSession,
|
|
22661
23536
|
invoke: graph.invoke,
|
|
@@ -22720,7 +23595,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22720
23595
|
await this.account.spaces.register(space);
|
|
22721
23596
|
}
|
|
22722
23597
|
});
|
|
22723
|
-
this._sharingService = new
|
|
23598
|
+
this._sharingService = new import_sdk_core9.SharingService({
|
|
22724
23599
|
hosts: [this.config.host],
|
|
22725
23600
|
session: serviceSession,
|
|
22726
23601
|
invoke: graph.invoke,
|
|
@@ -22740,8 +23615,8 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22740
23615
|
},
|
|
22741
23616
|
createKVService: (config) => {
|
|
22742
23617
|
graph.assertActive();
|
|
22743
|
-
const service = new
|
|
22744
|
-
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({
|
|
22745
23620
|
invoke: config.invoke,
|
|
22746
23621
|
fetch: config.fetch ?? graph.fetch,
|
|
22747
23622
|
hosts: config.hosts,
|
|
@@ -22749,6 +23624,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22749
23624
|
}));
|
|
22750
23625
|
context.setSession(config.session);
|
|
22751
23626
|
service.initialize(context);
|
|
23627
|
+
this.attachReplicationKV(config.session.spaceId, service);
|
|
22752
23628
|
return service;
|
|
22753
23629
|
},
|
|
22754
23630
|
onRootDelegationNeeded: this.signer ? async (params) => {
|
|
@@ -22834,15 +23710,15 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22834
23710
|
}
|
|
22835
23711
|
const permissions = ownerDelegationPermissions(params);
|
|
22836
23712
|
const now = /* @__PURE__ */ new Date();
|
|
22837
|
-
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) {
|
|
22838
23714
|
throw new Error("Owner delegation expiry must be explicit, future, and within EXPIRY.MAX_MS");
|
|
22839
23715
|
}
|
|
22840
23716
|
if (!this.signer) throw new Error("Owner wallet signer is required");
|
|
22841
23717
|
const session = this.currentTinyCloudSession();
|
|
22842
23718
|
if (!session) throw new Error("Owner session is required");
|
|
22843
|
-
const ownerDid = (0,
|
|
23719
|
+
const ownerDid = (0, import_sdk_core9.pkhDid)(session.address, session.chainId);
|
|
22844
23720
|
for (const permission of permissions) {
|
|
22845
|
-
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)) {
|
|
22846
23722
|
throw new Error("Owner delegation cannot grant a foreign encryption network");
|
|
22847
23723
|
}
|
|
22848
23724
|
}
|
|
@@ -22863,7 +23739,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22863
23739
|
const signature2 = await this.signer.signMessage(prepared.siwe);
|
|
22864
23740
|
assertOwnerGraphActive();
|
|
22865
23741
|
const delegationSession = this.wasmBindings.completeSessionSetup({ ...prepared, signature: signature2 });
|
|
22866
|
-
const activation = await (0,
|
|
23742
|
+
const activation = await (0, import_sdk_core9.activateSessionWithHost)(host, delegationSession.delegationHeader);
|
|
22867
23743
|
assertOwnerGraphActive();
|
|
22868
23744
|
if (!activation.success) {
|
|
22869
23745
|
throw Object.assign(
|
|
@@ -22899,7 +23775,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22899
23775
|
/** Register a signed policy and sibling roots with this Node's Policy/v3 runtime. */
|
|
22900
23776
|
async registerPolicy(params) {
|
|
22901
23777
|
this._serviceGraph.assertActive();
|
|
22902
|
-
return (0,
|
|
23778
|
+
return (0, import_sdk_core9.registerPolicyV3)({
|
|
22903
23779
|
...params,
|
|
22904
23780
|
nodeOrigin: this.config.host,
|
|
22905
23781
|
fetch: globalThis.fetch.bind(globalThis)
|
|
@@ -22926,23 +23802,23 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22926
23802
|
jti: base64UrlEncode(jtiDigest.slice(0, 16)),
|
|
22927
23803
|
expiresAt: new Date(input.expiresAt).toISOString().replace(/\.\d{3}Z$/, "Z")
|
|
22928
23804
|
};
|
|
22929
|
-
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)))));
|
|
22930
23806
|
const request = { ...body, requestBodyDigest };
|
|
22931
23807
|
const authorization = authorizationHeader(this.invokeAnyWithRuntimePermissions(serviceSession, [{ spaceId: session.spaceId, service: "kv", path: input.resourcePath, action: "tinycloud.kv/get" }]));
|
|
22932
23808
|
const response = await fetch(`${this.config.host}/policy/v3/deliveries/authorize`, {
|
|
22933
23809
|
method: "POST",
|
|
22934
23810
|
headers: { accept: "application/json", "content-type": "application/json", authorization },
|
|
22935
|
-
body: (0,
|
|
23811
|
+
body: (0, import_sdk_core9.canonicalizeEncryptionJson)(request)
|
|
22936
23812
|
});
|
|
22937
|
-
if (!response.ok) throw await (0,
|
|
22938
|
-
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()), {
|
|
22939
23815
|
request,
|
|
22940
23816
|
senderKeyDid: this.credentialHolderDid,
|
|
22941
23817
|
deliveryAudience: input.deliveryAudience
|
|
22942
23818
|
});
|
|
22943
23819
|
const requestDigest = new Uint8Array(await crypto.subtle.digest(
|
|
22944
23820
|
"SHA-256",
|
|
22945
|
-
new TextEncoder().encode(`${
|
|
23821
|
+
new TextEncoder().encode(`${import_sdk_core9.CREDENTIAL_INVITATION_REQUEST_DOMAIN}${(0, import_sdk_core9.canonicalizeEncryptionJson)(verified.request)}`)
|
|
22946
23822
|
));
|
|
22947
23823
|
return {
|
|
22948
23824
|
...verified,
|
|
@@ -23010,7 +23886,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
23010
23886
|
if (!this._sql) {
|
|
23011
23887
|
const features = this.nodeFeatures;
|
|
23012
23888
|
if (features.length > 0 && !features.includes("sql")) {
|
|
23013
|
-
throw new
|
|
23889
|
+
throw new import_sdk_core9.UnsupportedFeatureError("sql", this.config.host, features);
|
|
23014
23890
|
}
|
|
23015
23891
|
throw new Error("Not signed in. Call signIn() first.");
|
|
23016
23892
|
}
|
|
@@ -23034,8 +23910,8 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
23034
23910
|
if (!this._serviceContext || !this._serviceContext.session) {
|
|
23035
23911
|
throw new Error("Not signed in. Call signIn() first.");
|
|
23036
23912
|
}
|
|
23037
|
-
const sql = new
|
|
23038
|
-
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({
|
|
23039
23915
|
invoke: this._serviceContext.invoke,
|
|
23040
23916
|
invokeAny: this._serviceContext.invokeAny,
|
|
23041
23917
|
fetch: this._serviceContext.fetch,
|
|
@@ -23064,8 +23940,8 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
23064
23940
|
if (!this._serviceContext || !this._serviceContext.session) {
|
|
23065
23941
|
throw new Error("Not signed in. Call signIn() first.");
|
|
23066
23942
|
}
|
|
23067
|
-
const kv = new
|
|
23068
|
-
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({
|
|
23069
23945
|
invoke: this._serviceContext.invoke,
|
|
23070
23946
|
invokeAny: this._serviceContext.invokeAny,
|
|
23071
23947
|
fetch: this._serviceContext.fetch,
|
|
@@ -23073,6 +23949,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
23073
23949
|
}));
|
|
23074
23950
|
spaceScopedContext.setSession({ ...this._serviceContext.session, spaceId });
|
|
23075
23951
|
kv.initialize(spaceScopedContext);
|
|
23952
|
+
this.attachReplicationKV(spaceId, kv);
|
|
23076
23953
|
return kv;
|
|
23077
23954
|
}
|
|
23078
23955
|
/**
|
|
@@ -23082,7 +23959,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
23082
23959
|
if (!this._duckdb) {
|
|
23083
23960
|
const features = this.nodeFeatures;
|
|
23084
23961
|
if (features.length > 0 && !features.includes("duckdb")) {
|
|
23085
|
-
throw new
|
|
23962
|
+
throw new import_sdk_core9.UnsupportedFeatureError("duckdb", this.config.host, features);
|
|
23086
23963
|
}
|
|
23087
23964
|
throw new Error("Not signed in. Call signIn() first.");
|
|
23088
23965
|
}
|
|
@@ -23126,7 +24003,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
23126
24003
|
type: NETWORK_ADMIN_TYPE,
|
|
23127
24004
|
targetNode,
|
|
23128
24005
|
networkId,
|
|
23129
|
-
bodyHash: (0,
|
|
24006
|
+
bodyHash: (0, import_sdk_core9.canonicalHashHex)(
|
|
23130
24007
|
crypto3.sha256,
|
|
23131
24008
|
body
|
|
23132
24009
|
),
|
|
@@ -23144,7 +24021,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
23144
24021
|
Authorization: signed2.authorization,
|
|
23145
24022
|
"Content-Type": "application/json"
|
|
23146
24023
|
},
|
|
23147
|
-
body: (0,
|
|
24024
|
+
body: (0, import_sdk_core9.canonicalizeEncryptionJson)(
|
|
23148
24025
|
body
|
|
23149
24026
|
)
|
|
23150
24027
|
});
|
|
@@ -23156,7 +24033,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
23156
24033
|
);
|
|
23157
24034
|
}
|
|
23158
24035
|
if (!response.ok) {
|
|
23159
|
-
throw await (0,
|
|
24036
|
+
throw await (0, import_sdk_core9.httpResponseError)(response, `Failed to create encryption network ${networkId}`);
|
|
23160
24037
|
}
|
|
23161
24038
|
const created = await response.json();
|
|
23162
24039
|
return created.descriptor;
|
|
@@ -23175,7 +24052,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
23175
24052
|
return existing;
|
|
23176
24053
|
}
|
|
23177
24054
|
}
|
|
23178
|
-
const parsed = (0,
|
|
24055
|
+
const parsed = (0, import_sdk_core9.parseNetworkId)(networkId);
|
|
23179
24056
|
if (!didPrincipalMatches2(parsed.ownerDid, this.did)) {
|
|
23180
24057
|
throw new Error(
|
|
23181
24058
|
`Cannot create encryption network ${networkId}: owner ${parsed.ownerDid} does not match signed-in DID ${this.did}`
|
|
@@ -23223,14 +24100,14 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
23223
24100
|
* normal KV and encryption invocation paths.
|
|
23224
24101
|
*/
|
|
23225
24102
|
async readSecret(input) {
|
|
23226
|
-
const resolved = (0,
|
|
24103
|
+
const resolved = (0, import_sdk_core9.resolveSecretPath)(input.name, { scope: input.scope });
|
|
23227
24104
|
const targetSpace = input.space.startsWith("tinycloud:") ? input.space : this.ownedSpaceId(input.space);
|
|
23228
24105
|
const result = await this.getBaseVault(targetSpace).readNetworkEncrypted(
|
|
23229
24106
|
resolved.vaultKey
|
|
23230
24107
|
);
|
|
23231
24108
|
if (result.status !== "ok") {
|
|
23232
24109
|
if (result.status === "permission_required") {
|
|
23233
|
-
const hint = (0,
|
|
24110
|
+
const hint = (0, import_sdk_services3.parsePermissionHint)(result.hint);
|
|
23234
24111
|
if (hint === void 0) return { status: "read_failed" };
|
|
23235
24112
|
return {
|
|
23236
24113
|
status: "permission_required",
|
|
@@ -23256,7 +24133,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
23256
24133
|
const resolvedSpace = spaceId.startsWith("tinycloud:") ? spaceId : this.ownedSpaceId(spaceId);
|
|
23257
24134
|
let secrets = this._baseSecrets.get(resolvedSpace);
|
|
23258
24135
|
if (!secrets) {
|
|
23259
|
-
secrets = new
|
|
24136
|
+
secrets = new import_sdk_core9.SecretsService(() => this.getBaseVault(resolvedSpace));
|
|
23260
24137
|
this._baseSecrets.set(resolvedSpace, secrets);
|
|
23261
24138
|
}
|
|
23262
24139
|
return secrets;
|
|
@@ -23399,7 +24276,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
23399
24276
|
for (const grant of this.runtimePermissionGrants) {
|
|
23400
24277
|
if (grant.provenance === "primary") continue;
|
|
23401
24278
|
for (const operation of grant.operations) {
|
|
23402
|
-
const service =
|
|
24279
|
+
const service = import_sdk_core9.SERVICE_SHORT_TO_LONG[operation.service];
|
|
23403
24280
|
if (service === void 0 || typeof operation.path !== "string" || typeof operation.action !== "string") {
|
|
23404
24281
|
continue;
|
|
23405
24282
|
}
|
|
@@ -23417,7 +24294,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
23417
24294
|
service,
|
|
23418
24295
|
...space === void 0 ? {} : { space },
|
|
23419
24296
|
path: operation.path,
|
|
23420
|
-
caveats: (0,
|
|
24297
|
+
caveats: (0, import_sdk_core9.canonicalizeRecapCaveats)(caveats)
|
|
23421
24298
|
});
|
|
23422
24299
|
const existing = grouped.get(identity);
|
|
23423
24300
|
if (existing === void 0) {
|
|
@@ -23462,7 +24339,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
23462
24339
|
delegationCid: grant.delegationCid,
|
|
23463
24340
|
spaceId: grant.spaceId,
|
|
23464
24341
|
jwk: this.sessionKeyJwk,
|
|
23465
|
-
address: (0,
|
|
24342
|
+
address: (0, import_sdk_core9.canonicalizeAddress)(grant.address),
|
|
23466
24343
|
chainId: grant.chainId,
|
|
23467
24344
|
siwe: grant.siwe,
|
|
23468
24345
|
signature: grant.signature
|
|
@@ -23483,10 +24360,10 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
23483
24360
|
async useRuntimeDelegation(delegation) {
|
|
23484
24361
|
const session = this.currentTinyCloudSession();
|
|
23485
24362
|
if (!session) {
|
|
23486
|
-
throw new
|
|
24363
|
+
throw new import_sdk_core9.SessionExpiredError(/* @__PURE__ */ new Date(0));
|
|
23487
24364
|
}
|
|
23488
24365
|
if (delegation.expiry.getTime() <= Date.now()) {
|
|
23489
|
-
throw new
|
|
24366
|
+
throw new import_sdk_core9.SessionExpiredError(delegation.expiry);
|
|
23490
24367
|
}
|
|
23491
24368
|
const expectedDids = [session.verificationMethod, this.sessionDid];
|
|
23492
24369
|
if (!expectedDids.some((did) => didPrincipalMatches2(delegation.delegateDID, did))) {
|
|
@@ -23495,10 +24372,18 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
23495
24372
|
);
|
|
23496
24373
|
}
|
|
23497
24374
|
const targetHost = delegation.host ?? this.config.host;
|
|
23498
|
-
|
|
23499
|
-
|
|
23500
|
-
|
|
23501
|
-
|
|
24375
|
+
let activateResult;
|
|
24376
|
+
try {
|
|
24377
|
+
activateResult = await (0, import_sdk_core9.activateSessionWithHost)(
|
|
24378
|
+
targetHost,
|
|
24379
|
+
delegation.delegationHeader
|
|
24380
|
+
);
|
|
24381
|
+
} catch (cause) {
|
|
24382
|
+
throw Object.assign(
|
|
24383
|
+
new Error("The TinyCloud host could not be reached to activate the delegation."),
|
|
24384
|
+
{ code: "ACTIVATION_TRANSPORT_FAILED", cause }
|
|
24385
|
+
);
|
|
24386
|
+
}
|
|
23502
24387
|
if (!activateResult.success) {
|
|
23503
24388
|
if (this.operationsFromDelegation(delegation).some(
|
|
23504
24389
|
(operation) => operation.resource?.startsWith("urn:cid:") === true && operation.service === "delegation" && operation.action === "tinycloud.delegation/revoke"
|
|
@@ -23531,13 +24416,13 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
23531
24416
|
}
|
|
23532
24417
|
const session = this.currentTinyCloudSession();
|
|
23533
24418
|
if (!session) {
|
|
23534
|
-
throw new
|
|
24419
|
+
throw new import_sdk_core9.SessionExpiredError(/* @__PURE__ */ new Date(0));
|
|
23535
24420
|
}
|
|
23536
24421
|
const sessionExpiry = extractSiweExpiration(session.siwe);
|
|
23537
24422
|
if (sessionExpiry !== void 0) {
|
|
23538
24423
|
const marginMs = _TinyCloudNode.SESSION_EXPIRY_SAFETY_MARGIN_MS;
|
|
23539
24424
|
if (sessionExpiry.getTime() <= Date.now() + marginMs) {
|
|
23540
|
-
throw new
|
|
24425
|
+
throw new import_sdk_core9.SessionExpiredError(sessionExpiry);
|
|
23541
24426
|
}
|
|
23542
24427
|
}
|
|
23543
24428
|
const expanded = this.expandPermissionEntries(permissions);
|
|
@@ -23613,7 +24498,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
23613
24498
|
...prepared,
|
|
23614
24499
|
signature: signature2
|
|
23615
24500
|
});
|
|
23616
|
-
const activateResult = await (0,
|
|
24501
|
+
const activateResult = await (0, import_sdk_core9.activateSessionWithHost)(
|
|
23617
24502
|
this.config.host,
|
|
23618
24503
|
delegatedSession.delegationHeader
|
|
23619
24504
|
);
|
|
@@ -23786,10 +24671,10 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
23786
24671
|
throw new Error("Public space not enabled. Set enablePublicSpace: true in config.");
|
|
23787
24672
|
}
|
|
23788
24673
|
await this.auth.hostPublicSpace(publicSpaceId);
|
|
23789
|
-
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];
|
|
23790
24675
|
const abilities = { kv: { "": kvActions } };
|
|
23791
24676
|
const now = /* @__PURE__ */ new Date();
|
|
23792
|
-
const expiryMs =
|
|
24677
|
+
const expiryMs = import_sdk_core9.EXPIRY.EPHEMERAL_MS;
|
|
23793
24678
|
const expirationTime = new Date(now.getTime() + expiryMs);
|
|
23794
24679
|
const prepared = this.wasmBindings.prepareSession({
|
|
23795
24680
|
abilities,
|
|
@@ -23807,7 +24692,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
23807
24692
|
...prepared,
|
|
23808
24693
|
signature: signature2
|
|
23809
24694
|
});
|
|
23810
|
-
const activateResult = await (0,
|
|
24695
|
+
const activateResult = await (0, import_sdk_core9.activateSessionWithHost)(
|
|
23811
24696
|
this.config.host,
|
|
23812
24697
|
delegationSession.delegationHeader
|
|
23813
24698
|
);
|
|
@@ -23837,8 +24722,8 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
23837
24722
|
}]);
|
|
23838
24723
|
}
|
|
23839
24724
|
if (this._serviceContext) {
|
|
23840
|
-
const publicKV = new
|
|
23841
|
-
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({
|
|
23842
24727
|
invoke: this._serviceGraph.invoke,
|
|
23843
24728
|
fetch: this._serviceGraph.fetch,
|
|
23844
24729
|
hosts: this._serviceContext.hosts,
|
|
@@ -23990,14 +24875,14 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
23990
24875
|
}
|
|
23991
24876
|
const session = this.currentTinyCloudSession();
|
|
23992
24877
|
if (!session) {
|
|
23993
|
-
throw new
|
|
24878
|
+
throw new import_sdk_core9.SessionExpiredError(/* @__PURE__ */ new Date(0));
|
|
23994
24879
|
}
|
|
23995
24880
|
const sessionExpiry = extractSiweExpiration(session.siwe);
|
|
23996
24881
|
if (sessionExpiry !== void 0) {
|
|
23997
24882
|
const now2 = Date.now();
|
|
23998
24883
|
const marginMs = _TinyCloudNode.SESSION_EXPIRY_SAFETY_MARGIN_MS;
|
|
23999
24884
|
if (sessionExpiry.getTime() <= now2 + marginMs) {
|
|
24000
|
-
throw new
|
|
24885
|
+
throw new import_sdk_core9.SessionExpiredError(sessionExpiry);
|
|
24001
24886
|
}
|
|
24002
24887
|
}
|
|
24003
24888
|
if (!Array.isArray(permissions) || permissions.length === 0) {
|
|
@@ -24027,31 +24912,31 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24027
24912
|
);
|
|
24028
24913
|
return { delegation: delegation2, prompted: true };
|
|
24029
24914
|
}
|
|
24030
|
-
const
|
|
24031
|
-
|
|
24032
|
-
|
|
24033
|
-
|
|
24034
|
-
|
|
24035
|
-
|
|
24036
|
-
|
|
24037
|
-
)
|
|
24038
|
-
|
|
24039
|
-
const marginMs = _TinyCloudNode.SESSION_EXPIRY_SAFETY_MARGIN_MS;
|
|
24040
|
-
if (runtimeGrant.expiresAt.getTime() <= Date.now() + marginMs) {
|
|
24041
|
-
throw new import_sdk_core8.SessionExpiredError(runtimeGrant.expiresAt);
|
|
24042
|
-
}
|
|
24043
|
-
const runtimeExpiration = runtimeGrant.expiresAt < effectiveExpiration ? runtimeGrant.expiresAt : effectiveExpiration;
|
|
24044
|
-
const delegation2 = await this.createDelegationViaRuntimeGrant(
|
|
24045
|
-
did,
|
|
24046
|
-
expandedEntries,
|
|
24047
|
-
runtimeExpiration,
|
|
24048
|
-
runtimeGrant,
|
|
24049
|
-
runtimeOperations,
|
|
24050
|
-
onPrepared
|
|
24051
|
-
);
|
|
24052
|
-
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));
|
|
24053
24924
|
}
|
|
24054
|
-
|
|
24925
|
+
if (plan.refused === "CAVEATED_AUTHORITY") {
|
|
24926
|
+
throw new import_sdk_core9.CaveatedDelegationUnsupportedError(plan.caveated ?? []);
|
|
24927
|
+
}
|
|
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 };
|
|
24055
24940
|
}
|
|
24056
24941
|
const delegation = await this.createDelegationViaWasmPath(
|
|
24057
24942
|
did,
|
|
@@ -24062,6 +24947,149 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24062
24947
|
);
|
|
24063
24948
|
return { delegation, prompted: false };
|
|
24064
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
|
+
}
|
|
24065
25093
|
/**
|
|
24066
25094
|
* Materialize one manifest-declared delegation using the current session key.
|
|
24067
25095
|
* Delivery is intentionally out of band; callers decide how to transmit the
|
|
@@ -24135,7 +25163,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24135
25163
|
const spaceId = resolvedSpaces.size === 1 ? [...resolvedSpaces][0] : session.spaceId;
|
|
24136
25164
|
const abilities = {};
|
|
24137
25165
|
for (const entry of entries) {
|
|
24138
|
-
const shortService =
|
|
25166
|
+
const shortService = import_sdk_core9.SERVICE_LONG_TO_SHORT[entry.service];
|
|
24139
25167
|
if (shortService === void 0) {
|
|
24140
25168
|
throw new Error(
|
|
24141
25169
|
`delegateTo: unknown service '${entry.service}' \u2014 no short-form mapping`
|
|
@@ -24192,7 +25220,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24192
25220
|
if (onPrepared) {
|
|
24193
25221
|
await onPrepared(delegation);
|
|
24194
25222
|
}
|
|
24195
|
-
const activateResult = await (0,
|
|
25223
|
+
const activateResult = await (0, import_sdk_core9.activateSessionWithHost)(
|
|
24196
25224
|
this.config.host,
|
|
24197
25225
|
delegationHeader
|
|
24198
25226
|
);
|
|
@@ -24234,7 +25262,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24234
25262
|
if (onPrepared) {
|
|
24235
25263
|
await onPrepared(delegation);
|
|
24236
25264
|
}
|
|
24237
|
-
const activateResult = await (0,
|
|
25265
|
+
const activateResult = await (0, import_sdk_core9.activateSessionWithHost)(
|
|
24238
25266
|
targetHost,
|
|
24239
25267
|
delegationHeader
|
|
24240
25268
|
);
|
|
@@ -24263,7 +25291,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24263
25291
|
return this.wasmBindings.makeSpaceId(session.address, session.chainId, space);
|
|
24264
25292
|
}
|
|
24265
25293
|
expandPermissionEntries(permissions) {
|
|
24266
|
-
return (0,
|
|
25294
|
+
return (0, import_sdk_core9.expandPermissionEntries)(permissions);
|
|
24267
25295
|
}
|
|
24268
25296
|
/**
|
|
24269
25297
|
* The current WASM child-delegation APIs accept action-only maps. Refuse any
|
|
@@ -24271,10 +25299,10 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24271
25299
|
*/
|
|
24272
25300
|
assertDelegationCaveatsPreservable(entries) {
|
|
24273
25301
|
const caveated = entries.filter(
|
|
24274
|
-
(entry) => !(0,
|
|
25302
|
+
(entry) => !(0, import_sdk_core9.recapCaveatsEqual)(entry.caveats, void 0)
|
|
24275
25303
|
);
|
|
24276
25304
|
if (caveated.length > 0) {
|
|
24277
|
-
throw new
|
|
25305
|
+
throw new import_sdk_core9.CaveatedDelegationUnsupportedError(caveated);
|
|
24278
25306
|
}
|
|
24279
25307
|
}
|
|
24280
25308
|
/**
|
|
@@ -24284,6 +25312,18 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24284
25312
|
* it only accepts action maps, so reject the selected constrained branch.
|
|
24285
25313
|
*/
|
|
24286
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) {
|
|
24287
25327
|
let operationIndex = 0;
|
|
24288
25328
|
const caveated = [];
|
|
24289
25329
|
for (const entry of entries) {
|
|
@@ -24291,7 +25331,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24291
25331
|
const requested = requestedOperations[operationIndex++];
|
|
24292
25332
|
if (!requested) continue;
|
|
24293
25333
|
const constrained = grant.operations.find(
|
|
24294
|
-
(granted) => this.operationCovers(granted, requested) && !(0,
|
|
25334
|
+
(granted) => this.operationCovers(granted, requested) && !(0, import_sdk_core9.recapCaveatsEqual)(granted.caveats, void 0)
|
|
24295
25335
|
);
|
|
24296
25336
|
if (constrained) {
|
|
24297
25337
|
caveated.push({
|
|
@@ -24302,15 +25342,13 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24302
25342
|
}
|
|
24303
25343
|
}
|
|
24304
25344
|
}
|
|
24305
|
-
|
|
24306
|
-
throw new import_sdk_core8.CaveatedDelegationUnsupportedError(caveated);
|
|
24307
|
-
}
|
|
25345
|
+
return caveated;
|
|
24308
25346
|
}
|
|
24309
25347
|
/** Reject caveated parent branches before action-only child signing. */
|
|
24310
25348
|
assertPortableDelegationCaveatsPreservable(delegation) {
|
|
24311
25349
|
const entries = [];
|
|
24312
25350
|
const add3 = (service, space, path, actions, caveats) => {
|
|
24313
|
-
if ((0,
|
|
25351
|
+
if ((0, import_sdk_core9.recapCaveatsEqual)(caveats, void 0)) return;
|
|
24314
25352
|
entries.push({
|
|
24315
25353
|
service: service.startsWith("tinycloud.") ? service : `tinycloud.${service}`,
|
|
24316
25354
|
space,
|
|
@@ -24330,11 +25368,11 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24330
25368
|
add3(resource.service, resource.space, resource.path, resource.actions, resource.caveats);
|
|
24331
25369
|
}
|
|
24332
25370
|
if (entries.length > 0) {
|
|
24333
|
-
throw new
|
|
25371
|
+
throw new import_sdk_core9.CaveatedDelegationUnsupportedError(entries);
|
|
24334
25372
|
}
|
|
24335
25373
|
}
|
|
24336
25374
|
shortServiceName(service) {
|
|
24337
|
-
const short =
|
|
25375
|
+
const short = import_sdk_core9.SERVICE_LONG_TO_SHORT[service];
|
|
24338
25376
|
if (short === void 0) {
|
|
24339
25377
|
throw new Error(
|
|
24340
25378
|
`unknown service '${service}' \u2014 no short-form mapping`
|
|
@@ -24361,7 +25399,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24361
25399
|
return abilities;
|
|
24362
25400
|
}
|
|
24363
25401
|
isEncryptionPermissionEntry(entry) {
|
|
24364
|
-
return entry.service ===
|
|
25402
|
+
return entry.service === import_sdk_core9.ENCRYPTION_PERMISSION_SERVICE && this.isEncryptionNetworkOperation("encryption", entry.path, entry.space);
|
|
24365
25403
|
}
|
|
24366
25404
|
isRawRevocationPermissionEntry(entry) {
|
|
24367
25405
|
return entry.service === "tinycloud.delegation" && entry.path === "" && entry.space?.startsWith("urn:cid:") === true && entry.actions.includes("tinycloud.delegation/revoke");
|
|
@@ -24409,7 +25447,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24409
25447
|
const missing = requested.filter((entry) => {
|
|
24410
25448
|
const raw = this.isEncryptionPermissionEntry(entry) || this.isRawRevocationPermissionEntry(entry);
|
|
24411
25449
|
const comparable = raw && this.isEncryptionPermissionEntry(entry) ? { ...entry, space: "encryption" } : entry;
|
|
24412
|
-
return !(0,
|
|
25450
|
+
return !(0, import_sdk_core9.isCapabilitySubset)([comparable], raw ? rawGranted : spaceGranted).subset;
|
|
24413
25451
|
});
|
|
24414
25452
|
return { subset: missing.length === 0, missing };
|
|
24415
25453
|
}
|
|
@@ -24645,7 +25683,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24645
25683
|
if (granted.service !== requested.service || !this.actionContains(granted.action, requested.action)) {
|
|
24646
25684
|
return false;
|
|
24647
25685
|
}
|
|
24648
|
-
if (requested.caveats !== void 0 && !(0,
|
|
25686
|
+
if (requested.caveats !== void 0 && !(0, import_sdk_core9.recapCaveatsEqual)(granted.caveats, requested.caveats)) {
|
|
24649
25687
|
return false;
|
|
24650
25688
|
}
|
|
24651
25689
|
if (granted.resource !== void 0 || requested.resource !== void 0) {
|
|
@@ -24667,7 +25705,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24667
25705
|
if (grantedAction === requestedAction) {
|
|
24668
25706
|
return true;
|
|
24669
25707
|
}
|
|
24670
|
-
if ((0,
|
|
25708
|
+
if ((0, import_sdk_core9.isExplicitOnlyAction)(requestedAction)) {
|
|
24671
25709
|
return false;
|
|
24672
25710
|
}
|
|
24673
25711
|
if (grantedAction.endsWith("/*")) {
|
|
@@ -24779,7 +25817,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24779
25817
|
if (resolvedDelegateDID.endsWith(".eth") && this.config.ensResolver) {
|
|
24780
25818
|
const address = await this.config.ensResolver.resolveAddress(resolvedDelegateDID);
|
|
24781
25819
|
if (!address) throw new Error(`Could not resolve ENS name: ${resolvedDelegateDID}`);
|
|
24782
|
-
resolvedDelegateDID = (0,
|
|
25820
|
+
resolvedDelegateDID = (0, import_sdk_core9.pkhDid)(address, 1);
|
|
24783
25821
|
}
|
|
24784
25822
|
const entries = legacyParamsToPermissionEntries(
|
|
24785
25823
|
params.actions,
|
|
@@ -24794,7 +25832,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24794
25832
|
);
|
|
24795
25833
|
return result.delegation;
|
|
24796
25834
|
} catch (err) {
|
|
24797
|
-
if (err instanceof
|
|
25835
|
+
if (err instanceof import_sdk_core9.PermissionNotInManifestError) {
|
|
24798
25836
|
} else {
|
|
24799
25837
|
throw err;
|
|
24800
25838
|
}
|
|
@@ -24851,7 +25889,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24851
25889
|
...prepared,
|
|
24852
25890
|
signature: signature2
|
|
24853
25891
|
});
|
|
24854
|
-
const activateResult = await (0,
|
|
25892
|
+
const activateResult = await (0, import_sdk_core9.activateSessionWithHost)(
|
|
24855
25893
|
this.config.host,
|
|
24856
25894
|
delegationSession.delegationHeader
|
|
24857
25895
|
);
|
|
@@ -24876,12 +25914,12 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24876
25914
|
};
|
|
24877
25915
|
const hasKvActions = params.actions.some((a) => a.startsWith("tinycloud.kv/"));
|
|
24878
25916
|
if (hasKvActions && params.includePublicSpace !== false) {
|
|
24879
|
-
const publicSpaceId = (0,
|
|
25917
|
+
const publicSpaceId = (0, import_sdk_core9.makePublicSpaceId)(
|
|
24880
25918
|
this.wasmBindings.ensureEip55(session.address),
|
|
24881
25919
|
session.chainId
|
|
24882
25920
|
);
|
|
24883
25921
|
const publicAbilities = {
|
|
24884
|
-
kv: { "": [
|
|
25922
|
+
kv: { "": [import_sdk_core9.KV.GET, import_sdk_core9.KV.PUT, import_sdk_core9.KV.METADATA] }
|
|
24885
25923
|
};
|
|
24886
25924
|
const publicPrepared = this.wasmBindings.prepareSession({
|
|
24887
25925
|
abilities: publicAbilities,
|
|
@@ -24899,7 +25937,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24899
25937
|
...publicPrepared,
|
|
24900
25938
|
signature: publicSignature
|
|
24901
25939
|
});
|
|
24902
|
-
const publicActivateResult = await (0,
|
|
25940
|
+
const publicActivateResult = await (0, import_sdk_core9.activateSessionWithHost)(
|
|
24903
25941
|
this.config.host,
|
|
24904
25942
|
publicSession.delegationHeader
|
|
24905
25943
|
);
|
|
@@ -24909,7 +25947,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24909
25947
|
delegationHeader: publicSession.delegationHeader,
|
|
24910
25948
|
spaceId: publicSpaceId,
|
|
24911
25949
|
path: "",
|
|
24912
|
-
actions: [
|
|
25950
|
+
actions: [import_sdk_core9.KV.GET, import_sdk_core9.KV.PUT, import_sdk_core9.KV.METADATA],
|
|
24913
25951
|
disableSubDelegation: params.disableSubDelegation ?? false,
|
|
24914
25952
|
expiry: expirationTime,
|
|
24915
25953
|
delegateDID: params.delegateDID,
|
|
@@ -25004,7 +26042,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
25004
26042
|
...prepared,
|
|
25005
26043
|
signature: signature2
|
|
25006
26044
|
});
|
|
25007
|
-
const activateResult = await (0,
|
|
26045
|
+
const activateResult = await (0, import_sdk_core9.activateSessionWithHost)(
|
|
25008
26046
|
targetHost,
|
|
25009
26047
|
invokerSession.delegationHeader
|
|
25010
26048
|
);
|
|
@@ -25124,7 +26162,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
25124
26162
|
...prepared,
|
|
25125
26163
|
signature: signature2
|
|
25126
26164
|
});
|
|
25127
|
-
const activateResult = await (0,
|
|
26165
|
+
const activateResult = await (0, import_sdk_core9.activateSessionWithHost)(
|
|
25128
26166
|
targetHost,
|
|
25129
26167
|
subDelegationSession.delegationHeader
|
|
25130
26168
|
);
|
|
@@ -25174,12 +26212,18 @@ TinyCloudNode.registerNodeDefaults({
|
|
|
25174
26212
|
createSigner: (privateKey, chainId) => new PrivateKeySigner(privateKey, chainId)
|
|
25175
26213
|
});
|
|
25176
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
|
+
|
|
25177
26221
|
// src/index.ts
|
|
25178
|
-
var
|
|
25179
|
-
var
|
|
26222
|
+
var import_sdk_core14 = require("@tinycloud/sdk-core");
|
|
26223
|
+
var import_sdk_core15 = require("@tinycloud/sdk-core");
|
|
25180
26224
|
|
|
25181
26225
|
// src/storage/FileSessionStorage.ts
|
|
25182
|
-
var
|
|
26226
|
+
var import_sdk_core12 = require("@tinycloud/sdk-core");
|
|
25183
26227
|
var import_fs = require("fs");
|
|
25184
26228
|
var import_path = require("path");
|
|
25185
26229
|
var FileSessionStorage = class {
|
|
@@ -25234,7 +26278,7 @@ var FileSessionStorage = class {
|
|
|
25234
26278
|
try {
|
|
25235
26279
|
const data = (0, import_fs.readFileSync)(filePath, "utf-8");
|
|
25236
26280
|
const parsed = JSON.parse(data);
|
|
25237
|
-
const validation = (0,
|
|
26281
|
+
const validation = (0, import_sdk_core12.validatePersistedSessionData)(parsed);
|
|
25238
26282
|
if (!validation.ok) {
|
|
25239
26283
|
console.warn(`Invalid session data for ${address}:`, validation.error.message);
|
|
25240
26284
|
(0, import_fs.unlinkSync)(filePath);
|
|
@@ -25343,10 +26387,6 @@ function wireOpenKeyAuthorize(openkey) {
|
|
|
25343
26387
|
}
|
|
25344
26388
|
|
|
25345
26389
|
// src/index.ts
|
|
25346
|
-
var import_sdk_core12 = require("@tinycloud/sdk-core");
|
|
25347
|
-
var import_sdk_core13 = require("@tinycloud/sdk-core");
|
|
25348
|
-
var import_sdk_core14 = require("@tinycloud/sdk-core");
|
|
25349
|
-
var import_sdk_core15 = require("@tinycloud/sdk-core");
|
|
25350
26390
|
var import_sdk_core16 = require("@tinycloud/sdk-core");
|
|
25351
26391
|
var import_sdk_core17 = require("@tinycloud/sdk-core");
|
|
25352
26392
|
var import_sdk_core18 = require("@tinycloud/sdk-core");
|
|
@@ -25355,6 +26395,848 @@ var import_sdk_core20 = require("@tinycloud/sdk-core");
|
|
|
25355
26395
|
var import_sdk_core21 = require("@tinycloud/sdk-core");
|
|
25356
26396
|
var import_sdk_core22 = require("@tinycloud/sdk-core");
|
|
25357
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
|
+
}
|
|
25358
27240
|
// Annotate the CommonJS export names for ESM import in node:
|
|
25359
27241
|
0 && (module.exports = {
|
|
25360
27242
|
ACCEPTED_MARKER_VERSIONS,
|
|
@@ -25394,6 +27276,7 @@ var import_sdk_core23 = require("@tinycloud/sdk-core");
|
|
|
25394
27276
|
IdentityParseError,
|
|
25395
27277
|
InvalidRestoredSessionError,
|
|
25396
27278
|
KVService,
|
|
27279
|
+
MAX_SECRET_SCOPE_LENGTH,
|
|
25397
27280
|
ManifestValidationError,
|
|
25398
27281
|
MemorySessionStorage,
|
|
25399
27282
|
NETWORK_NAME_PATTERN,
|
|
@@ -25407,6 +27290,7 @@ var import_sdk_core23 = require("@tinycloud/sdk-core");
|
|
|
25407
27290
|
RUNTIME_DELEGATION_REJECTIONS,
|
|
25408
27291
|
RuntimeDelegationRejectedError,
|
|
25409
27292
|
SECRET_NAME_RE,
|
|
27293
|
+
SECRET_SCOPE_RE,
|
|
25410
27294
|
SQLAction,
|
|
25411
27295
|
SQLService,
|
|
25412
27296
|
STORAGE_FULL_MESSAGE,
|
|
@@ -25419,6 +27303,7 @@ var import_sdk_core23 = require("@tinycloud/sdk-core");
|
|
|
25419
27303
|
Space,
|
|
25420
27304
|
SpaceErrorCodes,
|
|
25421
27305
|
SpaceService,
|
|
27306
|
+
TC832_RESERVED_SCOPES,
|
|
25422
27307
|
TinyCloud,
|
|
25423
27308
|
TinyCloudDebugLogger,
|
|
25424
27309
|
TinyCloudNode,
|
|
@@ -25432,6 +27317,7 @@ var import_sdk_core23 = require("@tinycloud/sdk-core");
|
|
|
25432
27317
|
activateCompactRuntimeDelegation,
|
|
25433
27318
|
activateValidatedRuntimeDelegation,
|
|
25434
27319
|
addressStorageKey,
|
|
27320
|
+
appSecretScope,
|
|
25435
27321
|
buildCanonicalDecryptRequest,
|
|
25436
27322
|
buildDecryptAttenuation,
|
|
25437
27323
|
buildDecryptFacts,
|
|
@@ -25507,6 +27393,7 @@ var import_sdk_core23 = require("@tinycloud/sdk-core");
|
|
|
25507
27393
|
resourceCapabilitiesToSpaceAbilitiesMap,
|
|
25508
27394
|
serializeDelegation,
|
|
25509
27395
|
signedCompactUcanExpiry,
|
|
27396
|
+
sqliteReplicaStorage,
|
|
25510
27397
|
tinyCloudDebugLogger,
|
|
25511
27398
|
validateEnvelope,
|
|
25512
27399
|
validateManifest,
|