@docker-harpoon/core 0.1.3 → 0.1.5

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 (98) hide show
  1. package/dist/__tests__/bindings.test.js +9 -5
  2. package/dist/__tests__/container.test.js +30 -9
  3. package/dist/__tests__/database.test.js +0 -14
  4. package/dist/__tests__/docker-infra.template.d.ts +2 -0
  5. package/dist/__tests__/docker-infra.template.d.ts.map +1 -0
  6. package/dist/__tests__/docker-infra.template.js +174 -0
  7. package/dist/__tests__/test-setup.d.ts +9 -0
  8. package/dist/__tests__/test-setup.d.ts.map +1 -0
  9. package/dist/__tests__/test-setup.js +27 -0
  10. package/dist/api/index.d.ts +1 -1
  11. package/dist/api/index.d.ts.map +1 -1
  12. package/dist/api/promise.d.ts +13 -3
  13. package/dist/api/promise.d.ts.map +1 -1
  14. package/dist/api/promise.js +33 -18
  15. package/dist/bindings/index.d.ts +2 -2
  16. package/dist/bindings/index.d.ts.map +1 -1
  17. package/dist/bindings/index.js +1 -1
  18. package/dist/bindings/types.d.ts.map +1 -1
  19. package/dist/bindings/types.js +1 -3
  20. package/dist/build-strategies/types.d.ts.map +1 -1
  21. package/dist/config-patchers/index.d.ts.map +1 -1
  22. package/dist/config-patchers/types.d.ts.map +1 -1
  23. package/dist/dockerfile-transformers/core.d.ts.map +1 -1
  24. package/dist/dockerfile-transformers/core.js +2 -5
  25. package/dist/dockerfile-transformers/index.d.ts.map +1 -1
  26. package/dist/dockerfile-transformers/types.d.ts.map +1 -1
  27. package/dist/errors.d.ts +6 -1
  28. package/dist/errors.d.ts.map +1 -1
  29. package/dist/errors.js +3 -3
  30. package/dist/helpers/database.d.ts.map +1 -1
  31. package/dist/helpers/database.js +1 -3
  32. package/dist/index.d.ts +3 -3
  33. package/dist/index.d.ts.map +1 -1
  34. package/dist/index.js +1 -1
  35. package/dist/resources/container.d.ts +25 -2
  36. package/dist/resources/container.d.ts.map +1 -1
  37. package/dist/resources/container.js +301 -77
  38. package/dist/resources/image.d.ts.map +1 -1
  39. package/dist/resources/image.js +14 -35
  40. package/dist/resources/index.d.ts +1 -1
  41. package/dist/resources/index.d.ts.map +1 -1
  42. package/dist/resources/network.d.ts.map +1 -1
  43. package/dist/resources/network.js +23 -9
  44. package/dist/resources/schemas.d.ts +178 -18
  45. package/dist/resources/schemas.d.ts.map +1 -1
  46. package/dist/resources/schemas.js +2 -1
  47. package/dist/services/CircuitBreaker.d.ts +83 -0
  48. package/dist/services/CircuitBreaker.d.ts.map +1 -0
  49. package/dist/services/CircuitBreaker.js +164 -0
  50. package/dist/services/ContainerPool.d.ts +82 -0
  51. package/dist/services/ContainerPool.d.ts.map +1 -0
  52. package/dist/services/ContainerPool.js +186 -0
  53. package/dist/services/DockerBatcher.d.ts +74 -0
  54. package/dist/services/DockerBatcher.d.ts.map +1 -0
  55. package/dist/services/DockerBatcher.js +107 -0
  56. package/dist/services/DockerClient.d.ts +125 -0
  57. package/dist/services/DockerClient.d.ts.map +1 -0
  58. package/dist/services/DockerClient.js +220 -0
  59. package/dist/services/DockerErrors.d.ts +145 -0
  60. package/dist/services/DockerErrors.d.ts.map +1 -0
  61. package/dist/services/DockerErrors.js +224 -0
  62. package/dist/services/DockerRateLimiter.d.ts +80 -0
  63. package/dist/services/DockerRateLimiter.d.ts.map +1 -0
  64. package/dist/services/DockerRateLimiter.js +93 -0
  65. package/dist/services/EventBus.d.ts +126 -0
  66. package/dist/services/EventBus.d.ts.map +1 -0
  67. package/dist/services/EventBus.js +111 -0
  68. package/dist/services/Harpoon.d.ts +151 -0
  69. package/dist/services/Harpoon.d.ts.map +1 -0
  70. package/dist/services/Harpoon.js +148 -0
  71. package/dist/services/HarpoonConfig.d.ts +60 -0
  72. package/dist/services/HarpoonConfig.d.ts.map +1 -0
  73. package/dist/services/HarpoonConfig.js +67 -0
  74. package/dist/services/HarpoonLogger.d.ts +36 -0
  75. package/dist/services/HarpoonLogger.d.ts.map +1 -0
  76. package/dist/services/HarpoonLogger.js +94 -0
  77. package/dist/services/ReadinessCoordinator.d.ts +128 -0
  78. package/dist/services/ReadinessCoordinator.d.ts.map +1 -0
  79. package/dist/services/ReadinessCoordinator.js +170 -0
  80. package/dist/services/ResourceTracker.d.ts +74 -0
  81. package/dist/services/ResourceTracker.d.ts.map +1 -0
  82. package/dist/services/ResourceTracker.js +145 -0
  83. package/dist/services/index.d.ts +29 -0
  84. package/dist/services/index.d.ts.map +1 -0
  85. package/dist/services/index.js +47 -0
  86. package/dist/testing/helpers.d.ts +114 -0
  87. package/dist/testing/helpers.d.ts.map +1 -0
  88. package/dist/testing/helpers.js +140 -0
  89. package/dist/testing/index.d.ts +29 -0
  90. package/dist/testing/index.d.ts.map +1 -0
  91. package/dist/testing/index.js +47 -0
  92. package/dist/testing/mocks.d.ts +66 -0
  93. package/dist/testing/mocks.d.ts.map +1 -0
  94. package/dist/testing/mocks.js +224 -0
  95. package/dist/utils/process.d.ts +24 -0
  96. package/dist/utils/process.d.ts.map +1 -0
  97. package/dist/utils/process.js +49 -0
  98. package/package.json +12 -8
@@ -0,0 +1,93 @@
1
+ /**
2
+ * DockerRateLimiter Service
3
+ *
4
+ * Provides semaphore-based rate limiting for Docker API operations.
5
+ * Prevents overwhelming the Docker daemon with too many concurrent requests.
6
+ */
7
+ import { Context, Effect, Layer, Schedule, Duration } from 'effect';
8
+ import { HarpoonConfig } from './HarpoonConfig';
9
+ /**
10
+ * DockerRateLimiter service tag for dependency injection.
11
+ */
12
+ export class DockerRateLimiter extends Context.Tag('@harpoon/DockerRateLimiter')() {
13
+ }
14
+ // ============ Retry Schedules (Step 2) ============
15
+ /**
16
+ * Exponential backoff schedule for transient Docker API errors.
17
+ *
18
+ * - 5 retries maximum
19
+ * - Base delay: 100ms, exponentially increasing
20
+ * - Max delay: 30 seconds
21
+ * - Includes jitter to prevent thundering herd
22
+ */
23
+ export const dockerRetrySchedule = Schedule.exponential(Duration.millis(100), 2).pipe(Schedule.jittered, Schedule.either(Schedule.recurs(5)), Schedule.upTo(Duration.seconds(30)));
24
+ /**
25
+ * Aggressive retry schedule for cleanup operations.
26
+ *
27
+ * - 3 retries maximum
28
+ * - Base delay: 200ms
29
+ * - Max delay: 10 seconds
30
+ * - Quick cleanup attempts with short delays
31
+ */
32
+ export const cleanupRetrySchedule = Schedule.exponential(Duration.millis(200), 2).pipe(Schedule.jittered, Schedule.either(Schedule.recurs(3)), Schedule.upTo(Duration.seconds(10)));
33
+ /**
34
+ * Health check schedule with fixed intervals.
35
+ *
36
+ * - 1 second between checks
37
+ * - Used for container readiness polling
38
+ */
39
+ export const healthCheckSchedule = Schedule.spaced(Duration.seconds(1));
40
+ // ============ Live Implementation ============
41
+ /**
42
+ * Creates a simple semaphore-based rate limiter using Effect.
43
+ */
44
+ const makeSemaphore = (permits) => Effect.gen(function* () {
45
+ // Use Effect.makeSemaphore for a simple counting semaphore
46
+ const semaphore = yield* Effect.makeSemaphore(permits);
47
+ return {
48
+ withPermit: (effect) => semaphore.withPermits(1)(effect),
49
+ withPermits: (count) => (effect) => semaphore.withPermits(count)(effect),
50
+ // Return the current permits - Effect semaphores don't expose available count
51
+ // so we just return the configured limit as an approximation
52
+ available: () => Effect.succeed(permits),
53
+ };
54
+ });
55
+ /**
56
+ * Live implementation of DockerRateLimiter.
57
+ *
58
+ * Uses HarpoonConfig.parallelLimit to determine semaphore size.
59
+ */
60
+ export const DockerRateLimiterLive = Layer.scoped(DockerRateLimiter, Effect.gen(function* () {
61
+ const config = yield* HarpoonConfig;
62
+ const semaphore = yield* makeSemaphore(config.parallelLimit);
63
+ yield* Effect.logDebug('DockerRateLimiter initialized').pipe(Effect.annotateLogs({ permits: config.parallelLimit }));
64
+ return {
65
+ _tag: 'DockerRateLimiter',
66
+ withPermit: semaphore.withPermit,
67
+ withPermits: semaphore.withPermits,
68
+ available: semaphore.available,
69
+ };
70
+ }));
71
+ /**
72
+ * Test implementation with unlimited permits.
73
+ *
74
+ * Useful for unit tests that don't need rate limiting.
75
+ */
76
+ export const DockerRateLimiterTest = Layer.succeed(DockerRateLimiter, {
77
+ _tag: 'DockerRateLimiter',
78
+ withPermit: (effect) => effect,
79
+ withPermits: () => (effect) => effect,
80
+ available: () => Effect.succeed(Infinity),
81
+ });
82
+ /**
83
+ * Create a custom test rate limiter with specific permit count.
84
+ */
85
+ export const makeDockerRateLimiterTest = (permits) => Layer.scoped(DockerRateLimiter, Effect.gen(function* () {
86
+ const semaphore = yield* makeSemaphore(permits);
87
+ return {
88
+ _tag: 'DockerRateLimiter',
89
+ withPermit: semaphore.withPermit,
90
+ withPermits: semaphore.withPermits,
91
+ available: semaphore.available,
92
+ };
93
+ }));
@@ -0,0 +1,126 @@
1
+ /**
2
+ * EventBus Service
3
+ *
4
+ * Provides a publish/subscribe event system for Harpoon resource lifecycle events.
5
+ * Uses Effect's PubSub for type-safe, concurrent event distribution.
6
+ */
7
+ import { Context, Effect, Layer, Stream, Scope } from 'effect';
8
+ /**
9
+ * Container lifecycle event types.
10
+ */
11
+ export type ContainerEventType = 'Created' | 'Started' | 'Stopped' | 'Destroyed' | 'Error';
12
+ /**
13
+ * Network lifecycle event types.
14
+ */
15
+ export type NetworkEventType = 'Created' | 'Destroyed' | 'Connected' | 'Disconnected';
16
+ /**
17
+ * Container lifecycle event.
18
+ */
19
+ export interface ContainerEvent {
20
+ readonly _tag: 'ContainerEvent';
21
+ readonly type: ContainerEventType;
22
+ readonly containerId: string;
23
+ readonly containerName: string;
24
+ readonly timestamp: Date;
25
+ readonly metadata?: Record<string, unknown>;
26
+ readonly error?: Error;
27
+ }
28
+ /**
29
+ * Network lifecycle event.
30
+ */
31
+ export interface NetworkEvent {
32
+ readonly _tag: 'NetworkEvent';
33
+ readonly type: NetworkEventType;
34
+ readonly networkId: string;
35
+ readonly networkName: string;
36
+ readonly timestamp: Date;
37
+ readonly metadata?: Record<string, unknown>;
38
+ }
39
+ /**
40
+ * Database lifecycle event (extends container events with DB-specific info).
41
+ */
42
+ export interface DatabaseEvent {
43
+ readonly _tag: 'DatabaseEvent';
44
+ readonly type: ContainerEventType;
45
+ readonly containerId: string;
46
+ readonly databaseName: string;
47
+ readonly databaseType: string;
48
+ readonly timestamp: Date;
49
+ readonly connectionString?: string;
50
+ readonly metadata?: Record<string, unknown>;
51
+ }
52
+ /**
53
+ * Union type of all Harpoon events.
54
+ */
55
+ export type HarpoonEvent = ContainerEvent | NetworkEvent | DatabaseEvent;
56
+ /**
57
+ * Create a container event.
58
+ */
59
+ export declare const containerEvent: (type: ContainerEventType, containerId: string, containerName: string, options?: {
60
+ metadata?: Record<string, unknown>;
61
+ error?: Error;
62
+ } | undefined) => ContainerEvent;
63
+ /**
64
+ * Create a network event.
65
+ */
66
+ export declare const networkEvent: (type: NetworkEventType, networkId: string, networkName: string, options?: {
67
+ metadata?: Record<string, unknown>;
68
+ } | undefined) => NetworkEvent;
69
+ /**
70
+ * Create a database event.
71
+ */
72
+ export declare const databaseEvent: (type: ContainerEventType, containerId: string, databaseName: string, databaseType: string, options?: {
73
+ connectionString?: string;
74
+ metadata?: Record<string, unknown>;
75
+ } | undefined) => DatabaseEvent;
76
+ /**
77
+ * EventBus service interface.
78
+ */
79
+ export interface EventBusService {
80
+ readonly _tag: 'EventBus';
81
+ /**
82
+ * Publish an event to all subscribers.
83
+ */
84
+ readonly publish: (event: HarpoonEvent) => Effect.Effect<boolean>;
85
+ /**
86
+ * Subscribe to all events.
87
+ * Returns a Stream that emits events as they are published.
88
+ * Requires Scope for queue management.
89
+ */
90
+ readonly subscribe: () => Effect.Effect<Stream.Stream<HarpoonEvent, never>, never, Scope.Scope>;
91
+ /**
92
+ * Subscribe to container events only.
93
+ * Requires Scope for queue management.
94
+ */
95
+ readonly subscribeContainers: () => Effect.Effect<Stream.Stream<ContainerEvent, never>, never, Scope.Scope>;
96
+ /**
97
+ * Subscribe to network events only.
98
+ * Requires Scope for queue management.
99
+ */
100
+ readonly subscribeNetworks: () => Effect.Effect<Stream.Stream<NetworkEvent, never>, never, Scope.Scope>;
101
+ /**
102
+ * Subscribe to database events only.
103
+ * Requires Scope for queue management.
104
+ */
105
+ readonly subscribeDatabases: () => Effect.Effect<Stream.Stream<DatabaseEvent, never>, never, Scope.Scope>;
106
+ /**
107
+ * Get the number of current subscribers.
108
+ */
109
+ readonly subscriberCount: () => Effect.Effect<number>;
110
+ }
111
+ declare const EventBus_base: Context.TagClass<EventBus, "@harpoon/EventBus", EventBusService>;
112
+ /**
113
+ * EventBus service tag for dependency injection.
114
+ */
115
+ export declare class EventBus extends EventBus_base {
116
+ }
117
+ /**
118
+ * Live implementation using Effect PubSub.
119
+ */
120
+ export declare const EventBusLive: Layer.Layer<EventBus, never, never>;
121
+ /**
122
+ * Test implementation that collects all events for verification.
123
+ */
124
+ export declare const EventBusTest: Layer.Layer<EventBus, never, never>;
125
+ export {};
126
+ //# sourceMappingURL=EventBus.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EventBus.d.ts","sourceRoot":"","sources":["../../src/services/EventBus.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,111 @@
1
+ /**
2
+ * EventBus Service
3
+ *
4
+ * Provides a publish/subscribe event system for Harpoon resource lifecycle events.
5
+ * Uses Effect's PubSub for type-safe, concurrent event distribution.
6
+ */
7
+ import { Context, Effect, Layer, PubSub, Stream } from 'effect';
8
+ // ============ Event Constructors ============
9
+ /**
10
+ * Create a container event.
11
+ */
12
+ export const containerEvent = (type, containerId, containerName, options) => ({
13
+ _tag: 'ContainerEvent',
14
+ type,
15
+ containerId,
16
+ containerName,
17
+ timestamp: new Date(),
18
+ ...(options?.metadata !== undefined && { metadata: options.metadata }),
19
+ ...(options?.error !== undefined && { error: options.error }),
20
+ });
21
+ /**
22
+ * Create a network event.
23
+ */
24
+ export const networkEvent = (type, networkId, networkName, options) => ({
25
+ _tag: 'NetworkEvent',
26
+ type,
27
+ networkId,
28
+ networkName,
29
+ timestamp: new Date(),
30
+ ...(options?.metadata !== undefined && { metadata: options.metadata }),
31
+ });
32
+ /**
33
+ * Create a database event.
34
+ */
35
+ export const databaseEvent = (type, containerId, databaseName, databaseType, options) => ({
36
+ _tag: 'DatabaseEvent',
37
+ type,
38
+ containerId,
39
+ databaseName,
40
+ databaseType,
41
+ timestamp: new Date(),
42
+ ...(options?.connectionString !== undefined && { connectionString: options.connectionString }),
43
+ ...(options?.metadata !== undefined && { metadata: options.metadata }),
44
+ });
45
+ /**
46
+ * EventBus service tag for dependency injection.
47
+ */
48
+ export class EventBus extends Context.Tag('@harpoon/EventBus')() {
49
+ }
50
+ /**
51
+ * Live implementation using Effect PubSub.
52
+ */
53
+ export const EventBusLive = Layer.scoped(EventBus, Effect.gen(function* () {
54
+ // Create an unbounded PubSub for events
55
+ const pubsub = yield* PubSub.unbounded();
56
+ yield* Effect.logDebug('EventBus initialized');
57
+ const service = {
58
+ _tag: 'EventBus',
59
+ publish: (event) => PubSub.publish(pubsub, event).pipe(Effect.tap(() => Effect.logDebug('Event published').pipe(Effect.annotateLogs({
60
+ eventTag: event._tag,
61
+ eventType: event._tag === 'ContainerEvent' || event._tag === 'DatabaseEvent'
62
+ ? event.type
63
+ : event.type,
64
+ })))),
65
+ subscribe: () => Effect.gen(function* () {
66
+ const queue = yield* PubSub.subscribe(pubsub);
67
+ return Stream.fromQueue(queue);
68
+ }),
69
+ subscribeContainers: () => Effect.gen(function* () {
70
+ const queue = yield* PubSub.subscribe(pubsub);
71
+ return Stream.fromQueue(queue).pipe(Stream.filter((event) => event._tag === 'ContainerEvent'));
72
+ }),
73
+ subscribeNetworks: () => Effect.gen(function* () {
74
+ const queue = yield* PubSub.subscribe(pubsub);
75
+ return Stream.fromQueue(queue).pipe(Stream.filter((event) => event._tag === 'NetworkEvent'));
76
+ }),
77
+ subscribeDatabases: () => Effect.gen(function* () {
78
+ const queue = yield* PubSub.subscribe(pubsub);
79
+ return Stream.fromQueue(queue).pipe(Stream.filter((event) => event._tag === 'DatabaseEvent'));
80
+ }),
81
+ subscriberCount: () => PubSub.size(pubsub),
82
+ };
83
+ return service;
84
+ }));
85
+ /**
86
+ * Test implementation that collects all events for verification.
87
+ */
88
+ export const EventBusTest = Layer.scoped(EventBus, Effect.gen(function* () {
89
+ const pubsub = yield* PubSub.unbounded();
90
+ return {
91
+ _tag: 'EventBus',
92
+ publish: (event) => PubSub.publish(pubsub, event),
93
+ subscribe: () => Effect.gen(function* () {
94
+ const queue = yield* PubSub.subscribe(pubsub);
95
+ return Stream.fromQueue(queue);
96
+ }),
97
+ subscribeContainers: () => Effect.gen(function* () {
98
+ const queue = yield* PubSub.subscribe(pubsub);
99
+ return Stream.fromQueue(queue).pipe(Stream.filter((event) => event._tag === 'ContainerEvent'));
100
+ }),
101
+ subscribeNetworks: () => Effect.gen(function* () {
102
+ const queue = yield* PubSub.subscribe(pubsub);
103
+ return Stream.fromQueue(queue).pipe(Stream.filter((event) => event._tag === 'NetworkEvent'));
104
+ }),
105
+ subscribeDatabases: () => Effect.gen(function* () {
106
+ const queue = yield* PubSub.subscribe(pubsub);
107
+ return Stream.fromQueue(queue).pipe(Stream.filter((event) => event._tag === 'DatabaseEvent'));
108
+ }),
109
+ subscriberCount: () => PubSub.size(pubsub),
110
+ };
111
+ }));
@@ -0,0 +1,151 @@
1
+ /**
2
+ * Harpoon Unified Layer
3
+ *
4
+ * Provides pre-composed layers for all Harpoon services.
5
+ * Makes it easy to use Harpoon with a single layer provision.
6
+ */
7
+ import { Layer } from 'effect';
8
+ import { HarpoonConfig } from './HarpoonConfig';
9
+ import { DockerRateLimiter } from './DockerRateLimiter';
10
+ import { CircuitBreaker } from './CircuitBreaker';
11
+ import { DockerClient } from './DockerClient';
12
+ import { DockerBatcher } from './DockerBatcher';
13
+ import { ResourceTracker } from './ResourceTracker';
14
+ import { EventBus } from './EventBus';
15
+ import { ReadinessCoordinator } from './ReadinessCoordinator';
16
+ /**
17
+ * Core configuration layer.
18
+ * Provides HarpoonConfig.
19
+ */
20
+ export declare const CoreLive: Layer.Layer<HarpoonConfig, import("effect/ConfigError").ConfigError, never>;
21
+ /**
22
+ * Infrastructure layer with rate limiting and circuit breaker.
23
+ * Provides: DockerRateLimiter, CircuitBreaker
24
+ * Requires: HarpoonConfig
25
+ */
26
+ export declare const InfrastructureLive: Layer.Layer<CircuitBreaker | DockerRateLimiter, import("effect/ConfigError").ConfigError, never>;
27
+ /**
28
+ * Docker client layer with all integrations.
29
+ * Provides: DockerClient
30
+ * Requires: HarpoonConfig, DockerRateLimiter
31
+ */
32
+ export declare const DockerLive: Layer.Layer<DockerClient, import("./DockerErrors").DockerConnectionError | import("effect/ConfigError").ConfigError, never>;
33
+ /**
34
+ * Batching layer for Docker requests.
35
+ * Provides: DockerBatcher
36
+ * Requires: DockerClient
37
+ */
38
+ export declare const BatcherLive: Layer.Layer<DockerBatcher, import("./DockerErrors").DockerConnectionError | import("effect/ConfigError").ConfigError, never>;
39
+ /**
40
+ * Resource management layer.
41
+ * Provides: ResourceTracker
42
+ * Requires: HarpoonConfig
43
+ */
44
+ export declare const ResourcesLive: Layer.Layer<ResourceTracker, import("effect/ConfigError").ConfigError, never>;
45
+ /**
46
+ * Event bus layer.
47
+ * Provides: EventBus
48
+ */
49
+ export declare const EventsLive: Layer.Layer<EventBus, never, never>;
50
+ /**
51
+ * Readiness coordination layer.
52
+ * Provides: ReadinessCoordinator
53
+ */
54
+ export declare const ReadinessLive: Layer.Layer<ReadinessCoordinator, never, never>;
55
+ /**
56
+ * Services layer combining all coordination services.
57
+ * Provides: ResourceTracker, EventBus, ReadinessCoordinator
58
+ * Requires: HarpoonConfig
59
+ */
60
+ export declare const ServicesLive: Layer.Layer<EventBus | ReadinessCoordinator | ResourceTracker, import("effect/ConfigError").ConfigError, never>;
61
+ /**
62
+ * Full Harpoon layer for production use.
63
+ * Provides all services needed for Docker resource management.
64
+ *
65
+ * Includes:
66
+ * - HarpoonConfig
67
+ * - DockerRateLimiter
68
+ * - CircuitBreaker
69
+ * - DockerClient
70
+ * - DockerBatcher
71
+ * - ResourceTracker
72
+ * - EventBus
73
+ * - ReadinessCoordinator
74
+ *
75
+ * @example
76
+ * ```typescript
77
+ * import { HarpoonLive } from '@docker-harpoon/core/services';
78
+ *
79
+ * const program = Effect.gen(function* () {
80
+ * const docker = yield* DockerClient;
81
+ * const tracker = yield* ResourceTracker;
82
+ * // ... use services
83
+ * });
84
+ *
85
+ * Effect.runPromise(
86
+ * program.pipe(Effect.provide(HarpoonLive))
87
+ * );
88
+ * ```
89
+ */
90
+ export declare const HarpoonLive: Layer.Layer<CircuitBreaker | DockerBatcher | DockerClient | DockerRateLimiter | EventBus | HarpoonConfig | ReadinessCoordinator | ResourceTracker, import("./DockerErrors").DockerConnectionError | import("effect/ConfigError").ConfigError, never>;
91
+ /**
92
+ * Core test configuration layer.
93
+ */
94
+ export declare const CoreTest: Layer.Layer<HarpoonConfig, never, never>;
95
+ /**
96
+ * Infrastructure test layer.
97
+ */
98
+ export declare const InfrastructureTest: Layer.Layer<CircuitBreaker | DockerRateLimiter, never, never>;
99
+ /**
100
+ * Docker client test layer.
101
+ */
102
+ export declare const DockerTest: Layer.Layer<DockerClient, never, never>;
103
+ /**
104
+ * Batcher test layer.
105
+ */
106
+ export declare const BatcherTest: Layer.Layer<DockerBatcher, never, never>;
107
+ /**
108
+ * Resources test layer.
109
+ */
110
+ export declare const ResourcesTest: Layer.Layer<ResourceTracker, never, never>;
111
+ /**
112
+ * Events test layer.
113
+ */
114
+ export declare const EventsTest: Layer.Layer<EventBus, never, never>;
115
+ /**
116
+ * Readiness test layer.
117
+ */
118
+ export declare const ReadinessTest: Layer.Layer<ReadinessCoordinator, never, never>;
119
+ /**
120
+ * Services test layer.
121
+ */
122
+ export declare const ServicesTest: Layer.Layer<EventBus | ReadinessCoordinator | ResourceTracker, never, never>;
123
+ /**
124
+ * Full Harpoon test layer for unit testing.
125
+ * All services use mock implementations that don't require Docker.
126
+ *
127
+ * @example
128
+ * ```typescript
129
+ * import { HarpoonTest } from '@docker-harpoon/core/services';
130
+ *
131
+ * const test = Effect.gen(function* () {
132
+ * const docker = yield* DockerClient;
133
+ * // Uses mock Docker client
134
+ * });
135
+ *
136
+ * Effect.runPromise(
137
+ * test.pipe(Effect.provide(HarpoonTest))
138
+ * );
139
+ * ```
140
+ */
141
+ export declare const HarpoonTest: Layer.Layer<CircuitBreaker | DockerBatcher | DockerClient | DockerRateLimiter | EventBus | HarpoonConfig | ReadinessCoordinator | ResourceTracker, never, never>;
142
+ /**
143
+ * All services provided by HarpoonLive.
144
+ */
145
+ export type HarpoonServices = HarpoonConfig | DockerRateLimiter | CircuitBreaker | DockerClient | DockerBatcher | ResourceTracker | EventBus | ReadinessCoordinator;
146
+ /**
147
+ * Requirements for running a program with Harpoon.
148
+ * Use with Effect.provide(HarpoonLive) to satisfy.
149
+ */
150
+ export type HarpoonRequirements = HarpoonServices;
151
+ //# sourceMappingURL=Harpoon.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Harpoon.d.ts","sourceRoot":"","sources":["../../src/services/Harpoon.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,KAAK,EAAU,MAAM,QAAQ,CAAC;AAGvC,OAAO,EAAE,aAAa,EAAwC,MAAM,iBAAiB,CAAC;AAItF,OAAO,EACL,iBAAiB,EAGlB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,cAAc,EAA0C,MAAM,kBAAkB,CAAC;AAG1F,OAAO,EAAE,YAAY,EAAsC,MAAM,gBAAgB,CAAC;AAClF,OAAO,EAAE,aAAa,EAAwC,MAAM,iBAAiB,CAAC;AAGtF,OAAO,EAAE,eAAe,EAA4C,MAAM,mBAAmB,CAAC;AAG9F,OAAO,EAAE,QAAQ,EAA8B,MAAM,YAAY,CAAC;AAClE,OAAO,EACL,oBAAoB,EAGrB,MAAM,wBAAwB,CAAC;AAIhC;;;GAGG;AACH,eAAO,MAAM,QAAQ,6EAAoB,CAAC;AAE1C;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,kGAE9B,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,UAAU,6HAAiD,CAAC;AAEzE;;;;GAIG;AACH,eAAO,MAAM,WAAW,8HAAoD,CAAC;AAE7E;;;;GAIG;AACH,eAAO,MAAM,aAAa,+EAAoD,CAAC;AAE/E;;;GAGG;AACH,eAAO,MAAM,UAAU,qCAAe,CAAC;AAEvC;;;GAGG;AACH,eAAO,MAAM,aAAa,iDAA2B,CAAC;AAEtD;;;;GAIG;AACH,eAAO,MAAM,YAAY,iHAA2D,CAAC;AAErF;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,eAAO,MAAM,WAAW,sPAMvB,CAAC;AAIF;;GAEG;AACH,eAAO,MAAM,QAAQ,0CAAoB,CAAC;AAE1C;;GAEG;AACH,eAAO,MAAM,kBAAkB,+DAA4D,CAAC;AAE5F;;GAEG;AACH,eAAO,MAAM,UAAU,yCAAmB,CAAC;AAE3C;;GAEG;AACH,eAAO,MAAM,WAAW,0CAAoD,CAAC;AAE7E;;GAEG;AACH,eAAO,MAAM,aAAa,4CAAsB,CAAC;AAEjD;;GAEG;AACH,eAAO,MAAM,UAAU,qCAAe,CAAC;AAEvC;;GAEG;AACH,eAAO,MAAM,aAAa,iDAA2B,CAAC;AAEtD;;GAEG;AACH,eAAO,MAAM,YAAY,8EAA2D,CAAC;AAErF;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,WAAW,kKAMvB,CAAC;AAIF;;GAEG;AACH,MAAM,MAAM,eAAe,GACvB,aAAa,GACb,iBAAiB,GACjB,cAAc,GACd,YAAY,GACZ,aAAa,GACb,eAAe,GACf,QAAQ,GACR,oBAAoB,CAAC;AAEzB;;;GAGG;AACH,MAAM,MAAM,mBAAmB,GAAG,eAAe,CAAC"}
@@ -0,0 +1,148 @@
1
+ /**
2
+ * Harpoon Unified Layer
3
+ *
4
+ * Provides pre-composed layers for all Harpoon services.
5
+ * Makes it easy to use Harpoon with a single layer provision.
6
+ */
7
+ import { Layer } from 'effect';
8
+ // Core services
9
+ import { HarpoonConfigLive, HarpoonConfigTest } from './HarpoonConfig';
10
+ // Infrastructure services
11
+ import { DockerRateLimiterLive, DockerRateLimiterTest, } from './DockerRateLimiter';
12
+ import { CircuitBreakerLive, CircuitBreakerTest } from './CircuitBreaker';
13
+ // Docker services
14
+ import { DockerClientLive, DockerClientTest } from './DockerClient';
15
+ import { DockerBatcherLive, DockerBatcherTest } from './DockerBatcher';
16
+ // Resource management
17
+ import { ResourceTrackerLive, ResourceTrackerTest } from './ResourceTracker';
18
+ // Event and coordination
19
+ import { EventBusLive, EventBusTest } from './EventBus';
20
+ import { ReadinessCoordinatorLive, ReadinessCoordinatorTest, } from './ReadinessCoordinator';
21
+ // ============ Live Layers ============
22
+ /**
23
+ * Core configuration layer.
24
+ * Provides HarpoonConfig.
25
+ */
26
+ export const CoreLive = HarpoonConfigLive;
27
+ /**
28
+ * Infrastructure layer with rate limiting and circuit breaker.
29
+ * Provides: DockerRateLimiter, CircuitBreaker
30
+ * Requires: HarpoonConfig
31
+ */
32
+ export const InfrastructureLive = Layer.mergeAll(DockerRateLimiterLive, CircuitBreakerLive).pipe(Layer.provide(CoreLive));
33
+ /**
34
+ * Docker client layer with all integrations.
35
+ * Provides: DockerClient
36
+ * Requires: HarpoonConfig, DockerRateLimiter
37
+ */
38
+ export const DockerLive = DockerClientLive.pipe(Layer.provide(CoreLive));
39
+ /**
40
+ * Batching layer for Docker requests.
41
+ * Provides: DockerBatcher
42
+ * Requires: DockerClient
43
+ */
44
+ export const BatcherLive = DockerBatcherLive.pipe(Layer.provide(DockerLive));
45
+ /**
46
+ * Resource management layer.
47
+ * Provides: ResourceTracker
48
+ * Requires: HarpoonConfig
49
+ */
50
+ export const ResourcesLive = ResourceTrackerLive.pipe(Layer.provide(CoreLive));
51
+ /**
52
+ * Event bus layer.
53
+ * Provides: EventBus
54
+ */
55
+ export const EventsLive = EventBusLive;
56
+ /**
57
+ * Readiness coordination layer.
58
+ * Provides: ReadinessCoordinator
59
+ */
60
+ export const ReadinessLive = ReadinessCoordinatorLive;
61
+ /**
62
+ * Services layer combining all coordination services.
63
+ * Provides: ResourceTracker, EventBus, ReadinessCoordinator
64
+ * Requires: HarpoonConfig
65
+ */
66
+ export const ServicesLive = Layer.mergeAll(ResourcesLive, EventsLive, ReadinessLive);
67
+ /**
68
+ * Full Harpoon layer for production use.
69
+ * Provides all services needed for Docker resource management.
70
+ *
71
+ * Includes:
72
+ * - HarpoonConfig
73
+ * - DockerRateLimiter
74
+ * - CircuitBreaker
75
+ * - DockerClient
76
+ * - DockerBatcher
77
+ * - ResourceTracker
78
+ * - EventBus
79
+ * - ReadinessCoordinator
80
+ *
81
+ * @example
82
+ * ```typescript
83
+ * import { HarpoonLive } from '@docker-harpoon/core/services';
84
+ *
85
+ * const program = Effect.gen(function* () {
86
+ * const docker = yield* DockerClient;
87
+ * const tracker = yield* ResourceTracker;
88
+ * // ... use services
89
+ * });
90
+ *
91
+ * Effect.runPromise(
92
+ * program.pipe(Effect.provide(HarpoonLive))
93
+ * );
94
+ * ```
95
+ */
96
+ export const HarpoonLive = Layer.mergeAll(CoreLive, InfrastructureLive, DockerLive, BatcherLive, ServicesLive);
97
+ // ============ Test Layers ============
98
+ /**
99
+ * Core test configuration layer.
100
+ */
101
+ export const CoreTest = HarpoonConfigTest;
102
+ /**
103
+ * Infrastructure test layer.
104
+ */
105
+ export const InfrastructureTest = Layer.mergeAll(DockerRateLimiterTest, CircuitBreakerTest);
106
+ /**
107
+ * Docker client test layer.
108
+ */
109
+ export const DockerTest = DockerClientTest;
110
+ /**
111
+ * Batcher test layer.
112
+ */
113
+ export const BatcherTest = DockerBatcherTest.pipe(Layer.provide(DockerTest));
114
+ /**
115
+ * Resources test layer.
116
+ */
117
+ export const ResourcesTest = ResourceTrackerTest;
118
+ /**
119
+ * Events test layer.
120
+ */
121
+ export const EventsTest = EventBusTest;
122
+ /**
123
+ * Readiness test layer.
124
+ */
125
+ export const ReadinessTest = ReadinessCoordinatorTest;
126
+ /**
127
+ * Services test layer.
128
+ */
129
+ export const ServicesTest = Layer.mergeAll(ResourcesTest, EventsTest, ReadinessTest);
130
+ /**
131
+ * Full Harpoon test layer for unit testing.
132
+ * All services use mock implementations that don't require Docker.
133
+ *
134
+ * @example
135
+ * ```typescript
136
+ * import { HarpoonTest } from '@docker-harpoon/core/services';
137
+ *
138
+ * const test = Effect.gen(function* () {
139
+ * const docker = yield* DockerClient;
140
+ * // Uses mock Docker client
141
+ * });
142
+ *
143
+ * Effect.runPromise(
144
+ * test.pipe(Effect.provide(HarpoonTest))
145
+ * );
146
+ * ```
147
+ */
148
+ export const HarpoonTest = Layer.mergeAll(CoreTest, InfrastructureTest, DockerTest, BatcherTest, ServicesTest);