@tinycloud/sdk-services 2.3.0-beta.5 → 2.3.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.
package/dist/index.d.cts CHANGED
@@ -1,8 +1,8 @@
1
- import { I as IServiceContext, a as InvokeFunction, b as InvokeAnyFunction, F as FetchFunction, S as ServiceSession, R as RetryPolicy, c as IService, d as ServiceError, e as Result, B as BaseService, f as StorageQuotaInfo } from './BaseService-C_iXlTeN.cjs';
2
- export { E as ErrorCode, g as ErrorCodes, h as EventHandler, i as FetchRequestInit, j as FetchResponse, k as InvocationFact, l as InvocationFacts, m as InvokeAnyEntry, n as ServiceErrorEvent, o as ServiceHeaders, p as ServiceRequestEvent, q as ServiceResponseEvent, r as ServiceRetryEvent, T as TelemetryEvents, s as defaultRetryPolicy, t as err, u as ok, v as serviceError } from './BaseService-C_iXlTeN.cjs';
1
+ import { I as IServiceContext, a as InvokeFunction, b as InvokeAnyFunction, F as FetchFunction, S as ServiceSession, R as RetryPolicy, c as IService, d as ServiceError, e as Result, B as BaseService, f as StorageQuotaInfo } from './BaseService-DZ2hBJeD.cjs';
2
+ export { E as ErrorCode, g as ErrorCodes, h as EventHandler, i as FetchRequestInit, j as FetchResponse, k as InvocationFact, l as InvocationFacts, m as InvokeAnyEntry, n as ServiceErrorEvent, o as ServiceHeaders, p as ServiceRequestEvent, q as ServiceResponseEvent, r as ServiceRetryEvent, T as TelemetryEvents, s as defaultRetryPolicy, t as err, u as ok, v as serviceError } from './BaseService-DZ2hBJeD.cjs';
3
3
  import { z } from 'zod';
4
4
  import { IKVService } from './kv/index.cjs';
5
- export { DEFAULT_SIGNED_READ_URL_EXPIRY_MS, IPrefixedKVService, KVAction, KVActionType, KVCreateSignedReadUrlOptions, KVDeleteOptions, KVGetOptions, KVHeadOptions, KVListOptions, KVListResponse, KVPutOptions, KVResponse, KVResponseHeaders, KVService, KVServiceConfig, KVSignedReadUrlResponse, PrefixedKVService } from './kv/index.cjs';
5
+ export { DEFAULT_SIGNED_READ_URL_EXPIRY_MS, IPrefixedKVService, KVAction, KVActionType, KVBatchPutItem, KVBatchPutOptions, KVBatchPutResponse, KVCreateSignedReadUrlOptions, KVDeleteOptions, KVGetOptions, KVHeadOptions, KVListOptions, KVListResponse, KVPutOptions, KVResponse, KVResponseHeaders, KVService, KVServiceConfig, KVSignedReadUrlResponse, PrefixedKVService } from './kv/index.cjs';
6
6
  export { BatchOptions, BatchResponse, DatabaseHandle, ExecuteOptions, ExecuteResponse, IDatabaseHandle, ISQLService, QueryOptions, QueryResponse, SQLAction, SQLActionType, SQLService, SQLServiceConfig, SqlStatement, SqlValue } from './sql/index.cjs';
7
7
  import { IEncryptionService, DecryptCapabilityProof } from './encryption/index.cjs';
8
8
  export { BuildCanonicalDecryptRequestInput, BuildDecryptFactsInput, BuildDecryptInvocationInput, BuiltDecryptInvocation, CanonicalDecryptRequest, CanonicalJson, DECRYPT_ACTION, DECRYPT_FACT_TYPE, DECRYPT_RESULT_TYPE, DEFAULT_ENCRYPTION_ALG, DEFAULT_KEY_VERSION, DecryptEnvelopeOptions, DecryptInvocationFact, DecryptInvocationSigner, DecryptRequestBody, DecryptResponseBody, DecryptTransport, DiscoverNetworkInput, DiscoveredNetwork, DiscoverySource, ENCRYPTION_NETWORK_URN_PREFIX, ENCRYPTION_SERVICE, ENCRYPTION_SERVICE_SHORT, ENVELOPE_VERSION, EncryptToNetworkInput, EncryptToNetworkOptions, EncryptToNetworkResult, EncryptionCrypto, EncryptionError, EncryptionErrorInput, EncryptionService, EncryptionServiceConfig, InlineEncryptedEnvelope, Json, NETWORK_NAME_PATTERN, NetworkDescriptor, NetworkIdError, NodeDescriptorFetcher, ParsedNetworkId, RandomReceiverKeyInput, ReceiverKeyPair, ReceiverKeySigner, SignedReceiverKeyInput, VerifyDecryptResponseInput, WellKnownDescriptorFetcher, base64Decode, base64Encode, buildCanonicalDecryptRequest, buildDecryptAttenuation, buildDecryptFacts, buildDecryptInvocation, buildNetworkId, canonicalHashHex, canonicalSignedResponse, canonicalize as canonicalizeEncryptionJson, checkDecryptInvocationInput, decryptEnvelopeWithKey, deriveSignedReceiverKey, discoverNetwork, encryptToNetwork, encryptionError, ensureNetworkUsableForDecrypt, generateRandomReceiverKey, hexDecode, hexEncode, isNetworkId, networkDiscoveryKey, openWrappedKey, parseNetworkId, utf8Decode, utf8Encode, validateEnvelope, verifyDecryptResponse } from './encryption/index.cjs';
package/dist/index.d.ts CHANGED
@@ -1,8 +1,8 @@
1
- import { I as IServiceContext, a as InvokeFunction, b as InvokeAnyFunction, F as FetchFunction, S as ServiceSession, R as RetryPolicy, c as IService, d as ServiceError, e as Result, B as BaseService, f as StorageQuotaInfo } from './BaseService-C_iXlTeN.js';
2
- export { E as ErrorCode, g as ErrorCodes, h as EventHandler, i as FetchRequestInit, j as FetchResponse, k as InvocationFact, l as InvocationFacts, m as InvokeAnyEntry, n as ServiceErrorEvent, o as ServiceHeaders, p as ServiceRequestEvent, q as ServiceResponseEvent, r as ServiceRetryEvent, T as TelemetryEvents, s as defaultRetryPolicy, t as err, u as ok, v as serviceError } from './BaseService-C_iXlTeN.js';
1
+ import { I as IServiceContext, a as InvokeFunction, b as InvokeAnyFunction, F as FetchFunction, S as ServiceSession, R as RetryPolicy, c as IService, d as ServiceError, e as Result, B as BaseService, f as StorageQuotaInfo } from './BaseService-DZ2hBJeD.js';
2
+ export { E as ErrorCode, g as ErrorCodes, h as EventHandler, i as FetchRequestInit, j as FetchResponse, k as InvocationFact, l as InvocationFacts, m as InvokeAnyEntry, n as ServiceErrorEvent, o as ServiceHeaders, p as ServiceRequestEvent, q as ServiceResponseEvent, r as ServiceRetryEvent, T as TelemetryEvents, s as defaultRetryPolicy, t as err, u as ok, v as serviceError } from './BaseService-DZ2hBJeD.js';
3
3
  import { z } from 'zod';
4
4
  import { IKVService } from './kv/index.js';
5
- export { DEFAULT_SIGNED_READ_URL_EXPIRY_MS, IPrefixedKVService, KVAction, KVActionType, KVCreateSignedReadUrlOptions, KVDeleteOptions, KVGetOptions, KVHeadOptions, KVListOptions, KVListResponse, KVPutOptions, KVResponse, KVResponseHeaders, KVService, KVServiceConfig, KVSignedReadUrlResponse, PrefixedKVService } from './kv/index.js';
5
+ export { DEFAULT_SIGNED_READ_URL_EXPIRY_MS, IPrefixedKVService, KVAction, KVActionType, KVBatchPutItem, KVBatchPutOptions, KVBatchPutResponse, KVCreateSignedReadUrlOptions, KVDeleteOptions, KVGetOptions, KVHeadOptions, KVListOptions, KVListResponse, KVPutOptions, KVResponse, KVResponseHeaders, KVService, KVServiceConfig, KVSignedReadUrlResponse, PrefixedKVService } from './kv/index.js';
6
6
  export { BatchOptions, BatchResponse, DatabaseHandle, ExecuteOptions, ExecuteResponse, IDatabaseHandle, ISQLService, QueryOptions, QueryResponse, SQLAction, SQLActionType, SQLService, SQLServiceConfig, SqlStatement, SqlValue } from './sql/index.js';
7
7
  import { IEncryptionService, DecryptCapabilityProof } from './encryption/index.js';
8
8
  export { BuildCanonicalDecryptRequestInput, BuildDecryptFactsInput, BuildDecryptInvocationInput, BuiltDecryptInvocation, CanonicalDecryptRequest, CanonicalJson, DECRYPT_ACTION, DECRYPT_FACT_TYPE, DECRYPT_RESULT_TYPE, DEFAULT_ENCRYPTION_ALG, DEFAULT_KEY_VERSION, DecryptEnvelopeOptions, DecryptInvocationFact, DecryptInvocationSigner, DecryptRequestBody, DecryptResponseBody, DecryptTransport, DiscoverNetworkInput, DiscoveredNetwork, DiscoverySource, ENCRYPTION_NETWORK_URN_PREFIX, ENCRYPTION_SERVICE, ENCRYPTION_SERVICE_SHORT, ENVELOPE_VERSION, EncryptToNetworkInput, EncryptToNetworkOptions, EncryptToNetworkResult, EncryptionCrypto, EncryptionError, EncryptionErrorInput, EncryptionService, EncryptionServiceConfig, InlineEncryptedEnvelope, Json, NETWORK_NAME_PATTERN, NetworkDescriptor, NetworkIdError, NodeDescriptorFetcher, ParsedNetworkId, RandomReceiverKeyInput, ReceiverKeyPair, ReceiverKeySigner, SignedReceiverKeyInput, VerifyDecryptResponseInput, WellKnownDescriptorFetcher, base64Decode, base64Encode, buildCanonicalDecryptRequest, buildDecryptAttenuation, buildDecryptFacts, buildDecryptInvocation, buildNetworkId, canonicalHashHex, canonicalSignedResponse, canonicalize as canonicalizeEncryptionJson, checkDecryptInvocationInput, decryptEnvelopeWithKey, deriveSignedReceiverKey, discoverNetwork, encryptToNetwork, encryptionError, ensureNetworkUsableForDecrypt, generateRandomReceiverKey, hexDecode, hexEncode, isNetworkId, networkDiscoveryKey, openWrappedKey, parseNetworkId, utf8Decode, utf8Encode, validateEnvelope, verifyDecryptResponse } from './encryption/index.js';
package/dist/index.js CHANGED
@@ -793,6 +793,18 @@ var PrefixedKVService = class _PrefixedKVService {
793
793
  const fullKey = this.getFullKey(key);
794
794
  return this._kv.put(fullKey, value, { ...options, prefix: "" });
795
795
  }
796
+ /**
797
+ * Store multiple values within this prefix in one TinyCloud KV invocation.
798
+ */
799
+ async batchPut(items, options) {
800
+ return this._kv.batchPut(
801
+ items.map((item) => ({
802
+ ...item,
803
+ key: this.getFullKey(item.key)
804
+ })),
805
+ { ...options, prefix: "" }
806
+ );
807
+ }
796
808
  /**
797
809
  * List keys within this prefix.
798
810
  */
@@ -846,6 +858,12 @@ var KVAction = {
846
858
  };
847
859
 
848
860
  // src/kv/KVService.ts
861
+ function encodeKvBatchPartName(path) {
862
+ return encodeURIComponent(path).replace(
863
+ /[!'()*]/g,
864
+ (char) => `%${char.charCodeAt(0).toString(16).toUpperCase()}`
865
+ );
866
+ }
849
867
  var KVService = class extends BaseService {
850
868
  /**
851
869
  * Create a new KVService instance.
@@ -954,6 +972,53 @@ var KVService = class extends BaseService {
954
972
  signal: this.combineSignals(signal)
955
973
  });
956
974
  }
975
+ serializeBatchPutValue(item) {
976
+ const contentType = item.contentType;
977
+ if (item.value instanceof Blob) {
978
+ if (!contentType || item.value.type === contentType) {
979
+ return item.value;
980
+ }
981
+ return new Blob([item.value], { type: contentType });
982
+ }
983
+ if (item.value instanceof ArrayBuffer) {
984
+ return new Blob([item.value], {
985
+ type: contentType ?? "application/octet-stream"
986
+ });
987
+ }
988
+ if (ArrayBuffer.isView(item.value)) {
989
+ const value = item.value;
990
+ const bytes = new Uint8Array(value.byteLength);
991
+ bytes.set(new Uint8Array(value.buffer, value.byteOffset, value.byteLength));
992
+ return new Blob([bytes], {
993
+ type: contentType ?? "application/octet-stream"
994
+ });
995
+ }
996
+ if (typeof item.value === "string") {
997
+ return new Blob([item.value], {
998
+ type: contentType ?? "text/plain;charset=UTF-8"
999
+ });
1000
+ }
1001
+ const json = JSON.stringify(item.value);
1002
+ if (json === void 0) {
1003
+ throw new Error(`Cannot JSON serialize KV batch value for key "${item.key}"`);
1004
+ }
1005
+ return new Blob([json], {
1006
+ type: contentType ?? "application/json"
1007
+ });
1008
+ }
1009
+ normalizeBatchPutResponse(data) {
1010
+ if (!data || typeof data !== "object") {
1011
+ return void 0;
1012
+ }
1013
+ const response = data;
1014
+ if (!Array.isArray(response.written) || !response.written.every((key) => typeof key === "string") || typeof response.count !== "number") {
1015
+ return void 0;
1016
+ }
1017
+ return {
1018
+ written: response.written,
1019
+ count: response.count
1020
+ };
1021
+ }
957
1022
  /**
958
1023
  * Create KVResponseHeaders from fetch response headers.
959
1024
  *
@@ -1155,6 +1220,107 @@ var KVService = class extends BaseService {
1155
1220
  }
1156
1221
  });
1157
1222
  }
1223
+ /**
1224
+ * Store multiple values in one TinyCloud KV invocation.
1225
+ */
1226
+ async batchPut(items, options) {
1227
+ return this.withTelemetry("batchPut", String(items.length), async () => {
1228
+ if (!this.requireAuth()) {
1229
+ return err(authRequiredError("kv"));
1230
+ }
1231
+ if (items.length === 0) {
1232
+ return ok({ written: [], count: 0 });
1233
+ }
1234
+ if (!this.context.invokeAny) {
1235
+ return err(
1236
+ serviceError(
1237
+ ErrorCodes.INVALID_INPUT,
1238
+ "KV batchPut requires SDK runtime support for multi-resource invocations",
1239
+ "kv"
1240
+ )
1241
+ );
1242
+ }
1243
+ const session = this.context.session;
1244
+ const paths = items.map((item) => this.getFullPath(item.key, options?.prefix));
1245
+ const seen = /* @__PURE__ */ new Set();
1246
+ for (const path of paths) {
1247
+ if (seen.has(path)) {
1248
+ return err(
1249
+ serviceError(
1250
+ ErrorCodes.INVALID_INPUT,
1251
+ `KV batchPut received duplicate key after prefix resolution: ${path}`,
1252
+ "kv"
1253
+ )
1254
+ );
1255
+ }
1256
+ seen.add(path);
1257
+ }
1258
+ try {
1259
+ const body = new FormData();
1260
+ for (let index = 0; index < items.length; index++) {
1261
+ body.append(
1262
+ encodeKvBatchPartName(paths[index]),
1263
+ this.serializeBatchPutValue(items[index])
1264
+ );
1265
+ }
1266
+ const headers = this.context.invokeAny(
1267
+ session,
1268
+ paths.map((path) => ({
1269
+ spaceId: session.spaceId,
1270
+ service: "kv",
1271
+ path,
1272
+ action: KVAction.PUT
1273
+ }))
1274
+ );
1275
+ const response = await this.context.fetch(`${this.host}/invoke`, {
1276
+ method: "POST",
1277
+ headers,
1278
+ body,
1279
+ signal: this.combineSignals(options?.signal)
1280
+ });
1281
+ if (!response.ok) {
1282
+ const errorText = await response.text();
1283
+ if (response.status === 401 || response.status === 403) {
1284
+ const { resource, action } = parseAuthError(errorText);
1285
+ return err(authUnauthorizedError("kv", errorText, {
1286
+ status: response.status,
1287
+ ...action && { requiredAction: action },
1288
+ ...resource && { resource }
1289
+ }));
1290
+ }
1291
+ const quotaError = this.handleQuotaErrorResponse(
1292
+ response,
1293
+ errorText,
1294
+ "batch"
1295
+ );
1296
+ if (quotaError) {
1297
+ return quotaError;
1298
+ }
1299
+ return err(
1300
+ serviceError(
1301
+ ErrorCodes.KV_WRITE_FAILED,
1302
+ `Failed to batch put ${items.length} key(s): ${response.status} - ${errorText}`,
1303
+ "kv",
1304
+ { meta: { status: response.status, statusText: response.statusText } }
1305
+ )
1306
+ );
1307
+ }
1308
+ const batchResponse = this.normalizeBatchPutResponse(await response.json());
1309
+ if (!batchResponse || batchResponse.count !== batchResponse.written.length) {
1310
+ return err(
1311
+ serviceError(
1312
+ ErrorCodes.NETWORK_ERROR,
1313
+ "KV batchPut response did not include matching written keys and count",
1314
+ "kv"
1315
+ )
1316
+ );
1317
+ }
1318
+ return ok(batchResponse);
1319
+ } catch (error) {
1320
+ return err(wrapError("kv", error));
1321
+ }
1322
+ });
1323
+ }
1158
1324
  /**
1159
1325
  * List keys with optional prefix filtering.
1160
1326
  */
@@ -1504,7 +1670,7 @@ var SQLService = class extends BaseService {
1504
1670
  try {
1505
1671
  const response = await this.invokeSQL(
1506
1672
  dbName,
1507
- SQLAction.READ,
1673
+ this.actionForSql(sql, SQLAction.READ),
1508
1674
  { action: "query", sql, params: params ?? [] },
1509
1675
  options?.signal
1510
1676
  );
@@ -1534,7 +1700,7 @@ var SQLService = class extends BaseService {
1534
1700
  }
1535
1701
  const response = await this.invokeSQL(
1536
1702
  dbName,
1537
- SQLAction.WRITE,
1703
+ this.actionForSql(sql, SQLAction.WRITE),
1538
1704
  body,
1539
1705
  options?.signal
1540
1706
  );
@@ -1556,7 +1722,7 @@ var SQLService = class extends BaseService {
1556
1722
  try {
1557
1723
  const response = await this.invokeSQL(
1558
1724
  dbName,
1559
- SQLAction.WRITE,
1725
+ this.actionForSqlBatch(statements),
1560
1726
  { action: "batch", statements },
1561
1727
  options?.signal
1562
1728
  );
@@ -1633,6 +1799,14 @@ var SQLService = class extends BaseService {
1633
1799
  signal: this.combineSignals(signal)
1634
1800
  });
1635
1801
  }
1802
+ actionForSql(sql, fallback) {
1803
+ return firstSqlToken(sql) === "pragma" ? SQLAction.ADMIN : fallback;
1804
+ }
1805
+ actionForSqlBatch(statements) {
1806
+ return statements.some(
1807
+ (statement) => this.actionForSql(statement.sql, SQLAction.WRITE) === SQLAction.ADMIN
1808
+ ) ? SQLAction.ADMIN : SQLAction.WRITE;
1809
+ }
1636
1810
  async handleErrorResponse(response, operation) {
1637
1811
  const errorText = await response.text();
1638
1812
  let errorBody = {};
@@ -1678,6 +1852,33 @@ var SQLService = class extends BaseService {
1678
1852
  }
1679
1853
  };
1680
1854
  SQLService.serviceName = "sql";
1855
+ function firstSqlToken(sql) {
1856
+ let index = 0;
1857
+ while (index < sql.length) {
1858
+ while (index < sql.length && /\s/.test(sql[index])) {
1859
+ index++;
1860
+ }
1861
+ if (sql.startsWith("--", index)) {
1862
+ const newline = sql.indexOf("\n", index + 2);
1863
+ if (newline === -1) {
1864
+ return void 0;
1865
+ }
1866
+ index = newline + 1;
1867
+ continue;
1868
+ }
1869
+ if (sql.startsWith("/*", index)) {
1870
+ const end = sql.indexOf("*/", index + 2);
1871
+ if (end === -1) {
1872
+ return void 0;
1873
+ }
1874
+ index = end + 2;
1875
+ continue;
1876
+ }
1877
+ break;
1878
+ }
1879
+ const match = /^[A-Za-z_]+/.exec(sql.slice(index));
1880
+ return match?.[0].toLowerCase();
1881
+ }
1681
1882
 
1682
1883
  // src/duckdb/DuckDbDatabaseHandle.ts
1683
1884
  var DuckDbDatabaseHandle = class {