@distilled.cloud/fly-io 1.0.0-rc.15 → 1.0.0-rc.17

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 (84) hide show
  1. package/lib/.lazy.json +1 -0
  2. package/lib/_bundle/lazy.js +4 -0
  3. package/lib/_bundle/sdk.js +2 -0
  4. package/lib/_bundle/sdk.js.map +1 -0
  5. package/lib/credentials.d.ts +3 -3
  6. package/lib/credentials.d.ts.map +1 -1
  7. package/lib/credentials.js +1 -65
  8. package/lib/errors.d.ts +39 -24
  9. package/lib/errors.d.ts.map +1 -1
  10. package/lib/errors.js +1 -62
  11. package/lib/index.d.ts +2 -2
  12. package/lib/index.js +1 -33
  13. package/lib/index.lazy.js +7 -0
  14. package/lib/pagination.d.ts +1 -1
  15. package/lib/pagination.js +1 -5
  16. package/lib/protocol.d.ts +2 -2
  17. package/lib/protocol.d.ts.map +1 -1
  18. package/lib/protocol.js +1 -541
  19. package/lib/retry.d.ts +1 -1
  20. package/lib/retry.d.ts.map +1 -1
  21. package/lib/retry.js +1 -33
  22. package/lib/services/addons.d.ts +0 -65
  23. package/lib/services/addons.d.ts.map +1 -1
  24. package/lib/services/addons.js +22 -567
  25. package/lib/services/addons.js.map +1 -1
  26. package/lib/services/builders.d.ts +31 -0
  27. package/lib/services/builders.d.ts.map +1 -0
  28. package/lib/services/builders.js +2 -0
  29. package/lib/services/builders.js.map +1 -0
  30. package/lib/services/index.d.ts +1 -0
  31. package/lib/services/index.d.ts.map +1 -1
  32. package/lib/services/index.js +1 -2
  33. package/lib/services/machines.d.ts +25 -444
  34. package/lib/services/machines.d.ts.map +1 -1
  35. package/lib/services/machines.js +137 -2736
  36. package/lib/services/machines.js.map +1 -1
  37. package/lib/services/mpg.d.ts +1 -67
  38. package/lib/services/mpg.d.ts.map +1 -1
  39. package/lib/services/mpg.js +31 -453
  40. package/lib/services/mpg.js.map +1 -1
  41. package/lib/services/sprites.d.ts +1 -125
  42. package/lib/services/sprites.d.ts.map +1 -1
  43. package/lib/services/sprites.js +62 -890
  44. package/lib/services/sprites.js.map +1 -1
  45. package/lib/services.lazy/addons.js +3 -0
  46. package/lib/services.lazy/builders.js +1 -0
  47. package/lib/services.lazy/index.js +3 -0
  48. package/lib/services.lazy/machines.js +4 -0
  49. package/lib/services.lazy/mpg.js +3 -0
  50. package/lib/services.lazy/sprites.js +3 -0
  51. package/lib/traits.d.ts.map +1 -1
  52. package/lib/traits.js +1 -21
  53. package/package.json +20 -7
  54. package/src/credentials.ts +18 -15
  55. package/src/errors.ts +40 -28
  56. package/src/index.ts +2 -2
  57. package/src/pagination.ts +1 -1
  58. package/src/protocol.ts +67 -36
  59. package/src/retry.ts +6 -4
  60. package/src/services/addons.ts +593 -692
  61. package/src/services/builders.ts +93 -0
  62. package/src/services/index.ts +1 -0
  63. package/src/services/machines.ts +3332 -3364
  64. package/src/services/mpg.ts +582 -519
  65. package/src/services/sprites.ts +1008 -948
  66. package/src/traits.ts +8 -4
  67. package/lib/credentials.js.map +0 -1
  68. package/lib/errors.js.map +0 -1
  69. package/lib/pagination.js.map +0 -1
  70. package/lib/protocol.js.map +0 -1
  71. package/lib/protocol.test.d.ts +0 -2
  72. package/lib/protocol.test.d.ts.map +0 -1
  73. package/lib/protocol.test.js +0 -126
  74. package/lib/protocol.test.js.map +0 -1
  75. package/lib/retry.js.map +0 -1
  76. package/lib/services/index.js.map +0 -1
  77. package/lib/sprites-mint.test.d.ts +0 -2
  78. package/lib/sprites-mint.test.d.ts.map +0 -1
  79. package/lib/sprites-mint.test.js +0 -169
  80. package/lib/sprites-mint.test.js.map +0 -1
  81. package/lib/traits.js.map +0 -1
  82. package/src/protocol.test.ts +0 -214
  83. package/src/sprites-mint.test.ts +0 -228
  84. /package/lib/{index.js.map → index.lazy.js.map} +0 -0
package/src/protocol.ts CHANGED
@@ -11,14 +11,19 @@ import {
11
11
  matchTypedError,
12
12
  } from "@distilled.cloud/core/protocol-http";
13
13
  import {
14
+ hasSensitiveMember,
14
15
  makeRestProtocol,
15
16
  unwrapRedactedDeep,
16
17
  wrapSensitive,
17
18
  } from "@distilled.cloud/core/protocol-rest";
18
- import { failIfStrict, validateResponse } from "@distilled.cloud/core/response-validation";
19
+ import {
20
+ failUnlessLenient,
21
+ validateResponse,
22
+ withholdActual,
23
+ } from "@distilled.cloud/core/response-validation";
19
24
  import { parseRetryAfterForStatus } from "@distilled.cloud/core/retry-after";
20
25
  /**
21
- * Fly.io protocols — Machines REST, UI-EX REST (MPG), GraphQL add-ons, and
26
+ * Fly.io protocols -- Machines REST, UI-EX REST (MPG), GraphQL add-ons, and
22
27
  * Sprites REST.
23
28
  *
24
29
  * Machines (`FlyIoProtocol`) is a plain bearer-token JSON API at
@@ -116,7 +121,7 @@ const spritesErrorEnvelope = (body: unknown) => {
116
121
  return { message, code };
117
122
  };
118
123
 
119
- const resolveFlyCreds = Effect.gen(function* () {
124
+ const resolveFlyCreds = /*@__PURE__*/ Effect.gen(function* () {
120
125
  const resolve = yield* Credentials;
121
126
  return yield* resolve;
122
127
  });
@@ -127,11 +132,10 @@ const resolveFlyCreds = Effect.gen(function* () {
127
132
  * GetSecret in the same process; this service only changes headers:
128
133
  * omit `Authorization`, send `Connection: close`.
129
134
  */
130
- export class MachineIdentity extends Context.Service<MachineIdentity, true>()(
131
- "FlyIoMachineIdentity",
132
- ) {}
135
+ export class MachineIdentity
136
+ extends /*@__PURE__*/ Context.Service<MachineIdentity, true>()("FlyIoMachineIdentity") {}
133
137
 
134
- const FlyIoProtocolRest: Layer.Layer<API.Protocol> = makeRestProtocol<Config>({
138
+ const FlyIoProtocolRest: Layer.Layer<API.Protocol> = /*@__PURE__*/ makeRestProtocol<Config>({
135
139
  credentials: resolveFlyCreds,
136
140
  baseUrl: (creds) => creds.apiBaseUrl,
137
141
  headers: (creds) => ({
@@ -142,9 +146,9 @@ const FlyIoProtocolRest: Layer.Layer<API.Protocol> = makeRestProtocol<Config>({
142
146
  parseError: ({ body, cause }) => new FlyIoParseError({ body, cause }),
143
147
  });
144
148
 
145
- export const FlyIoProtocol: Layer.Layer<API.Protocol> = Layer.effect(
149
+ export const FlyIoProtocol: Layer.Layer<API.Protocol> = /*@__PURE__*/ Layer.effect(
146
150
  API.Protocol,
147
- Effect.gen(function* () {
151
+ /*@__PURE__*/ Effect.gen(function* () {
148
152
  const rest = yield* API.Protocol;
149
153
  return API.Protocol.of({
150
154
  encode: (args) =>
@@ -160,10 +164,10 @@ export const FlyIoProtocol: Layer.Layer<API.Protocol> = Layer.effect(
160
164
  decode: rest.decode,
161
165
  });
162
166
  }),
163
- ).pipe(Layer.provide(FlyIoProtocolRest));
167
+ ).pipe(/*@__PURE__*/ Layer.provide(FlyIoProtocolRest));
164
168
 
165
169
  /** MPG UI-EX REST at `https://api.fly.io` with the Machines bearer token. */
166
- export const FlyApiProtocol: Layer.Layer<API.Protocol> = makeRestProtocol<Config>({
170
+ export const FlyApiProtocol: Layer.Layer<API.Protocol> = /*@__PURE__*/ makeRestProtocol<Config>({
167
171
  credentials: resolveFlyCreds,
168
172
  baseUrl: () => DEFAULT_FLY_API_BASE_URL,
169
173
  headers: (creds) => ({
@@ -404,7 +408,7 @@ const mintOnce = (fly: Config) =>
404
408
  if (typeof token !== "string" || token.length === 0) {
405
409
  return yield* fail(
406
410
  new FlyIoParseError({
407
- body: json ?? text,
411
+ body: "[REDACTED]",
408
412
  cause: "mint response missing token",
409
413
  }),
410
414
  );
@@ -413,8 +417,11 @@ const mintOnce = (fly: Config) =>
413
417
  });
414
418
 
415
419
  // Keyed by the Fly token itself: `Redacted` hashes and compares by value.
416
- const mintedTokens = MutableHashMap.empty<Redacted.Redacted<string>, Redacted.Redacted<string>>();
417
- const mintInFlight = MutableHashMap.empty<
420
+ const mintedTokens = /*@__PURE__*/ MutableHashMap.empty<
421
+ Redacted.Redacted<string>,
422
+ Redacted.Redacted<string>
423
+ >();
424
+ const mintInFlight = /*@__PURE__*/ MutableHashMap.empty<
418
425
  Redacted.Redacted<string>,
419
426
  Deferred.Deferred<Redacted.Redacted<string>, Effect.Error<ReturnType<typeof mintOnce>>>
420
427
  >();
@@ -554,24 +561,32 @@ const decodeSpritesResponse = ({
554
561
  }
555
562
 
556
563
  // Strict mode checks the mapped body (or parsed exec frames) against the
557
- // output schema.
564
+ // output schema. For an output with sensitive members, a non-JSON body
565
+ // fails in every mode and parse errors withhold the body.
566
+ const sensitive = hasSensitiveMember(outputAst);
567
+ const reported = sensitive ? "[REDACTED]" : (execFrames ?? (nonJson ? text : json));
568
+ if (nonJson && sensitive) {
569
+ return yield* fail(
570
+ new FlyIoParseError({
571
+ body: "[REDACTED]",
572
+ cause: "Invalid JSON response",
573
+ }),
574
+ );
575
+ }
558
576
  const body: unknown = execFrames ?? parseMaybeNdjson(nonJson ? text : (json ?? {}));
559
577
  const mapped = yield* validateResponse(
560
578
  outputAst,
561
579
  mapKeys(outputAst, body, "decode"),
562
580
  (cause) =>
563
- new FlyIoParseError({
564
- body: execFrames ?? (nonJson ? text : json),
565
- cause,
566
- }),
581
+ new FlyIoParseError({ body: reported, cause: sensitive ? withholdActual(cause) : cause }),
567
582
  ).pipe(Effect.catch(fail));
568
583
  return wrapSensitive(outputAst, mapped);
569
584
  });
570
585
 
571
586
  /** Sprites REST at `https://api.sprites.dev/v1`, minted from `FLY_API_TOKEN`. */
572
- export const SpritesProtocol: Layer.Layer<API.Protocol> = Layer.succeed(
587
+ export const SpritesProtocol: Layer.Layer<API.Protocol> = /*@__PURE__*/ Layer.succeed(
573
588
  API.Protocol,
574
- API.Protocol.of({
589
+ /*@__PURE__*/ API.Protocol.of({
575
590
  encode: (args) =>
576
591
  encodeSpritesRequest(args) as Effect.Effect<HttpClientRequest.HttpClientRequest>,
577
592
  decode: (args) => decodeSpritesResponse(args) as Effect.Effect<unknown>,
@@ -579,25 +594,25 @@ export const SpritesProtocol: Layer.Layer<API.Protocol> = Layer.succeed(
579
594
  );
580
595
 
581
596
  // =============================================================================
582
- // GraphQL add-ons (Tigris, Redis) — POST https://api.fly.io/graphql
597
+ // GraphQL add-ons (Tigris, Redis) -- POST https://api.fly.io/graphql
583
598
  // =============================================================================
584
599
 
585
- const GraphQLError = Schema.Struct({
600
+ const GraphQLError = /*@__PURE__*/ Schema.Struct({
586
601
  message: Schema.String,
587
- path: Schema.optional(Schema.Array(Schema.Unknown)),
588
- extensions: Schema.optional(
589
- Schema.Struct({
590
- code: Schema.optional(Schema.String),
602
+ path: /*@__PURE__*/ Schema.optional(/*@__PURE__*/ Schema.Array(Schema.Unknown)),
603
+ extensions: /*@__PURE__*/ Schema.optional(
604
+ /*@__PURE__*/ Schema.Struct({
605
+ code: /*@__PURE__*/ Schema.optional(Schema.String),
591
606
  }),
592
607
  ),
593
608
  });
594
609
 
595
- const GraphQLEnvelope = Schema.Struct({
596
- data: Schema.optional(Schema.NullOr(Schema.Unknown)),
597
- errors: Schema.optional(Schema.Array(GraphQLError)),
610
+ const GraphQLEnvelope = /*@__PURE__*/ Schema.Struct({
611
+ data: /*@__PURE__*/ Schema.optional(/*@__PURE__*/ Schema.NullOr(Schema.Unknown)),
612
+ errors: /*@__PURE__*/ Schema.optional(/*@__PURE__*/ Schema.Array(GraphQLError)),
598
613
  });
599
614
 
600
- const decodeEnvelope = Schema.decodeUnknownOption(GraphQLEnvelope);
615
+ const decodeEnvelope = /*@__PURE__*/ Schema.decodeUnknownOption(GraphQLEnvelope);
601
616
 
602
617
  const matchGraphqlError = (
603
618
  status: number,
@@ -715,12 +730,23 @@ const graphqlDecode = ({
715
730
  }
716
731
  }
717
732
 
733
+ // For an output with sensitive members, a non-JSON body fails in every
734
+ // mode and parse errors withhold the body.
735
+ const sensitive = hasSensitiveMember(outputAst);
718
736
  if (!parsed) {
719
737
  if (status >= 400) {
720
738
  return yield* matchGraphqlError(status, text, headers, errors);
721
739
  }
740
+ if (sensitive) {
741
+ return yield* fail(
742
+ new FlyIoParseError({
743
+ body: "[REDACTED]",
744
+ cause: "response body is not valid JSON",
745
+ }),
746
+ );
747
+ }
722
748
  // Lenient mode returns the body as read.
723
- return yield* failIfStrict(
749
+ return yield* failUnlessLenient(
724
750
  new FlyIoParseError({
725
751
  body: text,
726
752
  cause: "response body is not valid JSON",
@@ -752,16 +778,21 @@ const graphqlDecode = ({
752
778
  }
753
779
  // Strict mode checks the payload at the response path against the
754
780
  // output schema.
755
- return yield* validateResponse(
781
+ const validated = yield* validateResponse(
756
782
  outputAst,
757
783
  payload === undefined ? null : payload,
758
- (cause) => new FlyIoParseError({ body: json, cause }),
784
+ (cause) =>
785
+ new FlyIoParseError({
786
+ body: sensitive ? "[REDACTED]" : json,
787
+ cause: sensitive ? withholdActual(cause) : cause,
788
+ }),
759
789
  ).pipe(Effect.catch(fail));
790
+ return wrapSensitive(outputAst, validated);
760
791
  });
761
792
 
762
- export const FlyGraphqlProtocol: Layer.Layer<API.Protocol> = Layer.succeed(
793
+ export const FlyGraphqlProtocol: Layer.Layer<API.Protocol> = /*@__PURE__*/ Layer.succeed(
763
794
  API.Protocol,
764
- API.Protocol.of({
795
+ /*@__PURE__*/ API.Protocol.of({
765
796
  encode: (args) => graphqlEncode(args) as Effect.Effect<HttpClientRequest.HttpClientRequest>,
766
797
  decode: graphqlDecode,
767
798
  }),
package/src/retry.ts CHANGED
@@ -33,17 +33,19 @@ export {
33
33
  } from "@distilled.cloud/core/retry";
34
34
 
35
35
  /** Context tag for configuring retry behavior of FlyIo API calls. */
36
- export class Retry extends Context.Service<Retry, Policy>()("FlyIoRetry") {}
36
+ export class Retry extends /*@__PURE__*/ Context.Service<Retry, Policy>()("FlyIoRetry") {}
37
37
 
38
38
  /** Provides a custom retry policy to every FlyIo API call below it. */
39
39
  export const policy = (optionsOrFactory: Policy) =>
40
40
  Effect.provide(Layer.succeed(Retry, optionsOrFactory));
41
41
 
42
42
  /** Disables all automatic retries. */
43
- export const none = Effect.provide(Layer.succeed(Retry, { while: () => false }));
43
+ export const none = /*@__PURE__*/ Effect.provide(
44
+ /*@__PURE__*/ Layer.succeed(Retry, { while: () => false }),
45
+ );
44
46
 
45
47
  /** Apply the throttling retry policy (retries throttling errors indefinitely). */
46
- export const throttling = policy(throttlingFactory);
48
+ export const throttling = /*@__PURE__*/ policy(throttlingFactory);
47
49
 
48
50
  /** Apply the transient retry policy (retries all transient errors indefinitely). */
49
- export const transient = policy(transientFactory);
51
+ export const transient = /*@__PURE__*/ policy(transientFactory);