@nestm/storage 0.1.0-alpha.5 → 0.1.0-alpha.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/CHANGELOG.md +26 -0
- package/README.md +158 -92
- package/SECURITY.md +40 -0
- package/dist/ai-sdk/ai-sdk-workspace-tools.d.ts +63 -0
- package/dist/ai-sdk/ai-sdk-workspace-tools.d.ts.map +1 -0
- package/dist/ai-sdk/ai-sdk-workspace-tools.js +383 -0
- package/dist/ai-sdk/ai-sdk-workspace-tools.js.map +1 -0
- package/dist/ai-sdk/index.d.ts +2 -0
- package/dist/ai-sdk/index.d.ts.map +1 -0
- package/dist/ai-sdk/index.js +2 -0
- package/dist/ai-sdk/index.js.map +1 -0
- package/dist/files-sdk/files-sdk.driver.d.ts +16 -2
- package/dist/files-sdk/files-sdk.driver.d.ts.map +1 -1
- package/dist/files-sdk/files-sdk.driver.js +159 -0
- package/dist/files-sdk/files-sdk.driver.js.map +1 -1
- package/dist/files-sdk/fs/index.d.ts +21 -2
- package/dist/files-sdk/fs/index.d.ts.map +1 -1
- package/dist/files-sdk/fs/index.js +600 -1
- package/dist/files-sdk/fs/index.js.map +1 -1
- package/dist/files-sdk/index.d.ts +1 -1
- package/dist/files-sdk/index.d.ts.map +1 -1
- package/dist/files-sdk/index.js.map +1 -1
- package/dist/files-sdk/provider/index.d.ts.map +1 -1
- package/dist/files-sdk/provider/index.js +7 -0
- package/dist/files-sdk/provider/index.js.map +1 -1
- package/dist/files-sdk/s3/index.d.ts +12 -3
- package/dist/files-sdk/s3/index.d.ts.map +1 -1
- package/dist/files-sdk/s3/index.js +203 -37
- package/dist/files-sdk/s3/index.js.map +1 -1
- package/dist/storage.client.d.ts +5 -1
- package/dist/storage.client.d.ts.map +1 -1
- package/dist/storage.client.js +49 -0
- package/dist/storage.client.js.map +1 -1
- package/dist/storage.driver.d.ts +3 -1
- package/dist/storage.driver.d.ts.map +1 -1
- package/dist/storage.driver.js.map +1 -1
- package/dist/storage.service.d.ts.map +1 -1
- package/dist/storage.service.js +28 -3
- package/dist/storage.service.js.map +1 -1
- package/dist/storage.types.d.ts +36 -0
- package/dist/storage.types.d.ts.map +1 -1
- package/dist/storage.types.js.map +1 -1
- package/dist/workspace/index.d.ts +4 -0
- package/dist/workspace/index.d.ts.map +1 -0
- package/dist/workspace/index.js +4 -0
- package/dist/workspace/index.js.map +1 -0
- package/dist/workspace/storage-workspace.cursor.d.ts +6 -0
- package/dist/workspace/storage-workspace.cursor.d.ts.map +1 -0
- package/dist/workspace/storage-workspace.cursor.js +45 -0
- package/dist/workspace/storage-workspace.cursor.js.map +1 -0
- package/dist/workspace/storage-workspace.d.ts +6 -0
- package/dist/workspace/storage-workspace.d.ts.map +1 -0
- package/dist/workspace/storage-workspace.error.d.ts +28 -0
- package/dist/workspace/storage-workspace.error.d.ts.map +1 -0
- package/dist/workspace/storage-workspace.error.js +67 -0
- package/dist/workspace/storage-workspace.error.js.map +1 -0
- package/dist/workspace/storage-workspace.js +747 -0
- package/dist/workspace/storage-workspace.js.map +1 -0
- package/dist/workspace/storage-workspace.path.d.ts +9 -0
- package/dist/workspace/storage-workspace.path.d.ts.map +1 -0
- package/dist/workspace/storage-workspace.path.js +68 -0
- package/dist/workspace/storage-workspace.path.js.map +1 -0
- package/dist/workspace/storage-workspace.types.d.ts +97 -0
- package/dist/workspace/storage-workspace.types.d.ts.map +1 -0
- package/dist/workspace/storage-workspace.types.js +20 -0
- package/dist/workspace/storage-workspace.types.js.map +1 -0
- package/package.json +23 -20
- package/dist/artifacts/artifact-storage.d.ts +0 -161
- package/dist/artifacts/artifact-storage.d.ts.map +0 -1
- package/dist/artifacts/artifact-storage.js +0 -452
- package/dist/artifacts/artifact-storage.js.map +0 -1
- package/dist/artifacts/crypto/codec.d.ts +0 -44
- package/dist/artifacts/crypto/codec.d.ts.map +0 -1
- package/dist/artifacts/crypto/codec.js +0 -273
- package/dist/artifacts/crypto/codec.js.map +0 -1
- package/dist/artifacts/crypto/context.d.ts +0 -48
- package/dist/artifacts/crypto/context.d.ts.map +0 -1
- package/dist/artifacts/crypto/context.js +0 -37
- package/dist/artifacts/crypto/context.js.map +0 -1
- package/dist/artifacts/crypto/dek-cache.d.ts +0 -38
- package/dist/artifacts/crypto/dek-cache.d.ts.map +0 -1
- package/dist/artifacts/crypto/dek-cache.js +0 -137
- package/dist/artifacts/crypto/dek-cache.js.map +0 -1
- package/dist/artifacts/crypto/index.d.ts +0 -25
- package/dist/artifacts/crypto/index.d.ts.map +0 -1
- package/dist/artifacts/crypto/index.js +0 -29
- package/dist/artifacts/crypto/index.js.map +0 -1
- package/dist/artifacts/crypto/key-provider.d.ts +0 -44
- package/dist/artifacts/crypto/key-provider.d.ts.map +0 -1
- package/dist/artifacts/crypto/key-provider.js +0 -36
- package/dist/artifacts/crypto/key-provider.js.map +0 -1
- package/dist/artifacts/crypto/kms-provider.d.ts +0 -16
- package/dist/artifacts/crypto/kms-provider.d.ts.map +0 -1
- package/dist/artifacts/crypto/kms-provider.js +0 -90
- package/dist/artifacts/crypto/kms-provider.js.map +0 -1
- package/dist/artifacts/crypto/local-provider.d.ts +0 -17
- package/dist/artifacts/crypto/local-provider.d.ts.map +0 -1
- package/dist/artifacts/crypto/local-provider.js +0 -58
- package/dist/artifacts/crypto/local-provider.js.map +0 -1
- package/dist/artifacts/env-config.d.ts +0 -15
- package/dist/artifacts/env-config.d.ts.map +0 -1
- package/dist/artifacts/env-config.js +0 -95
- package/dist/artifacts/env-config.js.map +0 -1
- package/dist/artifacts/index.d.ts +0 -6
- package/dist/artifacts/index.d.ts.map +0 -1
- package/dist/artifacts/index.js +0 -6
- package/dist/artifacts/index.js.map +0 -1
- package/dist/artifacts/nest/index.d.ts +0 -29
- package/dist/artifacts/nest/index.d.ts.map +0 -1
- package/dist/artifacts/nest/index.js +0 -129
- package/dist/artifacts/nest/index.js.map +0 -1
- package/dist/artifacts/object-store.d.ts +0 -27
- package/dist/artifacts/object-store.d.ts.map +0 -1
- package/dist/artifacts/object-store.js +0 -198
- package/dist/artifacts/object-store.js.map +0 -1
- package/dist/artifacts/storage-driver.d.ts +0 -48
- package/dist/artifacts/storage-driver.d.ts.map +0 -1
- package/dist/artifacts/storage-driver.js +0 -89
- package/dist/artifacts/storage-driver.js.map +0 -1
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
import { assertStorageProvider, defaultFsRoot, } from './storage-driver.js';
|
|
2
|
-
/**
|
|
3
|
-
* Shared env→storage-config validation for every service that constructs storage (the api's
|
|
4
|
-
* zod-validated env delegates here with normalized values; the sandbox passes process.env
|
|
5
|
-
* directly). One source of truth for the rules — the two services once drifted by
|
|
6
|
-
* re-implementing them independently.
|
|
7
|
-
*
|
|
8
|
-
* `STORAGE_PROVIDER` names any provider `@nestm/storage` can build (`fs`, `s3`, `gcs`, `azure`,
|
|
9
|
-
* `r2`, `minio`, `supabase`, …); the `STORAGE_*` values below are one flat bag that each provider
|
|
10
|
-
* reads what it needs from. The platform is not S3-only: it used to be, because storage shipped
|
|
11
|
-
* exactly two hand-written drivers, and the old `ARTIFACT_STORAGE=fs|s3` switch chose between
|
|
12
|
-
* them. Those names are still accepted so a deployment can migrate without a coordinated restart.
|
|
13
|
-
*/
|
|
14
|
-
export function artifactStorageConfigFromEnv(env) {
|
|
15
|
-
const provider = assertStorageProvider(env.STORAGE_PROVIDER || legacyProvider(env) || 'fs');
|
|
16
|
-
const prefix = env.STORAGE_PREFIX || env.S3_PREFIX || undefined;
|
|
17
|
-
const config = flatConfig(env);
|
|
18
|
-
// Both-or-neither: both set → static credentials (an IAM user, or any S3-compatible store);
|
|
19
|
-
// both unset → the provider SDK's own chain (the ECS task role, Application Default
|
|
20
|
-
// Credentials, a shared profile) so no long-lived keys sit in env.
|
|
21
|
-
if (!config.accessKeyId !== !config.secretAccessKey) {
|
|
22
|
-
throw new Error("STORAGE_ACCESS_KEY_ID and STORAGE_SECRET_ACCESS_KEY must be set together (omit both to use the provider's default credential chain)");
|
|
23
|
-
}
|
|
24
|
-
if (provider === 'fs') {
|
|
25
|
-
return {
|
|
26
|
-
provider,
|
|
27
|
-
...(prefix ? { prefix } : {}),
|
|
28
|
-
config: { root: config.root ?? defaultFsRoot() },
|
|
29
|
-
};
|
|
30
|
-
}
|
|
31
|
-
// `root` is filesystem-only, and the api's schema always defaults one. Carrying it onto an
|
|
32
|
-
// object-store provider would both litter the config and make the guard below think a bucketless
|
|
33
|
-
// deployment was configured.
|
|
34
|
-
const { root: _fsOnly, ...objectStoreConfig } = config;
|
|
35
|
-
// Generic "you configured nothing" guard. Which field a provider actually needs is the
|
|
36
|
-
// adapter's business — it fails closed on its own — but an empty config is always a
|
|
37
|
-
// deployment mistake, and catching it here names the variable to set.
|
|
38
|
-
if (!identifiesAStore(objectStoreConfig)) {
|
|
39
|
-
throw new Error(`STORAGE_PROVIDER=${provider} needs somewhere to write: set STORAGE_BUCKET (or the container/store field that provider uses)`);
|
|
40
|
-
}
|
|
41
|
-
return { provider, ...(prefix ? { prefix } : {}), config: objectStoreConfig };
|
|
42
|
-
}
|
|
43
|
-
/** The retired `ARTIFACT_STORAGE=fs|s3` switch, mapped onto a provider slug. */
|
|
44
|
-
function legacyProvider(env) {
|
|
45
|
-
return env.ARTIFACT_STORAGE || undefined;
|
|
46
|
-
}
|
|
47
|
-
function identifiesAStore(config) {
|
|
48
|
-
return [
|
|
49
|
-
config.bucket,
|
|
50
|
-
config.container,
|
|
51
|
-
config.connectionString,
|
|
52
|
-
config.storeName,
|
|
53
|
-
config.token,
|
|
54
|
-
config.url,
|
|
55
|
-
].some((value) => typeof value === 'string' && value.length > 0);
|
|
56
|
-
}
|
|
57
|
-
/**
|
|
58
|
-
* One flat bag of provider settings, assembled from `STORAGE_*` with the retired `S3_*` and
|
|
59
|
-
* `ARTIFACTS_DIR` names as fallbacks. Absent values are omitted rather than set to `undefined`,
|
|
60
|
-
* so a provider's own credential chain stays reachable.
|
|
61
|
-
*/
|
|
62
|
-
function flatConfig(env) {
|
|
63
|
-
const entries = [
|
|
64
|
-
['accessKeyId', env.STORAGE_ACCESS_KEY_ID || env.S3_ACCESS_KEY_ID],
|
|
65
|
-
['accountId', env.STORAGE_ACCOUNT_ID],
|
|
66
|
-
['accountKey', env.STORAGE_ACCOUNT_KEY],
|
|
67
|
-
['accountName', env.STORAGE_ACCOUNT_NAME],
|
|
68
|
-
['bucket', env.STORAGE_BUCKET || env.S3_BUCKET],
|
|
69
|
-
['connectionString', env.STORAGE_CONNECTION_STRING],
|
|
70
|
-
['container', env.STORAGE_CONTAINER],
|
|
71
|
-
['endpoint', env.STORAGE_ENDPOINT || env.S3_ENDPOINT],
|
|
72
|
-
['keyFilename', env.STORAGE_KEY_FILENAME],
|
|
73
|
-
['projectId', env.STORAGE_PROJECT_ID],
|
|
74
|
-
['publicBaseUrl', env.STORAGE_PUBLIC_BASE_URL],
|
|
75
|
-
['region', env.STORAGE_REGION || env.S3_REGION],
|
|
76
|
-
['root', env.STORAGE_ROOT || env.ARTIFACTS_DIR],
|
|
77
|
-
[
|
|
78
|
-
'secretAccessKey',
|
|
79
|
-
env.STORAGE_SECRET_ACCESS_KEY || env.S3_SECRET_ACCESS_KEY,
|
|
80
|
-
],
|
|
81
|
-
['serviceRoleKey', env.STORAGE_SERVICE_ROLE_KEY],
|
|
82
|
-
['sessionToken', env.STORAGE_SESSION_TOKEN],
|
|
83
|
-
['siteId', env.STORAGE_SITE_ID],
|
|
84
|
-
['storeName', env.STORAGE_STORE_NAME],
|
|
85
|
-
['token', env.STORAGE_TOKEN],
|
|
86
|
-
['url', env.STORAGE_URL],
|
|
87
|
-
];
|
|
88
|
-
const forcePathStyle = env.STORAGE_FORCE_PATH_STYLE || env.S3_FORCE_PATH_STYLE;
|
|
89
|
-
if (forcePathStyle)
|
|
90
|
-
entries.push(['forcePathStyle', forcePathStyle === 'true']);
|
|
91
|
-
// One dynamic bag by design: the fields are provider-specific and the union is wider than any
|
|
92
|
-
// one deployment uses, so it is assembled by name rather than spelled out per provider.
|
|
93
|
-
return Object.fromEntries(entries.flatMap(([key, value]) => value === undefined || value === '' ? [] : [[key, value]]));
|
|
94
|
-
}
|
|
95
|
-
//# sourceMappingURL=env-config.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"env-config.js","sourceRoot":"","sources":["../../src/artifacts/env-config.ts"],"names":[],"mappings":"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","sourcesContent":["import type { StorageProviderConfig } from '../files-sdk/provider/index.js';\n\nimport {\n assertStorageProvider,\n defaultFsRoot,\n type ArtifactStorageConfig,\n} from './storage-driver.js';\n\n/**\n * Shared env→storage-config validation for every service that constructs storage (the api's\n * zod-validated env delegates here with normalized values; the sandbox passes process.env\n * directly). One source of truth for the rules — the two services once drifted by\n * re-implementing them independently.\n *\n * `STORAGE_PROVIDER` names any provider `@nestm/storage` can build (`fs`, `s3`, `gcs`, `azure`,\n * `r2`, `minio`, `supabase`, …); the `STORAGE_*` values below are one flat bag that each provider\n * reads what it needs from. The platform is not S3-only: it used to be, because storage shipped\n * exactly two hand-written drivers, and the old `ARTIFACT_STORAGE=fs|s3` switch chose between\n * them. Those names are still accepted so a deployment can migrate without a coordinated restart.\n */\nexport function artifactStorageConfigFromEnv(\n env: NodeJS.ProcessEnv,\n): ArtifactStorageConfig {\n const provider = assertStorageProvider(\n env.STORAGE_PROVIDER || legacyProvider(env) || 'fs',\n );\n const prefix = env.STORAGE_PREFIX || env.S3_PREFIX || undefined;\n const config = flatConfig(env);\n\n // Both-or-neither: both set → static credentials (an IAM user, or any S3-compatible store);\n // both unset → the provider SDK's own chain (the ECS task role, Application Default\n // Credentials, a shared profile) so no long-lived keys sit in env.\n if (!config.accessKeyId !== !config.secretAccessKey) {\n throw new Error(\n \"STORAGE_ACCESS_KEY_ID and STORAGE_SECRET_ACCESS_KEY must be set together (omit both to use the provider's default credential chain)\",\n );\n }\n\n if (provider === 'fs') {\n return {\n provider,\n ...(prefix ? { prefix } : {}),\n config: { root: config.root ?? defaultFsRoot() },\n };\n }\n\n // `root` is filesystem-only, and the api's schema always defaults one. Carrying it onto an\n // object-store provider would both litter the config and make the guard below think a bucketless\n // deployment was configured.\n const { root: _fsOnly, ...objectStoreConfig } = config;\n\n // Generic \"you configured nothing\" guard. Which field a provider actually needs is the\n // adapter's business — it fails closed on its own — but an empty config is always a\n // deployment mistake, and catching it here names the variable to set.\n if (!identifiesAStore(objectStoreConfig)) {\n throw new Error(\n `STORAGE_PROVIDER=${provider} needs somewhere to write: set STORAGE_BUCKET (or the container/store field that provider uses)`,\n );\n }\n\n return { provider, ...(prefix ? { prefix } : {}), config: objectStoreConfig };\n}\n\n/** The retired `ARTIFACT_STORAGE=fs|s3` switch, mapped onto a provider slug. */\nfunction legacyProvider(env: NodeJS.ProcessEnv): string | undefined {\n return env.ARTIFACT_STORAGE || undefined;\n}\n\nfunction identifiesAStore(config: StorageProviderConfig): boolean {\n return [\n config.bucket,\n config.container,\n config.connectionString,\n config.storeName,\n config.token,\n config.url,\n ].some((value) => typeof value === 'string' && value.length > 0);\n}\n\n/**\n * One flat bag of provider settings, assembled from `STORAGE_*` with the retired `S3_*` and\n * `ARTIFACTS_DIR` names as fallbacks. Absent values are omitted rather than set to `undefined`,\n * so a provider's own credential chain stays reachable.\n */\nfunction flatConfig(env: NodeJS.ProcessEnv): StorageProviderConfig {\n const entries: Array<[string, string | boolean | undefined]> = [\n ['accessKeyId', env.STORAGE_ACCESS_KEY_ID || env.S3_ACCESS_KEY_ID],\n ['accountId', env.STORAGE_ACCOUNT_ID],\n ['accountKey', env.STORAGE_ACCOUNT_KEY],\n ['accountName', env.STORAGE_ACCOUNT_NAME],\n ['bucket', env.STORAGE_BUCKET || env.S3_BUCKET],\n ['connectionString', env.STORAGE_CONNECTION_STRING],\n ['container', env.STORAGE_CONTAINER],\n ['endpoint', env.STORAGE_ENDPOINT || env.S3_ENDPOINT],\n ['keyFilename', env.STORAGE_KEY_FILENAME],\n ['projectId', env.STORAGE_PROJECT_ID],\n ['publicBaseUrl', env.STORAGE_PUBLIC_BASE_URL],\n ['region', env.STORAGE_REGION || env.S3_REGION],\n ['root', env.STORAGE_ROOT || env.ARTIFACTS_DIR],\n [\n 'secretAccessKey',\n env.STORAGE_SECRET_ACCESS_KEY || env.S3_SECRET_ACCESS_KEY,\n ],\n ['serviceRoleKey', env.STORAGE_SERVICE_ROLE_KEY],\n ['sessionToken', env.STORAGE_SESSION_TOKEN],\n ['siteId', env.STORAGE_SITE_ID],\n ['storeName', env.STORAGE_STORE_NAME],\n ['token', env.STORAGE_TOKEN],\n ['url', env.STORAGE_URL],\n ];\n\n const forcePathStyle =\n env.STORAGE_FORCE_PATH_STYLE || env.S3_FORCE_PATH_STYLE;\n if (forcePathStyle)\n entries.push(['forcePathStyle', forcePathStyle === 'true']);\n\n // One dynamic bag by design: the fields are provider-specific and the union is wider than any\n // one deployment uses, so it is assembled by name rather than spelled out per provider.\n return Object.fromEntries(\n entries.flatMap(([key, value]) =>\n value === undefined || value === '' ? [] : [[key, value]],\n ),\n ) as StorageProviderConfig;\n}\n"]}
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
export * from './artifact-storage.js';
|
|
2
|
-
export * from './crypto/index.js';
|
|
3
|
-
export * from './env-config.js';
|
|
4
|
-
export * from './object-store.js';
|
|
5
|
-
export { ARTIFACT_STORAGE_CLIENT_NAME, DEFAULT_OBJECT_NAMESPACES, OBJECT_STORE_PREFIX, OBJECT_STORAGE_CLIENT_NAME, createArtifactStorageClient, createArtifactStorageDriver, createObjectStorageClient, createObjectStorageDriver, resolveObjectNamespaces, } from './storage-driver.js';
|
|
6
|
-
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/artifacts/index.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC;AACtC,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC;AAClC,OAAO,EACL,4BAA4B,EAC5B,yBAAyB,EACzB,mBAAmB,EACnB,0BAA0B,EAC1B,2BAA2B,EAC3B,2BAA2B,EAC3B,yBAAyB,EACzB,yBAAyB,EACzB,uBAAuB,GACxB,MAAM,qBAAqB,CAAC"}
|
package/dist/artifacts/index.js
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
export * from './artifact-storage.js';
|
|
2
|
-
export * from './crypto/index.js';
|
|
3
|
-
export * from './env-config.js';
|
|
4
|
-
export * from './object-store.js';
|
|
5
|
-
export { ARTIFACT_STORAGE_CLIENT_NAME, DEFAULT_OBJECT_NAMESPACES, OBJECT_STORE_PREFIX, OBJECT_STORAGE_CLIENT_NAME, createArtifactStorageClient, createArtifactStorageDriver, createObjectStorageClient, createObjectStorageDriver, resolveObjectNamespaces, } from './storage-driver.js';
|
|
6
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/artifacts/index.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC;AACtC,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC;AAClC,OAAO,EACL,4BAA4B,EAC5B,yBAAyB,EACzB,mBAAmB,EACnB,0BAA0B,EAC1B,2BAA2B,EAC3B,2BAA2B,EAC3B,yBAAyB,EACzB,yBAAyB,EACzB,uBAAuB,GACxB,MAAM,qBAAqB,CAAC","sourcesContent":["export * from './artifact-storage.js';\nexport * from './crypto/index.js';\nexport * from './env-config.js';\nexport * from './object-store.js';\nexport {\n ARTIFACT_STORAGE_CLIENT_NAME,\n DEFAULT_OBJECT_NAMESPACES,\n OBJECT_STORE_PREFIX,\n OBJECT_STORAGE_CLIENT_NAME,\n createArtifactStorageClient,\n createArtifactStorageDriver,\n createObjectStorageClient,\n createObjectStorageDriver,\n resolveObjectNamespaces,\n} from './storage-driver.js';\n"]}
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import { type DynamicModule, type FactoryProvider, type ModuleMetadata } from '@nestjs/common';
|
|
2
|
-
import type { StorageCrypto } from '../crypto/index.js';
|
|
3
|
-
import { type ArtifactStorageConfig } from '../storage-driver.js';
|
|
4
|
-
export declare const ARTIFACT_STORAGE: unique symbol;
|
|
5
|
-
export declare const OBJECT_STORE: unique symbol;
|
|
6
|
-
export declare const ARTIFACT_STORAGE_MODULE_OPTIONS: unique symbol;
|
|
7
|
-
export interface ArtifactStorageModuleOptions {
|
|
8
|
-
config: ArtifactStorageConfig;
|
|
9
|
-
crypto: StorageCrypto;
|
|
10
|
-
/** Makes the product adapters and @nestm/storage clients globally injectable. */
|
|
11
|
-
isGlobal?: boolean;
|
|
12
|
-
}
|
|
13
|
-
interface ResolvedArtifactStorageModuleOptions {
|
|
14
|
-
config: ArtifactStorageConfig;
|
|
15
|
-
crypto: StorageCrypto;
|
|
16
|
-
}
|
|
17
|
-
export interface ArtifactStorageModuleAsyncOptions extends Pick<ModuleMetadata, 'imports'> {
|
|
18
|
-
inject?: FactoryProvider['inject'];
|
|
19
|
-
isGlobal?: boolean;
|
|
20
|
-
useFactory: (...dependencies: never[]) => ResolvedArtifactStorageModuleOptions | Promise<ResolvedArtifactStorageModuleOptions>;
|
|
21
|
-
}
|
|
22
|
-
export declare function InjectArtifactStorage(): ParameterDecorator & PropertyDecorator;
|
|
23
|
-
export declare function InjectObjectStore(): ParameterDecorator & PropertyDecorator;
|
|
24
|
-
export declare class ArtifactStorageModule {
|
|
25
|
-
static forRoot(options: ArtifactStorageModuleOptions): DynamicModule;
|
|
26
|
-
static forRootAsync(options: ArtifactStorageModuleAsyncOptions): DynamicModule;
|
|
27
|
-
}
|
|
28
|
-
export {};
|
|
29
|
-
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/artifacts/nest/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,aAAa,EAClB,KAAK,eAAe,EACpB,KAAK,cAAc,EAGpB,MAAM,gBAAgB,CAAC;AASxB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAKxD,OAAO,EAKL,KAAK,qBAAqB,EAC3B,MAAM,sBAAsB,CAAC;AAE9B,eAAO,MAAM,gBAAgB,eAE5B,CAAC;AACF,eAAO,MAAM,YAAY,eAAsD,CAAC;AAChF,eAAO,MAAM,+BAA+B,eAE3C,CAAC;AAEF,MAAM,WAAW,4BAA4B;IAC3C,MAAM,EAAE,qBAAqB,CAAC;IAC9B,MAAM,EAAE,aAAa,CAAC;IACtB,iFAAiF;IACjF,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,UAAU,oCAAoC;IAC5C,MAAM,EAAE,qBAAqB,CAAC;IAC9B,MAAM,EAAE,aAAa,CAAC;CACvB;AAED,MAAM,WAAW,iCAAkC,SAAQ,IAAI,CAC7D,cAAc,EACd,SAAS,CACV;IACC,MAAM,CAAC,EAAE,eAAe,CAAC,QAAQ,CAAC,CAAC;IACnC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,CACV,GAAG,YAAY,EAAE,KAAK,EAAE,KAEtB,oCAAoC,GACpC,OAAO,CAAC,oCAAoC,CAAC,CAAC;CACnD;AAED,wBAAgB,qBAAqB,IAAI,kBAAkB,GACzD,iBAAiB,CAElB;AAED,wBAAgB,iBAAiB,IAAI,kBAAkB,GAAG,iBAAiB,CAE1E;AA4GD,qBACa,qBAAqB;IAChC,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,4BAA4B,GAAG,aAAa,CAMnE;IAED,MAAM,CAAC,YAAY,CACjB,OAAO,EAAE,iCAAiC,GACzC,aAAa,CAEf;CACF"}
|
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
-
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
-
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
-
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
-
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
-
};
|
|
7
|
-
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
|
-
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
|
-
};
|
|
10
|
-
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
11
|
-
return function (target, key) { decorator(target, key, paramIndex); }
|
|
12
|
-
};
|
|
13
|
-
import { Inject, Module, } from '@nestjs/common';
|
|
14
|
-
import { StorageModule } from '../../storage.module.js';
|
|
15
|
-
import { getStorageToken } from '../../storage.tokens.js';
|
|
16
|
-
import { createArtifactStorageWithClient, } from '../artifact-storage.js';
|
|
17
|
-
import { createObjectStoreWithClient, } from '../object-store.js';
|
|
18
|
-
import { ARTIFACT_STORAGE_CLIENT_NAME, OBJECT_STORAGE_CLIENT_NAME, createArtifactStorageDriver, createObjectStorageDriver, } from '../storage-driver.js';
|
|
19
|
-
export const ARTIFACT_STORAGE = Symbol.for('@nestm/storage/artifacts/artifact-storage');
|
|
20
|
-
export const OBJECT_STORE = Symbol.for('@nestm/storage/artifacts/object-store');
|
|
21
|
-
export const ARTIFACT_STORAGE_MODULE_OPTIONS = Symbol.for('@nestm/storage/artifacts/module-options');
|
|
22
|
-
export function InjectArtifactStorage() {
|
|
23
|
-
return Inject(ARTIFACT_STORAGE);
|
|
24
|
-
}
|
|
25
|
-
export function InjectObjectStore() {
|
|
26
|
-
return Inject(OBJECT_STORE);
|
|
27
|
-
}
|
|
28
|
-
let ArtifactStorageOptionsHostModule = class ArtifactStorageOptionsHostModule {
|
|
29
|
-
};
|
|
30
|
-
ArtifactStorageOptionsHostModule = __decorate([
|
|
31
|
-
Module({})
|
|
32
|
-
], ArtifactStorageOptionsHostModule);
|
|
33
|
-
function syncOptionsHost(options) {
|
|
34
|
-
return {
|
|
35
|
-
module: ArtifactStorageOptionsHostModule,
|
|
36
|
-
providers: [
|
|
37
|
-
{ provide: ARTIFACT_STORAGE_MODULE_OPTIONS, useValue: options },
|
|
38
|
-
],
|
|
39
|
-
exports: [ARTIFACT_STORAGE_MODULE_OPTIONS],
|
|
40
|
-
};
|
|
41
|
-
}
|
|
42
|
-
function asyncOptionsHost(options) {
|
|
43
|
-
return {
|
|
44
|
-
module: ArtifactStorageOptionsHostModule,
|
|
45
|
-
imports: options.imports ?? [],
|
|
46
|
-
providers: [
|
|
47
|
-
{
|
|
48
|
-
provide: ARTIFACT_STORAGE_MODULE_OPTIONS,
|
|
49
|
-
inject: options.inject ?? [],
|
|
50
|
-
useFactory: options.useFactory,
|
|
51
|
-
},
|
|
52
|
-
],
|
|
53
|
-
exports: [ARTIFACT_STORAGE_MODULE_OPTIONS],
|
|
54
|
-
};
|
|
55
|
-
}
|
|
56
|
-
function domainProviders() {
|
|
57
|
-
return [
|
|
58
|
-
{
|
|
59
|
-
provide: ARTIFACT_STORAGE,
|
|
60
|
-
inject: [
|
|
61
|
-
ARTIFACT_STORAGE_MODULE_OPTIONS,
|
|
62
|
-
getStorageToken(ARTIFACT_STORAGE_CLIENT_NAME),
|
|
63
|
-
],
|
|
64
|
-
useFactory: (options, client) => createArtifactStorageWithClient(options.config, options.crypto, client),
|
|
65
|
-
},
|
|
66
|
-
{
|
|
67
|
-
provide: OBJECT_STORE,
|
|
68
|
-
inject: [
|
|
69
|
-
ARTIFACT_STORAGE_MODULE_OPTIONS,
|
|
70
|
-
getStorageToken(OBJECT_STORAGE_CLIENT_NAME),
|
|
71
|
-
],
|
|
72
|
-
useFactory: (options, client) => createObjectStoreWithClient(options.config, options.crypto, client),
|
|
73
|
-
},
|
|
74
|
-
ArtifactStorageCryptoShutdown,
|
|
75
|
-
];
|
|
76
|
-
}
|
|
77
|
-
let ArtifactStorageCryptoShutdown = class ArtifactStorageCryptoShutdown {
|
|
78
|
-
options;
|
|
79
|
-
constructor(options) {
|
|
80
|
-
this.options = options;
|
|
81
|
-
}
|
|
82
|
-
onApplicationShutdown() {
|
|
83
|
-
this.options.crypto.keyProvider.clear();
|
|
84
|
-
}
|
|
85
|
-
};
|
|
86
|
-
ArtifactStorageCryptoShutdown = __decorate([
|
|
87
|
-
__param(0, Inject(ARTIFACT_STORAGE_MODULE_OPTIONS)),
|
|
88
|
-
__metadata("design:paramtypes", [Object])
|
|
89
|
-
], ArtifactStorageCryptoShutdown);
|
|
90
|
-
function composeModule(optionsHost, isGlobal) {
|
|
91
|
-
const rawStorageModule = StorageModule.forRootAsync({
|
|
92
|
-
imports: [optionsHost],
|
|
93
|
-
default: ARTIFACT_STORAGE_CLIENT_NAME,
|
|
94
|
-
isGlobal,
|
|
95
|
-
stores: [
|
|
96
|
-
{
|
|
97
|
-
name: ARTIFACT_STORAGE_CLIENT_NAME,
|
|
98
|
-
inject: [ARTIFACT_STORAGE_MODULE_OPTIONS],
|
|
99
|
-
useFactory: (options) => createArtifactStorageDriver(options.config),
|
|
100
|
-
},
|
|
101
|
-
{
|
|
102
|
-
name: OBJECT_STORAGE_CLIENT_NAME,
|
|
103
|
-
inject: [ARTIFACT_STORAGE_MODULE_OPTIONS],
|
|
104
|
-
useFactory: (options) => createObjectStorageDriver(options.config),
|
|
105
|
-
},
|
|
106
|
-
],
|
|
107
|
-
});
|
|
108
|
-
return {
|
|
109
|
-
module: ArtifactStorageModule,
|
|
110
|
-
global: isGlobal,
|
|
111
|
-
imports: [optionsHost, rawStorageModule],
|
|
112
|
-
providers: domainProviders(),
|
|
113
|
-
exports: [ARTIFACT_STORAGE, OBJECT_STORE, StorageModule],
|
|
114
|
-
};
|
|
115
|
-
}
|
|
116
|
-
let ArtifactStorageModule = class ArtifactStorageModule {
|
|
117
|
-
static forRoot(options) {
|
|
118
|
-
const { config, crypto } = options;
|
|
119
|
-
return composeModule(syncOptionsHost({ config, crypto }), options.isGlobal === true);
|
|
120
|
-
}
|
|
121
|
-
static forRootAsync(options) {
|
|
122
|
-
return composeModule(asyncOptionsHost(options), options.isGlobal === true);
|
|
123
|
-
}
|
|
124
|
-
};
|
|
125
|
-
ArtifactStorageModule = __decorate([
|
|
126
|
-
Module({})
|
|
127
|
-
], ArtifactStorageModule);
|
|
128
|
-
export { ArtifactStorageModule };
|
|
129
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/artifacts/nest/index.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Inject,\n Module,\n type DynamicModule,\n type FactoryProvider,\n type ModuleMetadata,\n type OnApplicationShutdown,\n type Provider,\n} from '@nestjs/common';\nimport type { StorageClient } from '../../storage.client.js';\nimport { StorageModule } from '../../storage.module.js';\nimport { getStorageToken } from '../../storage.tokens.js';\n\nimport {\n createArtifactStorageWithClient,\n type ArtifactStorage,\n} from '../artifact-storage.js';\nimport type { StorageCrypto } from '../crypto/index.js';\nimport {\n createObjectStoreWithClient,\n type ObjectStore,\n} from '../object-store.js';\nimport {\n ARTIFACT_STORAGE_CLIENT_NAME,\n OBJECT_STORAGE_CLIENT_NAME,\n createArtifactStorageDriver,\n createObjectStorageDriver,\n type ArtifactStorageConfig,\n} from '../storage-driver.js';\n\nexport const ARTIFACT_STORAGE = Symbol.for(\n '@nestm/storage/artifacts/artifact-storage',\n);\nexport const OBJECT_STORE = Symbol.for('@nestm/storage/artifacts/object-store');\nexport const ARTIFACT_STORAGE_MODULE_OPTIONS = Symbol.for(\n '@nestm/storage/artifacts/module-options',\n);\n\nexport interface ArtifactStorageModuleOptions {\n config: ArtifactStorageConfig;\n crypto: StorageCrypto;\n /** Makes the product adapters and @nestm/storage clients globally injectable. */\n isGlobal?: boolean;\n}\n\ninterface ResolvedArtifactStorageModuleOptions {\n config: ArtifactStorageConfig;\n crypto: StorageCrypto;\n}\n\nexport interface ArtifactStorageModuleAsyncOptions extends Pick<\n ModuleMetadata,\n 'imports'\n> {\n inject?: FactoryProvider['inject'];\n isGlobal?: boolean;\n useFactory: (\n ...dependencies: never[]\n ) =>\n | ResolvedArtifactStorageModuleOptions\n | Promise<ResolvedArtifactStorageModuleOptions>;\n}\n\nexport function InjectArtifactStorage(): ParameterDecorator &\n PropertyDecorator {\n return Inject(ARTIFACT_STORAGE);\n}\n\nexport function InjectObjectStore(): ParameterDecorator & PropertyDecorator {\n return Inject(OBJECT_STORE);\n}\n\n@Module({})\nclass ArtifactStorageOptionsHostModule {}\n\nfunction syncOptionsHost(\n options: ResolvedArtifactStorageModuleOptions,\n): DynamicModule {\n return {\n module: ArtifactStorageOptionsHostModule,\n providers: [\n { provide: ARTIFACT_STORAGE_MODULE_OPTIONS, useValue: options },\n ],\n exports: [ARTIFACT_STORAGE_MODULE_OPTIONS],\n };\n}\n\nfunction asyncOptionsHost(\n options: ArtifactStorageModuleAsyncOptions,\n): DynamicModule {\n return {\n module: ArtifactStorageOptionsHostModule,\n imports: options.imports ?? [],\n providers: [\n {\n provide: ARTIFACT_STORAGE_MODULE_OPTIONS,\n inject: options.inject ?? [],\n useFactory: options.useFactory,\n },\n ],\n exports: [ARTIFACT_STORAGE_MODULE_OPTIONS],\n };\n}\n\nfunction domainProviders(): Provider[] {\n return [\n {\n provide: ARTIFACT_STORAGE,\n inject: [\n ARTIFACT_STORAGE_MODULE_OPTIONS,\n getStorageToken(ARTIFACT_STORAGE_CLIENT_NAME),\n ],\n useFactory: (\n options: ResolvedArtifactStorageModuleOptions,\n client: StorageClient,\n ): ArtifactStorage =>\n createArtifactStorageWithClient(options.config, options.crypto, client),\n },\n {\n provide: OBJECT_STORE,\n inject: [\n ARTIFACT_STORAGE_MODULE_OPTIONS,\n getStorageToken(OBJECT_STORAGE_CLIENT_NAME),\n ],\n useFactory: (\n options: ResolvedArtifactStorageModuleOptions,\n client: StorageClient,\n ): ObjectStore =>\n createObjectStoreWithClient(options.config, options.crypto, client),\n },\n ArtifactStorageCryptoShutdown,\n ];\n}\n\nclass ArtifactStorageCryptoShutdown implements OnApplicationShutdown {\n constructor(\n @Inject(ARTIFACT_STORAGE_MODULE_OPTIONS)\n private readonly options: ResolvedArtifactStorageModuleOptions,\n ) {}\n\n onApplicationShutdown(): void {\n this.options.crypto.keyProvider.clear();\n }\n}\n\nfunction composeModule(\n optionsHost: DynamicModule,\n isGlobal: boolean,\n): DynamicModule {\n const rawStorageModule = StorageModule.forRootAsync({\n imports: [optionsHost],\n default: ARTIFACT_STORAGE_CLIENT_NAME,\n isGlobal,\n stores: [\n {\n name: ARTIFACT_STORAGE_CLIENT_NAME,\n inject: [ARTIFACT_STORAGE_MODULE_OPTIONS],\n useFactory: (options: ResolvedArtifactStorageModuleOptions) =>\n createArtifactStorageDriver(options.config),\n },\n {\n name: OBJECT_STORAGE_CLIENT_NAME,\n inject: [ARTIFACT_STORAGE_MODULE_OPTIONS],\n useFactory: (options: ResolvedArtifactStorageModuleOptions) =>\n createObjectStorageDriver(options.config),\n },\n ],\n });\n\n return {\n module: ArtifactStorageModule,\n global: isGlobal,\n imports: [optionsHost, rawStorageModule],\n providers: domainProviders(),\n exports: [ARTIFACT_STORAGE, OBJECT_STORE, StorageModule],\n };\n}\n\n@Module({})\nexport class ArtifactStorageModule {\n static forRoot(options: ArtifactStorageModuleOptions): DynamicModule {\n const { config, crypto } = options;\n return composeModule(\n syncOptionsHost({ config, crypto }),\n options.isGlobal === true,\n );\n }\n\n static forRootAsync(\n options: ArtifactStorageModuleAsyncOptions,\n ): DynamicModule {\n return composeModule(asyncOptionsHost(options), options.isGlobal === true);\n }\n}\n"]}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { type StorageClient } from '../core/index.js';
|
|
2
|
-
import { type ReadRef, type ScopeRef } from './artifact-storage.js';
|
|
3
|
-
import { type StorageCrypto } from './crypto/index.js';
|
|
4
|
-
import { type ArtifactStorageConfig } from './storage-driver.js';
|
|
5
|
-
/**
|
|
6
|
-
* Generic key→bytes object store (not artifact-shaped). Backs org-logo uploads and staged
|
|
7
|
-
* artifact uploads. Objects are CAE1 envelopes like artifact files; the content type lives in
|
|
8
|
-
* the authenticated envelope header on every provider. Filesystem `.ct` sidecars remain read-only
|
|
9
|
-
* compatibility data and are never emitted.
|
|
10
|
-
*/
|
|
11
|
-
export interface ObjectStore {
|
|
12
|
-
putObject(key: string, body: Buffer, contentType: string, ref: ScopeRef): Promise<void>;
|
|
13
|
-
/** `null` if absent; throws `EnvelopeError` on decrypt failure (never masked as a miss). */
|
|
14
|
-
getObject(key: string, ref: ReadRef): Promise<{
|
|
15
|
-
body: Buffer;
|
|
16
|
-
contentType?: string;
|
|
17
|
-
} | null>;
|
|
18
|
-
deleteObject(key: string): Promise<void>;
|
|
19
|
-
/** Delete every object under `prefix` last modified more than `olderThanMs` ago. Returns the count deleted. */
|
|
20
|
-
sweepObjects(prefix: string, olderThanMs: number): Promise<number>;
|
|
21
|
-
/** Keys beginning with `prefix` (store namespace), sorted lexicographically. */
|
|
22
|
-
listObjects(prefix: string): Promise<string[]>;
|
|
23
|
-
}
|
|
24
|
-
export declare function createObjectStore(cfg: ArtifactStorageConfig, crypto: StorageCrypto): Promise<ObjectStore>;
|
|
25
|
-
/** Framework-neutral domain adapter used by both direct consumers and the Nest composition entry. */
|
|
26
|
-
export declare function createObjectStoreWithClient(cfg: ArtifactStorageConfig, crypto: StorageCrypto, client: StorageClient): ObjectStore;
|
|
27
|
-
//# sourceMappingURL=object-store.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"object-store.d.ts","sourceRoot":"","sources":["../../src/artifacts/object-store.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,aAAa,EAEnB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAEL,KAAK,OAAO,EACZ,KAAK,QAAQ,EACd,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAIL,KAAK,aAAa,EACnB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAIL,KAAK,qBAAqB,EAC3B,MAAM,qBAAqB,CAAC;AAE7B;;;;;GAKG;AACH,MAAM,WAAW,WAAW;IAC1B,SAAS,CACP,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,EACnB,GAAG,EAAE,QAAQ,GACZ,OAAO,CAAC,IAAI,CAAC,CAAC;IACjB,4FAA4F;IAC5F,SAAS,CACP,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,OAAO,GACX,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC,CAAC;IAC1D,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACzC,+GAA+G;IAC/G,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACnE,gFAAgF;IAChF,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;CAChD;AAED,wBAAsB,iBAAiB,CACrC,GAAG,EAAE,qBAAqB,EAC1B,MAAM,EAAE,aAAa,GACpB,OAAO,CAAC,WAAW,CAAC,CAGtB;AAED,qGAAqG;AACrG,wBAAgB,2BAA2B,CACzC,GAAG,EAAE,qBAAqB,EAC1B,MAAM,EAAE,aAAa,EACrB,MAAM,EAAE,aAAa,GACpB,WAAW,CAOb"}
|
|
@@ -1,198 +0,0 @@
|
|
|
1
|
-
import { StorageErrorCode, isStorageError, } from '../core/index.js';
|
|
2
|
-
import { warnLegacyRead, } from './artifact-storage.js';
|
|
3
|
-
import { open, seal, } from './crypto/index.js';
|
|
4
|
-
import { createObjectStorageClient, DEFAULT_OBJECT_NAMESPACES, resolveObjectNamespaces, } from './storage-driver.js';
|
|
5
|
-
export async function createObjectStore(cfg, crypto) {
|
|
6
|
-
const client = await createObjectStorageClient(cfg);
|
|
7
|
-
return createObjectStoreWithClient(cfg, crypto, client);
|
|
8
|
-
}
|
|
9
|
-
/** Framework-neutral domain adapter used by both direct consumers and the Nest composition entry. */
|
|
10
|
-
export function createObjectStoreWithClient(cfg, crypto, client) {
|
|
11
|
-
return new ClientObjectStore(client, crypto, cfg.provider === 'fs', cfg.objectNamespaces ?? DEFAULT_OBJECT_NAMESPACES);
|
|
12
|
-
}
|
|
13
|
-
/**
|
|
14
|
-
* Envelope context for a store object. `path` is the store-relative KEY on every provider —
|
|
15
|
-
* the fs `_objects/` nesting is a driver-level prefix and must never reach the AAD, or two
|
|
16
|
-
* providers would bind ciphertext to different addresses for the same logical object.
|
|
17
|
-
*/
|
|
18
|
-
function objectCtx(key, ref) {
|
|
19
|
-
return {
|
|
20
|
-
scope: ref.scope,
|
|
21
|
-
artifactId: null,
|
|
22
|
-
version: ref.version ?? null,
|
|
23
|
-
path: key,
|
|
24
|
-
};
|
|
25
|
-
}
|
|
26
|
-
function aliasesLegacyFilesystemSidecar(segment) {
|
|
27
|
-
let end = segment.length;
|
|
28
|
-
while (end > 0 &&
|
|
29
|
-
(segment.charCodeAt(end - 1) === 0x2e ||
|
|
30
|
-
segment.charCodeAt(end - 1) === 0x20)) {
|
|
31
|
-
end--;
|
|
32
|
-
}
|
|
33
|
-
return segment.slice(0, end).toLowerCase().endsWith('.ct');
|
|
34
|
-
}
|
|
35
|
-
function assertObjectKey(key, namespaces, filesystemLayout, allowEmpty = false) {
|
|
36
|
-
const firstSegment = key.split(/[/\\]/, 1)[0] ?? '';
|
|
37
|
-
const segments = key.split(/[/\\]/);
|
|
38
|
-
if (allowEmpty && segments.at(-1) === '')
|
|
39
|
-
segments.pop();
|
|
40
|
-
if ((!allowEmpty && key === '') ||
|
|
41
|
-
key.startsWith('/') ||
|
|
42
|
-
key.includes('\0') ||
|
|
43
|
-
(filesystemLayout && segments.some(aliasesLegacyFilesystemSidecar)) ||
|
|
44
|
-
segments.some((segment) => segment === '' || segment === '.' || segment === '..') ||
|
|
45
|
-
(key !== '' && !namespaces.has(firstSegment.toLowerCase()))) {
|
|
46
|
-
throw new Error(`invalid object key: ${key}`);
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
async function collectRawObject(object) {
|
|
50
|
-
const chunks = [];
|
|
51
|
-
const reader = object.body.getReader();
|
|
52
|
-
try {
|
|
53
|
-
while (true) {
|
|
54
|
-
const { done, value } = await reader.read();
|
|
55
|
-
if (done)
|
|
56
|
-
break;
|
|
57
|
-
chunks.push(Buffer.from(value));
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
finally {
|
|
61
|
-
reader.releaseLock();
|
|
62
|
-
}
|
|
63
|
-
return Buffer.concat(chunks);
|
|
64
|
-
}
|
|
65
|
-
function isObjectKeyAllowed(key, namespaces, filesystemLayout) {
|
|
66
|
-
try {
|
|
67
|
-
assertObjectKey(key, namespaces, filesystemLayout);
|
|
68
|
-
return true;
|
|
69
|
-
}
|
|
70
|
-
catch {
|
|
71
|
-
return false;
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
class ClientObjectStore {
|
|
75
|
-
client;
|
|
76
|
-
crypto;
|
|
77
|
-
filesystemLayout;
|
|
78
|
-
namespaces;
|
|
79
|
-
constructor(client, crypto, filesystemLayout, namespaces) {
|
|
80
|
-
this.client = client;
|
|
81
|
-
this.crypto = crypto;
|
|
82
|
-
this.filesystemLayout = filesystemLayout;
|
|
83
|
-
this.namespaces = resolveObjectNamespaces(namespaces);
|
|
84
|
-
}
|
|
85
|
-
async putObject(key, body, contentType, ref) {
|
|
86
|
-
assertObjectKey(key, this.namespaces, this.filesystemLayout);
|
|
87
|
-
const sealed = await seal(body, objectCtx(key, ref), this.crypto.keyProvider, contentType);
|
|
88
|
-
await this.client.upload(key, sealed, {
|
|
89
|
-
// Real content type rides the authenticated envelope; raw storage remains opaque.
|
|
90
|
-
contentType: 'application/octet-stream',
|
|
91
|
-
});
|
|
92
|
-
if (this.filesystemLayout)
|
|
93
|
-
await this.client.delete(`${key}.ct`);
|
|
94
|
-
}
|
|
95
|
-
async getObject(key, ref) {
|
|
96
|
-
assertObjectKey(key, this.namespaces, this.filesystemLayout);
|
|
97
|
-
const stored = await this.downloadRaw(this.client, key);
|
|
98
|
-
if (stored === null)
|
|
99
|
-
return null;
|
|
100
|
-
const out = await open(stored.raw, objectCtx(key, ref), this.crypto.keyProvider, this.crypto.allowLegacyPlaintext === undefined
|
|
101
|
-
? {}
|
|
102
|
-
: { allowLegacyPlaintext: this.crypto.allowLegacyPlaintext });
|
|
103
|
-
let contentType = out.contentType;
|
|
104
|
-
if (out.legacy) {
|
|
105
|
-
warnLegacyRead(this.filesystemLayout ? 'fs-object' : 'object', key);
|
|
106
|
-
if (this.filesystemLayout) {
|
|
107
|
-
contentType = await this.readLegacyFilesystemContentType(key);
|
|
108
|
-
}
|
|
109
|
-
else {
|
|
110
|
-
contentType = stored.contentType;
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
return {
|
|
114
|
-
body: out.plain,
|
|
115
|
-
...(contentType === undefined ? {} : { contentType }),
|
|
116
|
-
};
|
|
117
|
-
}
|
|
118
|
-
async deleteObject(key) {
|
|
119
|
-
assertObjectKey(key, this.namespaces, this.filesystemLayout);
|
|
120
|
-
await this.client.delete(key);
|
|
121
|
-
if (this.filesystemLayout)
|
|
122
|
-
await this.client.delete(`${key}.ct`);
|
|
123
|
-
}
|
|
124
|
-
async sweepObjects(prefix, olderThanMs) {
|
|
125
|
-
assertObjectKey(prefix, this.namespaces, this.filesystemLayout, true);
|
|
126
|
-
if (!Number.isFinite(olderThanMs) || olderThanMs < 0) {
|
|
127
|
-
throw new RangeError('olderThanMs must be a finite non-negative number');
|
|
128
|
-
}
|
|
129
|
-
const cutoff = Date.now() - olderThanMs;
|
|
130
|
-
let deleted = 0;
|
|
131
|
-
for await (const object of this.client.listAll({ prefix })) {
|
|
132
|
-
if (!isObjectKeyAllowed(object.key, this.namespaces, this.filesystemLayout)) {
|
|
133
|
-
continue;
|
|
134
|
-
}
|
|
135
|
-
if (this.filesystemLayout && object.key.toLowerCase().endsWith('.ct'))
|
|
136
|
-
continue;
|
|
137
|
-
if (!isExpired(object.lastModified, cutoff))
|
|
138
|
-
continue;
|
|
139
|
-
await this.client.delete(object.key);
|
|
140
|
-
if (this.filesystemLayout)
|
|
141
|
-
await this.client.delete(`${object.key}.ct`);
|
|
142
|
-
deleted++;
|
|
143
|
-
}
|
|
144
|
-
return deleted;
|
|
145
|
-
}
|
|
146
|
-
async listObjects(prefix) {
|
|
147
|
-
assertObjectKey(prefix, this.namespaces, this.filesystemLayout, true);
|
|
148
|
-
const keys = new Set();
|
|
149
|
-
for await (const object of this.client.listAll({ prefix })) {
|
|
150
|
-
if (!isObjectKeyAllowed(object.key, this.namespaces, this.filesystemLayout)) {
|
|
151
|
-
continue;
|
|
152
|
-
}
|
|
153
|
-
if (this.filesystemLayout && object.key.toLowerCase().endsWith('.ct'))
|
|
154
|
-
continue;
|
|
155
|
-
keys.add(object.key);
|
|
156
|
-
}
|
|
157
|
-
return [...keys].sort();
|
|
158
|
-
}
|
|
159
|
-
async downloadRaw(client, key) {
|
|
160
|
-
try {
|
|
161
|
-
const object = await client.downloadStream(key);
|
|
162
|
-
const raw = await collectRawObject(object);
|
|
163
|
-
return {
|
|
164
|
-
raw,
|
|
165
|
-
...(object.contentType === undefined
|
|
166
|
-
? {}
|
|
167
|
-
: { contentType: object.contentType }),
|
|
168
|
-
};
|
|
169
|
-
}
|
|
170
|
-
catch (error) {
|
|
171
|
-
if (isStorageError(error) && error.code === StorageErrorCode.NOT_FOUND) {
|
|
172
|
-
return null;
|
|
173
|
-
}
|
|
174
|
-
throw error;
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
async readLegacyFilesystemContentType(key) {
|
|
178
|
-
try {
|
|
179
|
-
return await this.client.downloadText(`${key}.ct`, {
|
|
180
|
-
maxBytes: 64 * 1024,
|
|
181
|
-
});
|
|
182
|
-
}
|
|
183
|
-
catch (error) {
|
|
184
|
-
if (isStorageError(error) && error.code === StorageErrorCode.NOT_FOUND) {
|
|
185
|
-
return undefined;
|
|
186
|
-
}
|
|
187
|
-
throw error;
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
function isExpired(lastModified, cutoff) {
|
|
192
|
-
const modifiedAt = lastModified?.getTime();
|
|
193
|
-
// A provider that cannot supply a trustworthy timestamp cannot prove an object is expired.
|
|
194
|
-
return (modifiedAt !== undefined &&
|
|
195
|
-
Number.isFinite(modifiedAt) &&
|
|
196
|
-
modifiedAt < cutoff);
|
|
197
|
-
}
|
|
198
|
-
//# sourceMappingURL=object-store.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"object-store.js","sourceRoot":"","sources":["../../src/artifacts/object-store.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n StorageErrorCode,\n isStorageError,\n type StorageClient,\n type StorageObject,\n} from '../core/index.js';\n\nimport {\n warnLegacyRead,\n type ReadRef,\n type ScopeRef,\n} from './artifact-storage.js';\nimport {\n open,\n seal,\n type EnvelopeContext,\n type StorageCrypto,\n} from './crypto/index.js';\nimport {\n createObjectStorageClient,\n DEFAULT_OBJECT_NAMESPACES,\n resolveObjectNamespaces,\n type ArtifactStorageConfig,\n} from './storage-driver.js';\n\n/**\n * Generic key→bytes object store (not artifact-shaped). Backs org-logo uploads and staged\n * artifact uploads. Objects are CAE1 envelopes like artifact files; the content type lives in\n * the authenticated envelope header on every provider. Filesystem `.ct` sidecars remain read-only\n * compatibility data and are never emitted.\n */\nexport interface ObjectStore {\n putObject(\n key: string,\n body: Buffer,\n contentType: string,\n ref: ScopeRef,\n ): Promise<void>;\n /** `null` if absent; throws `EnvelopeError` on decrypt failure (never masked as a miss). */\n getObject(\n key: string,\n ref: ReadRef,\n ): Promise<{ body: Buffer; contentType?: string } | null>;\n deleteObject(key: string): Promise<void>;\n /** Delete every object under `prefix` last modified more than `olderThanMs` ago. Returns the count deleted. */\n sweepObjects(prefix: string, olderThanMs: number): Promise<number>;\n /** Keys beginning with `prefix` (store namespace), sorted lexicographically. */\n listObjects(prefix: string): Promise<string[]>;\n}\n\nexport async function createObjectStore(\n cfg: ArtifactStorageConfig,\n crypto: StorageCrypto,\n): Promise<ObjectStore> {\n const client = await createObjectStorageClient(cfg);\n return createObjectStoreWithClient(cfg, crypto, client);\n}\n\n/** Framework-neutral domain adapter used by both direct consumers and the Nest composition entry. */\nexport function createObjectStoreWithClient(\n cfg: ArtifactStorageConfig,\n crypto: StorageCrypto,\n client: StorageClient,\n): ObjectStore {\n return new ClientObjectStore(\n client,\n crypto,\n cfg.provider === 'fs',\n cfg.objectNamespaces ?? DEFAULT_OBJECT_NAMESPACES,\n );\n}\n\n/**\n * Envelope context for a store object. `path` is the store-relative KEY on every provider —\n * the fs `_objects/` nesting is a driver-level prefix and must never reach the AAD, or two\n * providers would bind ciphertext to different addresses for the same logical object.\n */\nfunction objectCtx(key: string, ref: ScopeRef | ReadRef): EnvelopeContext {\n return {\n scope: ref.scope as string,\n artifactId: null,\n version: ref.version ?? null,\n path: key,\n };\n}\n\nfunction aliasesLegacyFilesystemSidecar(segment: string): boolean {\n let end = segment.length;\n while (\n end > 0 &&\n (segment.charCodeAt(end - 1) === 0x2e ||\n segment.charCodeAt(end - 1) === 0x20)\n ) {\n end--;\n }\n return segment.slice(0, end).toLowerCase().endsWith('.ct');\n}\n\nfunction assertObjectKey(\n key: string,\n namespaces: ReadonlySet<string>,\n filesystemLayout: boolean,\n allowEmpty = false,\n): void {\n const firstSegment = key.split(/[/\\\\]/, 1)[0] ?? '';\n const segments = key.split(/[/\\\\]/);\n if (allowEmpty && segments.at(-1) === '') segments.pop();\n if (\n (!allowEmpty && key === '') ||\n key.startsWith('/') ||\n key.includes('\\0') ||\n (filesystemLayout && segments.some(aliasesLegacyFilesystemSidecar)) ||\n segments.some(\n (segment) => segment === '' || segment === '.' || segment === '..',\n ) ||\n (key !== '' && !namespaces.has(firstSegment.toLowerCase()))\n ) {\n throw new Error(`invalid object key: ${key}`);\n }\n}\n\nasync function collectRawObject(object: StorageObject): Promise<Buffer> {\n const chunks: Buffer[] = [];\n const reader = object.body.getReader();\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n chunks.push(Buffer.from(value));\n }\n } finally {\n reader.releaseLock();\n }\n return Buffer.concat(chunks);\n}\n\ninterface RawObject {\n raw: Buffer;\n contentType?: string;\n}\n\nfunction isObjectKeyAllowed(\n key: string,\n namespaces: ReadonlySet<string>,\n filesystemLayout: boolean,\n): boolean {\n try {\n assertObjectKey(key, namespaces, filesystemLayout);\n return true;\n } catch {\n return false;\n }\n}\n\nclass ClientObjectStore implements ObjectStore {\n private readonly namespaces: ReadonlySet<string>;\n\n constructor(\n private readonly client: StorageClient,\n private readonly crypto: StorageCrypto,\n private readonly filesystemLayout: boolean,\n namespaces: readonly string[],\n ) {\n this.namespaces = resolveObjectNamespaces(namespaces);\n }\n\n async putObject(\n key: string,\n body: Buffer,\n contentType: string,\n ref: ScopeRef,\n ): Promise<void> {\n assertObjectKey(key, this.namespaces, this.filesystemLayout);\n const sealed = await seal(\n body,\n objectCtx(key, ref),\n this.crypto.keyProvider,\n contentType,\n );\n await this.client.upload(key, sealed, {\n // Real content type rides the authenticated envelope; raw storage remains opaque.\n contentType: 'application/octet-stream',\n });\n if (this.filesystemLayout) await this.client.delete(`${key}.ct`);\n }\n\n async getObject(\n key: string,\n ref: ReadRef,\n ): Promise<{ body: Buffer; contentType?: string } | null> {\n assertObjectKey(key, this.namespaces, this.filesystemLayout);\n const stored = await this.downloadRaw(this.client, key);\n if (stored === null) return null;\n const out = await open(\n stored.raw,\n objectCtx(key, ref),\n this.crypto.keyProvider,\n this.crypto.allowLegacyPlaintext === undefined\n ? {}\n : { allowLegacyPlaintext: this.crypto.allowLegacyPlaintext },\n );\n let contentType = out.contentType;\n if (out.legacy) {\n warnLegacyRead(this.filesystemLayout ? 'fs-object' : 'object', key);\n if (this.filesystemLayout) {\n contentType = await this.readLegacyFilesystemContentType(key);\n } else {\n contentType = stored.contentType;\n }\n }\n return {\n body: out.plain,\n ...(contentType === undefined ? {} : { contentType }),\n };\n }\n\n async deleteObject(key: string): Promise<void> {\n assertObjectKey(key, this.namespaces, this.filesystemLayout);\n await this.client.delete(key);\n if (this.filesystemLayout) await this.client.delete(`${key}.ct`);\n }\n\n async sweepObjects(prefix: string, olderThanMs: number): Promise<number> {\n assertObjectKey(prefix, this.namespaces, this.filesystemLayout, true);\n if (!Number.isFinite(olderThanMs) || olderThanMs < 0) {\n throw new RangeError('olderThanMs must be a finite non-negative number');\n }\n const cutoff = Date.now() - olderThanMs;\n let deleted = 0;\n for await (const object of this.client.listAll({ prefix })) {\n if (\n !isObjectKeyAllowed(object.key, this.namespaces, this.filesystemLayout)\n ) {\n continue;\n }\n if (this.filesystemLayout && object.key.toLowerCase().endsWith('.ct'))\n continue;\n if (!isExpired(object.lastModified, cutoff)) continue;\n await this.client.delete(object.key);\n if (this.filesystemLayout) await this.client.delete(`${object.key}.ct`);\n deleted++;\n }\n return deleted;\n }\n\n async listObjects(prefix: string): Promise<string[]> {\n assertObjectKey(prefix, this.namespaces, this.filesystemLayout, true);\n const keys = new Set<string>();\n for await (const object of this.client.listAll({ prefix })) {\n if (\n !isObjectKeyAllowed(object.key, this.namespaces, this.filesystemLayout)\n ) {\n continue;\n }\n if (this.filesystemLayout && object.key.toLowerCase().endsWith('.ct'))\n continue;\n keys.add(object.key);\n }\n return [...keys].sort();\n }\n\n private async downloadRaw(\n client: StorageClient,\n key: string,\n ): Promise<RawObject | null> {\n try {\n const object = await client.downloadStream(key);\n const raw = await collectRawObject(object);\n return {\n raw,\n ...(object.contentType === undefined\n ? {}\n : { contentType: object.contentType }),\n };\n } catch (error) {\n if (isStorageError(error) && error.code === StorageErrorCode.NOT_FOUND) {\n return null;\n }\n throw error;\n }\n }\n\n private async readLegacyFilesystemContentType(\n key: string,\n ): Promise<string | undefined> {\n try {\n return await this.client.downloadText(`${key}.ct`, {\n maxBytes: 64 * 1024,\n });\n } catch (error) {\n if (isStorageError(error) && error.code === StorageErrorCode.NOT_FOUND) {\n return undefined;\n }\n throw error;\n }\n }\n}\n\nfunction isExpired(lastModified: Date | undefined, cutoff: number): boolean {\n const modifiedAt = lastModified?.getTime();\n // A provider that cannot supply a trustworthy timestamp cannot prove an object is expired.\n return (\n modifiedAt !== undefined &&\n Number.isFinite(modifiedAt) &&\n modifiedAt < cutoff\n );\n}\n"]}
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import { StorageClient, type StorageDriver } from '../core/index.js';
|
|
2
|
-
import { type StorageProviderConfig, type StorageProviderName } from '../files-sdk/provider/index.js';
|
|
3
|
-
export declare const ARTIFACT_STORAGE_CLIENT_NAME = "artifacts";
|
|
4
|
-
export declare const OBJECT_STORAGE_CLIENT_NAME = "objects";
|
|
5
|
-
export declare const DEFAULT_OBJECT_NAMESPACES: readonly ['_staging', 'org-logos'];
|
|
6
|
-
/**
|
|
7
|
-
* Where the generic object store lives relative to the artifact store on a filesystem. Artifact
|
|
8
|
-
* keys are `<artifactId>/<path>`, so an unprefixed object key like `org-logos/x.png` would read
|
|
9
|
-
* back as an artifact directory named `org-logos` — listing, sweeping, and removal would all
|
|
10
|
-
* cross the two. Filesystems therefore retain the historical `_objects` directory. Object-store
|
|
11
|
-
* providers retain their historical unprefixed keys; the configured top-level namespace
|
|
12
|
-
* allowlist keeps those keys disjoint from artifact ids without a rolling-deploy layout change.
|
|
13
|
-
*/
|
|
14
|
-
export declare const OBJECT_STORE_PREFIX = "_objects";
|
|
15
|
-
/**
|
|
16
|
-
* Which store backs artifacts, and how to reach it. `provider` is any slug `@nestm/storage`
|
|
17
|
-
* can build — `fs`, `s3`, `gcs`, `azure`, `r2`, `minio`, `supabase`, and ~40 more — so a
|
|
18
|
-
* deployment picks its store from the environment instead of the platform shipping a driver
|
|
19
|
-
* per backend. Only the selected provider's SDK is ever imported.
|
|
20
|
-
*/
|
|
21
|
-
export interface ArtifactStorageConfig {
|
|
22
|
-
provider: StorageProviderName;
|
|
23
|
-
/** Key prefix so artifacts can share a bucket (or a directory tree) with other apps. */
|
|
24
|
-
prefix?: string;
|
|
25
|
-
/**
|
|
26
|
-
* Flat provider settings: `bucket`/`region`/`endpoint` for an object store, `root` for the
|
|
27
|
-
* filesystem, `accountName`/`container` for Azure. Each provider reads what it needs.
|
|
28
|
-
* Credentials may be omitted wherever the provider's SDK resolves its own chain — on AWS that
|
|
29
|
-
* is the ECS task role, so S3 needs no long-lived keys in env.
|
|
30
|
-
*/
|
|
31
|
-
config?: StorageProviderConfig;
|
|
32
|
-
/**
|
|
33
|
-
* Allowed top-level ObjectStore namespaces. Artifact ids matching one of these values are
|
|
34
|
-
* rejected, keeping the two public facades disjoint on providers where they share a key root.
|
|
35
|
-
*/
|
|
36
|
-
objectNamespaces?: readonly string[];
|
|
37
|
-
}
|
|
38
|
-
/** Default filesystem root, shared by the api and the sandbox so zero-config dev lines up. */
|
|
39
|
-
export declare function defaultFsRoot(): string;
|
|
40
|
-
/** Resolve and validate the case-insensitive top-level ObjectStore namespace allowlist. */
|
|
41
|
-
export declare function resolveObjectNamespaces(namespaces?: readonly string[]): ReadonlySet<string>;
|
|
42
|
-
/** Fail fast on an unknown slug with the full list, rather than at the first upload. */
|
|
43
|
-
export declare function assertStorageProvider(provider: string): StorageProviderName;
|
|
44
|
-
export declare function createArtifactStorageDriver(cfg: ArtifactStorageConfig): Promise<StorageDriver>;
|
|
45
|
-
export declare function createObjectStorageDriver(cfg: ArtifactStorageConfig): Promise<StorageDriver>;
|
|
46
|
-
export declare function createArtifactStorageClient(cfg: ArtifactStorageConfig): Promise<StorageClient>;
|
|
47
|
-
export declare function createObjectStorageClient(cfg: ArtifactStorageConfig): Promise<StorageClient>;
|
|
48
|
-
//# sourceMappingURL=storage-driver.d.ts.map
|