the-moby-effect 1.51.0 → 1.51.1

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 (120) hide show
  1. package/dist/Callbacks.d.ts +3 -3
  2. package/dist/DindEngine.d.ts +3 -3
  3. package/dist/DockerComposeEngine.d.ts +4 -4
  4. package/dist/DockerEngine.d.ts +12 -5
  5. package/dist/DockerEngine.d.ts.map +1 -1
  6. package/dist/DockerEngine.js +7 -0
  7. package/dist/DockerEngine.js.map +1 -1
  8. package/dist/MobyConvey.d.ts +1 -1
  9. package/dist/MobyDemux.d.ts +21 -1
  10. package/dist/MobyDemux.d.ts.map +1 -1
  11. package/dist/MobyDemux.js +20 -0
  12. package/dist/MobyDemux.js.map +1 -1
  13. package/dist/MobyEndpoints.d.ts +15 -15
  14. package/dist/MobyPlatforms.d.ts +1 -1
  15. package/dist/MobySchemas.d.ts +1 -1
  16. package/dist/PodmanEngine.d.ts +2 -2
  17. package/dist/Promises.d.ts +3 -3
  18. package/dist/internal/demux/multiplexed.js +4 -0
  19. package/dist/internal/demux/multiplexed.js.map +1 -1
  20. package/dist/internal/demux/raw.js +4 -0
  21. package/dist/internal/demux/raw.js.map +1 -1
  22. package/dist/internal/endpoints/auth.d.ts +56 -0
  23. package/dist/internal/endpoints/auth.d.ts.map +1 -0
  24. package/dist/internal/endpoints/auth.js +82 -0
  25. package/dist/internal/endpoints/auth.js.map +1 -0
  26. package/dist/internal/endpoints/containers.d.ts.map +1 -1
  27. package/dist/internal/endpoints/containers.js +3 -3
  28. package/dist/internal/endpoints/containers.js.map +1 -1
  29. package/dist/internal/endpoints/execs.d.ts.map +1 -1
  30. package/dist/internal/endpoints/execs.js +1 -1
  31. package/dist/internal/endpoints/execs.js.map +1 -1
  32. package/dist/internal/endpoints/images.d.ts +8 -8
  33. package/dist/internal/endpoints/images.d.ts.map +1 -1
  34. package/dist/internal/endpoints/images.js +21 -17
  35. package/dist/internal/endpoints/images.js.map +1 -1
  36. package/dist/internal/endpoints/networks.d.ts +26 -4
  37. package/dist/internal/endpoints/networks.d.ts.map +1 -1
  38. package/dist/internal/endpoints/networks.js +5 -5
  39. package/dist/internal/endpoints/networks.js.map +1 -1
  40. package/dist/internal/endpoints/plugins.d.ts +3 -3
  41. package/dist/internal/endpoints/plugins.d.ts.map +1 -1
  42. package/dist/internal/endpoints/plugins.js +12 -11
  43. package/dist/internal/endpoints/plugins.js.map +1 -1
  44. package/dist/internal/endpoints/services.d.ts +25 -3
  45. package/dist/internal/endpoints/services.d.ts.map +1 -1
  46. package/dist/internal/endpoints/services.js +8 -11
  47. package/dist/internal/endpoints/services.js.map +1 -1
  48. package/dist/internal/endpoints/system.d.ts +1 -1
  49. package/dist/internal/endpoints/system.d.ts.map +1 -1
  50. package/dist/internal/endpoints/system.js.map +1 -1
  51. package/dist/internal/engines/dind.js +9 -2
  52. package/dist/internal/engines/dind.js.map +1 -1
  53. package/dist/internal/generated/ContainerConfig.generated.d.ts +3 -3
  54. package/dist/internal/generated/ContainerConfig.generated.js +1 -1
  55. package/dist/internal/generated/ContainerConfig.generated.js.map +1 -1
  56. package/dist/internal/generated/ContainerContainerJSONBase.generated.d.ts +3 -3
  57. package/dist/internal/generated/ContainerContainerJSONBase.generated.js +2 -1
  58. package/dist/internal/generated/ContainerContainerJSONBase.generated.js.map +1 -1
  59. package/dist/internal/generated/ContainerCreateRequest.generated.d.ts +3 -3
  60. package/dist/internal/generated/ContainerDefaultNetworkSettings.generated.d.ts +24 -24
  61. package/dist/internal/generated/ContainerDefaultNetworkSettings.generated.js +15 -8
  62. package/dist/internal/generated/ContainerDefaultNetworkSettings.generated.js.map +1 -1
  63. package/dist/internal/generated/ContainerInspectResponse.generated.d.ts +3 -3
  64. package/dist/internal/generated/ContainerNetworkSettings.generated.d.ts +45 -45
  65. package/dist/internal/generated/ContainerNetworkSettingsBase.generated.d.ts +21 -21
  66. package/dist/internal/generated/ContainerNetworkSettingsBase.generated.js +11 -6
  67. package/dist/internal/generated/ContainerNetworkSettingsBase.generated.js.map +1 -1
  68. package/dist/internal/generated/ImageInspectResponse.generated.d.ts +14 -14
  69. package/dist/internal/generated/ImageInspectResponse.generated.js +8 -4
  70. package/dist/internal/generated/ImageInspectResponse.generated.js.map +1 -1
  71. package/dist/internal/generated/NetworkCreateOptions.generated.d.ts +66 -34
  72. package/dist/internal/generated/NetworkCreateOptions.generated.d.ts.map +1 -1
  73. package/dist/internal/generated/NetworkCreateOptions.generated.js +28 -12
  74. package/dist/internal/generated/NetworkCreateOptions.generated.js.map +1 -1
  75. package/dist/internal/generated/NetworkCreateRequest.generated.d.ts +66 -34
  76. package/dist/internal/generated/NetworkCreateRequest.generated.d.ts.map +1 -1
  77. package/dist/internal/generated/NetworkInspect.generated.d.ts +11 -11
  78. package/dist/internal/generated/NetworkInspect.generated.js +5 -3
  79. package/dist/internal/generated/NetworkInspect.generated.js.map +1 -1
  80. package/dist/internal/generated/TypesDiskUsage.generated.d.ts +3 -3
  81. package/dist/internal/generated/TypesDiskUsage.generated.js +2 -1
  82. package/dist/internal/generated/TypesDiskUsage.generated.js.map +1 -1
  83. package/dist/internal/platforms/undici.js +88 -59
  84. package/dist/internal/platforms/undici.js.map +1 -1
  85. package/dist/internal/schemas/id.js +1 -1
  86. package/dist/internal/schemas/id.js.map +1 -1
  87. package/package.json +1 -1
  88. package/src/Callbacks.ts +3 -3
  89. package/src/DindEngine.ts +4 -4
  90. package/src/DockerComposeEngine.ts +4 -4
  91. package/src/DockerEngine.ts +16 -7
  92. package/src/MobyConnection.ts +1 -1
  93. package/src/MobyConvey.ts +2 -2
  94. package/src/MobyDemux.ts +31 -7
  95. package/src/MobyEndpoints.ts +15 -15
  96. package/src/MobyPlatforms.ts +8 -8
  97. package/src/MobySchemas.ts +1 -1
  98. package/src/PodmanEngine.ts +3 -3
  99. package/src/Promises.ts +3 -3
  100. package/src/internal/demux/multiplexed.ts +9 -0
  101. package/src/internal/demux/raw.ts +6 -0
  102. package/src/internal/endpoints/auth.ts +120 -0
  103. package/src/internal/endpoints/containers.ts +7 -4
  104. package/src/internal/endpoints/execs.ts +7 -2
  105. package/src/internal/endpoints/images.ts +59 -24
  106. package/src/internal/endpoints/networks.ts +11 -5
  107. package/src/internal/endpoints/plugins.ts +17 -7
  108. package/src/internal/endpoints/services.ts +21 -6
  109. package/src/internal/endpoints/system.ts +1 -1
  110. package/src/internal/engines/dind.ts +8 -2
  111. package/src/internal/generated/ContainerConfig.generated.ts +1 -1
  112. package/src/internal/generated/ContainerContainerJSONBase.generated.ts +1 -1
  113. package/src/internal/generated/ContainerDefaultNetworkSettings.generated.ts +8 -8
  114. package/src/internal/generated/ContainerNetworkSettingsBase.generated.ts +6 -6
  115. package/src/internal/generated/ImageInspectResponse.generated.ts +4 -4
  116. package/src/internal/generated/NetworkCreateOptions.generated.ts +10 -10
  117. package/src/internal/generated/NetworkInspect.generated.ts +3 -3
  118. package/src/internal/generated/TypesDiskUsage.generated.ts +1 -1
  119. package/src/internal/platforms/undici.ts +121 -90
  120. package/src/internal/schemas/id.ts +1 -1
@@ -6,16 +6,16 @@
6
6
 
7
7
  import type * as HttpClient from "@effect/platform/HttpClient";
8
8
  import type * as Socket from "@effect/platform/Socket";
9
- import type * as MobyConnection from "./MobyConnection.js";
9
+ import type * as MobyConnection from "./MobyConnection.ts";
10
10
 
11
11
  import type * as Layer from "effect/Layer";
12
- import * as internalAgnostic from "./internal/platforms/agnostic.js";
13
- import * as internalBun from "./internal/platforms/bun.js";
14
- import * as internalDeno from "./internal/platforms/deno.js";
15
- import * as internalFetch from "./internal/platforms/fetch.js";
16
- import * as internalNode from "./internal/platforms/node.js";
17
- import * as internalUndici from "./internal/platforms/undici.js";
18
- import * as internalWeb from "./internal/platforms/web.js";
12
+ import * as internalAgnostic from "./internal/platforms/agnostic.ts";
13
+ import * as internalBun from "./internal/platforms/bun.ts";
14
+ import * as internalDeno from "./internal/platforms/deno.ts";
15
+ import * as internalFetch from "./internal/platforms/fetch.ts";
16
+ import * as internalNode from "./internal/platforms/node.ts";
17
+ import * as internalUndici from "./internal/platforms/undici.ts";
18
+ import * as internalWeb from "./internal/platforms/web.ts";
19
19
 
20
20
  /**
21
21
  * Given the moby connection options, it will construct a layer that provides a
@@ -5,7 +5,7 @@
5
5
  */
6
6
 
7
7
  /** @since 1.0.0 */
8
- export * from "./internal/generated/index.js";
8
+ export * from "./internal/generated/index.ts";
9
9
 
10
10
  /** @since 1.0.0 */
11
11
  export * from "./internal/schemas/id.ts";
@@ -6,12 +6,12 @@
6
6
 
7
7
  import type * as HttpClient from "@effect/platform/HttpClient";
8
8
  import type * as Socket from "@effect/platform/Socket";
9
- import type * as MobyConnection from "./MobyConnection.js";
9
+ import type * as MobyConnection from "./MobyConnection.ts";
10
10
 
11
11
  import * as Function from "effect/Function";
12
12
  import * as Layer from "effect/Layer";
13
- import * as MobyEndpoints from "./MobyEndpoints.js";
14
- import * as MobyPlatforms from "./MobyPlatforms.js";
13
+ import * as MobyEndpoints from "./MobyEndpoints.ts";
14
+ import * as MobyPlatforms from "./MobyPlatforms.ts";
15
15
 
16
16
  /**
17
17
  * @since 1.0.0
package/src/Promises.ts CHANGED
@@ -5,15 +5,15 @@
5
5
  */
6
6
 
7
7
  import type * as Layer from "effect/Layer";
8
- import type * as MobySchemas from "./MobySchemas.js";
8
+ import type * as MobySchemas from "./MobySchemas.ts";
9
9
 
10
10
  import * as Chunk from "effect/Chunk";
11
11
  import * as Effect from "effect/Effect";
12
12
  import * as Function from "effect/Function";
13
13
  import * as ManagedRuntime from "effect/ManagedRuntime";
14
14
  import * as Stream from "effect/Stream";
15
- import * as DockerEngine from "./DockerEngine.js";
16
- import * as MobyConvey from "./MobyConvey.js";
15
+ import * as DockerEngine from "./DockerEngine.ts";
16
+ import * as MobyConvey from "./MobyConvey.ts";
17
17
 
18
18
  /**
19
19
  * Create a promise client for the docker engine
@@ -70,6 +70,15 @@ export const isMultiplexedChannel = <IE = unknown, OE = Socket.SocketError, R =
70
70
  u: unknown
71
71
  ): u is MobyDemux.MultiplexedChannel<IE, IE | OE, R> => Predicate.hasProperty(u, MultiplexedChannelTypeId);
72
72
 
73
+ /** @internal */
74
+ export const never: MobyDemux.MultiplexedChannel<never, never, never> = makeMultiplexedChannel<never, never, never>(
75
+ Channel.never
76
+ );
77
+
78
+ /** @internal */
79
+ export const neverWith = <IE>(): MobyDemux.MultiplexedChannel<IE, IE, never> =>
80
+ makeMultiplexedChannel<IE, never, never>(Channel.never);
81
+
73
82
  /** @internal */
74
83
  export const responseIsMultiplexedResponse = (response: HttpClientResponse.HttpClientResponse): boolean =>
75
84
  response.headers["content-type"] === MultiplexedContentType;
@@ -65,6 +65,12 @@ export const isRawChannel = <IE = unknown, OE = Socket.SocketError, R = never>(
65
65
  u: unknown
66
66
  ): u is MobyDemux.RawChannel<IE, IE | OE, R> => Predicate.hasProperty(u, RawChannelTypeId);
67
67
 
68
+ /** @internal */
69
+ export const never: MobyDemux.RawChannel<never, never, never> = makeRawChannel<never, never, never>(Channel.never);
70
+
71
+ /** @internal */
72
+ export const neverWith = <IE>(): MobyDemux.RawChannel<IE, IE, never> => makeRawChannel<IE, never, never>(Channel.never);
73
+
68
74
  /** @internal */
69
75
  export const responseIsRawResponse = (response: HttpClientResponse.HttpClientResponse): boolean =>
70
76
  response.headers["content-type"] === RawContentType;
@@ -0,0 +1,120 @@
1
+ import { HttpClient, HttpClientRequest, type HttpApiEndpoint } from "@effect/platform";
2
+ import { Effect, Layer, Option, pipe, Predicate, Redacted, type Array } from "effect";
3
+
4
+ import { DockerError } from "./circular.ts";
5
+ import { System } from "./system.js";
6
+
7
+ /**
8
+ * @since 1.0.0
9
+ * @category Auth
10
+ * @see https://docs.docker.com/reference/api/engine/version/v1.51/#section/Authentication
11
+ */
12
+ export class RegistryAuth extends Effect.Service<RegistryAuth>()(
13
+ "the-moby-effect/endpoints/httpApiHacks/RegistryAuth",
14
+ {
15
+ accessors: false,
16
+ dependencies: [],
17
+ effect: (authHeader: Redacted.Redacted<string>) =>
18
+ Effect.gen(function* () {
19
+ return { authHeader } as const;
20
+ }),
21
+ }
22
+ ) {
23
+ /**
24
+ * @since 1.0.0
25
+ * @category Auth
26
+ * @see https://docs.docker.com/reference/api/engine/version/v1.51/#section/Authentication
27
+ */
28
+ static readonly Live = RegistryAuth.Default;
29
+
30
+ /**
31
+ * @since 1.0.0
32
+ * @category Auth
33
+ * @see https://docs.docker.com/reference/api/engine/version/v1.51/#section/Authentication
34
+ */
35
+ static readonly Credentials = (credentials: {
36
+ serverAddress?: string | undefined;
37
+ username: Redacted.Redacted<string>;
38
+ password: Redacted.Redacted<string>;
39
+ email?: Redacted.Redacted<string> | undefined;
40
+ }) =>
41
+ Layer.sync(RegistryAuth, () => {
42
+ const encoded = Buffer.from(
43
+ JSON.stringify({
44
+ serveraddress: credentials.serverAddress,
45
+ username: Redacted.value(credentials.username),
46
+ password: Redacted.value(credentials.password),
47
+ email: credentials.email ? Redacted.value(credentials.email) : undefined,
48
+ })
49
+ ).toString("base64");
50
+
51
+ const redacted = Redacted.make(encoded);
52
+ return RegistryAuth.make({ authHeader: redacted });
53
+ });
54
+
55
+ /**
56
+ * @since 1.0.0
57
+ * @category Auth
58
+ * @see https://docs.docker.com/reference/api/engine/version/v1.51/#section/Authentication
59
+ */
60
+ static readonly Token = (credentials: {
61
+ serverAddress?: string | undefined;
62
+ username: Redacted.Redacted<string>;
63
+ password: Redacted.Redacted<string>;
64
+ email?: Redacted.Redacted<string> | undefined;
65
+ }) =>
66
+ pipe(
67
+ System.use((systems) =>
68
+ systems.auth({
69
+ serveraddress: credentials.serverAddress,
70
+ username: Redacted.value(credentials.username),
71
+ password: Redacted.value(credentials.password),
72
+ email: credentials.email ? Redacted.value(credentials.email) : undefined,
73
+ })
74
+ ),
75
+ Effect.flatMap((response) => {
76
+ const WrapError = DockerError.WrapForModule("system")("auth");
77
+
78
+ if (Predicate.isObject(response) && "IdentityToken" in response) {
79
+ return Effect.succeed(response.IdentityToken);
80
+ }
81
+
82
+ return WrapError(new Error("Registry authentication returned no response"));
83
+ }),
84
+ Effect.map((token) =>
85
+ RegistryAuth.make({
86
+ authHeader: Redacted.make(token),
87
+ })
88
+ ),
89
+ Layer.effect(RegistryAuth)
90
+ );
91
+ }
92
+
93
+ /**
94
+ * @since 1.0.0
95
+ * @category Auth
96
+ * @see https://docs.docker.com/reference/api/engine/version/v1.51/#section/Authentication
97
+ */
98
+ export const WithRegistryAuthHeader = (
99
+ ...sendHeaderWithEndpoints: Array.NonEmptyReadonlyArray<HttpApiEndpoint.HttpApiEndpoint.Any & { path: string }>
100
+ ) =>
101
+ HttpClient.mapRequestEffect(
102
+ Effect.fn("HttpApiHacks.withRegistryAUthHeader")(function* (request: HttpClientRequest.HttpClientRequest) {
103
+ const url = HttpClientRequest.toUrl(request);
104
+ if (Option.isNone(url)) {
105
+ return request;
106
+ }
107
+
108
+ if (!sendHeaderWithEndpoints.some((endpoint) => url.value.pathname.startsWith(endpoint.path))) {
109
+ return request;
110
+ }
111
+
112
+ const auth = yield* Effect.serviceOption(RegistryAuth);
113
+ if (Option.isNone(auth)) {
114
+ return request;
115
+ }
116
+
117
+ const header = Redacted.value(auth.value.authHeader);
118
+ return HttpClientRequest.setHeader(request, "X-Registry-Auth", header);
119
+ })
120
+ );
@@ -512,7 +512,7 @@ export class Containers extends Effect.Service<Containers>()("@the-moby-effect/e
512
512
  )({
513
513
  path: { identifier },
514
514
  urlParams: { ...options },
515
- headers: { Connection: "Upgrade", Upgrade: "tcp" },
515
+ headers: { Connection: "Upgrade", Upgrade: "tcp" }, // FIXME: Broken on undici
516
516
  }),
517
517
  ContainersError("attach")
518
518
  );
@@ -522,7 +522,10 @@ export class Containers extends Effect.Service<Containers>()("@the-moby-effect/e
522
522
  ContainersApi,
523
523
  "containers",
524
524
  "attachWebsocket"
525
- )({ path: { identifier }, urlParams: { ...options } }).pipe(Effect.provide(context)),
525
+ )({
526
+ path: { identifier },
527
+ urlParams: { ...options },
528
+ }).pipe(Effect.provide(context)),
526
529
  ContainersError("attachWebsocket")
527
530
  );
528
531
  const wait_ = (identifier: ContainerIdentifier, options?: Options<"wait">) =>
@@ -550,7 +553,7 @@ export class Containers extends Effect.Service<Containers>()("@the-moby-effect/e
550
553
  Effect.flatMap(
551
554
  HttpClientResponse.schemaHeaders(
552
555
  Schema.Struct({
553
- "X-Docker-Container-Path-Stat": Schema.compose(
556
+ "x-docker-container-path-stat": Schema.compose(
554
557
  Schema.StringFromBase64,
555
558
  Schema.parseJson()
556
559
  ).pipe(Schema.optional),
@@ -558,7 +561,7 @@ export class Containers extends Effect.Service<Containers>()("@the-moby-effect/e
558
561
  )
559
562
  )
560
563
  )
561
- .pipe(Effect.map(({ "X-Docker-Container-Path-Stat": pathStat }) => pathStat))
564
+ .pipe(Effect.map(({ "x-docker-container-path-stat": pathStat }) => pathStat))
562
565
  .pipe(Effect.mapError(ContainersError("archiveInfo")));
563
566
  const putArchive_ = <E, R>(
564
567
  identifier: ContainerIdentifier,
@@ -24,7 +24,12 @@ const createExecEndpoint = HttpApiEndpoint.post("container", "/containers/:id/ex
24
24
  /** @see https://docs.docker.com/reference/api/engine/latest/#tag/Exec/operation/ExecStart */
25
25
  const startExecEndpoint = HttpApiEndpoint.post("start", "/exec/:id/start")
26
26
  .setPath(Schema.Struct({ id: ExecIdentifier }))
27
- .setHeaders(Schema.Struct({ Upgrade: Schema.Literal("tcp"), Connection: Schema.Literal("Upgrade") }))
27
+ .setHeaders(
28
+ Schema.Struct({
29
+ Upgrade: Schema.Literal("tcp"),
30
+ Connection: Schema.Literal("Upgrade"),
31
+ })
32
+ )
28
33
  .setPayload(ContainerExecStartOptions)
29
34
  .addSuccess(HttpApiSchema.Empty(101))
30
35
  .addSuccess(HttpApiSchema.Empty(200))
@@ -102,7 +107,7 @@ export class Execs extends Effect.Service<Execs>()("@the-moby-effect/endpoints/E
102
107
  )({
103
108
  path: { id },
104
109
  payload: ContainerExecStartOptions.make(payload),
105
- headers: { Connection: "Upgrade", Upgrade: "tcp" },
110
+ headers: { Connection: "Upgrade", Upgrade: "tcp" }, // FIXME: Broken on undici
106
111
  })
107
112
  .pipe(
108
113
  Effect.map(
@@ -1,6 +1,7 @@
1
1
  import { HttpApi, HttpApiClient, HttpApiEndpoint, HttpApiGroup, HttpApiSchema, HttpClient } from "@effect/platform";
2
2
  import { Effect, Schema, Stream, type Layer } from "effect";
3
3
 
4
+ import * as ParseResult from "effect/ParseResult";
4
5
  import { MobyConnectionOptions } from "../../MobyConnection.js";
5
6
  import { makeAgnosticHttpClientLayer } from "../../MobyPlatforms.js";
6
7
  import { mapError } from "../convey/sinks.ts";
@@ -13,6 +14,7 @@ import {
13
14
  JSONMessage,
14
15
  RegistrySearchResult,
15
16
  } from "../generated/index.js";
17
+ import { WithRegistryAuthHeader } from "./auth.ts";
16
18
  import { DockerError } from "./circular.ts";
17
19
  import {
18
20
  BadRequest,
@@ -38,8 +40,20 @@ export class ListFilters extends Schema.parseJson(
38
40
  /** @since 1.0.0 */
39
41
  export class SearchFilters extends Schema.parseJson(
40
42
  Schema.Struct({
41
- "is-official": Schema.optional(Schema.BooleanFromString),
42
- "is-automated": Schema.optional(Schema.BooleanFromString),
43
+ "is-official": Schema.transformOrFail(Schema.Tuple(Schema.String), Schema.BooleanFromString, {
44
+ decode: (_fromA, _options, ast) =>
45
+ ParseResult.fail(
46
+ new ParseResult.Forbidden(ast, _fromA, "Decoding 'is-official' filter is not supported")
47
+ ),
48
+ encode: (automated) => ParseResult.succeed([automated] as const),
49
+ }).pipe(Schema.optional),
50
+ "is-automated": Schema.transformOrFail(Schema.Tuple(Schema.String), Schema.BooleanFromString, {
51
+ decode: (_fromA, _options, ast) =>
52
+ ParseResult.fail(
53
+ new ParseResult.Forbidden(ast, _fromA, "Decoding 'is-automated' filter is not supported")
54
+ ),
55
+ encode: (automated) => ParseResult.succeed([automated] as const),
56
+ }).pipe(Schema.optional),
43
57
  stars: Schema.optional(Schema.NumberFromString),
44
58
  })
45
59
  ) {}
@@ -155,7 +169,7 @@ const historyImageEndpoint = HttpApiEndpoint.get("history", "/images/:name/histo
155
169
  const pushImageEndpoint = HttpApiEndpoint.post("push", "/images/:name/push")
156
170
  .setPath(Schema.Struct({ name: Schema.String }))
157
171
  .setUrlParams(Schema.Struct({ tag: Schema.optional(Schema.String), platform: Schema.optional(Schema.String) }))
158
- .setHeaders(Schema.Struct({ "X-Registry-Auth": Schema.String }))
172
+ .setHeaders(Schema.Struct({ "X-Registry-Auth": Schema.optional(Schema.String) }))
159
173
  .addSuccess(HttpApiSchema.Empty(200))
160
174
  .addError(NotFound); // 404 No such image
161
175
 
@@ -203,7 +217,7 @@ const pruneImagesEndpoint = HttpApiEndpoint.post("prune", "/images/prune")
203
217
  .addSuccess(
204
218
  Schema.Struct({
205
219
  SpaceReclaimed: Schema.Number,
206
- ImagesDeleted: Schema.optional(Schema.Array(ImageDeleteResponse)),
220
+ ImagesDeleted: Schema.NullishOr(Schema.Array(ImageDeleteResponse)),
207
221
  }),
208
222
  { status: 200 }
209
223
  );
@@ -297,7 +311,11 @@ export class Images extends Effect.Service<Images>()("@the-moby-effect/endpoints
297
311
  HttpApiEndpoint.HttpApiEndpoint.WithName<(typeof ImagesGroup.endpoints)[number], Name>
298
312
  >;
299
313
 
300
- const httpClient = yield* HttpClient.HttpClient;
314
+ const httpClient = yield* Effect.map(
315
+ HttpClient.HttpClient,
316
+ WithRegistryAuthHeader(buildImageEndpoint, createImageEndpoint, pushImageEndpoint)
317
+ );
318
+
301
319
  const ImagesError = DockerError.WrapForModule("images");
302
320
  const client = yield* HttpApiClient.group(ImagesApi, { group: "images", httpClient });
303
321
 
@@ -328,8 +346,8 @@ export class Images extends Effect.Service<Images>()("@the-moby-effect/endpoints
328
346
  "create",
329
347
  httpClient
330
348
  )({
349
+ headers: {},
331
350
  urlParams: { ...options },
332
- headers: { "X-Registry-Auth": undefined },
333
351
  })
334
352
  .pipe(Stream.decodeText())
335
353
  .pipe(Stream.splitLines)
@@ -349,7 +367,7 @@ export class Images extends Effect.Service<Images>()("@the-moby-effect/endpoints
349
367
  )({
350
368
  path: { name },
351
369
  urlParams: { ...options },
352
- headers: { "X-Registry-Auth": "" },
370
+ headers: {},
353
371
  })
354
372
  .pipe(Stream.decodeText())
355
373
  .pipe(Stream.splitLines)
@@ -367,25 +385,42 @@ export class Images extends Effect.Service<Images>()("@the-moby-effect/endpoints
367
385
  const commit_ = (payload: ContainerCreateRequest, options: Options<"commit">) =>
368
386
  Effect.mapError(client.commit({ urlParams: { ...options }, payload }), ImagesError("commit"));
369
387
  const export_ = (name: string, options?: Options<"export">) =>
370
- Stream.mapError(
371
- HttpApiStreamingResponse(
372
- ImagesApi,
373
- "images",
374
- "export",
375
- httpClient
376
- )({ path: { name }, urlParams: { ...options } }),
377
- ImagesError("export")
378
- );
388
+ HttpApiStreamingResponse(
389
+ ImagesApi,
390
+ "images",
391
+ "export",
392
+ httpClient
393
+ )({ path: { name }, urlParams: { ...options } })
394
+ .pipe(Stream.decodeText())
395
+ .pipe(Stream.splitLines)
396
+ .pipe(Stream.mapEffect(Schema.decode(Schema.parseJson(JSONMessage))))
397
+ .pipe(mapError)
398
+ .pipe(Stream.mapError(ImagesError("export")));
379
399
  const exportMany_ = (options?: Options<"exportMany">) =>
380
- Stream.mapError(
381
- HttpApiStreamingResponse(ImagesApi, "images", "exportMany", httpClient)({ urlParams: { ...options } }),
382
- ImagesError("exportMany")
383
- );
400
+ HttpApiStreamingResponse(
401
+ ImagesApi,
402
+ "images",
403
+ "exportMany",
404
+ httpClient
405
+ )({ urlParams: { ...options } })
406
+ .pipe(Stream.decodeText())
407
+ .pipe(Stream.splitLines)
408
+ .pipe(Stream.mapEffect(Schema.decode(Schema.parseJson(JSONMessage))))
409
+ .pipe(mapError)
410
+ .pipe(Stream.mapError(ImagesError("exportMany")));
384
411
  const import_ = <E>(context: Stream.Stream<Uint8Array, E, never>, options?: Options<"import">) =>
385
- Stream.mapError(
386
- HttpApiStreamingBoth(ImagesApi, "images", "import", httpClient, context)({ urlParams: { ...options } }),
387
- ImagesError("import")
388
- );
412
+ HttpApiStreamingBoth(
413
+ ImagesApi,
414
+ "images",
415
+ "import",
416
+ httpClient,
417
+ context
418
+ )({ urlParams: { ...options } })
419
+ .pipe(Stream.decodeText())
420
+ .pipe(Stream.splitLines)
421
+ .pipe(Stream.mapEffect(Schema.decode(Schema.parseJson(JSONMessage))))
422
+ .pipe(mapError)
423
+ .pipe(Stream.mapError(ImagesError("import")));
389
424
 
390
425
  return {
391
426
  list: list_,
@@ -81,7 +81,7 @@ const disconnectNetworkEndpoint = HttpApiEndpoint.post("disconnect", "/:id/disco
81
81
  /** @see https://docs.docker.com/reference/api/engine/latest/#tag/Network/operation/NetworkPrune */
82
82
  const pruneNetworkEndpoint = HttpApiEndpoint.post("prune", "/prune")
83
83
  .setUrlParams(Schema.Struct({ filters: Schema.optional(PruneFilters) }))
84
- .addSuccess(Schema.Struct({ NetworksDeleted: Schema.optional(Schema.Array(Schema.String)) }), { status: 200 });
84
+ .addSuccess(Schema.Struct({ NetworksDeleted: Schema.NullishOr(Schema.Array(Schema.String)) }), { status: 200 });
85
85
 
86
86
  /** @see https://docs.docker.com/reference/api/engine/latest/#tag/Network */
87
87
  const NetworksGroup = HttpApiGroup.make("networks")
@@ -129,13 +129,19 @@ export class Networks extends Effect.Service<Networks>()("@the-moby-effect/endpo
129
129
 
130
130
  const list_ = (filters?: Schema.Schema.Type<ListFilters>) =>
131
131
  Effect.mapError(client.list({ urlParams: { filters } }), NetworksError("list"));
132
- const create_ = (payload: NetworkCreateRequest) =>
133
- Effect.mapError(client.create({ payload }), NetworksError("create"));
132
+ const create_ = (...payload: ConstructorParameters<typeof NetworkCreateRequest>) =>
133
+ Effect.mapError(client.create({ payload: NetworkCreateRequest.make(...payload) }), NetworksError("create"));
134
134
  const inspect_ = (id: string, options?: Options<"inspect">) =>
135
135
  Effect.mapError(client.inspect({ path: { id }, urlParams: { ...options } }), NetworksError("inspect"));
136
136
  const delete_ = (id: string) => Effect.mapError(client.delete({ path: { id } }), NetworksError("delete"));
137
- const connect_ = (id: string, payload: NetworkConnectOptions) =>
138
- Effect.mapError(client.connect({ path: { id }, payload }), NetworksError("connect"));
137
+ const connect_ = (id: string, ...payload: ConstructorParameters<typeof NetworkConnectOptions>) =>
138
+ Effect.mapError(
139
+ client.connect({
140
+ path: { id },
141
+ payload: NetworkConnectOptions.make(...payload),
142
+ }),
143
+ NetworksError("connect")
144
+ );
139
145
  const disconnect_ = (
140
146
  id: string,
141
147
  containerId: ContainerIdentifier,
@@ -1,18 +1,23 @@
1
1
  import { HttpApi, HttpApiClient, HttpApiEndpoint, HttpApiGroup, HttpApiSchema, HttpClient } from "@effect/platform";
2
- import { Array, Effect, Schema, Stream, type Layer } from "effect";
2
+ import { Array, Effect, ParseResult, Schema, Stream, type Layer } from "effect";
3
3
 
4
4
  import { MobyConnectionOptions } from "../../MobyConnection.js";
5
5
  import { makeAgnosticHttpClientLayer } from "../../MobyPlatforms.js";
6
6
  import { mapError } from "../convey/sinks.ts";
7
7
  import { JSONMessage, TypesPlugin as Plugin, RuntimePluginPrivilege as PluginPrivilege } from "../generated/index.js";
8
+ import { WithRegistryAuthHeader } from "./auth.ts";
8
9
  import { DockerError } from "./circular.ts";
9
10
  import { HttpApiStreamingRequest, HttpApiStreamingResponse, InternalServerError, NotFound } from "./httpApiHacks.js";
10
11
 
11
12
  /** @since 1.0.0 */
12
13
  export class ListFilters extends Schema.parseJson(
13
14
  Schema.Struct({
14
- enabled: Schema.optional(Schema.BooleanFromString),
15
- capability: Schema.optional(Schema.String),
15
+ capability: Schema.optional(Schema.Array(Schema.String)),
16
+ enabled: Schema.transformOrFail(Schema.Tuple(Schema.String), Schema.BooleanFromString, {
17
+ decode: (_fromA, _options, ast) =>
18
+ ParseResult.fail(new ParseResult.Forbidden(ast, _fromA, "Decoding 'enabled' filter is not supported")),
19
+ encode: (automated) => ParseResult.succeed([automated] as const),
20
+ }).pipe(Schema.optional),
16
21
  })
17
22
  ) {}
18
23
 
@@ -67,7 +72,8 @@ const upgradePluginEndpoint = HttpApiEndpoint.post("upgrade", "/:name/upgrade")
67
72
  .setUrlParams(Schema.Struct({ remote: Schema.String }))
68
73
  .setHeaders(Schema.Struct({ "X-Registry-Auth": Schema.optional(Schema.String) }))
69
74
  .setPayload(Schema.Array(PluginPrivilege))
70
- .addSuccess(HttpApiSchema.NoContent) // 204 No Content
75
+ .addSuccess(HttpApiSchema.Empty(200)) // 200 OK
76
+ .addSuccess(HttpApiSchema.Empty(204)) // 204 No Content
71
77
  .addError(NotFound); // 404 No such plugin
72
78
 
73
79
  /** @see https://docs.docker.com/reference/api/engine/latest/#tag/Plugin/operation/PluginCreate */
@@ -132,7 +138,11 @@ export class Plugins extends Effect.Service<Plugins>()("@the-moby-effect/endpoin
132
138
  HttpApiEndpoint.HttpApiEndpoint.WithName<(typeof PluginsGroup.endpoints)[number], Name>
133
139
  >;
134
140
 
135
- const httpClient = yield* HttpClient.HttpClient;
141
+ const httpClient = yield* Effect.map(
142
+ HttpClient.HttpClient,
143
+ WithRegistryAuthHeader(pullPluginEndpoint, upgradePluginEndpoint)
144
+ );
145
+
136
146
  const PluginsError = DockerError.WrapForModule("plugins");
137
147
  const client = yield* HttpApiClient.group(PluginsApi, { group: "plugins", httpClient });
138
148
 
@@ -153,7 +163,7 @@ export class Plugins extends Effect.Service<Plugins>()("@the-moby-effect/endpoin
153
163
  "pull",
154
164
  httpClient
155
165
  )({
156
- headers: { "X-Registry-Auth": undefined },
166
+ headers: {},
157
167
  urlParams: { remote, name: options?.name },
158
168
  payload: Array.map(options?.privileges ?? [], (privilege) => PluginPrivilege.make(privilege)),
159
169
  })
@@ -182,9 +192,9 @@ export class Plugins extends Effect.Service<Plugins>()("@the-moby-effect/endpoin
182
192
  ) =>
183
193
  Effect.mapError(
184
194
  client.upgrade({
195
+ headers: {},
185
196
  path: { name },
186
197
  urlParams: { remote },
187
- headers: { "X-Registry-Auth": "" },
188
198
  payload: Array.map(privileges ?? [], (privilege) => PluginPrivilege.make(privilege)),
189
199
  }),
190
200
  PluginsError("upgrade")
@@ -5,6 +5,7 @@ import { MobyConnectionOptions } from "../../MobyConnection.js";
5
5
  import { makeAgnosticHttpClientLayer } from "../../MobyPlatforms.js";
6
6
  import { SwarmService, SwarmServiceSpec } from "../generated/index.js";
7
7
  import { ServiceIdentifier } from "../schemas/id.js";
8
+ import { WithRegistryAuthHeader } from "./auth.ts";
8
9
  import { DockerError } from "./circular.ts";
9
10
  import {
10
11
  BadRequest,
@@ -151,24 +152,38 @@ export class Services extends Effect.Service<Services>()("@the-moby-effect/endpo
151
152
  HttpApiEndpoint.HttpApiEndpoint.WithName<(typeof ServicesGroup.endpoints)[number], Name>
152
153
  >;
153
154
 
154
- const httpClient = yield* HttpClient.HttpClient;
155
+ const httpClient = yield* Effect.map(
156
+ HttpClient.HttpClient,
157
+ WithRegistryAuthHeader(createServiceEndpoint, updateServiceEndpoint)
158
+ );
159
+
155
160
  const ServicesError = DockerError.WrapForModule("services");
156
161
  const client = yield* HttpApiClient.group(ServicesApi, { group: "services", httpClient });
157
162
 
158
163
  const list_ = (options?: Options<"list">) =>
159
164
  Effect.mapError(client.list({ urlParams: { ...options } }), ServicesError("list"));
160
- const create_ = (payload: SwarmServiceSpec) =>
161
- Effect.mapError(client.create({ payload, headers: { "X-Registry-Auth": "" } }), ServicesError("create"));
165
+ const create_ = (...payload: ConstructorParameters<typeof SwarmServiceSpec>) =>
166
+ Effect.mapError(
167
+ client.create({
168
+ headers: {},
169
+ payload: SwarmServiceSpec.make(...payload),
170
+ }),
171
+ ServicesError("create")
172
+ );
162
173
  const delete_ = (id: string) => Effect.mapError(client.delete({ path: { id } }), ServicesError("delete"));
163
174
  const inspect_ = (id: string, options?: Options<"inspect">) =>
164
175
  Effect.mapError(client.inspect({ path: { id }, urlParams: { ...options } }), ServicesError("inspect"));
165
- const update_ = (id: string, payload: SwarmServiceSpec, options: Options<"update">) =>
176
+ const update_ = (
177
+ id: string,
178
+ options: Options<"update">,
179
+ ...payload: ConstructorParameters<typeof SwarmServiceSpec>
180
+ ) =>
166
181
  Effect.mapError(
167
182
  client.update({
168
- payload,
183
+ headers: {},
169
184
  path: { id },
170
185
  urlParams: { ...options },
171
- headers: { "X-Registry-Auth": "" },
186
+ payload: SwarmServiceSpec.make(...payload),
172
187
  }),
173
188
  ServicesError("update")
174
189
  );
@@ -1,5 +1,5 @@
1
1
  import { HttpApi, HttpApiClient, HttpApiEndpoint, HttpApiGroup, HttpApiSchema, HttpClient } from "@effect/platform";
2
- import { Effect, Schema, Stream, type Layer } from "effect";
2
+ import { Effect, type Layer, Schema, Stream } from "effect";
3
3
 
4
4
  import { MobyConnectionOptions } from "../../MobyConnection.js";
5
5
  import { makeAgnosticHttpClientLayer } from "../../MobyPlatforms.js";
@@ -103,7 +103,7 @@ const makeDindBinds = <ExposeDindBy extends MobyConnection.MobyConnectionOptions
103
103
  Effect.gen(function* () {
104
104
  const acquireScopedVolume = Effect.acquireRelease(
105
105
  MobyEndpoints.Volumes.use((volumes) => volumes.create({})),
106
- ({ Name }) => Effect.orDie(MobyEndpoints.Volumes.use((volumes) => volumes.delete(Name)))
106
+ ({ Name }) => Effect.orDie(MobyEndpoints.Volumes.use((volumes) => volumes.delete(Name, { force: true })))
107
107
  );
108
108
 
109
109
  const volume1 = yield* acquireScopedVolume;
@@ -111,7 +111,13 @@ const makeDindBinds = <ExposeDindBy extends MobyConnection.MobyConnectionOptions
111
111
 
112
112
  const tempSocketDirectory = yield* Effect.if(exposeDindBy === "socket", {
113
113
  onFalse: () => Effect.succeed(""),
114
- onTrue: () => Effect.flatMap(FileSystem.FileSystem, (fs) => fs.makeTempDirectoryScoped()),
114
+ onTrue: () =>
115
+ Effect.gen(function* () {
116
+ const fs = yield* FileSystem.FileSystem;
117
+ const folder = yield* fs.makeTempDirectoryScoped();
118
+ yield* fs.chmod(folder, 0o777); // Ew, for github actions where uid != 1000 🤮
119
+ return folder;
120
+ }),
115
121
  });
116
122
 
117
123
  const boundDockerSocket = yield* Effect.if(exposeDindBy === "socket", {
@@ -33,7 +33,7 @@ export class ContainerConfig extends Schema.Class<ContainerConfig>("ContainerCon
33
33
  .pipe(Schema.withConstructorDefault(() => null)),
34
34
  NetworkDisabled: Schema.optional(Schema.Boolean),
35
35
  MacAddress: Schema.optional(Schema.String),
36
- OnBuild: Schema.NullOr(Schema.Array(Schema.String))
36
+ OnBuild: Schema.NullishOr(Schema.Array(Schema.String))
37
37
  .pipe(Schema.propertySignature)
38
38
  .pipe(Schema.withConstructorDefault(() => null)),
39
39
  Labels: Schema.NullOr(Schema.Record({ key: Schema.String, value: Schema.String }))
@@ -26,7 +26,7 @@ export class ContainerContainerJSONBase extends Schema.Class<ContainerContainerJ
26
26
  AppArmorProfile: Schema.String,
27
27
  ExecIDs: Schema.NullOr(Schema.Array(Schema.String)),
28
28
  HostConfig: Schema.NullOr(ContainerHostConfig.ContainerHostConfig),
29
- GraphDriver: Schema.NullOr(StorageDriverData.StorageDriverData),
29
+ GraphDriver: Schema.NullishOr(StorageDriverData.StorageDriverData), // optional for docker.io/library/docker:26-dind-rootless
30
30
  SizeRw: Schema.optionalWith(EffectSchemas.Number.I64, { nullable: true }),
31
31
  SizeRootFs: Schema.optionalWith(EffectSchemas.Number.I64, { nullable: true }),
32
32
  },