@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 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"storage-driver.d.ts","sourceRoot":"","sources":["../../src/artifacts/storage-driver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,KAAK,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACrE,OAAO,EAIL,KAAK,qBAAqB,EAC1B,KAAK,mBAAmB,EACzB,MAAM,gCAAgC,CAAC;AAIxC,eAAO,MAAM,4BAA4B,cAAc,CAAC;AACxD,eAAO,MAAM,0BAA0B,YAAY,CAAC;AACpD,eAAO,MAAM,yBAAyB,YAAI,UAAU,EAAE,WAAW,CAAU,CAAC;AAE5E;;;;;;;GAOG;AACH,eAAO,MAAM,mBAAmB,aAAa,CAAC;AAE9C;;;;;GAKG;AACH,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,mBAAmB,CAAC;IAC9B,wFAAwF;IACxF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;;OAKG;IACH,MAAM,CAAC,EAAE,qBAAqB,CAAC;IAC/B;;;OAGG;IACH,gBAAgB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACtC;AAED,8FAA8F;AAC9F,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAMD,2FAA2F;AAC3F,wBAAgB,uBAAuB,CACrC,UAAU,GAAE,SAAS,MAAM,EAA8B,GACxD,WAAW,CAAC,MAAM,CAAC,CAyBrB;AAUD,wFAAwF;AACxF,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,mBAAmB,CAU3E;AAmBD,wBAAgB,2BAA2B,CACzC,GAAG,EAAE,qBAAqB,GACzB,OAAO,CAAC,aAAa,CAAC,CAExB;AAED,wBAAgB,yBAAyB,CACvC,GAAG,EAAE,qBAAqB,GACzB,OAAO,CAAC,aAAa,CAAC,CAKxB;AAED,wBAAsB,2BAA2B,CAC/C,GAAG,EAAE,qBAAqB,GACzB,OAAO,CAAC,aAAa,CAAC,CAKxB;AAED,wBAAsB,yBAAyB,CAC7C,GAAG,EAAE,qBAAqB,GACzB,OAAO,CAAC,aAAa,CAAC,CAKxB"}
|
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
import { StorageClient } from '../core/index.js';
|
|
2
|
-
import { createProviderStorageDriver, isStorageProvider, listStorageProviders, } from '../files-sdk/provider/index.js';
|
|
3
|
-
import { tmpdir } from 'node:os';
|
|
4
|
-
import { join } from 'node:path';
|
|
5
|
-
export const ARTIFACT_STORAGE_CLIENT_NAME = 'artifacts';
|
|
6
|
-
export const OBJECT_STORAGE_CLIENT_NAME = 'objects';
|
|
7
|
-
export const DEFAULT_OBJECT_NAMESPACES = ['_staging', 'org-logos'];
|
|
8
|
-
/**
|
|
9
|
-
* Where the generic object store lives relative to the artifact store on a filesystem. Artifact
|
|
10
|
-
* keys are `<artifactId>/<path>`, so an unprefixed object key like `org-logos/x.png` would read
|
|
11
|
-
* back as an artifact directory named `org-logos` — listing, sweeping, and removal would all
|
|
12
|
-
* cross the two. Filesystems therefore retain the historical `_objects` directory. Object-store
|
|
13
|
-
* providers retain their historical unprefixed keys; the configured top-level namespace
|
|
14
|
-
* allowlist keeps those keys disjoint from artifact ids without a rolling-deploy layout change.
|
|
15
|
-
*/
|
|
16
|
-
export const OBJECT_STORE_PREFIX = '_objects';
|
|
17
|
-
/** Default filesystem root, shared by the api and the sandbox so zero-config dev lines up. */
|
|
18
|
-
export function defaultFsRoot() {
|
|
19
|
-
return join(tmpdir(), 'concepta-artifacts-artifacts');
|
|
20
|
-
}
|
|
21
|
-
function trimSlashes(value) {
|
|
22
|
-
return value.replace(/^\/+|\/+$/g, '');
|
|
23
|
-
}
|
|
24
|
-
/** Resolve and validate the case-insensitive top-level ObjectStore namespace allowlist. */
|
|
25
|
-
export function resolveObjectNamespaces(namespaces = DEFAULT_OBJECT_NAMESPACES) {
|
|
26
|
-
const resolved = new Set();
|
|
27
|
-
for (const namespace of namespaces) {
|
|
28
|
-
const normalized = namespace.toLowerCase();
|
|
29
|
-
if (namespace === '' ||
|
|
30
|
-
namespace === '.' ||
|
|
31
|
-
namespace === '..' ||
|
|
32
|
-
namespace.includes('/') ||
|
|
33
|
-
namespace.includes('\\') ||
|
|
34
|
-
namespace.includes('\0') ||
|
|
35
|
-
Buffer.byteLength(namespace, 'utf8') > 255 ||
|
|
36
|
-
normalized === OBJECT_STORE_PREFIX ||
|
|
37
|
-
resolved.has(normalized)) {
|
|
38
|
-
throw new Error(`invalid or duplicate object namespace: ${JSON.stringify(namespace)}`);
|
|
39
|
-
}
|
|
40
|
-
resolved.add(normalized);
|
|
41
|
-
}
|
|
42
|
-
if (resolved.size === 0) {
|
|
43
|
-
throw new Error('at least one object namespace is required');
|
|
44
|
-
}
|
|
45
|
-
return resolved;
|
|
46
|
-
}
|
|
47
|
-
function joinPrefix(...parts) {
|
|
48
|
-
const joined = parts
|
|
49
|
-
.flatMap((part) => (part === undefined ? [] : [trimSlashes(part)]))
|
|
50
|
-
.filter((part) => part.length > 0)
|
|
51
|
-
.join('/');
|
|
52
|
-
return joined.length === 0 ? undefined : joined;
|
|
53
|
-
}
|
|
54
|
-
/** Fail fast on an unknown slug with the full list, rather than at the first upload. */
|
|
55
|
-
export function assertStorageProvider(provider) {
|
|
56
|
-
if (!isStorageProvider(provider)) {
|
|
57
|
-
const known = listStorageProviders()
|
|
58
|
-
.map((candidate) => candidate.slug)
|
|
59
|
-
.join(', ');
|
|
60
|
-
throw new Error(`Unknown storage provider ${JSON.stringify(provider)}. Known providers: ${known}`);
|
|
61
|
-
}
|
|
62
|
-
return provider;
|
|
63
|
-
}
|
|
64
|
-
function providerConfig(cfg) {
|
|
65
|
-
if (cfg.provider !== 'fs')
|
|
66
|
-
return cfg.config ?? {};
|
|
67
|
-
// The filesystem adapter needs a root; every other provider names its store some other way.
|
|
68
|
-
return { root: defaultFsRoot(), ...cfg.config };
|
|
69
|
-
}
|
|
70
|
-
function driver(cfg, prefix) {
|
|
71
|
-
return createProviderStorageDriver({
|
|
72
|
-
provider: cfg.provider,
|
|
73
|
-
config: providerConfig(cfg),
|
|
74
|
-
...(prefix === undefined ? {} : { prefix }),
|
|
75
|
-
});
|
|
76
|
-
}
|
|
77
|
-
export function createArtifactStorageDriver(cfg) {
|
|
78
|
-
return driver(cfg, joinPrefix(cfg.prefix));
|
|
79
|
-
}
|
|
80
|
-
export function createObjectStorageDriver(cfg) {
|
|
81
|
-
return driver(cfg, joinPrefix(cfg.prefix, cfg.provider === 'fs' ? OBJECT_STORE_PREFIX : ''));
|
|
82
|
-
}
|
|
83
|
-
export async function createArtifactStorageClient(cfg) {
|
|
84
|
-
return new StorageClient(ARTIFACT_STORAGE_CLIENT_NAME, await createArtifactStorageDriver(cfg));
|
|
85
|
-
}
|
|
86
|
-
export async function createObjectStorageClient(cfg) {
|
|
87
|
-
return new StorageClient(OBJECT_STORAGE_CLIENT_NAME, await createObjectStorageDriver(cfg));
|
|
88
|
-
}
|
|
89
|
-
//# sourceMappingURL=storage-driver.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"storage-driver.js","sourceRoot":"","sources":["../../src/artifacts/storage-driver.ts"],"names":[],"mappings":"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","sourcesContent":["import { StorageClient, type StorageDriver } from '../core/index.js';\nimport {\n createProviderStorageDriver,\n isStorageProvider,\n listStorageProviders,\n type StorageProviderConfig,\n type StorageProviderName,\n} from '../files-sdk/provider/index.js';\nimport { tmpdir } from 'node:os';\nimport { join } from 'node:path';\n\nexport const ARTIFACT_STORAGE_CLIENT_NAME = 'artifacts';\nexport const OBJECT_STORAGE_CLIENT_NAME = 'objects';\nexport const DEFAULT_OBJECT_NAMESPACES = ['_staging', 'org-logos'] as const;\n\n/**\n * Where the generic object store lives relative to the artifact store on a filesystem. Artifact\n * keys are `<artifactId>/<path>`, so an unprefixed object key like `org-logos/x.png` would read\n * back as an artifact directory named `org-logos` — listing, sweeping, and removal would all\n * cross the two. Filesystems therefore retain the historical `_objects` directory. Object-store\n * providers retain their historical unprefixed keys; the configured top-level namespace\n * allowlist keeps those keys disjoint from artifact ids without a rolling-deploy layout change.\n */\nexport const OBJECT_STORE_PREFIX = '_objects';\n\n/**\n * Which store backs artifacts, and how to reach it. `provider` is any slug `@nestm/storage`\n * can build — `fs`, `s3`, `gcs`, `azure`, `r2`, `minio`, `supabase`, and ~40 more — so a\n * deployment picks its store from the environment instead of the platform shipping a driver\n * per backend. Only the selected provider's SDK is ever imported.\n */\nexport interface ArtifactStorageConfig {\n provider: StorageProviderName;\n /** Key prefix so artifacts can share a bucket (or a directory tree) with other apps. */\n prefix?: string;\n /**\n * Flat provider settings: `bucket`/`region`/`endpoint` for an object store, `root` for the\n * filesystem, `accountName`/`container` for Azure. Each provider reads what it needs.\n * Credentials may be omitted wherever the provider's SDK resolves its own chain — on AWS that\n * is the ECS task role, so S3 needs no long-lived keys in env.\n */\n config?: StorageProviderConfig;\n /**\n * Allowed top-level ObjectStore namespaces. Artifact ids matching one of these values are\n * rejected, keeping the two public facades disjoint on providers where they share a key root.\n */\n objectNamespaces?: readonly string[];\n}\n\n/** Default filesystem root, shared by the api and the sandbox so zero-config dev lines up. */\nexport function defaultFsRoot(): string {\n return join(tmpdir(), 'concepta-artifacts-artifacts');\n}\n\nfunction trimSlashes(value: string): string {\n return value.replace(/^\\/+|\\/+$/g, '');\n}\n\n/** Resolve and validate the case-insensitive top-level ObjectStore namespace allowlist. */\nexport function resolveObjectNamespaces(\n namespaces: readonly string[] = DEFAULT_OBJECT_NAMESPACES,\n): ReadonlySet<string> {\n const resolved = new Set<string>();\n for (const namespace of namespaces) {\n const normalized = namespace.toLowerCase();\n if (\n namespace === '' ||\n namespace === '.' ||\n namespace === '..' ||\n namespace.includes('/') ||\n namespace.includes('\\\\') ||\n namespace.includes('\\0') ||\n Buffer.byteLength(namespace, 'utf8') > 255 ||\n normalized === OBJECT_STORE_PREFIX ||\n resolved.has(normalized)\n ) {\n throw new Error(\n `invalid or duplicate object namespace: ${JSON.stringify(namespace)}`,\n );\n }\n resolved.add(normalized);\n }\n if (resolved.size === 0) {\n throw new Error('at least one object namespace is required');\n }\n return resolved;\n}\n\nfunction joinPrefix(...parts: Array<string | undefined>): string | undefined {\n const joined = parts\n .flatMap((part) => (part === undefined ? [] : [trimSlashes(part)]))\n .filter((part) => part.length > 0)\n .join('/');\n return joined.length === 0 ? undefined : joined;\n}\n\n/** Fail fast on an unknown slug with the full list, rather than at the first upload. */\nexport function assertStorageProvider(provider: string): StorageProviderName {\n if (!isStorageProvider(provider)) {\n const known = listStorageProviders()\n .map((candidate) => candidate.slug)\n .join(', ');\n throw new Error(\n `Unknown storage provider ${JSON.stringify(provider)}. Known providers: ${known}`,\n );\n }\n return provider;\n}\n\nfunction providerConfig(cfg: ArtifactStorageConfig): StorageProviderConfig {\n if (cfg.provider !== 'fs') return cfg.config ?? {};\n // The filesystem adapter needs a root; every other provider names its store some other way.\n return { root: defaultFsRoot(), ...cfg.config };\n}\n\nfunction driver(\n cfg: ArtifactStorageConfig,\n prefix: string | undefined,\n): Promise<StorageDriver> {\n return createProviderStorageDriver({\n provider: cfg.provider,\n config: providerConfig(cfg),\n ...(prefix === undefined ? {} : { prefix }),\n });\n}\n\nexport function createArtifactStorageDriver(\n cfg: ArtifactStorageConfig,\n): Promise<StorageDriver> {\n return driver(cfg, joinPrefix(cfg.prefix));\n}\n\nexport function createObjectStorageDriver(\n cfg: ArtifactStorageConfig,\n): Promise<StorageDriver> {\n return driver(\n cfg,\n joinPrefix(cfg.prefix, cfg.provider === 'fs' ? OBJECT_STORE_PREFIX : ''),\n );\n}\n\nexport async function createArtifactStorageClient(\n cfg: ArtifactStorageConfig,\n): Promise<StorageClient> {\n return new StorageClient(\n ARTIFACT_STORAGE_CLIENT_NAME,\n await createArtifactStorageDriver(cfg),\n );\n}\n\nexport async function createObjectStorageClient(\n cfg: ArtifactStorageConfig,\n): Promise<StorageClient> {\n return new StorageClient(\n OBJECT_STORAGE_CLIENT_NAME,\n await createObjectStorageDriver(cfg),\n );\n}\n"]}
|