@tinycloud/sdk-services 3.2.0-beta.3 → 3.2.0-beta.7

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.
Files changed (45) hide show
  1. package/dist/{BaseService-BDQXjWMx.d.cts → BaseService-4wwJq1Gn.d.cts} +1 -1
  2. package/dist/{BaseService-Di_hVfUV.d.ts → BaseService-BGr2slUz.d.ts} +1 -1
  3. package/dist/encryption/index.cjs +5 -1
  4. package/dist/encryption/index.cjs.map +1 -1
  5. package/dist/encryption/index.d.cts +2 -2
  6. package/dist/encryption/index.d.ts +2 -2
  7. package/dist/encryption/index.js +5 -1
  8. package/dist/encryption/index.js.map +1 -1
  9. package/dist/index.cjs +190 -11
  10. package/dist/index.cjs.map +1 -1
  11. package/dist/index.d.cts +157 -6
  12. package/dist/index.d.ts +157 -6
  13. package/dist/index.js +184 -11
  14. package/dist/index.js.map +1 -1
  15. package/dist/internal/decrypt-transport-response-error.d.cts +1 -1
  16. package/dist/internal/decrypt-transport-response-error.d.ts +1 -1
  17. package/dist/kv/index.cjs +56 -11
  18. package/dist/kv/index.cjs.map +1 -1
  19. package/dist/kv/index.d.cts +5 -4
  20. package/dist/kv/index.d.ts +5 -4
  21. package/dist/kv/index.js +56 -11
  22. package/dist/kv/index.js.map +1 -1
  23. package/dist/kv/replication/index.cjs +44 -19
  24. package/dist/kv/replication/index.cjs.map +1 -1
  25. package/dist/kv/replication/index.d.cts +4 -3
  26. package/dist/kv/replication/index.d.ts +4 -3
  27. package/dist/kv/replication/index.js +44 -19
  28. package/dist/kv/replication/index.js.map +1 -1
  29. package/dist/kv/replication/prefix.cjs +43 -0
  30. package/dist/kv/replication/prefix.cjs.map +1 -0
  31. package/dist/kv/replication/prefix.d.cts +6 -0
  32. package/dist/kv/replication/prefix.d.ts +6 -0
  33. package/dist/kv/replication/prefix.js +17 -0
  34. package/dist/kv/replication/prefix.js.map +1 -0
  35. package/dist/{scope-BmLxwyl-.d.ts → scope-CoKKmMiI.d.ts} +5 -5
  36. package/dist/{scope-D855kRDx.d.cts → scope-D7wmjbMH.d.cts} +5 -5
  37. package/dist/sql/index.cjs +44 -2
  38. package/dist/sql/index.cjs.map +1 -1
  39. package/dist/sql/index.d.cts +2 -2
  40. package/dist/sql/index.d.ts +2 -2
  41. package/dist/sql/index.js +44 -2
  42. package/dist/sql/index.js.map +1 -1
  43. package/dist/{types-7A5rHWRY.d.cts → types-D-9A3Sut.d.cts} +6 -0
  44. package/dist/{types-7A5rHWRY.d.ts → types-D-9A3Sut.d.ts} +6 -0
  45. package/package.json +14 -1
@@ -1,6 +1,7 @@
1
- import { K as KVReplicationDeps, a as KVReplicationController, R as ReplicationIdentity, P as PendingWriteStore } from '../../scope-D855kRDx.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 kvPrefixCovers, G as replicationIdentityKey, H as requiresSecretsOptIn } from '../../scope-D855kRDx.cjs';
3
- import '../../types-7A5rHWRY.cjs';
1
+ import { K as KVReplicationDeps, a as KVReplicationController, R as ReplicationIdentity, P as PendingWriteStore } from '../../scope-D7wmjbMH.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-D7wmjbMH.cjs';
3
+ export { kvPrefixCovers } from './prefix.cjs';
4
+ import '../../types-D-9A3Sut.cjs';
4
5
 
5
6
  declare function createKVReplication(deps: KVReplicationDeps): KVReplicationController;
6
7
 
@@ -1,6 +1,7 @@
1
- import { K as KVReplicationDeps, a as KVReplicationController, R as ReplicationIdentity, P as PendingWriteStore } from '../../scope-BmLxwyl-.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 kvPrefixCovers, G as replicationIdentityKey, H as requiresSecretsOptIn } from '../../scope-BmLxwyl-.js';
3
- import '../../types-7A5rHWRY.js';
1
+ import { K as KVReplicationDeps, a as KVReplicationController, R as ReplicationIdentity, P as PendingWriteStore } from '../../scope-CoKKmMiI.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-CoKKmMiI.js';
3
+ export { kvPrefixCovers } from './prefix.js';
4
+ import '../../types-D-9A3Sut.js';
4
5
 
5
6
  declare function createKVReplication(deps: KVReplicationDeps): KVReplicationController;
6
7
 
@@ -45,16 +45,17 @@ ${canonical.space}
45
45
  ${canonical.principal}`;
46
46
  }
47
47
 
48
- // src/kv/replication/scope.ts
48
+ // src/kv/replication/prefix.ts
49
49
  function kvPrefixCovers(prefix, key) {
50
- if (prefix === "") return true;
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
  }
@@ -100,6 +101,8 @@ var ErrorCodes = {
100
101
  // Storage quota errors
101
102
  STORAGE_QUOTA_EXCEEDED: "STORAGE_QUOTA_EXCEEDED",
102
103
  STORAGE_LIMIT_REACHED: "STORAGE_LIMIT_REACHED",
104
+ /** The node answered the usage read without usage numbers (it predates the read). */
105
+ STORAGE_STATUS_UNAVAILABLE: "STORAGE_STATUS_UNAVAILABLE",
103
106
  // DuckDB-specific errors
104
107
  DUCKDB_ERROR: "DUCKDB_ERROR",
105
108
  DUCKDB_PERMISSION_DENIED: "DUCKDB_PERMISSION_DENIED",
@@ -339,9 +342,9 @@ function cursorRestart() {
339
342
  }
340
343
  function localList(handle, space, path, limit, cursor, validateMeta) {
341
344
  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);
345
+ const exact = path !== "" && !path.endsWith("/") && (after === void 0 || utf8Compare(path, after) > 0) ? awaitExact(handle, path, after, validateMeta) : Promise.resolve(false);
343
346
  return exact.then(async (hasExact) => {
344
- const child = path.endsWith("/") ? path : `${path}/`;
347
+ const child = path === "" ? "" : path.endsWith("/") ? path : `${path}/`;
345
348
  const want = limit === void 0 ? void 0 : limit + 1 - (hasExact ? 1 : 0);
346
349
  const children = await handle.list({ prefix: child, after, limit: want });
347
350
  validateMeta(children.meta);
@@ -358,9 +361,7 @@ async function awaitExact(handle, path, after, validateMeta) {
358
361
  return result.keys[0] === path;
359
362
  }
360
363
  function listPathCovered(prefixes, path) {
361
- const descendant = path.endsWith("/") ? path : `${path}/`;
362
- const covering = prefixes.filter((prefix) => kvPrefixCovers(prefix, path) && kvPrefixCovers(prefix, descendant));
363
- return covering.length === 1 ? covering[0] : void 0;
364
+ return prefixes.find((prefix) => kvPrefixCovers(prefix, path));
364
365
  }
365
366
 
366
367
  // src/kv/replication/events.ts
@@ -389,6 +390,7 @@ function raceSignal(job, signal) {
389
390
  }
390
391
  function createKVReplication(deps) {
391
392
  const { options, mode, storage, identity, session, authority, pending, scheduler } = deps;
393
+ const emit = (event) => emitEvent(deps.emit, scheduler, event);
392
394
  const replicas = /* @__PURE__ */ new Map();
393
395
  const statusInspections = /* @__PURE__ */ new Set();
394
396
  let isClosed = false;
@@ -397,7 +399,6 @@ function createKVReplication(deps) {
397
399
  let previous = deps.previous;
398
400
  let pinnedStateReported = false;
399
401
  const inProcessProof = /* @__PURE__ */ new Set();
400
- const emit = (event) => emitEvent(deps.emit, scheduler, event);
401
402
  const configuredPrefix = (path) => options.prefixes.find((prefix) => kvPrefixCovers(prefix, path));
402
403
  function recordRevocation(prefix, error) {
403
404
  if (errorCode(error) !== "GRANT_REVOKED") return;
@@ -407,6 +408,20 @@ function createKVReplication(deps) {
407
408
  state.lastError = "GRANT_REVOKED";
408
409
  replicas.set(prefix, state);
409
410
  }
411
+ function markRootUnsupported(prefix) {
412
+ const state = replicas.get(prefix) ?? {};
413
+ const firstRefusal = state.lastError !== "REPLICATION_ROOT_UNSUPPORTED";
414
+ state.reason = "replica_unavailable";
415
+ state.lastError = "REPLICATION_ROOT_UNSUPPORTED";
416
+ replicas.set(prefix, state);
417
+ if (firstRefusal) {
418
+ emit({ type: "replication.state", space: session.space, replica: prefix, state: "unavailable", code: "REPLICATION_ROOT_UNSUPPORTED" });
419
+ }
420
+ }
421
+ function unsupportedRoot(prefix) {
422
+ markRootUnsupported(prefix);
423
+ return Object.assign(new Error("This node doesn't support whole-space sync yet."), { code: "REPLICATION_ROOT_UNSUPPORTED" });
424
+ }
410
425
  async function open(prefix) {
411
426
  if (isClosed || purgeStarted) throw Object.assign(new Error("Replication controller is closed"), { code: "REPLICA_CLOSED" });
412
427
  let state = replicas.get(prefix);
@@ -440,6 +455,9 @@ function createKVReplication(deps) {
440
455
  state.strategy = "session";
441
456
  }
442
457
  const spec = { identity, space: session.space, prefix, allowSecrets: options.allowSecrets, ...device ? { device } : {}, ...deps.fetch ? { fetch: deps.fetch } : {} };
458
+ if (prefix === "/" && deps.nodeFeatures !== void 0 && !deps.nodeFeatures.includes("kv-sync-root")) {
459
+ throw unsupportedRoot(prefix);
460
+ }
443
461
  const handle = await storage.open(spec);
444
462
  state.handle = handle;
445
463
  emit({ type: "replication.state", space: session.space, replica: prefix, state: "opened" });
@@ -489,7 +507,7 @@ function createKVReplication(deps) {
489
507
  state.lastError = code;
490
508
  state.failures = (state.failures ?? 0) + 1;
491
509
  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));
510
+ 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
511
  state.handle?.close().catch(() => void 0);
494
512
  state.handle = void 0;
495
513
  throw error;
@@ -506,6 +524,9 @@ function createKVReplication(deps) {
506
524
  }, options.syncIntervalMs);
507
525
  }
508
526
  async function syncPrefix(prefix, trigger, signal, context) {
527
+ if (prefix === "/" && deps.nodeFeatures !== void 0 && !deps.nodeFeatures.includes("kv-sync-root")) {
528
+ throw unsupportedRoot(prefix);
529
+ }
509
530
  const handle = await open(prefix);
510
531
  const state = replicas.get(prefix);
511
532
  if (state.sync) return state.sync;
@@ -807,7 +828,7 @@ function createKVReplication(deps) {
807
828
  observeNetworkRequested({ op: "get", space: r.space, path: r.path, reason: "NETWORK_REQUESTED", outcome, latencyMs: scheduler.now() - started });
808
829
  }
809
830
  }
810
- if (!prefix) {
831
+ if (prefix === void 0) {
811
832
  const value = await r.network();
812
833
  readEvent("get", r.path, null, "network", "not_covered", value.ok ? "found" : value.error.code === ErrorCodes.KV_NOT_FOUND ? "not_found" : "error", started);
813
834
  return value;
@@ -958,10 +979,10 @@ function createKVReplication(deps) {
958
979
  return cursorRestart();
959
980
  };
960
981
  if (cursor && decoded && (decoded.space !== r.space || decoded.path !== r.listPath)) return restart();
961
- if (!prefix || !r.listPath || r.options?.raw) {
982
+ if (prefix === void 0 || r.options?.raw) {
962
983
  if (cursor && decoded) return restart();
963
984
  const result = await r.network();
964
- readEvent("list", r.listPath, prefix ?? null, "network", prefix ? "unsupported_option" : "not_covered", result.ok ? "found" : "error", started);
985
+ readEvent("list", r.listPath, prefix ?? null, "network", prefix !== void 0 ? "unsupported_option" : "not_covered", result.ok ? "found" : "error", started);
965
986
  return result;
966
987
  }
967
988
  let handle;
@@ -1056,7 +1077,7 @@ function createKVReplication(deps) {
1056
1077
  async function write(r) {
1057
1078
  const covered = r.entries.flatMap((entry) => {
1058
1079
  const prefix = configuredPrefix(entry.path);
1059
- return prefix ? [{ key: entry.path, op: r.op === "delete" ? "delete" : "put" }] : [];
1080
+ return prefix !== void 0 ? [{ key: entry.path, op: r.op === "delete" ? "delete" : "put" }] : [];
1060
1081
  });
1061
1082
  if (covered.length === 0) return r.network();
1062
1083
  await reportExistingPins();
@@ -1132,6 +1153,9 @@ function createKVReplication(deps) {
1132
1153
  const persistedSnapshot = pending.readExisting ? await pending.readExisting() : await pending.read();
1133
1154
  const snapshot = persistedSnapshot ?? emptyPendingState(identity);
1134
1155
  const entries = await Promise.all(options.prefixes.map(async (prefix) => {
1156
+ if (prefix === "/" && deps.nodeFeatures !== void 0 && !deps.nodeFeatures.includes("kv-sync-root")) {
1157
+ markRootUnsupported(prefix);
1158
+ }
1135
1159
  const records = snapshot.records.filter((r) => kvPrefixCovers(prefix, r.key));
1136
1160
  const opened = replicas.get(prefix);
1137
1161
  let local;
@@ -1146,12 +1170,13 @@ function createKVReplication(deps) {
1146
1170
  local ?? (local = inspected.local);
1147
1171
  if (inspected.missing && !opened?.reason && !opened?.authorityRevoked && !opened?.opening && !isClosed) return void 0;
1148
1172
  const revoked = opened?.authorityRevoked === true || local?.authority.state === "revoked";
1149
- const state = isClosed ? "closed" : revoked ? "revoked" : opened?.reason === "grant_missing" ? "grant_missing" : local?.coverage === "complete" && local.authority.state === "valid" ? "ready" : opened?.reason || inspected.errorCode ? "unavailable" : "idle";
1173
+ const rootUnsupported = opened?.lastError === "REPLICATION_ROOT_UNSUPPORTED";
1174
+ 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
1175
  return {
1151
1176
  prefix,
1152
1177
  state,
1153
1178
  ...opened?.reason ? { reason: opened.reason } : inspected.errorCode ? { reason: "replica_unavailable" } : {},
1154
- ...inspected.errorCode ? { errorCode: inspected.errorCode } : {},
1179
+ ...inspected.errorCode ?? opened?.lastError ? { errorCode: inspected.errorCode ?? opened?.lastError } : {},
1155
1180
  ...local ?? {},
1156
1181
  ...revoked ? { authority: { state: "revoked", expiresAt: local?.authority.expiresAt ?? null } } : {},
1157
1182
  pending: {
@@ -1166,7 +1191,7 @@ function createKVReplication(deps) {
1166
1191
  return entries.filter((entry) => entry !== void 0);
1167
1192
  }
1168
1193
  async function sync(o) {
1169
- const prefixes = o?.prefix ? options.prefixes.filter((p) => p === o.prefix) : options.prefixes;
1194
+ const prefixes = o?.prefix !== void 0 ? options.prefixes.filter((p) => p === o.prefix) : options.prefixes;
1170
1195
  await Promise.all(prefixes.map((prefix) => syncPrefix(prefix, "manual", o?.signal).then(() => void 0)));
1171
1196
  }
1172
1197
  async function clearPending2() {