@nestm/storage 0.1.0-alpha.7 → 0.1.0-alpha.9

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.
Files changed (74) hide show
  1. package/CHANGELOG.md +135 -0
  2. package/README.md +302 -18
  3. package/SECURITY.md +34 -5
  4. package/dist/ai-sdk/ai-sdk-workspace-tools.d.ts +21 -3
  5. package/dist/ai-sdk/ai-sdk-workspace-tools.d.ts.map +1 -1
  6. package/dist/ai-sdk/ai-sdk-workspace-tools.js +163 -73
  7. package/dist/ai-sdk/ai-sdk-workspace-tools.js.map +1 -1
  8. package/dist/ai-sdk/index.d.ts +1 -1
  9. package/dist/ai-sdk/index.d.ts.map +1 -1
  10. package/dist/ai-sdk/index.js.map +1 -1
  11. package/dist/files-sdk/files-sdk.driver.d.ts +54 -10
  12. package/dist/files-sdk/files-sdk.driver.d.ts.map +1 -1
  13. package/dist/files-sdk/files-sdk.driver.js +831 -63
  14. package/dist/files-sdk/files-sdk.driver.js.map +1 -1
  15. package/dist/files-sdk/fs/index.d.ts +4 -4
  16. package/dist/files-sdk/fs/index.d.ts.map +1 -1
  17. package/dist/files-sdk/fs/index.js +242 -9
  18. package/dist/files-sdk/fs/index.js.map +1 -1
  19. package/dist/files-sdk/index.d.ts +1 -1
  20. package/dist/files-sdk/index.d.ts.map +1 -1
  21. package/dist/files-sdk/index.js.map +1 -1
  22. package/dist/files-sdk/provider/index.d.ts +9 -5
  23. package/dist/files-sdk/provider/index.d.ts.map +1 -1
  24. package/dist/files-sdk/provider/index.js +53 -15
  25. package/dist/files-sdk/provider/index.js.map +1 -1
  26. package/dist/files-sdk/s3/construction-metadata.d.ts +7 -0
  27. package/dist/files-sdk/s3/construction-metadata.d.ts.map +1 -0
  28. package/dist/files-sdk/s3/construction-metadata.js +13 -0
  29. package/dist/files-sdk/s3/construction-metadata.js.map +1 -0
  30. package/dist/files-sdk/s3/index.d.ts +39 -19
  31. package/dist/files-sdk/s3/index.d.ts.map +1 -1
  32. package/dist/files-sdk/s3/index.js +936 -113
  33. package/dist/files-sdk/s3/index.js.map +1 -1
  34. package/dist/gateway/storage-gateway.controller.d.ts.map +1 -1
  35. package/dist/gateway/storage-gateway.controller.js +25 -5
  36. package/dist/gateway/storage-gateway.controller.js.map +1 -1
  37. package/dist/storage-etag.d.ts +13 -0
  38. package/dist/storage-etag.d.ts.map +1 -0
  39. package/dist/storage-etag.js +31 -0
  40. package/dist/storage-etag.js.map +1 -0
  41. package/dist/storage.client.d.ts +3 -1
  42. package/dist/storage.client.d.ts.map +1 -1
  43. package/dist/storage.client.js +87 -22
  44. package/dist/storage.client.js.map +1 -1
  45. package/dist/storage.driver.d.ts +21 -1
  46. package/dist/storage.driver.d.ts.map +1 -1
  47. package/dist/storage.driver.js.map +1 -1
  48. package/dist/storage.types.d.ts +90 -19
  49. package/dist/storage.types.d.ts.map +1 -1
  50. package/dist/storage.types.js.map +1 -1
  51. package/dist/testing/index.d.ts +1 -0
  52. package/dist/testing/index.d.ts.map +1 -1
  53. package/dist/testing/index.js +1 -0
  54. package/dist/testing/index.js.map +1 -1
  55. package/dist/testing/provider-conformance.d.ts +65 -0
  56. package/dist/testing/provider-conformance.d.ts.map +1 -0
  57. package/dist/testing/provider-conformance.js +853 -0
  58. package/dist/testing/provider-conformance.js.map +1 -0
  59. package/dist/workspace/index.d.ts +2 -1
  60. package/dist/workspace/index.d.ts.map +1 -1
  61. package/dist/workspace/index.js +1 -0
  62. package/dist/workspace/index.js.map +1 -1
  63. package/dist/workspace/storage-workspace.cursor.d.ts +68 -3
  64. package/dist/workspace/storage-workspace.cursor.d.ts.map +1 -1
  65. package/dist/workspace/storage-workspace.cursor.js +402 -39
  66. package/dist/workspace/storage-workspace.cursor.js.map +1 -1
  67. package/dist/workspace/storage-workspace.d.ts.map +1 -1
  68. package/dist/workspace/storage-workspace.js +162 -62
  69. package/dist/workspace/storage-workspace.js.map +1 -1
  70. package/dist/workspace/storage-workspace.types.d.ts +31 -5
  71. package/dist/workspace/storage-workspace.types.d.ts.map +1 -1
  72. package/dist/workspace/storage-workspace.types.js +2 -0
  73. package/dist/workspace/storage-workspace.types.js.map +1 -1
  74. package/package.json +3 -3
@@ -2,6 +2,7 @@ import type { Adapter } from 'files-sdk';
2
2
  import { type LoadFilesOptions } from 'files-sdk/loader';
3
3
  import { type EnvVar, type Provider, type ProviderSlug } from 'files-sdk/providers';
4
4
  import { type FilesSdkDriverOptions, type FilesSdkStorageDriver } from '../files-sdk.driver.js';
5
+ import type { S3ProviderProfile } from '../s3/index.js';
5
6
  /** Slug of a storage provider this package can build a driver for. */
6
7
  export type StorageProviderName = ProviderSlug;
7
8
  /**
@@ -18,6 +19,8 @@ export interface ProviderStorageDriverOptions extends Omit<FilesSdkDriverOptions
18
19
  /** Which provider to build. Validate untrusted input with {@link isStorageProvider}. */
19
20
  provider: StorageProviderName;
20
21
  config?: StorageProviderConfig;
22
+ /** Verified operation profile for the `s3` slug, especially custom endpoints. */
23
+ s3ProviderProfile?: S3ProviderProfile;
21
24
  }
22
25
  /**
23
26
  * Builds a {@link FilesSdkStorageDriver} for a provider named at runtime,
@@ -26,11 +29,12 @@ export interface ProviderStorageDriverOptions extends Omit<FilesSdkDriverOptions
26
29
  * `'r2'`, `'fs'`, …) and installs one native SDK, instead of the application
27
30
  * hard-coding a driver per backend.
28
31
  *
29
- * The `s3` slug additionally gets the conditional-promotion and signed-policy
30
- * capabilities {@link createS3StorageDriver} attaches; every other provider
31
- * exposes exactly what its adapter declares. Import
32
- * `@nestm/storage/files-sdk/s3` directly when the provider is known at build
33
- * time and the extra indirection buys nothing.
32
+ * The `s3` slug additionally gets the exact verified provider profile and
33
+ * signed-policy capabilities {@link createS3StorageDriver} attaches. Providers
34
+ * not backed by the AWS S3 SDK expose what their adapter declares;
35
+ * noncanonical S3-backed providers default to an unverified, read-only profile.
36
+ * Import `@nestm/storage/files-sdk/s3` directly when the provider is known at
37
+ * build time and the extra indirection buys nothing.
34
38
  *
35
39
  * @throws StorageError `INVALID_ARGUMENT` for an unknown slug, and whatever the
36
40
  * adapter reports (mapped) when required config or credentials are missing.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/files-sdk/provider/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAa,KAAK,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpE,OAAO,EAKL,KAAK,MAAM,EACX,KAAK,QAAQ,EACb,KAAK,YAAY,EAClB,MAAM,qBAAqB,CAAC;AAG7B,OAAO,EAGL,KAAK,qBAAqB,EAC1B,KAAK,qBAAqB,EAC3B,MAAM,wBAAwB,CAAC;AAEhC,sEAAsE;AACtE,MAAM,MAAM,mBAAmB,GAAG,YAAY,CAAC;AAE/C;;;;;;;;GAQG;AACH,MAAM,MAAM,qBAAqB,GAAG,IAAI,CAAC,gBAAgB,EAAE,UAAU,CAAC,CAAC;AAEvE,MAAM,WAAW,4BAA6B,SAAQ,IAAI,CACxD,qBAAqB,CAAC,OAAO,CAAC,EAC9B,SAAS,CACV;IACC,wFAAwF;IACxF,QAAQ,EAAE,mBAAmB,CAAC;IAC9B,MAAM,CAAC,EAAE,qBAAqB,CAAC;CAChC;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,2BAA2B,CAC/C,OAAO,EAAE,4BAA4B,GACpC,OAAO,CAAC,qBAAqB,CAAC,CAWhC;AA6CD,iFAAiF;AACjF,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,IAAI,mBAAmB,CAE7E;AAED,wDAAwD;AACxD,wBAAgB,oBAAoB,IAAI,SAAS,QAAQ,EAAE,CAE1D;AAED,+EAA+E;AAC/E,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAErE;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAEjE;AAED,6EAA6E;AAC7E,wBAAgB,gCAAgC,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAEvE;AAED,YAAY,EACV,MAAM,IAAI,qBAAqB,EAC/B,QAAQ,IAAI,mBAAmB,GAChC,MAAM,qBAAqB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/files-sdk/provider/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAa,KAAK,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpE,OAAO,EAKL,KAAK,MAAM,EACX,KAAK,QAAQ,EACb,KAAK,YAAY,EAClB,MAAM,qBAAqB,CAAC;AAG7B,OAAO,EAGL,KAAK,qBAAqB,EAC1B,KAAK,qBAAqB,EAC3B,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAa,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAGnE,sEAAsE;AACtE,MAAM,MAAM,mBAAmB,GAAG,YAAY,CAAC;AAE/C;;;;;;;;GAQG;AACH,MAAM,MAAM,qBAAqB,GAAG,IAAI,CAAC,gBAAgB,EAAE,UAAU,CAAC,CAAC;AAEvE,MAAM,WAAW,4BAA6B,SAAQ,IAAI,CACxD,qBAAqB,CAAC,OAAO,CAAC,EAC9B,SAAS,CACV;IACC,wFAAwF;IACxF,QAAQ,EAAE,mBAAmB,CAAC;IAC9B,MAAM,CAAC,EAAE,qBAAqB,CAAC;IAC/B,iFAAiF;IACjF,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;CACvC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,2BAA2B,CAC/C,OAAO,EAAE,4BAA4B,GACpC,OAAO,CAAC,qBAAqB,CAAC,CAoBhC;AA+ED,iFAAiF;AACjF,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,IAAI,mBAAmB,CAE7E;AAED,wDAAwD;AACxD,wBAAgB,oBAAoB,IAAI,SAAS,QAAQ,EAAE,CAE1D;AAED,+EAA+E;AAC/E,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAErE;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAEjE;AAED,6EAA6E;AAC7E,wBAAgB,gCAAgC,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAEvE;AAED,YAAY,EACV,MAAM,IAAI,qBAAqB,EAC/B,QAAQ,IAAI,mBAAmB,GAChC,MAAM,qBAAqB,CAAC"}
@@ -2,6 +2,7 @@ import { loadFiles } from 'files-sdk/loader';
2
2
  import { PROVIDER_NAMES, getProvider, getSecretEnvVars, listEnvVars, } from 'files-sdk/providers';
3
3
  import { StorageError, StorageErrorCode } from '../../storage.error.js';
4
4
  import { createFilesSdkDriver, mapFilesSdkError, } from '../files-sdk.driver.js';
5
+ import { recordS3ConstructionMetadata } from '../s3/construction-metadata.js';
5
6
  /**
6
7
  * Builds a {@link FilesSdkStorageDriver} for a provider named at runtime,
7
8
  * importing that provider's adapter — and only that one — on demand. A
@@ -9,27 +10,49 @@ import { createFilesSdkDriver, mapFilesSdkError, } from '../files-sdk.driver.js'
9
10
  * `'r2'`, `'fs'`, …) and installs one native SDK, instead of the application
10
11
  * hard-coding a driver per backend.
11
12
  *
12
- * The `s3` slug additionally gets the conditional-promotion and signed-policy
13
- * capabilities {@link createS3StorageDriver} attaches; every other provider
14
- * exposes exactly what its adapter declares. Import
15
- * `@nestm/storage/files-sdk/s3` directly when the provider is known at build
16
- * time and the extra indirection buys nothing.
13
+ * The `s3` slug additionally gets the exact verified provider profile and
14
+ * signed-policy capabilities {@link createS3StorageDriver} attaches. Providers
15
+ * not backed by the AWS S3 SDK expose what their adapter declares;
16
+ * noncanonical S3-backed providers default to an unverified, read-only profile.
17
+ * Import `@nestm/storage/files-sdk/s3` directly when the provider is known at
18
+ * build time and the extra indirection buys nothing.
17
19
  *
18
20
  * @throws StorageError `INVALID_ARGUMENT` for an unknown slug, and whatever the
19
21
  * adapter reports (mapped) when required config or credentials are missing.
20
22
  */
21
23
  export async function createProviderStorageDriver(options) {
22
- const { provider, config, ...filesOptions } = options;
24
+ const { provider, config, s3ProviderProfile, ...filesOptions } = options;
23
25
  if (!isStorageProvider(provider)) {
24
26
  throw unknownProvider(provider);
25
27
  }
26
28
  // `loadFiles` owns the slug → adapter mapping and keeps the import lazy; the
27
29
  // client it returns is discarded so the caller's own driver options (prefix,
28
30
  // hooks, plugins, readonly, retries) apply to the instance the bridge builds.
29
- const adapter = await resolveAdapter(provider, config);
30
- return createFilesSdkDriver({ ...filesOptions, adapter });
31
+ if (s3ProviderProfile !== undefined && provider !== 's3') {
32
+ throw new StorageError('s3ProviderProfile can only be used with the "s3" provider.', { code: StorageErrorCode.INVALID_ARGUMENT, permanent: true });
33
+ }
34
+ const adapter = await resolveAdapter(provider, config, s3ProviderProfile);
35
+ return createFilesSdkDriver({
36
+ ...filesOptions,
37
+ adapter,
38
+ });
39
+ }
40
+ function isS3BackedAdapter(adapter) {
41
+ try {
42
+ const raw = adapter.raw;
43
+ if (typeof raw !== 'object' || raw === null)
44
+ return false;
45
+ const candidate = raw;
46
+ return (typeof candidate.send === 'function' &&
47
+ typeof candidate.config === 'object' &&
48
+ candidate.config !== null &&
49
+ candidate.config.serviceId === 'S3');
50
+ }
51
+ catch {
52
+ return false;
53
+ }
31
54
  }
32
- async function resolveAdapter(provider, config) {
55
+ async function resolveAdapter(provider, config, s3ProviderProfile) {
33
56
  let resolved;
34
57
  try {
35
58
  resolved = await loadFiles({ ...config, provider });
@@ -42,18 +65,33 @@ async function resolveAdapter(provider, config) {
42
65
  const { withFsConditionalMutation } = await import('../fs/index.js');
43
66
  return withFsConditionalMutation(adapter);
44
67
  }
45
- if (provider !== 's3') {
68
+ if (!isS3BackedAdapter(adapter)) {
46
69
  return adapter;
47
70
  }
48
- // Built by `s3(...)`, so its `raw` is an S3Client and the promotion path
49
- // holds. The S3-compatible wrappers keep only what they declare themselves.
71
+ // Every AWS-SDK-backed wrapper gets fail-closed S3 provenance and endpoint
72
+ // hardening. Only the canonical `s3` slug may infer native AWS or accept an
73
+ // explicit verified profile; named compatibles remain unverified/read-only.
50
74
  const { withS3Capabilities } = await import('../s3/index.js');
51
- return withS3Capabilities(adapter, {
75
+ const configJsonPublicBaseUrl = config?.configJson?.publicBaseUrl;
76
+ const publicBaseUrl = config?.publicBaseUrl ??
77
+ (typeof configJsonPublicBaseUrl === 'string'
78
+ ? configJsonPublicBaseUrl
79
+ : undefined);
80
+ const s3Adapter = adapter;
81
+ recordS3ConstructionMetadata(s3Adapter.raw, {
82
+ publicBaseUrlConfigured: provider !== 's3' ||
83
+ config?.publicBaseUrl !== undefined ||
84
+ configJsonPublicBaseUrl !== undefined,
85
+ });
86
+ return withS3Capabilities(s3Adapter, {
52
87
  ...(typeof config?.endpoint === 'string' && {
53
88
  endpoint: config.endpoint,
54
89
  }),
55
- ...(config?.publicBaseUrl !== undefined && {
56
- publicBaseUrl: config.publicBaseUrl,
90
+ ...(publicBaseUrl !== undefined && {
91
+ publicBaseUrl,
92
+ }),
93
+ ...(s3ProviderProfile !== undefined && {
94
+ providerProfile: s3ProviderProfile,
57
95
  }),
58
96
  });
59
97
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/files-sdk/provider/index.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Adapter } from 'files-sdk';\nimport { loadFiles, type LoadFilesOptions } from 'files-sdk/loader';\nimport {\n PROVIDER_NAMES,\n getProvider,\n getSecretEnvVars,\n listEnvVars,\n type EnvVar,\n type Provider,\n type ProviderSlug,\n} from 'files-sdk/providers';\n\nimport { StorageError, StorageErrorCode } from '../../storage.error.js';\nimport {\n createFilesSdkDriver,\n mapFilesSdkError,\n type FilesSdkDriverOptions,\n type FilesSdkStorageDriver,\n} from '../files-sdk.driver.js';\n\n/** Slug of a storage provider this package can build a driver for. */\nexport type StorageProviderName = ProviderSlug;\n\n/**\n * Flat, provider-specific settings — `bucket` and `region` for an object store,\n * `root` for the filesystem, `accountName` and `container` for Azure, and so\n * on. Every provider reads what it needs and ignores the rest, so one config\n * shape serves a deployment that switches providers by name.\n *\n * Credentials may be omitted for any provider whose SDK resolves its own chain\n * (an IAM role, Application Default Credentials, a shared profile).\n */\nexport type StorageProviderConfig = Omit<LoadFilesOptions, 'provider'>;\n\nexport interface ProviderStorageDriverOptions extends Omit<\n FilesSdkDriverOptions<Adapter>,\n 'adapter'\n> {\n /** Which provider to build. Validate untrusted input with {@link isStorageProvider}. */\n provider: StorageProviderName;\n config?: StorageProviderConfig;\n}\n\n/**\n * Builds a {@link FilesSdkStorageDriver} for a provider named at runtime,\n * importing that provider's adapter — and only that one — on demand. A\n * deployment selects its store with a string (`'s3'`, `'gcs'`, `'azure'`,\n * `'r2'`, `'fs'`, …) and installs one native SDK, instead of the application\n * hard-coding a driver per backend.\n *\n * The `s3` slug additionally gets the conditional-promotion and signed-policy\n * capabilities {@link createS3StorageDriver} attaches; every other provider\n * exposes exactly what its adapter declares. Import\n * `@nestm/storage/files-sdk/s3` directly when the provider is known at build\n * time and the extra indirection buys nothing.\n *\n * @throws StorageError `INVALID_ARGUMENT` for an unknown slug, and whatever the\n * adapter reports (mapped) when required config or credentials are missing.\n */\nexport async function createProviderStorageDriver(\n options: ProviderStorageDriverOptions,\n): Promise<FilesSdkStorageDriver> {\n const { provider, config, ...filesOptions } = options;\n if (!isStorageProvider(provider)) {\n throw unknownProvider(provider);\n }\n\n // `loadFiles` owns the slug → adapter mapping and keeps the import lazy; the\n // client it returns is discarded so the caller's own driver options (prefix,\n // hooks, plugins, readonly, retries) apply to the instance the bridge builds.\n const adapter = await resolveAdapter(provider, config);\n return createFilesSdkDriver({ ...filesOptions, adapter });\n}\n\nasync function resolveAdapter(\n provider: StorageProviderName,\n config: StorageProviderConfig | undefined,\n): Promise<Adapter> {\n let resolved;\n try {\n resolved = await loadFiles({ ...config, provider });\n } catch (error) {\n throw mapFilesSdkError(error);\n }\n const { adapter } = resolved.files;\n if (provider === 'fs') {\n const { withFsConditionalMutation } = await import('../fs/index.js');\n return withFsConditionalMutation(\n adapter as Parameters<typeof withFsConditionalMutation>[0],\n );\n }\n if (provider !== 's3') {\n return adapter;\n }\n // Built by `s3(...)`, so its `raw` is an S3Client and the promotion path\n // holds. The S3-compatible wrappers keep only what they declare themselves.\n const { withS3Capabilities } = await import('../s3/index.js');\n return withS3Capabilities(\n adapter as Parameters<typeof withS3Capabilities>[0],\n {\n ...(typeof config?.endpoint === 'string' && {\n endpoint: config.endpoint,\n }),\n ...(config?.publicBaseUrl !== undefined && {\n publicBaseUrl: config.publicBaseUrl,\n }),\n },\n );\n}\n\nfunction unknownProvider(provider: string): StorageError {\n return new StorageError(\n `Unknown storage provider: ${JSON.stringify(provider)}. Known providers: ${PROVIDER_NAMES.join(', ')}.`,\n { code: StorageErrorCode.INVALID_ARGUMENT, permanent: true },\n );\n}\n\n/** Narrows an untrusted string — an env var, a config file — to a known slug. */\nexport function isStorageProvider(value: string): value is StorageProviderName {\n return getProvider(value) !== undefined;\n}\n\n/** Every provider that can be named, sorted by slug. */\nexport function listStorageProviders(): readonly Provider[] {\n return PROVIDER_NAMES.flatMap((slug) => getProvider(slug) ?? []);\n}\n\n/** One provider's display name, description, native SDKs, and env contract. */\nexport function getStorageProvider(slug: string): Provider | undefined {\n return getProvider(slug);\n}\n\n/**\n * Every environment variable a provider reads, flattened across required, all\n * credential modes, and optional. Useful for validating a deployment's config\n * before the first upload rather than at it.\n */\nexport function listStorageProviderEnvVars(slug: string): EnvVar[] {\n return listEnvVars(slug);\n}\n\n/** The subset of {@link listStorageProviderEnvVars} that carries secrets. */\nexport function listStorageProviderSecretEnvVars(slug: string): EnvVar[] {\n return getSecretEnvVars(slug);\n}\n\nexport type {\n EnvVar as StorageProviderEnvVar,\n Provider as StorageProviderInfo,\n} from 'files-sdk/providers';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/files-sdk/provider/index.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Adapter } from 'files-sdk';\nimport { loadFiles, type LoadFilesOptions } from 'files-sdk/loader';\nimport {\n PROVIDER_NAMES,\n getProvider,\n getSecretEnvVars,\n listEnvVars,\n type EnvVar,\n type Provider,\n type ProviderSlug,\n} from 'files-sdk/providers';\n\nimport { StorageError, StorageErrorCode } from '../../storage.error.js';\nimport {\n createFilesSdkDriver,\n mapFilesSdkError,\n type FilesSdkDriverOptions,\n type FilesSdkStorageDriver,\n} from '../files-sdk.driver.js';\nimport type { S3Adapter, S3ProviderProfile } from '../s3/index.js';\nimport { recordS3ConstructionMetadata } from '../s3/construction-metadata.js';\n\n/** Slug of a storage provider this package can build a driver for. */\nexport type StorageProviderName = ProviderSlug;\n\n/**\n * Flat, provider-specific settings — `bucket` and `region` for an object store,\n * `root` for the filesystem, `accountName` and `container` for Azure, and so\n * on. Every provider reads what it needs and ignores the rest, so one config\n * shape serves a deployment that switches providers by name.\n *\n * Credentials may be omitted for any provider whose SDK resolves its own chain\n * (an IAM role, Application Default Credentials, a shared profile).\n */\nexport type StorageProviderConfig = Omit<LoadFilesOptions, 'provider'>;\n\nexport interface ProviderStorageDriverOptions extends Omit<\n FilesSdkDriverOptions<Adapter>,\n 'adapter'\n> {\n /** Which provider to build. Validate untrusted input with {@link isStorageProvider}. */\n provider: StorageProviderName;\n config?: StorageProviderConfig;\n /** Verified operation profile for the `s3` slug, especially custom endpoints. */\n s3ProviderProfile?: S3ProviderProfile;\n}\n\n/**\n * Builds a {@link FilesSdkStorageDriver} for a provider named at runtime,\n * importing that provider's adapter — and only that one — on demand. A\n * deployment selects its store with a string (`'s3'`, `'gcs'`, `'azure'`,\n * `'r2'`, `'fs'`, …) and installs one native SDK, instead of the application\n * hard-coding a driver per backend.\n *\n * The `s3` slug additionally gets the exact verified provider profile and\n * signed-policy capabilities {@link createS3StorageDriver} attaches. Providers\n * not backed by the AWS S3 SDK expose what their adapter declares;\n * noncanonical S3-backed providers default to an unverified, read-only profile.\n * Import `@nestm/storage/files-sdk/s3` directly when the provider is known at\n * build time and the extra indirection buys nothing.\n *\n * @throws StorageError `INVALID_ARGUMENT` for an unknown slug, and whatever the\n * adapter reports (mapped) when required config or credentials are missing.\n */\nexport async function createProviderStorageDriver(\n options: ProviderStorageDriverOptions,\n): Promise<FilesSdkStorageDriver> {\n const { provider, config, s3ProviderProfile, ...filesOptions } = options;\n if (!isStorageProvider(provider)) {\n throw unknownProvider(provider);\n }\n\n // `loadFiles` owns the slug → adapter mapping and keeps the import lazy; the\n // client it returns is discarded so the caller's own driver options (prefix,\n // hooks, plugins, readonly, retries) apply to the instance the bridge builds.\n if (s3ProviderProfile !== undefined && provider !== 's3') {\n throw new StorageError(\n 's3ProviderProfile can only be used with the \"s3\" provider.',\n { code: StorageErrorCode.INVALID_ARGUMENT, permanent: true },\n );\n }\n const adapter = await resolveAdapter(provider, config, s3ProviderProfile);\n return createFilesSdkDriver({\n ...filesOptions,\n adapter,\n });\n}\n\nfunction isS3BackedAdapter(adapter: Adapter): adapter is S3Adapter {\n try {\n const raw = adapter.raw;\n if (typeof raw !== 'object' || raw === null) return false;\n const candidate = raw as {\n readonly config?: unknown;\n readonly send?: unknown;\n };\n return (\n typeof candidate.send === 'function' &&\n typeof candidate.config === 'object' &&\n candidate.config !== null &&\n (candidate.config as { readonly serviceId?: unknown }).serviceId === 'S3'\n );\n } catch {\n return false;\n }\n}\n\nasync function resolveAdapter(\n provider: StorageProviderName,\n config: StorageProviderConfig | undefined,\n s3ProviderProfile: S3ProviderProfile | undefined,\n): Promise<Adapter> {\n let resolved;\n try {\n resolved = await loadFiles({ ...config, provider });\n } catch (error) {\n throw mapFilesSdkError(error);\n }\n const { adapter } = resolved.files;\n if (provider === 'fs') {\n const { withFsConditionalMutation } = await import('../fs/index.js');\n return withFsConditionalMutation(\n adapter as Parameters<typeof withFsConditionalMutation>[0],\n );\n }\n if (!isS3BackedAdapter(adapter)) {\n return adapter;\n }\n // Every AWS-SDK-backed wrapper gets fail-closed S3 provenance and endpoint\n // hardening. Only the canonical `s3` slug may infer native AWS or accept an\n // explicit verified profile; named compatibles remain unverified/read-only.\n const { withS3Capabilities } = await import('../s3/index.js');\n const configJsonPublicBaseUrl = config?.configJson?.publicBaseUrl;\n const publicBaseUrl =\n config?.publicBaseUrl ??\n (typeof configJsonPublicBaseUrl === 'string'\n ? configJsonPublicBaseUrl\n : undefined);\n const s3Adapter = adapter as Parameters<typeof withS3Capabilities>[0];\n recordS3ConstructionMetadata(s3Adapter.raw, {\n publicBaseUrlConfigured:\n provider !== 's3' ||\n config?.publicBaseUrl !== undefined ||\n configJsonPublicBaseUrl !== undefined,\n });\n return withS3Capabilities(s3Adapter, {\n ...(typeof config?.endpoint === 'string' && {\n endpoint: config.endpoint,\n }),\n ...(publicBaseUrl !== undefined && {\n publicBaseUrl,\n }),\n ...(s3ProviderProfile !== undefined && {\n providerProfile: s3ProviderProfile,\n }),\n });\n}\n\nfunction unknownProvider(provider: string): StorageError {\n return new StorageError(\n `Unknown storage provider: ${JSON.stringify(provider)}. Known providers: ${PROVIDER_NAMES.join(', ')}.`,\n { code: StorageErrorCode.INVALID_ARGUMENT, permanent: true },\n );\n}\n\n/** Narrows an untrusted string — an env var, a config file — to a known slug. */\nexport function isStorageProvider(value: string): value is StorageProviderName {\n return getProvider(value) !== undefined;\n}\n\n/** Every provider that can be named, sorted by slug. */\nexport function listStorageProviders(): readonly Provider[] {\n return PROVIDER_NAMES.flatMap((slug) => getProvider(slug) ?? []);\n}\n\n/** One provider's display name, description, native SDKs, and env contract. */\nexport function getStorageProvider(slug: string): Provider | undefined {\n return getProvider(slug);\n}\n\n/**\n * Every environment variable a provider reads, flattened across required, all\n * credential modes, and optional. Useful for validating a deployment's config\n * before the first upload rather than at it.\n */\nexport function listStorageProviderEnvVars(slug: string): EnvVar[] {\n return listEnvVars(slug);\n}\n\n/** The subset of {@link listStorageProviderEnvVars} that carries secrets. */\nexport function listStorageProviderSecretEnvVars(slug: string): EnvVar[] {\n return getSecretEnvVars(slug);\n}\n\nexport type {\n EnvVar as StorageProviderEnvVar,\n Provider as StorageProviderInfo,\n} from 'files-sdk/providers';\n"]}
@@ -0,0 +1,7 @@
1
+ export interface S3ConstructionMetadata {
2
+ /** Whether URL generation bypasses signing through a configured public origin. */
3
+ readonly publicBaseUrlConfigured: boolean;
4
+ }
5
+ export declare function recordS3ConstructionMetadata(raw: object, metadata: S3ConstructionMetadata): void;
6
+ export declare function getS3ConstructionMetadata(raw: object): Readonly<S3ConstructionMetadata> | undefined;
7
+ //# sourceMappingURL=construction-metadata.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"construction-metadata.d.ts","sourceRoot":"","sources":["../../../src/files-sdk/s3/construction-metadata.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,sBAAsB;IACrC,kFAAkF;IAClF,QAAQ,CAAC,uBAAuB,EAAE,OAAO,CAAC;CAC3C;AAOD,wBAAgB,4BAA4B,CAC1C,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,sBAAsB,GAC/B,IAAI,CASN;AAED,wBAAgB,yBAAyB,CACvC,GAAG,EAAE,MAAM,GACV,QAAQ,CAAC,sBAAsB,CAAC,GAAG,SAAS,CAE9C"}
@@ -0,0 +1,13 @@
1
+ const constructionMetadata = new WeakMap();
2
+ export function recordS3ConstructionMetadata(raw, metadata) {
3
+ const existing = constructionMetadata.get(raw);
4
+ if (existing !== undefined &&
5
+ existing.publicBaseUrlConfigured !== metadata.publicBaseUrlConfigured) {
6
+ throw new TypeError('S3 adapter construction metadata cannot be changed.');
7
+ }
8
+ constructionMetadata.set(raw, Object.freeze({ ...metadata }));
9
+ }
10
+ export function getS3ConstructionMetadata(raw) {
11
+ return constructionMetadata.get(raw);
12
+ }
13
+ //# sourceMappingURL=construction-metadata.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"construction-metadata.js","sourceRoot":"","sources":["../../../src/files-sdk/s3/construction-metadata.ts"],"names":[],"mappings":"AAKA,MAAM,oBAAoB,GAAG,IAAI,OAAO,EAGrC,CAAC;AAEJ,MAAM,UAAU,4BAA4B,CAC1C,GAAW,EACX,QAAgC;IAEhC,MAAM,QAAQ,GAAG,oBAAoB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC/C,IACE,QAAQ,KAAK,SAAS;QACtB,QAAQ,CAAC,uBAAuB,KAAK,QAAQ,CAAC,uBAAuB,EACrE,CAAC;QACD,MAAM,IAAI,SAAS,CAAC,qDAAqD,CAAC,CAAC;IAC7E,CAAC;IACD,oBAAoB,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,GAAG,QAAQ,EAAE,CAAC,CAAC,CAAC;AAChE,CAAC;AAED,MAAM,UAAU,yBAAyB,CACvC,GAAW;IAEX,OAAO,oBAAoB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AACvC,CAAC","sourcesContent":["export interface S3ConstructionMetadata {\n /** Whether URL generation bypasses signing through a configured public origin. */\n readonly publicBaseUrlConfigured: boolean;\n}\n\nconst constructionMetadata = new WeakMap<\n object,\n Readonly<S3ConstructionMetadata>\n>();\n\nexport function recordS3ConstructionMetadata(\n raw: object,\n metadata: S3ConstructionMetadata,\n): void {\n const existing = constructionMetadata.get(raw);\n if (\n existing !== undefined &&\n existing.publicBaseUrlConfigured !== metadata.publicBaseUrlConfigured\n ) {\n throw new TypeError('S3 adapter construction metadata cannot be changed.');\n }\n constructionMetadata.set(raw, Object.freeze({ ...metadata }));\n}\n\nexport function getS3ConstructionMetadata(\n raw: object,\n): Readonly<S3ConstructionMetadata> | undefined {\n return constructionMetadata.get(raw);\n}\n"]}
@@ -1,34 +1,54 @@
1
- import { type S3Adapter, type S3AdapterOptions } from 'files-sdk/s3';
2
- import { type FilesSdkConditionalCopyAdapter, type FilesSdkConditionalMutationAdapter, type FilesSdkDriverOptions, type FilesSdkSignedUploadPolicyAdapter, type FilesSdkSignedDownloadPolicyAdapter, type FilesSdkStorageDriver } from '../files-sdk.driver.js';
1
+ import { mapS3Error, type S3Adapter, type S3AdapterOptions } from 'files-sdk/s3';
2
+ import type { StorageCapabilities } from '../../storage.types.js';
3
+ import { type FilesSdkConditionalCopyAdapter, type FilesSdkConditionalDeleteAdapter, type FilesSdkConditionalReadAdapter, type FilesSdkConditionalUploadAdapter, type FilesSdkDriverOptions, type FilesSdkPhysicalKeyAdapter, type FilesSdkSignedUploadPolicyAdapter, type FilesSdkSignedDownloadPolicyAdapter, type FilesSdkStorageDriver } from '../files-sdk.driver.js';
3
4
  export interface S3StorageDriverOptions extends Omit<FilesSdkDriverOptions<S3Adapter>, 'adapter'> {
4
5
  adapter: S3AdapterOptions;
5
6
  /**
6
- * Opt in or out of conditional writes for an S3-compatible endpoint whose
7
- * support is known. Native AWS S3 enables them by default; custom endpoints
8
- * default to false because compatibility varies.
7
+ * Exact, conformance-verified provider behavior. Native AWS S3 uses the
8
+ * built-in AWS profile when no endpoint override is present; an explicit
9
+ * native profile may only narrow that immutable ceiling. Endpoint overrides
10
+ * without an explicit profile force the whole driver read-only.
9
11
  */
10
- conditionalMutation?: boolean;
12
+ providerProfile?: S3ProviderProfile;
11
13
  }
12
- type S3StorageAdapterBase = S3Adapter & FilesSdkConditionalCopyAdapter & FilesSdkSignedDownloadPolicyAdapter & FilesSdkSignedUploadPolicyAdapter;
13
- export type S3StorageAdapter = S3StorageAdapterBase & Partial<FilesSdkConditionalMutationAdapter>;
14
+ type S3ProfileCapabilities = Pick<StorageCapabilities, 'conditionalCreate' | 'conditionalReplace' | 'conditionalDelete' | 'conditionalRead' | 'conditionalCopySource' | 'conditionalCopyDestination' | 'conditionalMultipartCompletion' | 'physicalKey' | 'signedUploadPolicy'>;
15
+ declare const verifiedS3ProviderProfile: unique symbol;
16
+ export interface S3ProviderProfileInput extends S3ProfileCapabilities {
17
+ /** Stable profile identity for configuration, diagnostics, and audit. */
18
+ readonly name: string;
19
+ /** Every S3-compatible profile must declare its complete-key byte budget. */
20
+ readonly physicalKey: NonNullable<S3ProfileCapabilities['physicalKey']>;
21
+ /** Constraints the provider proves; omission defaults both claims to false. */
22
+ readonly signedUploadPolicy?: NonNullable<S3ProfileCapabilities['signedUploadPolicy']>;
23
+ }
24
+ /** A validated profile created by {@link defineS3ProviderProfile}. */
25
+ export type S3ProviderProfile = Readonly<Omit<S3ProviderProfileInput, 'signedUploadPolicy'> & {
26
+ readonly signedUploadPolicy: NonNullable<S3ProfileCapabilities['signedUploadPolicy']>;
27
+ }> & {
28
+ readonly [verifiedS3ProviderProfile]: true;
29
+ };
30
+ /** Validates and deeply freezes an explicitly verified S3-compatible profile. */
31
+ export declare function defineS3ProviderProfile(profile: S3ProviderProfileInput): S3ProviderProfile;
32
+ export declare const AWS_S3_PROVIDER_PROFILE: S3ProviderProfile;
33
+ export declare const CLOUDFLARE_R2_PROVIDER_PROFILE: S3ProviderProfile;
34
+ type S3StorageAdapterBase = S3Adapter & FilesSdkPhysicalKeyAdapter & FilesSdkSignedDownloadPolicyAdapter & FilesSdkSignedUploadPolicyAdapter;
35
+ export type S3StorageAdapter = S3StorageAdapterBase & Partial<FilesSdkConditionalCopyAdapter & FilesSdkConditionalDeleteAdapter & FilesSdkConditionalReadAdapter & FilesSdkConditionalUploadAdapter>;
36
+ /** Constructs the upstream S3 adapter while retaining security-relevant metadata. */
37
+ export declare function s3(options: S3AdapterOptions): S3Adapter;
14
38
  /**
15
- * Adds the S3-only capabilities to an adapter already built by `s3(...)`: an
16
- * ETag/version-conditional server-side promotion, and the signed upload and
17
- * download policies the bridge advertises through `capabilities`.
18
- *
19
- * Exported so the provider factory can apply them to the adapter `loadFiles`
20
- * resolved for the `s3` slug instead of re-deriving {@link S3AdapterOptions}
21
- * from flat provider config. It expects an adapter whose `raw` is an `S3Client`
22
- * — pass one built by `s3(...)`, not an S3-compatible wrapper.
39
+ * Adds only the exact operations declared by one verified provider profile.
40
+ * Each raw adapter may be decorated once so capability state cannot depend on
41
+ * profile application order. A native AWS SDK endpoint also bounds every
42
+ * explicit profile by the built-in AWS capability ceiling.
23
43
  */
24
44
  export declare function withS3Capabilities(base: S3Adapter, options?: Pick<S3AdapterOptions, 'endpoint' | 'publicBaseUrl'> & {
25
- conditionalMutation?: boolean;
45
+ providerProfile?: S3ProviderProfile;
26
46
  }): S3StorageAdapter;
27
47
  /**
28
48
  * Creates the files-sdk S3 driver from the storage package's own dependency
29
- * context and adds an ETag/version-conditional server-side promotion.
49
+ * context and exposes only the operations in its verified provider profile.
30
50
  */
31
51
  export declare function createS3StorageDriver(options: S3StorageDriverOptions): FilesSdkStorageDriver<S3StorageAdapter>;
32
- export { mapS3Error, s3 } from 'files-sdk/s3';
52
+ export { mapS3Error };
33
53
  export type { S3Adapter, S3AdapterOptions, S3Sdk } from 'files-sdk/s3';
34
54
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/files-sdk/s3/index.ts"],"names":[],"mappings":"AAMA,OAAO,EAGL,KAAK,SAAS,EACd,KAAK,gBAAgB,EACtB,MAAM,cAAc,CAAC;AAWtB,OAAO,EAEL,KAAK,8BAA8B,EACnC,KAAK,kCAAkC,EACvC,KAAK,qBAAqB,EAC1B,KAAK,iCAAiC,EACtC,KAAK,mCAAmC,EACxC,KAAK,qBAAqB,EAE3B,MAAM,wBAAwB,CAAC;AAEhC,MAAM,WAAW,sBAAuB,SAAQ,IAAI,CAClD,qBAAqB,CAAC,SAAS,CAAC,EAChC,SAAS,CACV;IACC,OAAO,EAAE,gBAAgB,CAAC;IAC1B;;;;OAIG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC/B;AAED,KAAK,oBAAoB,GAAG,SAAS,GACnC,8BAA8B,GAC9B,mCAAmC,GACnC,iCAAiC,CAAC;AAEpC,MAAM,MAAM,gBAAgB,GAAG,oBAAoB,GACjD,OAAO,CAAC,kCAAkC,CAAC,CAAC;AAmL9C;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,SAAS,EACf,OAAO,GAAE,IAAI,CAAC,gBAAgB,EAAE,UAAU,GAAG,eAAe,CAAC,GAAG;IAC9D,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC1B,GACL,gBAAgB,CA6JlB;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,sBAAsB,GAC9B,qBAAqB,CAAC,gBAAgB,CAAC,CAUzC;AAED,OAAO,EAAE,UAAU,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAC9C,YAAY,EAAE,SAAS,EAAE,gBAAgB,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/files-sdk/s3/index.ts"],"names":[],"mappings":"AAgBA,OAAO,EACL,UAAU,EAEV,KAAK,SAAS,EACd,KAAK,gBAAgB,EACtB,MAAM,cAAc,CAAC;AAEtB,OAAO,KAAK,EAEV,mBAAmB,EAQpB,MAAM,wBAAwB,CAAC;AAUhC,OAAO,EAKL,KAAK,8BAA8B,EACnC,KAAK,gCAAgC,EACrC,KAAK,8BAA8B,EACnC,KAAK,gCAAgC,EACrC,KAAK,qBAAqB,EAC1B,KAAK,0BAA0B,EAC/B,KAAK,iCAAiC,EACtC,KAAK,mCAAmC,EACxC,KAAK,qBAAqB,EAE3B,MAAM,wBAAwB,CAAC;AAMhC,MAAM,WAAW,sBAAuB,SAAQ,IAAI,CAClD,qBAAqB,CAAC,SAAS,CAAC,EAChC,SAAS,CACV;IACC,OAAO,EAAE,gBAAgB,CAAC;IAC1B;;;;;OAKG;IACH,eAAe,CAAC,EAAE,iBAAiB,CAAC;CACrC;AAED,KAAK,qBAAqB,GAAG,IAAI,CAC/B,mBAAmB,EACjB,mBAAmB,GACnB,oBAAoB,GACpB,mBAAmB,GACnB,iBAAiB,GACjB,uBAAuB,GACvB,4BAA4B,GAC5B,gCAAgC,GAChC,aAAa,GACb,oBAAoB,CACvB,CAAC;AAEF,QAAA,MAAM,yBAAyB,eAAsC,CAAC;AAGtE,MAAM,WAAW,sBAAuB,SAAQ,qBAAqB;IACnE,yEAAyE;IACzE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,6EAA6E;IAC7E,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC,qBAAqB,CAAC,aAAa,CAAC,CAAC,CAAC;IACxE,+EAA+E;IAC/E,QAAQ,CAAC,kBAAkB,CAAC,EAAE,WAAW,CACvC,qBAAqB,CAAC,oBAAoB,CAAC,CAC5C,CAAC;CACH;AAED,sEAAsE;AACtE,MAAM,MAAM,iBAAiB,GAAG,QAAQ,CACtC,IAAI,CAAC,sBAAsB,EAAE,oBAAoB,CAAC,GAAG;IACnD,QAAQ,CAAC,kBAAkB,EAAE,WAAW,CACtC,qBAAqB,CAAC,oBAAoB,CAAC,CAC5C,CAAC;CACH,CACF,GAAG;IACF,QAAQ,CAAC,CAAC,yBAAyB,CAAC,EAAE,IAAI,CAAC;CAC5C,CAAC;AAWF,iFAAiF;AACjF,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,sBAAsB,GAC9B,iBAAiB,CA4KnB;AA0ID,eAAO,MAAM,uBAAuB,mBAelC,CAAC;AAEH,eAAO,MAAM,8BAA8B,mBAQzC,CAAC;AAQH,KAAK,oBAAoB,GAAG,SAAS,GACnC,0BAA0B,GAC1B,mCAAmC,GACnC,iCAAiC,CAAC;AAEpC,MAAM,MAAM,gBAAgB,GAAG,oBAAoB,GACjD,OAAO,CACL,8BAA8B,GAC5B,gCAAgC,GAChC,8BAA8B,GAC9B,gCAAgC,CACnC,CAAC;AAwlBJ,qFAAqF;AACrF,wBAAgB,EAAE,CAAC,OAAO,EAAE,gBAAgB,GAAG,SAAS,CAOvD;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,SAAS,EACf,OAAO,GAAE,IAAI,CAAC,gBAAgB,EAAE,UAAU,GAAG,eAAe,CAAC,GAAG;IAC9D,eAAe,CAAC,EAAE,iBAAiB,CAAC;CAChC,GACL,gBAAgB,CAqalB;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,sBAAsB,GAC9B,qBAAqB,CAAC,gBAAgB,CAAC,CAazC;AAED,OAAO,EAAE,UAAU,EAAE,CAAC;AACtB,YAAY,EAAE,SAAS,EAAE,gBAAgB,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC"}