@tinycloud/sdk-services 3.3.0-beta.7 → 3.3.0

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 (39) hide show
  1. package/dist/{BaseService-Cc6Ueicm.d.cts → BaseService-BhfKzKke.d.cts} +5 -1
  2. package/dist/{BaseService-DOdXd7sr.d.ts → BaseService-x4AFZiEa.d.ts} +5 -1
  3. package/dist/encryption/index.cjs +18 -5
  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 +18 -5
  8. package/dist/encryption/index.js.map +1 -1
  9. package/dist/index.cjs +911 -797
  10. package/dist/index.cjs.map +1 -1
  11. package/dist/index.d.cts +95 -11
  12. package/dist/index.d.ts +95 -11
  13. package/dist/index.js +911 -797
  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 +72 -80
  18. package/dist/kv/index.cjs.map +1 -1
  19. package/dist/kv/index.d.cts +4 -5
  20. package/dist/kv/index.d.ts +4 -5
  21. package/dist/kv/index.js +72 -80
  22. package/dist/kv/index.js.map +1 -1
  23. package/dist/kv/replication/index.cjs +6 -5
  24. package/dist/kv/replication/index.cjs.map +1 -1
  25. package/dist/kv/replication/index.d.cts +3 -3
  26. package/dist/kv/replication/index.d.ts +3 -3
  27. package/dist/kv/replication/index.js +6 -5
  28. package/dist/kv/replication/index.js.map +1 -1
  29. package/dist/{scope-B-m6cKH-.d.ts → scope-BHTkk5Yk.d.ts} +13 -2
  30. package/dist/{scope-B7oeKdLM.d.cts → scope-DMhalRFn.d.cts} +13 -2
  31. package/dist/sql/index.cjs +30 -16
  32. package/dist/sql/index.cjs.map +1 -1
  33. package/dist/sql/index.d.cts +2 -2
  34. package/dist/sql/index.d.ts +2 -2
  35. package/dist/sql/index.js +30 -16
  36. package/dist/sql/index.js.map +1 -1
  37. package/dist/{types-BjH0ZtGy.d.cts → types-eVS1Whuf.d.cts} +24 -4
  38. package/dist/{types-BjH0ZtGy.d.ts → types-eVS1Whuf.d.ts} +24 -4
  39. package/package.json +2 -2
@@ -1,4 +1,4 @@
1
- import { R as Result, F as FetchFunction } from './types-BjH0ZtGy.js';
1
+ import { e as RetryStats, R as Result, f as FetchFunction } from './types-eVS1Whuf.js';
2
2
  import { REPLICA_KV_STORES } from './kv/replication/contractConstants.js';
3
3
  import { ReplicaConsentAnchor, ReplicaGrantPolicy } from './kv/replication/grantPolicyTypes.js';
4
4
 
@@ -334,6 +334,8 @@ interface KVResponse<T = unknown> {
334
334
  * Response headers with metadata.
335
335
  */
336
336
  headers: KVResponseHeaders;
337
+ /** Attempts and total backoff for the request behind this response; see `RetryPolicy`. */
338
+ retry?: RetryStats;
337
339
  }
338
340
  /**
339
341
  * Response from KV list operations.
@@ -1172,7 +1174,12 @@ interface ReplicaQuotaSpec {
1172
1174
  /** Node/CLI page admission keeps its existing blob/entry interpretation. */
1173
1175
  interface ReplicaPageAdmission {
1174
1176
  partitionId: string;
1175
- /** Sum of the page's new blob bytes (node admission hook's existing metric). */
1177
+ /**
1178
+ * Node/CLI: the page's NET blob bytes, only blob content counted (not the database, WAL, rows or
1179
+ * pending store): new blobs not already stored, minus blobs only replaced or deleted entries
1180
+ * referenced. Negative when the page frees more than it adds; a page with `blobBytes <= 0` is
1181
+ * always admitted. Browser hosts keep their own ledger metric.
1182
+ */
1176
1183
  blobBytes: number;
1177
1184
  /** Number of entry writes; not the browser ciphertext-row accounting metric. */
1178
1185
  entries: number;
@@ -1779,6 +1786,10 @@ interface ReplicationOptions {
1779
1786
  /**
1780
1787
  * Replica byte budget; absent means unbounded. Browser: origin-wide across every partition.
1781
1788
  * Node/CLI: per profile (per storage dir). Forwarded to storage via `KVReplicaSpec.quota`.
1789
+ * Node/CLI bounds the COMMITTED replica blob content only; the database, WAL, rows and the
1790
+ * pending store are not counted. During a page commit the previous blobs of replaced entries
1791
+ * stay until the commit completes, so on-disk bytes can transiently reach `maxBytes` plus the
1792
+ * bytes that page replaces. Orphaned blobs left by a crash are counted until collected on open.
1782
1793
  */
1783
1794
  maxBytes?: number;
1784
1795
  /** Browser free-space floor; default DEFAULT_MIN_FREE_BYTES (64 MiB). Ignored on node/CLI. */
@@ -1,4 +1,4 @@
1
- import { R as Result, F as FetchFunction } from './types-BjH0ZtGy.cjs';
1
+ import { e as RetryStats, R as Result, f as FetchFunction } from './types-eVS1Whuf.cjs';
2
2
  import { REPLICA_KV_STORES } from './kv/replication/contractConstants.cjs';
3
3
  import { ReplicaConsentAnchor, ReplicaGrantPolicy } from './kv/replication/grantPolicyTypes.cjs';
4
4
 
@@ -334,6 +334,8 @@ interface KVResponse<T = unknown> {
334
334
  * Response headers with metadata.
335
335
  */
336
336
  headers: KVResponseHeaders;
337
+ /** Attempts and total backoff for the request behind this response; see `RetryPolicy`. */
338
+ retry?: RetryStats;
337
339
  }
338
340
  /**
339
341
  * Response from KV list operations.
@@ -1172,7 +1174,12 @@ interface ReplicaQuotaSpec {
1172
1174
  /** Node/CLI page admission keeps its existing blob/entry interpretation. */
1173
1175
  interface ReplicaPageAdmission {
1174
1176
  partitionId: string;
1175
- /** Sum of the page's new blob bytes (node admission hook's existing metric). */
1177
+ /**
1178
+ * Node/CLI: the page's NET blob bytes, only blob content counted (not the database, WAL, rows or
1179
+ * pending store): new blobs not already stored, minus blobs only replaced or deleted entries
1180
+ * referenced. Negative when the page frees more than it adds; a page with `blobBytes <= 0` is
1181
+ * always admitted. Browser hosts keep their own ledger metric.
1182
+ */
1176
1183
  blobBytes: number;
1177
1184
  /** Number of entry writes; not the browser ciphertext-row accounting metric. */
1178
1185
  entries: number;
@@ -1779,6 +1786,10 @@ interface ReplicationOptions {
1779
1786
  /**
1780
1787
  * Replica byte budget; absent means unbounded. Browser: origin-wide across every partition.
1781
1788
  * Node/CLI: per profile (per storage dir). Forwarded to storage via `KVReplicaSpec.quota`.
1789
+ * Node/CLI bounds the COMMITTED replica blob content only; the database, WAL, rows and the
1790
+ * pending store are not counted. During a page commit the previous blobs of replaced entries
1791
+ * stay until the commit completes, so on-disk bytes can transiently reach `maxBytes` plus the
1792
+ * bytes that page replaces. Orphaned blobs left by a crash are counted until collected on open.
1782
1793
  */
1783
1794
  maxBytes?: number;
1784
1795
  /** Browser free-space floor; default DEFAULT_MIN_FREE_BYTES (64 MiB). Ignored on node/CLI. */
@@ -45,7 +45,7 @@ var ErrorCodes = {
45
45
  PERMISSION_DENIED: "PERMISSION_DENIED",
46
46
  // Node retry signals (tinycloud-node #347). `meta.retryable` says whether a
47
47
  // retry is safe; `meta.retryAfterMs` carries the node's Retry-After.
48
- /** HTTP 503 `sql_busy:<stage>` / `unavailable_retryable`: nothing was applied; retry after `meta.retryAfterMs`. */
48
+ /** HTTP 503 `sql_busy:<stage>` / `unavailable_retryable`/`read_audit_busy`: nothing was applied; retry after `meta.retryAfterMs`. */
49
49
  NODE_BUSY: "NODE_BUSY",
50
50
  /** HTTP 503 `request_timeout`: the node's deadline passed before any write began; nothing was applied. */
51
51
  REQUEST_TIMEOUT: "REQUEST_TIMEOUT",
@@ -86,11 +86,12 @@ var ErrorCodes = {
86
86
  DUCKDB_READONLY_VIOLATION: "DUCKDB_READONLY_VIOLATION"
87
87
  };
88
88
  var defaultRetryPolicy = {
89
- maxAttempts: 3,
89
+ maxAttempts: 4,
90
90
  backoff: "exponential",
91
- baseDelayMs: 1e3,
92
- maxDelayMs: 1e4,
93
- retryableErrors: [ErrorCodes.NETWORK_ERROR, ErrorCodes.TIMEOUT]
91
+ baseDelayMs: 250,
92
+ maxDelayMs: 4e3,
93
+ retryableErrors: [ErrorCodes.NODE_BUSY, ErrorCodes.REQUEST_TIMEOUT],
94
+ maxTotalMs: 12e3
94
95
  };
95
96
  var TelemetryEvents = {
96
97
  SPAN: "telemetry.span",
@@ -175,7 +176,7 @@ function nodeRetryError(service, message, response, errorText) {
175
176
  const body = errorText.trim();
176
177
  const [, token, stage] = /^([a-z_]+)(?::\s*([a-z_]+):)?/.exec(body) ?? [];
177
178
  let code;
178
- if (response.status === 503 && (token === "sql_busy" || token === "unavailable_retryable")) {
179
+ if (response.status === 503 && (token === "sql_busy" || token === "unavailable_retryable" || token === "read_audit_busy")) {
179
180
  code = ErrorCodes.NODE_BUSY;
180
181
  } else if (response.status === 503 && token === "request_timeout") {
181
182
  code = ErrorCodes.REQUEST_TIMEOUT;
@@ -514,6 +515,18 @@ var BaseService = class {
514
515
  }
515
516
  return controller.signal;
516
517
  }
518
+ /** POST a signed invocation with retry; `mint` re-signs per attempt, `init.headers` add to the signed ones. */
519
+ invokeWithRetry(url, mint, { headers: extra, ...init } = {}) {
520
+ const build = () => {
521
+ const signed = mint();
522
+ return {
523
+ method: "POST",
524
+ ...init,
525
+ headers: Array.isArray(signed) ? [...signed, ...Object.entries(extra ?? {})] : { ...signed, ...extra }
526
+ };
527
+ };
528
+ return this.context.invokeWithRetry ? this.context.invokeWithRetry(url, build) : this.context.fetch(url, build());
529
+ }
517
530
  /**
518
531
  * Create the abort signal for one request, bounded by the request timeout.
519
532
  *
@@ -965,18 +978,19 @@ var SQLService = class extends BaseService {
965
978
  }
966
979
  // === Private helpers ===
967
980
  async invokeSQL(dbName, actions, body, signal) {
968
- const session = this.context.session;
969
981
  const actionList = Array.isArray(actions) ? actions : [actions];
970
- const headers = actionList.length === 1 ? this.context.invoke(session, "sql", dbName, actionList[0]) : this.invokeSQLAny(session, dbName, actionList);
971
- return this.context.fetch(`${this.host}/invoke`, {
972
- method: "POST",
973
- headers: {
974
- ...headers,
975
- "Content-Type": "application/json"
982
+ return this.invokeWithRetry(
983
+ `${this.host}/invoke`,
984
+ () => {
985
+ const session = this.context.session;
986
+ return actionList.length === 1 ? this.context.invoke(session, "sql", dbName, actionList[0]) : this.invokeSQLAny(session, dbName, actionList);
976
987
  },
977
- body: JSON.stringify(body),
978
- signal
979
- });
988
+ {
989
+ headers: { "Content-Type": "application/json" },
990
+ body: JSON.stringify(body),
991
+ signal
992
+ }
993
+ );
980
994
  }
981
995
  actionForSql(sql, fallback) {
982
996
  const token = firstSqlToken(sql);