@tinycloud/sdk-services 2.1.0 → 2.2.0-beta.12

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
@@ -2,7 +2,7 @@ import { I as IServiceContext, a as InvokeFunction, b as InvokeAnyFunction, F as
2
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-BiS6HRwE.cjs';
3
3
  import { z } from 'zod';
4
4
  import { IKVService } from './kv/index.cjs';
5
- export { IPrefixedKVService, KVAction, KVActionType, KVDeleteOptions, KVGetOptions, KVHeadOptions, KVListOptions, KVListResponse, KVPutOptions, KVResponse, KVResponseHeaders, KVService, KVServiceConfig, PrefixedKVService } 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';
6
6
  export { BatchOptions, BatchResponse, DatabaseHandle, ExecuteOptions, ExecuteResponse, IDatabaseHandle, ISQLService, QueryOptions, QueryResponse, SQLAction, SQLActionType, SQLService, SQLServiceConfig, SqlStatement, SqlValue } from './sql/index.cjs';
7
7
 
8
8
  /**
@@ -1937,4 +1937,55 @@ interface WasmVaultFunctions {
1937
1937
  }
1938
1938
  declare function createVaultCrypto(wasm: WasmVaultFunctions): VaultCrypto;
1939
1939
 
1940
- export { BaseService, type BaseServiceOptions, type ColumnInfo, type DataVaultConfig, DataVaultService, DuckDbAction, type DuckDbActionType, type DuckDbBatchOptions, type BatchResponse as DuckDbBatchResponse, DuckDbDatabaseHandle, type DuckDbExecuteOptions, type ExecuteResponse as DuckDbExecuteResponse, type DuckDbOptions, type DuckDbQueryOptions, type QueryResponse as DuckDbQueryResponse, DuckDbService, type DuckDbServiceConfig, type DuckDbStatement, type DuckDbValue, FetchFunction, GenericKVResponseSchema, type GenericKVResponseType, GenericResultSchema, type HookEvent, type HookServiceName, type HookStreamEvent, type HookSubscription, type HookWebhookListOptions, type HookWebhookRecord, type HookWebhookRegistration, type HookWebhookScope, type HookWebhookUnregisterOptions, HooksService, type HooksServiceConfig, type IDataVaultService, type IDuckDbDatabaseHandle, type IDuckDbService, type IHooksService, IKVService, IService, IServiceContext, InvokeAnyFunction, InvokeFunction, KVListResponseSchema, type KVListResponseType, KVListResultSchema, type KVListResultType, KVResponseHeadersSchema, type KVResponseHeadersType, type QuotaConfig, type QuotaStatus, Result, RetryPolicy, RetryPolicySchema, type RetryPolicyType, type SchemaInfo, type ServiceConstructor, ServiceContext, type ServiceContextConfig, ServiceError, ServiceErrorEventSchema, type ServiceErrorEventType, ServiceErrorSchema, type ServiceErrorType, type ServiceRegistration, ServiceRequestEventSchema, type ServiceRequestEventType, ServiceResponseEventSchema, type ServiceResponseEventType, ServiceRetryEventSchema, type ServiceRetryEventType, ServiceSession, ServiceSessionSchema, type ServiceSessionType, StorageQuotaInfo, type SubscribeOptions, type TableInfo, TinyCloudQuota, type ValidationError, type VaultCrypto, type VaultEntry, type VaultError, type VaultGetOptions, type VaultGrantOptions, VaultHeaders, type VaultListOptions, VaultPublicSpaceKVActions, type VaultPutOptions, type ViewInfo, type WasmVaultFunctions, abortedError, authExpiredError, authRequiredError, authUnauthorizedError, createKVResponseSchema, createResultSchema, createVaultCrypto, errorResult, networkError, notFoundError, parseAuthError, permissionDeniedError, storageLimitReachedError, storageQuotaExceededError, timeoutError, validateKVListResponse, validateKVResponseHeaders, validateRetryPolicy, validateServiceError, validateServiceRequestEvent, validateServiceResponseEvent, validateServiceSession, wrapError };
1940
+ declare const SECRET_NAME_RE: RegExp;
1941
+ interface SecretScopeOptions {
1942
+ /** Optional logical scope. Omit for the global secret namespace. */
1943
+ scope?: string;
1944
+ }
1945
+ interface ResolvedSecretPath {
1946
+ /** Canonical env-style secret name. */
1947
+ name: string;
1948
+ /** Canonical scope. Undefined means global. */
1949
+ scope?: string;
1950
+ /** Key passed to the data vault service. */
1951
+ vaultKey: string;
1952
+ /** KV permission paths that back the encrypted vault entry. */
1953
+ permissionPaths: {
1954
+ keys: string;
1955
+ vault: string;
1956
+ };
1957
+ }
1958
+ declare function canonicalizeSecretScope(scope: string | undefined): string | undefined;
1959
+ declare function resolveSecretPath(name: string, options?: SecretScopeOptions): ResolvedSecretPath;
1960
+
1961
+ interface SecretPayload {
1962
+ value: string;
1963
+ createdAt: string;
1964
+ updatedAt: string;
1965
+ }
1966
+ type SecretsError = VaultError | ServiceError;
1967
+ interface ISecretsService {
1968
+ readonly vault: IDataVaultService;
1969
+ unlock(signer?: unknown): Promise<Result<void, VaultError>>;
1970
+ lock(): void;
1971
+ readonly isUnlocked: boolean;
1972
+ get(name: string, options?: SecretScopeOptions): Promise<Result<string, SecretsError>>;
1973
+ put(name: string, value: string, options?: SecretScopeOptions): Promise<Result<void, SecretsError>>;
1974
+ delete(name: string, options?: SecretScopeOptions): Promise<Result<void, SecretsError>>;
1975
+ list(options?: SecretScopeOptions): Promise<Result<string[], SecretsError>>;
1976
+ }
1977
+
1978
+ declare class SecretsService implements ISecretsService {
1979
+ private readonly getVault;
1980
+ constructor(vault: IDataVaultService | (() => IDataVaultService));
1981
+ get vault(): IDataVaultService;
1982
+ get isUnlocked(): boolean;
1983
+ unlock(signer?: unknown): Promise<Result<void, VaultError>>;
1984
+ lock(): void;
1985
+ get(name: string, options?: SecretScopeOptions): Promise<Result<string, SecretsError>>;
1986
+ put(name: string, value: string, options?: SecretScopeOptions): Promise<Result<void, SecretsError>>;
1987
+ delete(name: string, options?: SecretScopeOptions): Promise<Result<void, SecretsError>>;
1988
+ list(options?: SecretScopeOptions): Promise<Result<string[], SecretsError>>;
1989
+ }
1990
+
1991
+ export { BaseService, type BaseServiceOptions, type ColumnInfo, type DataVaultConfig, DataVaultService, DuckDbAction, type DuckDbActionType, type DuckDbBatchOptions, type BatchResponse as DuckDbBatchResponse, DuckDbDatabaseHandle, type DuckDbExecuteOptions, type ExecuteResponse as DuckDbExecuteResponse, type DuckDbOptions, type DuckDbQueryOptions, type QueryResponse as DuckDbQueryResponse, DuckDbService, type DuckDbServiceConfig, type DuckDbStatement, type DuckDbValue, FetchFunction, GenericKVResponseSchema, type GenericKVResponseType, GenericResultSchema, type HookEvent, type HookServiceName, type HookStreamEvent, type HookSubscription, type HookWebhookListOptions, type HookWebhookRecord, type HookWebhookRegistration, type HookWebhookScope, type HookWebhookUnregisterOptions, HooksService, type HooksServiceConfig, type IDataVaultService, type IDuckDbDatabaseHandle, type IDuckDbService, type IHooksService, IKVService, type ISecretsService, IService, IServiceContext, InvokeAnyFunction, InvokeFunction, KVListResponseSchema, type KVListResponseType, KVListResultSchema, type KVListResultType, KVResponseHeadersSchema, type KVResponseHeadersType, type QuotaConfig, type QuotaStatus, type ResolvedSecretPath, Result, RetryPolicy, RetryPolicySchema, type RetryPolicyType, SECRET_NAME_RE, type SchemaInfo, type SecretPayload, type SecretScopeOptions, type SecretsError, SecretsService, type ServiceConstructor, ServiceContext, type ServiceContextConfig, ServiceError, ServiceErrorEventSchema, type ServiceErrorEventType, ServiceErrorSchema, type ServiceErrorType, type ServiceRegistration, ServiceRequestEventSchema, type ServiceRequestEventType, ServiceResponseEventSchema, type ServiceResponseEventType, ServiceRetryEventSchema, type ServiceRetryEventType, ServiceSession, ServiceSessionSchema, type ServiceSessionType, StorageQuotaInfo, type SubscribeOptions, type TableInfo, TinyCloudQuota, type ValidationError, type VaultCrypto, type VaultEntry, type VaultError, type VaultGetOptions, type VaultGrantOptions, VaultHeaders, type VaultListOptions, VaultPublicSpaceKVActions, type VaultPutOptions, type ViewInfo, type WasmVaultFunctions, abortedError, authExpiredError, authRequiredError, authUnauthorizedError, canonicalizeSecretScope, createKVResponseSchema, createResultSchema, createVaultCrypto, errorResult, networkError, notFoundError, parseAuthError, permissionDeniedError, resolveSecretPath, storageLimitReachedError, storageQuotaExceededError, timeoutError, validateKVListResponse, validateKVResponseHeaders, validateRetryPolicy, validateServiceError, validateServiceRequestEvent, validateServiceResponseEvent, validateServiceSession, wrapError };
package/dist/index.d.ts CHANGED
@@ -2,7 +2,7 @@ import { I as IServiceContext, a as InvokeFunction, b as InvokeAnyFunction, F as
2
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-BiS6HRwE.js';
3
3
  import { z } from 'zod';
4
4
  import { IKVService } from './kv/index.js';
5
- export { IPrefixedKVService, KVAction, KVActionType, KVDeleteOptions, KVGetOptions, KVHeadOptions, KVListOptions, KVListResponse, KVPutOptions, KVResponse, KVResponseHeaders, KVService, KVServiceConfig, PrefixedKVService } 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';
6
6
  export { BatchOptions, BatchResponse, DatabaseHandle, ExecuteOptions, ExecuteResponse, IDatabaseHandle, ISQLService, QueryOptions, QueryResponse, SQLAction, SQLActionType, SQLService, SQLServiceConfig, SqlStatement, SqlValue } from './sql/index.js';
7
7
 
8
8
  /**
@@ -1937,4 +1937,55 @@ interface WasmVaultFunctions {
1937
1937
  }
1938
1938
  declare function createVaultCrypto(wasm: WasmVaultFunctions): VaultCrypto;
1939
1939
 
1940
- export { BaseService, type BaseServiceOptions, type ColumnInfo, type DataVaultConfig, DataVaultService, DuckDbAction, type DuckDbActionType, type DuckDbBatchOptions, type BatchResponse as DuckDbBatchResponse, DuckDbDatabaseHandle, type DuckDbExecuteOptions, type ExecuteResponse as DuckDbExecuteResponse, type DuckDbOptions, type DuckDbQueryOptions, type QueryResponse as DuckDbQueryResponse, DuckDbService, type DuckDbServiceConfig, type DuckDbStatement, type DuckDbValue, FetchFunction, GenericKVResponseSchema, type GenericKVResponseType, GenericResultSchema, type HookEvent, type HookServiceName, type HookStreamEvent, type HookSubscription, type HookWebhookListOptions, type HookWebhookRecord, type HookWebhookRegistration, type HookWebhookScope, type HookWebhookUnregisterOptions, HooksService, type HooksServiceConfig, type IDataVaultService, type IDuckDbDatabaseHandle, type IDuckDbService, type IHooksService, IKVService, IService, IServiceContext, InvokeAnyFunction, InvokeFunction, KVListResponseSchema, type KVListResponseType, KVListResultSchema, type KVListResultType, KVResponseHeadersSchema, type KVResponseHeadersType, type QuotaConfig, type QuotaStatus, Result, RetryPolicy, RetryPolicySchema, type RetryPolicyType, type SchemaInfo, type ServiceConstructor, ServiceContext, type ServiceContextConfig, ServiceError, ServiceErrorEventSchema, type ServiceErrorEventType, ServiceErrorSchema, type ServiceErrorType, type ServiceRegistration, ServiceRequestEventSchema, type ServiceRequestEventType, ServiceResponseEventSchema, type ServiceResponseEventType, ServiceRetryEventSchema, type ServiceRetryEventType, ServiceSession, ServiceSessionSchema, type ServiceSessionType, StorageQuotaInfo, type SubscribeOptions, type TableInfo, TinyCloudQuota, type ValidationError, type VaultCrypto, type VaultEntry, type VaultError, type VaultGetOptions, type VaultGrantOptions, VaultHeaders, type VaultListOptions, VaultPublicSpaceKVActions, type VaultPutOptions, type ViewInfo, type WasmVaultFunctions, abortedError, authExpiredError, authRequiredError, authUnauthorizedError, createKVResponseSchema, createResultSchema, createVaultCrypto, errorResult, networkError, notFoundError, parseAuthError, permissionDeniedError, storageLimitReachedError, storageQuotaExceededError, timeoutError, validateKVListResponse, validateKVResponseHeaders, validateRetryPolicy, validateServiceError, validateServiceRequestEvent, validateServiceResponseEvent, validateServiceSession, wrapError };
1940
+ declare const SECRET_NAME_RE: RegExp;
1941
+ interface SecretScopeOptions {
1942
+ /** Optional logical scope. Omit for the global secret namespace. */
1943
+ scope?: string;
1944
+ }
1945
+ interface ResolvedSecretPath {
1946
+ /** Canonical env-style secret name. */
1947
+ name: string;
1948
+ /** Canonical scope. Undefined means global. */
1949
+ scope?: string;
1950
+ /** Key passed to the data vault service. */
1951
+ vaultKey: string;
1952
+ /** KV permission paths that back the encrypted vault entry. */
1953
+ permissionPaths: {
1954
+ keys: string;
1955
+ vault: string;
1956
+ };
1957
+ }
1958
+ declare function canonicalizeSecretScope(scope: string | undefined): string | undefined;
1959
+ declare function resolveSecretPath(name: string, options?: SecretScopeOptions): ResolvedSecretPath;
1960
+
1961
+ interface SecretPayload {
1962
+ value: string;
1963
+ createdAt: string;
1964
+ updatedAt: string;
1965
+ }
1966
+ type SecretsError = VaultError | ServiceError;
1967
+ interface ISecretsService {
1968
+ readonly vault: IDataVaultService;
1969
+ unlock(signer?: unknown): Promise<Result<void, VaultError>>;
1970
+ lock(): void;
1971
+ readonly isUnlocked: boolean;
1972
+ get(name: string, options?: SecretScopeOptions): Promise<Result<string, SecretsError>>;
1973
+ put(name: string, value: string, options?: SecretScopeOptions): Promise<Result<void, SecretsError>>;
1974
+ delete(name: string, options?: SecretScopeOptions): Promise<Result<void, SecretsError>>;
1975
+ list(options?: SecretScopeOptions): Promise<Result<string[], SecretsError>>;
1976
+ }
1977
+
1978
+ declare class SecretsService implements ISecretsService {
1979
+ private readonly getVault;
1980
+ constructor(vault: IDataVaultService | (() => IDataVaultService));
1981
+ get vault(): IDataVaultService;
1982
+ get isUnlocked(): boolean;
1983
+ unlock(signer?: unknown): Promise<Result<void, VaultError>>;
1984
+ lock(): void;
1985
+ get(name: string, options?: SecretScopeOptions): Promise<Result<string, SecretsError>>;
1986
+ put(name: string, value: string, options?: SecretScopeOptions): Promise<Result<void, SecretsError>>;
1987
+ delete(name: string, options?: SecretScopeOptions): Promise<Result<void, SecretsError>>;
1988
+ list(options?: SecretScopeOptions): Promise<Result<string[], SecretsError>>;
1989
+ }
1990
+
1991
+ export { BaseService, type BaseServiceOptions, type ColumnInfo, type DataVaultConfig, DataVaultService, DuckDbAction, type DuckDbActionType, type DuckDbBatchOptions, type BatchResponse as DuckDbBatchResponse, DuckDbDatabaseHandle, type DuckDbExecuteOptions, type ExecuteResponse as DuckDbExecuteResponse, type DuckDbOptions, type DuckDbQueryOptions, type QueryResponse as DuckDbQueryResponse, DuckDbService, type DuckDbServiceConfig, type DuckDbStatement, type DuckDbValue, FetchFunction, GenericKVResponseSchema, type GenericKVResponseType, GenericResultSchema, type HookEvent, type HookServiceName, type HookStreamEvent, type HookSubscription, type HookWebhookListOptions, type HookWebhookRecord, type HookWebhookRegistration, type HookWebhookScope, type HookWebhookUnregisterOptions, HooksService, type HooksServiceConfig, type IDataVaultService, type IDuckDbDatabaseHandle, type IDuckDbService, type IHooksService, IKVService, type ISecretsService, IService, IServiceContext, InvokeAnyFunction, InvokeFunction, KVListResponseSchema, type KVListResponseType, KVListResultSchema, type KVListResultType, KVResponseHeadersSchema, type KVResponseHeadersType, type QuotaConfig, type QuotaStatus, type ResolvedSecretPath, Result, RetryPolicy, RetryPolicySchema, type RetryPolicyType, SECRET_NAME_RE, type SchemaInfo, type SecretPayload, type SecretScopeOptions, type SecretsError, SecretsService, type ServiceConstructor, ServiceContext, type ServiceContextConfig, ServiceError, ServiceErrorEventSchema, type ServiceErrorEventType, ServiceErrorSchema, type ServiceErrorType, type ServiceRegistration, ServiceRequestEventSchema, type ServiceRequestEventType, ServiceResponseEventSchema, type ServiceResponseEventType, ServiceRetryEventSchema, type ServiceRetryEventType, ServiceSession, ServiceSessionSchema, type ServiceSessionType, StorageQuotaInfo, type SubscribeOptions, type TableInfo, TinyCloudQuota, type ValidationError, type VaultCrypto, type VaultEntry, type VaultError, type VaultGetOptions, type VaultGrantOptions, VaultHeaders, type VaultListOptions, VaultPublicSpaceKVActions, type VaultPutOptions, type ViewInfo, type WasmVaultFunctions, abortedError, authExpiredError, authRequiredError, authUnauthorizedError, canonicalizeSecretScope, createKVResponseSchema, createResultSchema, createVaultCrypto, errorResult, networkError, notFoundError, parseAuthError, permissionDeniedError, resolveSecretPath, storageLimitReachedError, storageQuotaExceededError, timeoutError, validateKVListResponse, validateKVResponseHeaders, validateRetryPolicy, validateServiceError, validateServiceRequestEvent, validateServiceResponseEvent, validateServiceSession, wrapError };
package/dist/index.js CHANGED
@@ -818,6 +818,13 @@ var PrefixedKVService = class _PrefixedKVService {
818
818
  const fullKey = this.getFullKey(key);
819
819
  return this._kv.head(fullKey, { ...options, prefix: "" });
820
820
  }
821
+ /**
822
+ * Create a short-lived signed URL for reading a KV object.
823
+ */
824
+ async createSignedReadUrl(key, options) {
825
+ const fullKey = this.getFullKey(key);
826
+ return this._kv.createSignedReadUrl(fullKey, { ...options, prefix: "" });
827
+ }
821
828
  /**
822
829
  * Create a nested prefix-scoped view.
823
830
  */
@@ -829,6 +836,7 @@ var PrefixedKVService = class _PrefixedKVService {
829
836
  };
830
837
 
831
838
  // src/kv/types.ts
839
+ var DEFAULT_SIGNED_READ_URL_EXPIRY_MS = 5 * 60 * 1e3;
832
840
  var KVAction = {
833
841
  GET: "tinycloud.kv/get",
834
842
  PUT: "tinycloud.kv/put",
@@ -913,6 +921,15 @@ var KVService = class extends BaseService {
913
921
  get host() {
914
922
  return this.context.hosts[0];
915
923
  }
924
+ withJsonContentType(headers) {
925
+ if (Array.isArray(headers)) {
926
+ return [...headers, ["content-type", "application/json"]];
927
+ }
928
+ return {
929
+ ...headers,
930
+ "content-type": "application/json"
931
+ };
932
+ }
916
933
  /**
917
934
  * Execute an invoke operation.
918
935
  *
@@ -982,6 +999,48 @@ var KVService = class extends BaseService {
982
999
  return text;
983
1000
  }
984
1001
  }
1002
+ async createSignedReadUrlError(response, key) {
1003
+ let errorText = response.statusText;
1004
+ try {
1005
+ const text = await response.text();
1006
+ if (text) {
1007
+ errorText = text;
1008
+ }
1009
+ } catch {
1010
+ }
1011
+ if (response.status === 401 || response.status === 403) {
1012
+ const { resource, action } = parseAuthError(errorText);
1013
+ return err(authUnauthorizedError("kv", errorText, {
1014
+ status: response.status,
1015
+ ...action && { requiredAction: action },
1016
+ ...resource && { resource }
1017
+ }));
1018
+ }
1019
+ const code = response.status === 400 ? ErrorCodes.INVALID_INPUT : ErrorCodes.NETWORK_ERROR;
1020
+ return err(
1021
+ serviceError(
1022
+ code,
1023
+ `Failed to create signed read URL for key "${key}": ${response.status} - ${errorText}`,
1024
+ "kv",
1025
+ { meta: { status: response.status, statusText: response.statusText } }
1026
+ )
1027
+ );
1028
+ }
1029
+ normalizeSignedReadUrlResponse(data) {
1030
+ if (!data || typeof data !== "object") {
1031
+ return void 0;
1032
+ }
1033
+ const response = data;
1034
+ if (typeof response.url !== "string" || typeof response.ticketId !== "string" || typeof response.expiresAt !== "string") {
1035
+ return void 0;
1036
+ }
1037
+ return {
1038
+ url: new URL(response.url, this.host).toString(),
1039
+ relativeUrl: response.url,
1040
+ ticketId: response.ticketId,
1041
+ expiresAt: response.expiresAt
1042
+ };
1043
+ }
985
1044
  /**
986
1045
  * Get a value by key.
987
1046
  */
@@ -1254,6 +1313,61 @@ var KVService = class extends BaseService {
1254
1313
  }
1255
1314
  });
1256
1315
  }
1316
+ /**
1317
+ * Create a short-lived signed URL for reading a KV object.
1318
+ */
1319
+ async createSignedReadUrl(key, options) {
1320
+ return this.withTelemetry("createSignedReadUrl", key, async () => {
1321
+ if (!this.requireAuth()) {
1322
+ return err(authRequiredError("kv"));
1323
+ }
1324
+ const path = this.getFullPath(key, options?.prefix);
1325
+ const session = this.context.session;
1326
+ const headers = this.context.invoke(
1327
+ session,
1328
+ "kv",
1329
+ path,
1330
+ KVAction.GET
1331
+ );
1332
+ const body = {
1333
+ space: session.spaceId,
1334
+ path,
1335
+ ttl_seconds: options?.expiresInSeconds ?? Math.ceil(DEFAULT_SIGNED_READ_URL_EXPIRY_MS / 1e3)
1336
+ };
1337
+ if (options?.contentHash !== void 0) {
1338
+ body.content_hash = options.contentHash;
1339
+ }
1340
+ if (options?.etag !== void 0) {
1341
+ body.etag = options.etag;
1342
+ }
1343
+ try {
1344
+ const response = await this.context.fetch(`${this.host}/signed/kv`, {
1345
+ method: "POST",
1346
+ headers: this.withJsonContentType(headers),
1347
+ body: JSON.stringify(body),
1348
+ signal: this.combineSignals(options?.signal)
1349
+ });
1350
+ if (!response.ok) {
1351
+ return this.createSignedReadUrlError(response, key);
1352
+ }
1353
+ const signedUrl = this.normalizeSignedReadUrlResponse(
1354
+ await response.json()
1355
+ );
1356
+ if (!signedUrl) {
1357
+ return err(
1358
+ serviceError(
1359
+ ErrorCodes.NETWORK_ERROR,
1360
+ "Signed read URL response did not include url, ticketId, and expiresAt",
1361
+ "kv"
1362
+ )
1363
+ );
1364
+ }
1365
+ return ok(signedUrl);
1366
+ } catch (error) {
1367
+ return err(wrapError("kv", error));
1368
+ }
1369
+ });
1370
+ }
1257
1371
  /**
1258
1372
  * Create a prefix-scoped view of this KV service.
1259
1373
  *
@@ -3762,8 +3876,130 @@ function createVaultCrypto(wasm) {
3762
3876
  sha256: (data) => wasm.vault_sha256(data)
3763
3877
  };
3764
3878
  }
3879
+
3880
+ // src/secrets/paths.ts
3881
+ var SECRET_NAME_RE = /^[A-Z][A-Z0-9_]*$/;
3882
+ var SECRET_PREFIX = "secrets/";
3883
+ var SCOPED_SECRET_PREFIX = "secrets/scoped/";
3884
+ var RESERVED_SECRET_SCOPES = /* @__PURE__ */ new Set(["default", "global"]);
3885
+ function canonicalizeSecretScope(scope) {
3886
+ if (scope === void 0) {
3887
+ return void 0;
3888
+ }
3889
+ const trimmed = scope.trim();
3890
+ if (trimmed === "") {
3891
+ throw new Error("Secret scope must be non-empty; omit scope for global secrets.");
3892
+ }
3893
+ const canonical = trimmed.toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
3894
+ if (canonical === "") {
3895
+ throw new Error("Secret scope must contain at least one letter or number.");
3896
+ }
3897
+ if (RESERVED_SECRET_SCOPES.has(canonical)) {
3898
+ throw new Error(
3899
+ `Secret scope ${JSON.stringify(scope)} is reserved; omit scope for global secrets.`
3900
+ );
3901
+ }
3902
+ return canonical;
3903
+ }
3904
+ function resolveSecretPath(name, options = {}) {
3905
+ const normalizedName = name.trim();
3906
+ if (!SECRET_NAME_RE.test(normalizedName)) {
3907
+ throw new Error(
3908
+ `Invalid secret name ${JSON.stringify(name)}. Secret names must match ${SECRET_NAME_RE.source}.`
3909
+ );
3910
+ }
3911
+ const scope = canonicalizeSecretScope(options.scope);
3912
+ const vaultKey = scope === void 0 ? `${SECRET_PREFIX}${normalizedName}` : `${SCOPED_SECRET_PREFIX}${scope}/${normalizedName}`;
3913
+ return {
3914
+ name: normalizedName,
3915
+ ...scope !== void 0 ? { scope } : {},
3916
+ vaultKey,
3917
+ permissionPaths: {
3918
+ keys: `keys/${vaultKey}`,
3919
+ vault: `vault/${vaultKey}`
3920
+ }
3921
+ };
3922
+ }
3923
+
3924
+ // src/secrets/SecretsService.ts
3925
+ function invalidSecretInput(message) {
3926
+ return err({
3927
+ code: ErrorCodes.INVALID_INPUT,
3928
+ service: "secrets",
3929
+ message
3930
+ });
3931
+ }
3932
+ function resolveSecretPathResult(name, options) {
3933
+ try {
3934
+ return resolveSecretPath(name, options);
3935
+ } catch (error) {
3936
+ return invalidSecretInput(error instanceof Error ? error.message : String(error));
3937
+ }
3938
+ }
3939
+ var SecretsService = class {
3940
+ constructor(vault) {
3941
+ this.getVault = typeof vault === "function" ? vault : () => vault;
3942
+ }
3943
+ get vault() {
3944
+ return this.getVault();
3945
+ }
3946
+ get isUnlocked() {
3947
+ return this.vault.isUnlocked;
3948
+ }
3949
+ unlock(signer) {
3950
+ return this.vault.unlock(signer);
3951
+ }
3952
+ lock() {
3953
+ this.vault.lock();
3954
+ }
3955
+ async get(name, options) {
3956
+ const secretPath = resolveSecretPathResult(name, options);
3957
+ if ("ok" in secretPath) return secretPath;
3958
+ const result = await this.vault.get(secretPath.vaultKey);
3959
+ if (!result.ok) {
3960
+ return result;
3961
+ }
3962
+ return { ok: true, data: result.data.value.value };
3963
+ }
3964
+ async put(name, value, options) {
3965
+ const secretPath = resolveSecretPathResult(name, options);
3966
+ if ("ok" in secretPath) return secretPath;
3967
+ const now = (/* @__PURE__ */ new Date()).toISOString();
3968
+ return this.vault.put(secretPath.vaultKey, {
3969
+ value,
3970
+ createdAt: now,
3971
+ updatedAt: now
3972
+ });
3973
+ }
3974
+ async delete(name, options) {
3975
+ const secretPath = resolveSecretPathResult(name, options);
3976
+ if ("ok" in secretPath) return secretPath;
3977
+ return this.vault.delete(secretPath.vaultKey);
3978
+ }
3979
+ async list(options) {
3980
+ let prefix;
3981
+ try {
3982
+ const scope = canonicalizeSecretScope(options?.scope);
3983
+ prefix = scope === void 0 ? "secrets/" : `secrets/scoped/${scope}/`;
3984
+ } catch (error) {
3985
+ return invalidSecretInput(error instanceof Error ? error.message : String(error));
3986
+ }
3987
+ const result = await this.vault.list({
3988
+ prefix,
3989
+ removePrefix: true
3990
+ });
3991
+ if (!result.ok) {
3992
+ return result;
3993
+ }
3994
+ return {
3995
+ ok: true,
3996
+ data: result.data.filter((name) => SECRET_NAME_RE.test(name))
3997
+ };
3998
+ }
3999
+ };
3765
4000
  export {
3766
4001
  BaseService,
4002
+ DEFAULT_SIGNED_READ_URL_EXPIRY_MS,
3767
4003
  DataVaultService,
3768
4004
  DatabaseHandle,
3769
4005
  DuckDbAction,
@@ -3780,8 +4016,10 @@ export {
3780
4016
  KVService,
3781
4017
  PrefixedKVService,
3782
4018
  RetryPolicySchema,
4019
+ SECRET_NAME_RE,
3783
4020
  SQLAction,
3784
4021
  SQLService,
4022
+ SecretsService,
3785
4023
  ServiceContext,
3786
4024
  ServiceErrorEventSchema,
3787
4025
  ServiceErrorSchema,
@@ -3797,6 +4035,7 @@ export {
3797
4035
  authExpiredError,
3798
4036
  authRequiredError,
3799
4037
  authUnauthorizedError,
4038
+ canonicalizeSecretScope,
3800
4039
  createKVResponseSchema,
3801
4040
  createResultSchema,
3802
4041
  createVaultCrypto,
@@ -3808,6 +4047,7 @@ export {
3808
4047
  ok,
3809
4048
  parseAuthError,
3810
4049
  permissionDeniedError,
4050
+ resolveSecretPath,
3811
4051
  serviceError,
3812
4052
  storageLimitReachedError,
3813
4053
  storageQuotaExceededError,