@btravstack/storage 0.7.0 → 0.9.0

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/README.md CHANGED
@@ -57,32 +57,30 @@ class Invoices extends InvoicePort("ReadmeInvoices")<{
57
57
  const keyFor = (tenantId: string, id: string) =>
58
58
  `invoices/${tenantId}/${id}.pdf`;
59
59
 
60
- export const invoices = InvoiceProvider(Invoices)(
61
- { storage: Storage },
62
- {
63
- sync: ({ storage }) => ({
64
- store: (tenantId, id, pdf) =>
65
- storage
66
- .put(keyFor(tenantId, id), pdf, { contentType: "application/pdf" })
67
- // A document that failed to store is YOUR decision to make; here it
68
- // is swallowed because the instrumented store already logged and
69
- // counted it one layer down.
70
- .recoverErrCases((matcher) =>
71
- matcher.with(P.tag("StorageUnavailable"), () => undefined),
72
- ),
73
- // Serving bytes through your own process is the anti-pattern this arm
74
- // exists to avoid: the caller fetches the object directly, for a minute.
75
- link: (tenantId, id) =>
76
- storage
77
- .presignedUrl(keyFor(tenantId, id), { ttlMs: 60_000 })
78
- .recoverErrCases((matcher) =>
79
- matcher
80
- .with(P.tag("StorageUnavailable"), () => undefined)
81
- .with(P.tag("PresignNotSupported"), () => undefined),
82
- ),
83
- }),
84
- },
85
- );
60
+ export const invoices = InvoiceProvider(Invoices)({
61
+ inject: { storage: Storage },
62
+ sync: ({ storage }) => ({
63
+ store: (tenantId, id, pdf) =>
64
+ storage
65
+ .put(keyFor(tenantId, id), pdf, { contentType: "application/pdf" })
66
+ // A document that failed to store is YOUR decision to make; here it
67
+ // is swallowed because the instrumented store already logged and
68
+ // counted it one layer down.
69
+ .recoverErrCases((matcher) =>
70
+ matcher.with(P.tag("StorageUnavailable"), () => undefined),
71
+ ),
72
+ // Serving bytes through your own process is the anti-pattern this arm
73
+ // exists to avoid: the caller fetches the object directly, for a minute.
74
+ link: (tenantId, id) =>
75
+ storage
76
+ .presignedUrl(keyFor(tenantId, id), { ttlMs: 60_000 })
77
+ .recoverErrCases((matcher) =>
78
+ matcher
79
+ .with(P.tag("StorageUnavailable"), () => undefined)
80
+ .with(P.tag("PresignNotSupported"), () => undefined),
81
+ ),
82
+ }),
83
+ });
86
84
  ```
87
85
 
88
86
  The composition — the adapter, and whether operations are instrumented,
package/dist/index.cjs CHANGED
@@ -37,7 +37,10 @@ const memoryStorageBackend = () => {
37
37
  };
38
38
  };
39
39
  /** The adapter as a provider, which is the shape `@btravstack/testing`'s `overridden` takes. */
40
- const memoryStorageProvider = () => (0, _btravstack_di.Provider)(require_storage.StorageBackend)({}, { sync: () => memoryStorageBackend() });
40
+ const memoryStorageProvider = () => (0, _btravstack_di.Provider)(require_storage.StorageBackend)({
41
+ inject: {},
42
+ sync: () => memoryStorageBackend()
43
+ });
41
44
  /** The adapter as a module, which is the shape `storage({ adapter })` takes. */
42
45
  const memoryStorage = () => (0, _btravstack_di.Module)("MemoryStorage")({
43
46
  provides: [memoryStorageProvider()],
@@ -116,10 +119,13 @@ const instrument = (backend, logger, tracer, meter) => {
116
119
  * why instrumentation is a flag on the composition rather than a wrapper.
117
120
  */
118
121
  const storage = ({ adapter, instrumented }) => {
119
- const healthCheck = _btravstack_di.Provider.member(_btravstack_core.HealthChecks)({ backend: require_storage.StorageBackend }, { sync: ({ backend }) => ({
120
- name: "storage",
121
- check: () => backend.get("btravstack:health").map(() => void 0).flatMapErrCases((matcher) => matcher.with(unthrown.P.tag("ObjectNotFound"), () => (0, unthrown.Ok)(void 0)).with(unthrown.P.tag("StorageUnavailable"), ({ reason }) => (0, unthrown.Err)(new _btravstack_core.HealthCheckFailed({ reason: `storage unavailable (${reason})` }))))
122
- }) });
122
+ const healthCheck = _btravstack_di.Provider.member(_btravstack_core.HealthChecks)({
123
+ inject: { backend: require_storage.StorageBackend },
124
+ sync: ({ backend }) => ({
125
+ name: "storage",
126
+ check: () => backend.get("btravstack:health").map(() => void 0).flatMapErrCases((matcher) => matcher.with(unthrown.P.tag("ObjectNotFound"), () => (0, unthrown.Ok)(void 0)).with(unthrown.P.tag("StorageUnavailable"), ({ reason }) => (0, unthrown.Err)(new _btravstack_core.HealthCheckFailed({ reason: `storage unavailable (${reason})` }))))
127
+ })
128
+ });
123
129
  return instrumented !== false ? (0, _btravstack_di.Module)("InstrumentedStorage")({
124
130
  needs: [
125
131
  _btravstack_core.Logger,
@@ -128,15 +134,21 @@ const storage = ({ adapter, instrumented }) => {
128
134
  ],
129
135
  imports: [adapter],
130
136
  provides: [(0, _btravstack_di.Provider)(require_storage.Storage)({
131
- backend: require_storage.StorageBackend,
132
- logger: _btravstack_core.Logger,
133
- tracer: _btravstack_core.Tracer,
134
- meter: _btravstack_core.Meter
135
- }, { sync: ({ backend, logger, tracer, meter }) => instrument(backend, logger, tracer, meter) }), healthCheck],
137
+ inject: {
138
+ backend: require_storage.StorageBackend,
139
+ logger: _btravstack_core.Logger,
140
+ tracer: _btravstack_core.Tracer,
141
+ meter: _btravstack_core.Meter
142
+ },
143
+ sync: ({ backend, logger, tracer, meter }) => instrument(backend, logger, tracer, meter)
144
+ }), healthCheck],
136
145
  exports: [require_storage.Storage, _btravstack_core.HealthChecks]
137
146
  }) : (0, _btravstack_di.Module)("Storage")({
138
147
  imports: [adapter],
139
- provides: [(0, _btravstack_di.Provider)(require_storage.Storage)({ backend: require_storage.StorageBackend }, { sync: ({ backend }) => backend }), healthCheck],
148
+ provides: [(0, _btravstack_di.Provider)(require_storage.Storage)({
149
+ inject: { backend: require_storage.StorageBackend },
150
+ sync: ({ backend }) => backend
151
+ }), healthCheck],
140
152
  exports: [require_storage.Storage, _btravstack_core.HealthChecks]
141
153
  });
142
154
  };
package/dist/index.mjs CHANGED
@@ -36,7 +36,10 @@ const memoryStorageBackend = () => {
36
36
  };
37
37
  };
38
38
  /** The adapter as a provider, which is the shape `@btravstack/testing`'s `overridden` takes. */
39
- const memoryStorageProvider = () => Provider(StorageBackend)({}, { sync: () => memoryStorageBackend() });
39
+ const memoryStorageProvider = () => Provider(StorageBackend)({
40
+ inject: {},
41
+ sync: () => memoryStorageBackend()
42
+ });
40
43
  /** The adapter as a module, which is the shape `storage({ adapter })` takes. */
41
44
  const memoryStorage = () => Module("MemoryStorage")({
42
45
  provides: [memoryStorageProvider()],
@@ -115,10 +118,13 @@ const instrument = (backend, logger, tracer, meter) => {
115
118
  * why instrumentation is a flag on the composition rather than a wrapper.
116
119
  */
117
120
  const storage = ({ adapter, instrumented }) => {
118
- const healthCheck = Provider.member(HealthChecks)({ backend: StorageBackend }, { sync: ({ backend }) => ({
119
- name: "storage",
120
- check: () => backend.get("btravstack:health").map(() => void 0).flatMapErrCases((matcher) => matcher.with(P.tag("ObjectNotFound"), () => Ok(void 0)).with(P.tag("StorageUnavailable"), ({ reason }) => Err(new HealthCheckFailed({ reason: `storage unavailable (${reason})` }))))
121
- }) });
121
+ const healthCheck = Provider.member(HealthChecks)({
122
+ inject: { backend: StorageBackend },
123
+ sync: ({ backend }) => ({
124
+ name: "storage",
125
+ check: () => backend.get("btravstack:health").map(() => void 0).flatMapErrCases((matcher) => matcher.with(P.tag("ObjectNotFound"), () => Ok(void 0)).with(P.tag("StorageUnavailable"), ({ reason }) => Err(new HealthCheckFailed({ reason: `storage unavailable (${reason})` }))))
126
+ })
127
+ });
122
128
  return instrumented !== false ? Module("InstrumentedStorage")({
123
129
  needs: [
124
130
  Logger,
@@ -127,15 +133,21 @@ const storage = ({ adapter, instrumented }) => {
127
133
  ],
128
134
  imports: [adapter],
129
135
  provides: [Provider(Storage)({
130
- backend: StorageBackend,
131
- logger: Logger,
132
- tracer: Tracer,
133
- meter: Meter
134
- }, { sync: ({ backend, logger, tracer, meter }) => instrument(backend, logger, tracer, meter) }), healthCheck],
136
+ inject: {
137
+ backend: StorageBackend,
138
+ logger: Logger,
139
+ tracer: Tracer,
140
+ meter: Meter
141
+ },
142
+ sync: ({ backend, logger, tracer, meter }) => instrument(backend, logger, tracer, meter)
143
+ }), healthCheck],
135
144
  exports: [Storage, HealthChecks]
136
145
  }) : Module("Storage")({
137
146
  imports: [adapter],
138
- provides: [Provider(Storage)({ backend: StorageBackend }, { sync: ({ backend }) => backend }), healthCheck],
147
+ provides: [Provider(Storage)({
148
+ inject: { backend: StorageBackend },
149
+ sync: ({ backend }) => backend
150
+ }), healthCheck],
139
151
  exports: [Storage, HealthChecks]
140
152
  });
141
153
  };
package/dist/s3.cjs CHANGED
@@ -81,7 +81,8 @@ const s3Storage = () => (0, _btravstack_di.Module)("S3Storage")({
81
81
  needs: [_btravstack_config.Env],
82
82
  provides: [
83
83
  _btravstack_config.Config.provider(StorageConfig)(s3Schema),
84
- (0, _btravstack_di.Provider)(S3Connection)({ config: StorageConfig }, {
84
+ (0, _btravstack_di.Provider)(S3Connection)({
85
+ inject: { config: StorageConfig },
85
86
  acquire: ({ config }) => (0, unthrown.fromSafePromise)(Promise.resolve({
86
87
  client: new _aws_sdk_client_s3.S3Client({
87
88
  endpoint: config.endpoint,
@@ -98,7 +99,10 @@ const s3Storage = () => (0, _btravstack_di.Module)("S3Storage")({
98
99
  client.destroy();
99
100
  }
100
101
  }),
101
- (0, _btravstack_di.Provider)(require_storage.StorageBackend)({ connection: S3Connection }, { sync: ({ connection }) => s3StorageBackend(connection.client, connection.bucket) })
102
+ (0, _btravstack_di.Provider)(require_storage.StorageBackend)({
103
+ inject: { connection: S3Connection },
104
+ sync: ({ connection }) => s3StorageBackend(connection.client, connection.bucket)
105
+ })
102
106
  ],
103
107
  exports: [require_storage.StorageBackend]
104
108
  });
package/dist/s3.mjs CHANGED
@@ -80,7 +80,8 @@ const s3Storage = () => Module("S3Storage")({
80
80
  needs: [Env],
81
81
  provides: [
82
82
  Config.provider(StorageConfig)(s3Schema),
83
- Provider(S3Connection)({ config: StorageConfig }, {
83
+ Provider(S3Connection)({
84
+ inject: { config: StorageConfig },
84
85
  acquire: ({ config }) => fromSafePromise(Promise.resolve({
85
86
  client: new S3Client({
86
87
  endpoint: config.endpoint,
@@ -97,7 +98,10 @@ const s3Storage = () => Module("S3Storage")({
97
98
  client.destroy();
98
99
  }
99
100
  }),
100
- Provider(StorageBackend)({ connection: S3Connection }, { sync: ({ connection }) => s3StorageBackend(connection.client, connection.bucket) })
101
+ Provider(StorageBackend)({
102
+ inject: { connection: S3Connection },
103
+ sync: ({ connection }) => s3StorageBackend(connection.client, connection.bucket)
104
+ })
101
105
  ],
102
106
  exports: [StorageBackend]
103
107
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@btravstack/storage",
3
- "version": "0.7.0",
3
+ "version": "0.9.0",
4
4
  "description": "A Storage port for @btravstack/core: an in-memory adapter, an S3-compatible adapter with presigned reads, and a composition that spans, counts and logs every operation",
5
5
  "keywords": [
6
6
  "dependency-injection",
@@ -53,33 +53,33 @@
53
53
  "./package.json": "./package.json"
54
54
  },
55
55
  "devDependencies": {
56
- "@aws-sdk/client-s3": "3.1117.0",
57
- "@aws-sdk/s3-request-presigner": "3.1117.0",
56
+ "@aws-sdk/client-s3": "3.1121.0",
57
+ "@aws-sdk/s3-request-presigner": "3.1121.0",
58
58
  "@btravstack/tsconfig": "0.2.0",
59
59
  "@opentelemetry/api": "1.9.1",
60
60
  "@opentelemetry/sdk-metrics": "2.10.0",
61
61
  "@opentelemetry/sdk-node": "0.221.0",
62
62
  "@opentelemetry/sdk-trace": "2.10.0",
63
- "@types/node": "26.2.0",
63
+ "@types/node": "26.4.0",
64
64
  "@unthrown/vitest": "5.7.0",
65
65
  "@vitest/coverage-v8": "4.1.11",
66
66
  "tsdown": "0.22.14",
67
67
  "typescript": "7.0.2",
68
68
  "unthrown": "5.7.0",
69
69
  "vitest": "4.1.11",
70
- "@btravstack/config": "0.7.0",
71
- "@btravstack/core": "0.7.0",
72
- "@btravstack/observability": "0.7.0",
73
- "@btravstack/di": "0.7.0",
74
- "@btravstack/internal-test-infra": "0.0.0"
70
+ "@btravstack/config": "0.9.0",
71
+ "@btravstack/di": "0.9.0",
72
+ "@btravstack/internal-test-infra": "0.0.0",
73
+ "@btravstack/observability": "0.9.0",
74
+ "@btravstack/core": "0.9.0"
75
75
  },
76
76
  "peerDependencies": {
77
77
  "@aws-sdk/client-s3": "^3.1000.0",
78
78
  "@aws-sdk/s3-request-presigner": "^3.1000.0",
79
79
  "unthrown": "^5.0.0",
80
- "@btravstack/config": "^0.7.0",
81
- "@btravstack/di": "^0.7.0",
82
- "@btravstack/core": "^0.7.0"
80
+ "@btravstack/config": "^0.9.0",
81
+ "@btravstack/core": "^0.9.0",
82
+ "@btravstack/di": "^0.9.0"
83
83
  },
84
84
  "peerDependenciesMeta": {
85
85
  "@aws-sdk/client-s3": {