@tinycloud/sdk-services 3.2.0-beta.3 → 3.2.0-beta.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +14 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +14 -8
- package/dist/index.js.map +1 -1
- package/dist/kv/index.cjs +14 -8
- package/dist/kv/index.cjs.map +1 -1
- package/dist/kv/index.d.cts +3 -2
- package/dist/kv/index.d.ts +3 -2
- package/dist/kv/index.js +14 -8
- package/dist/kv/index.js.map +1 -1
- package/dist/kv/replication/index.cjs +42 -19
- package/dist/kv/replication/index.cjs.map +1 -1
- package/dist/kv/replication/index.d.cts +3 -2
- package/dist/kv/replication/index.d.ts +3 -2
- package/dist/kv/replication/index.js +42 -19
- package/dist/kv/replication/index.js.map +1 -1
- package/dist/kv/replication/prefix.cjs +43 -0
- package/dist/kv/replication/prefix.cjs.map +1 -0
- package/dist/kv/replication/prefix.d.cts +6 -0
- package/dist/kv/replication/prefix.d.ts +6 -0
- package/dist/kv/replication/prefix.js +17 -0
- package/dist/kv/replication/prefix.js.map +1 -0
- package/dist/{scope-BmLxwyl-.d.ts → scope-BKge7zDT.d.ts} +4 -4
- package/dist/{scope-D855kRDx.d.cts → scope-C05VVAXH.d.cts} +4 -4
- package/package.json +14 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { K as KVReplicationDeps, a as KVReplicationController, R as ReplicationIdentity, P as PendingWriteStore } from '../../scope-
|
|
2
|
-
export { A as AuthorityRefusal, C as CLEAR_PENDING_WARNING, b as KVListPage, c as KVReadThrough, d as KVReplicaHandle, e as KVReplicaSpec, f as KVReplicaStorage, L as LocalGetResult, g as LocalListResult, h as LocalReadMeta, i as LocalReplicaStatus, j as LocalSyncResult, k as PendingWriteRecord, l as PendingWriteState, m as PinnedKey, n as PurgeTarget, o as ReplicaAuthorityState, p as ReplicaCoverage, q as ReplicaDevice, r as ReplicaGrantInfo, s as ReplicaState, t as ReplicaStatusEntry, u as ReplicationAuthority, v as ReplicationControl, w as ReplicationEvent, x as ReplicationOptions, y as ReplicationPurgeReport, z as ReplicationReason, B as ReplicationScheduler, D as ResolvedReplicationOptions, E as canonicalReplicationIdentity, F as
|
|
1
|
+
import { K as KVReplicationDeps, a as KVReplicationController, R as ReplicationIdentity, P as PendingWriteStore } from '../../scope-C05VVAXH.cjs';
|
|
2
|
+
export { A as AuthorityRefusal, C as CLEAR_PENDING_WARNING, b as KVListPage, c as KVReadThrough, d as KVReplicaHandle, e as KVReplicaSpec, f as KVReplicaStorage, L as LocalGetResult, g as LocalListResult, h as LocalReadMeta, i as LocalReplicaStatus, j as LocalSyncResult, k as PendingWriteRecord, l as PendingWriteState, m as PinnedKey, n as PurgeTarget, o as ReplicaAuthorityState, p as ReplicaCoverage, q as ReplicaDevice, r as ReplicaGrantInfo, s as ReplicaState, t as ReplicaStatusEntry, u as ReplicationAuthority, v as ReplicationControl, w as ReplicationEvent, x as ReplicationOptions, y as ReplicationPurgeReport, z as ReplicationReason, B as ReplicationScheduler, D as ResolvedReplicationOptions, E as canonicalReplicationIdentity, F as replicationIdentityKey, G as requiresSecretsOptIn } from '../../scope-C05VVAXH.cjs';
|
|
3
|
+
export { kvPrefixCovers } from './prefix.cjs';
|
|
3
4
|
import '../../types-7A5rHWRY.cjs';
|
|
4
5
|
|
|
5
6
|
declare function createKVReplication(deps: KVReplicationDeps): KVReplicationController;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { K as KVReplicationDeps, a as KVReplicationController, R as ReplicationIdentity, P as PendingWriteStore } from '../../scope-
|
|
2
|
-
export { A as AuthorityRefusal, C as CLEAR_PENDING_WARNING, b as KVListPage, c as KVReadThrough, d as KVReplicaHandle, e as KVReplicaSpec, f as KVReplicaStorage, L as LocalGetResult, g as LocalListResult, h as LocalReadMeta, i as LocalReplicaStatus, j as LocalSyncResult, k as PendingWriteRecord, l as PendingWriteState, m as PinnedKey, n as PurgeTarget, o as ReplicaAuthorityState, p as ReplicaCoverage, q as ReplicaDevice, r as ReplicaGrantInfo, s as ReplicaState, t as ReplicaStatusEntry, u as ReplicationAuthority, v as ReplicationControl, w as ReplicationEvent, x as ReplicationOptions, y as ReplicationPurgeReport, z as ReplicationReason, B as ReplicationScheduler, D as ResolvedReplicationOptions, E as canonicalReplicationIdentity, F as
|
|
1
|
+
import { K as KVReplicationDeps, a as KVReplicationController, R as ReplicationIdentity, P as PendingWriteStore } from '../../scope-BKge7zDT.js';
|
|
2
|
+
export { A as AuthorityRefusal, C as CLEAR_PENDING_WARNING, b as KVListPage, c as KVReadThrough, d as KVReplicaHandle, e as KVReplicaSpec, f as KVReplicaStorage, L as LocalGetResult, g as LocalListResult, h as LocalReadMeta, i as LocalReplicaStatus, j as LocalSyncResult, k as PendingWriteRecord, l as PendingWriteState, m as PinnedKey, n as PurgeTarget, o as ReplicaAuthorityState, p as ReplicaCoverage, q as ReplicaDevice, r as ReplicaGrantInfo, s as ReplicaState, t as ReplicaStatusEntry, u as ReplicationAuthority, v as ReplicationControl, w as ReplicationEvent, x as ReplicationOptions, y as ReplicationPurgeReport, z as ReplicationReason, B as ReplicationScheduler, D as ResolvedReplicationOptions, E as canonicalReplicationIdentity, F as replicationIdentityKey, G as requiresSecretsOptIn } from '../../scope-BKge7zDT.js';
|
|
3
|
+
export { kvPrefixCovers } from './prefix.js';
|
|
3
4
|
import '../../types-7A5rHWRY.js';
|
|
4
5
|
|
|
5
6
|
declare function createKVReplication(deps: KVReplicationDeps): KVReplicationController;
|
|
@@ -45,16 +45,17 @@ ${canonical.space}
|
|
|
45
45
|
${canonical.principal}`;
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
// src/kv/replication/
|
|
48
|
+
// src/kv/replication/prefix.ts
|
|
49
49
|
function kvPrefixCovers(prefix, key) {
|
|
50
|
-
|
|
51
|
-
if (prefix.endsWith("/")) return key.startsWith(prefix);
|
|
52
|
-
return key === prefix || key.startsWith(`${prefix}/`);
|
|
50
|
+
return prefix === "/" || key.startsWith(prefix);
|
|
53
51
|
}
|
|
52
|
+
|
|
53
|
+
// src/kv/replication/scope.ts
|
|
54
54
|
function listRangeCovers(path, key) {
|
|
55
|
-
return key === path || key.startsWith(path.endsWith("/") ? path : `${path}/`);
|
|
55
|
+
return path === "" || key === path || key.startsWith(path.endsWith("/") ? path : `${path}/`);
|
|
56
56
|
}
|
|
57
57
|
function requiresSecretsOptIn(space, prefix) {
|
|
58
|
+
if (prefix === "/") return true;
|
|
58
59
|
if (space === "secrets" || space.endsWith(":secrets")) return true;
|
|
59
60
|
return prefix.split("/", 1)[0] === "vault";
|
|
60
61
|
}
|
|
@@ -339,9 +340,9 @@ function cursorRestart() {
|
|
|
339
340
|
}
|
|
340
341
|
function localList(handle, space, path, limit, cursor, validateMeta) {
|
|
341
342
|
const after = cursor ? decodeTcr1(cursor)?.last : void 0;
|
|
342
|
-
const exact = !path.endsWith("/") && (after === void 0 || utf8Compare(path, after) > 0) ? awaitExact(handle, path, after, validateMeta) : Promise.resolve(false);
|
|
343
|
+
const exact = path !== "" && !path.endsWith("/") && (after === void 0 || utf8Compare(path, after) > 0) ? awaitExact(handle, path, after, validateMeta) : Promise.resolve(false);
|
|
343
344
|
return exact.then(async (hasExact) => {
|
|
344
|
-
const child = path.endsWith("/") ? path : `${path}/`;
|
|
345
|
+
const child = path === "" ? "" : path.endsWith("/") ? path : `${path}/`;
|
|
345
346
|
const want = limit === void 0 ? void 0 : limit + 1 - (hasExact ? 1 : 0);
|
|
346
347
|
const children = await handle.list({ prefix: child, after, limit: want });
|
|
347
348
|
validateMeta(children.meta);
|
|
@@ -358,9 +359,7 @@ async function awaitExact(handle, path, after, validateMeta) {
|
|
|
358
359
|
return result.keys[0] === path;
|
|
359
360
|
}
|
|
360
361
|
function listPathCovered(prefixes, path) {
|
|
361
|
-
|
|
362
|
-
const covering = prefixes.filter((prefix) => kvPrefixCovers(prefix, path) && kvPrefixCovers(prefix, descendant));
|
|
363
|
-
return covering.length === 1 ? covering[0] : void 0;
|
|
362
|
+
return prefixes.find((prefix) => kvPrefixCovers(prefix, path));
|
|
364
363
|
}
|
|
365
364
|
|
|
366
365
|
// src/kv/replication/events.ts
|
|
@@ -389,6 +388,7 @@ function raceSignal(job, signal) {
|
|
|
389
388
|
}
|
|
390
389
|
function createKVReplication(deps) {
|
|
391
390
|
const { options, mode, storage, identity, session, authority, pending, scheduler } = deps;
|
|
391
|
+
const emit = (event) => emitEvent(deps.emit, scheduler, event);
|
|
392
392
|
const replicas = /* @__PURE__ */ new Map();
|
|
393
393
|
const statusInspections = /* @__PURE__ */ new Set();
|
|
394
394
|
let isClosed = false;
|
|
@@ -397,7 +397,6 @@ function createKVReplication(deps) {
|
|
|
397
397
|
let previous = deps.previous;
|
|
398
398
|
let pinnedStateReported = false;
|
|
399
399
|
const inProcessProof = /* @__PURE__ */ new Set();
|
|
400
|
-
const emit = (event) => emitEvent(deps.emit, scheduler, event);
|
|
401
400
|
const configuredPrefix = (path) => options.prefixes.find((prefix) => kvPrefixCovers(prefix, path));
|
|
402
401
|
function recordRevocation(prefix, error) {
|
|
403
402
|
if (errorCode(error) !== "GRANT_REVOKED") return;
|
|
@@ -407,6 +406,20 @@ function createKVReplication(deps) {
|
|
|
407
406
|
state.lastError = "GRANT_REVOKED";
|
|
408
407
|
replicas.set(prefix, state);
|
|
409
408
|
}
|
|
409
|
+
function markRootUnsupported(prefix) {
|
|
410
|
+
const state = replicas.get(prefix) ?? {};
|
|
411
|
+
const firstRefusal = state.lastError !== "REPLICATION_ROOT_UNSUPPORTED";
|
|
412
|
+
state.reason = "replica_unavailable";
|
|
413
|
+
state.lastError = "REPLICATION_ROOT_UNSUPPORTED";
|
|
414
|
+
replicas.set(prefix, state);
|
|
415
|
+
if (firstRefusal) {
|
|
416
|
+
emit({ type: "replication.state", space: session.space, replica: prefix, state: "unavailable", code: "REPLICATION_ROOT_UNSUPPORTED" });
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
function unsupportedRoot(prefix) {
|
|
420
|
+
markRootUnsupported(prefix);
|
|
421
|
+
return Object.assign(new Error("This node doesn't support whole-space sync yet."), { code: "REPLICATION_ROOT_UNSUPPORTED" });
|
|
422
|
+
}
|
|
410
423
|
async function open(prefix) {
|
|
411
424
|
if (isClosed || purgeStarted) throw Object.assign(new Error("Replication controller is closed"), { code: "REPLICA_CLOSED" });
|
|
412
425
|
let state = replicas.get(prefix);
|
|
@@ -440,6 +453,9 @@ function createKVReplication(deps) {
|
|
|
440
453
|
state.strategy = "session";
|
|
441
454
|
}
|
|
442
455
|
const spec = { identity, space: session.space, prefix, allowSecrets: options.allowSecrets, ...device ? { device } : {}, ...deps.fetch ? { fetch: deps.fetch } : {} };
|
|
456
|
+
if (prefix === "/" && deps.nodeFeatures !== void 0 && !deps.nodeFeatures.includes("kv-sync-root")) {
|
|
457
|
+
throw unsupportedRoot(prefix);
|
|
458
|
+
}
|
|
443
459
|
const handle = await storage.open(spec);
|
|
444
460
|
state.handle = handle;
|
|
445
461
|
emit({ type: "replication.state", space: session.space, replica: prefix, state: "opened" });
|
|
@@ -489,7 +505,7 @@ function createKVReplication(deps) {
|
|
|
489
505
|
state.lastError = code;
|
|
490
506
|
state.failures = (state.failures ?? 0) + 1;
|
|
491
507
|
if (code === "RUNTIME_UNSUPPORTED") state.unsupported = true;
|
|
492
|
-
else if (code !== "REPLICA_CLOSED") state.retryAt = scheduler.now() + Math.min(3e5, 5e3 * 2 ** Math.min(state.failures - 1, 6));
|
|
508
|
+
else if (code !== "REPLICA_CLOSED" && code !== "REPLICATION_ROOT_UNSUPPORTED") state.retryAt = scheduler.now() + Math.min(3e5, 5e3 * 2 ** Math.min(state.failures - 1, 6));
|
|
493
509
|
state.handle?.close().catch(() => void 0);
|
|
494
510
|
state.handle = void 0;
|
|
495
511
|
throw error;
|
|
@@ -506,6 +522,9 @@ function createKVReplication(deps) {
|
|
|
506
522
|
}, options.syncIntervalMs);
|
|
507
523
|
}
|
|
508
524
|
async function syncPrefix(prefix, trigger, signal, context) {
|
|
525
|
+
if (prefix === "/" && deps.nodeFeatures !== void 0 && !deps.nodeFeatures.includes("kv-sync-root")) {
|
|
526
|
+
throw unsupportedRoot(prefix);
|
|
527
|
+
}
|
|
509
528
|
const handle = await open(prefix);
|
|
510
529
|
const state = replicas.get(prefix);
|
|
511
530
|
if (state.sync) return state.sync;
|
|
@@ -807,7 +826,7 @@ function createKVReplication(deps) {
|
|
|
807
826
|
observeNetworkRequested({ op: "get", space: r.space, path: r.path, reason: "NETWORK_REQUESTED", outcome, latencyMs: scheduler.now() - started });
|
|
808
827
|
}
|
|
809
828
|
}
|
|
810
|
-
if (
|
|
829
|
+
if (prefix === void 0) {
|
|
811
830
|
const value = await r.network();
|
|
812
831
|
readEvent("get", r.path, null, "network", "not_covered", value.ok ? "found" : value.error.code === ErrorCodes.KV_NOT_FOUND ? "not_found" : "error", started);
|
|
813
832
|
return value;
|
|
@@ -958,10 +977,10 @@ function createKVReplication(deps) {
|
|
|
958
977
|
return cursorRestart();
|
|
959
978
|
};
|
|
960
979
|
if (cursor && decoded && (decoded.space !== r.space || decoded.path !== r.listPath)) return restart();
|
|
961
|
-
if (
|
|
980
|
+
if (prefix === void 0 || r.options?.raw) {
|
|
962
981
|
if (cursor && decoded) return restart();
|
|
963
982
|
const result = await r.network();
|
|
964
|
-
readEvent("list", r.listPath, prefix ?? null, "network", prefix ? "unsupported_option" : "not_covered", result.ok ? "found" : "error", started);
|
|
983
|
+
readEvent("list", r.listPath, prefix ?? null, "network", prefix !== void 0 ? "unsupported_option" : "not_covered", result.ok ? "found" : "error", started);
|
|
965
984
|
return result;
|
|
966
985
|
}
|
|
967
986
|
let handle;
|
|
@@ -1056,7 +1075,7 @@ function createKVReplication(deps) {
|
|
|
1056
1075
|
async function write(r) {
|
|
1057
1076
|
const covered = r.entries.flatMap((entry) => {
|
|
1058
1077
|
const prefix = configuredPrefix(entry.path);
|
|
1059
|
-
return prefix ? [{ key: entry.path, op: r.op === "delete" ? "delete" : "put" }] : [];
|
|
1078
|
+
return prefix !== void 0 ? [{ key: entry.path, op: r.op === "delete" ? "delete" : "put" }] : [];
|
|
1060
1079
|
});
|
|
1061
1080
|
if (covered.length === 0) return r.network();
|
|
1062
1081
|
await reportExistingPins();
|
|
@@ -1132,6 +1151,9 @@ function createKVReplication(deps) {
|
|
|
1132
1151
|
const persistedSnapshot = pending.readExisting ? await pending.readExisting() : await pending.read();
|
|
1133
1152
|
const snapshot = persistedSnapshot ?? emptyPendingState(identity);
|
|
1134
1153
|
const entries = await Promise.all(options.prefixes.map(async (prefix) => {
|
|
1154
|
+
if (prefix === "/" && deps.nodeFeatures !== void 0 && !deps.nodeFeatures.includes("kv-sync-root")) {
|
|
1155
|
+
markRootUnsupported(prefix);
|
|
1156
|
+
}
|
|
1135
1157
|
const records = snapshot.records.filter((r) => kvPrefixCovers(prefix, r.key));
|
|
1136
1158
|
const opened = replicas.get(prefix);
|
|
1137
1159
|
let local;
|
|
@@ -1146,12 +1168,13 @@ function createKVReplication(deps) {
|
|
|
1146
1168
|
local ?? (local = inspected.local);
|
|
1147
1169
|
if (inspected.missing && !opened?.reason && !opened?.authorityRevoked && !opened?.opening && !isClosed) return void 0;
|
|
1148
1170
|
const revoked = opened?.authorityRevoked === true || local?.authority.state === "revoked";
|
|
1149
|
-
const
|
|
1171
|
+
const rootUnsupported = opened?.lastError === "REPLICATION_ROOT_UNSUPPORTED";
|
|
1172
|
+
const state = isClosed ? "closed" : revoked ? "revoked" : rootUnsupported ? "unavailable" : opened?.reason === "grant_missing" ? "grant_missing" : local?.coverage === "complete" && local.authority.state === "valid" ? "ready" : opened?.reason || inspected.errorCode ? "unavailable" : "idle";
|
|
1150
1173
|
return {
|
|
1151
1174
|
prefix,
|
|
1152
1175
|
state,
|
|
1153
1176
|
...opened?.reason ? { reason: opened.reason } : inspected.errorCode ? { reason: "replica_unavailable" } : {},
|
|
1154
|
-
...inspected.errorCode ? { errorCode: inspected.errorCode } : {},
|
|
1177
|
+
...inspected.errorCode ?? opened?.lastError ? { errorCode: inspected.errorCode ?? opened?.lastError } : {},
|
|
1155
1178
|
...local ?? {},
|
|
1156
1179
|
...revoked ? { authority: { state: "revoked", expiresAt: local?.authority.expiresAt ?? null } } : {},
|
|
1157
1180
|
pending: {
|
|
@@ -1166,7 +1189,7 @@ function createKVReplication(deps) {
|
|
|
1166
1189
|
return entries.filter((entry) => entry !== void 0);
|
|
1167
1190
|
}
|
|
1168
1191
|
async function sync(o) {
|
|
1169
|
-
const prefixes = o?.prefix ? options.prefixes.filter((p) => p === o.prefix) : options.prefixes;
|
|
1192
|
+
const prefixes = o?.prefix !== void 0 ? options.prefixes.filter((p) => p === o.prefix) : options.prefixes;
|
|
1170
1193
|
await Promise.all(prefixes.map((prefix) => syncPrefix(prefix, "manual", o?.signal).then(() => void 0)));
|
|
1171
1194
|
}
|
|
1172
1195
|
async function clearPending2() {
|