@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.cjs +245 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +53 -2
- package/dist/index.d.ts +53 -2
- package/dist/index.js +240 -0
- package/dist/index.js.map +1 -1
- package/dist/kv/index.cjs +116 -0
- package/dist/kv/index.cjs.map +1 -1
- package/dist/kv/index.d.cts +99 -1
- package/dist/kv/index.d.ts +99 -1
- package/dist/kv/index.js +115 -0
- package/dist/kv/index.js.map +1 -1
- package/package.json +3 -3
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
|
-
|
|
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
|
-
|
|
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,
|