@distilled.cloud/fly-io 1.0.0-rc.1 → 1.0.0-rc.11

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 (57) hide show
  1. package/LICENSE +201 -0
  2. package/lib/credentials.d.ts +24 -1
  3. package/lib/credentials.d.ts.map +1 -1
  4. package/lib/credentials.js +46 -8
  5. package/lib/credentials.js.map +1 -1
  6. package/lib/errors.d.ts +32 -0
  7. package/lib/errors.d.ts.map +1 -1
  8. package/lib/errors.js +35 -2
  9. package/lib/errors.js.map +1 -1
  10. package/lib/index.d.ts +27 -2
  11. package/lib/index.d.ts.map +1 -1
  12. package/lib/index.js +27 -2
  13. package/lib/index.js.map +1 -1
  14. package/lib/pagination.d.ts +5 -0
  15. package/lib/pagination.d.ts.map +1 -0
  16. package/lib/pagination.js +5 -0
  17. package/lib/pagination.js.map +1 -0
  18. package/lib/protocol.d.ts +49 -7
  19. package/lib/protocol.d.ts.map +1 -1
  20. package/lib/protocol.js +529 -29
  21. package/lib/protocol.js.map +1 -1
  22. package/lib/services/addons.d.ts +466 -0
  23. package/lib/services/addons.d.ts.map +1 -0
  24. package/lib/services/addons.js +613 -0
  25. package/lib/services/addons.js.map +1 -0
  26. package/lib/services/index.d.ts +3 -0
  27. package/lib/services/index.d.ts.map +1 -1
  28. package/lib/services/index.js +3 -0
  29. package/lib/services/index.js.map +1 -1
  30. package/lib/services/machines.d.ts +1689 -1162
  31. package/lib/services/machines.d.ts.map +1 -1
  32. package/lib/services/machines.js +1932 -1306
  33. package/lib/services/machines.js.map +1 -1
  34. package/lib/services/mpg.d.ts +376 -0
  35. package/lib/services/mpg.d.ts.map +1 -0
  36. package/lib/services/mpg.js +570 -0
  37. package/lib/services/mpg.js.map +1 -0
  38. package/lib/services/sprites.d.ts +321 -0
  39. package/lib/services/sprites.d.ts.map +1 -0
  40. package/lib/services/sprites.js +407 -0
  41. package/lib/services/sprites.js.map +1 -0
  42. package/lib/traits.d.ts +18 -8
  43. package/lib/traits.d.ts.map +1 -1
  44. package/lib/traits.js +13 -3
  45. package/lib/traits.js.map +1 -1
  46. package/package.json +39 -13
  47. package/src/credentials.ts +60 -8
  48. package/src/errors.ts +41 -2
  49. package/src/index.ts +32 -1
  50. package/src/pagination.ts +12 -0
  51. package/src/protocol.ts +747 -34
  52. package/src/services/addons.ts +1313 -0
  53. package/src/services/index.ts +3 -0
  54. package/src/services/machines.ts +4756 -3280
  55. package/src/services/mpg.ts +1188 -0
  56. package/src/services/sprites.ts +917 -0
  57. package/src/traits.ts +37 -3
@@ -1,10 +1,17 @@
1
1
  /**
2
2
  * Fly.io credentials — hand-written.
3
3
  *
4
- * API-compatible port of the distilled v0 fly-io credentials module: the
5
- * `Credentials` service holds an *effect* that resolves the current
4
+ * The `Credentials` service holds an *effect* that resolves the current
6
5
  * credentials on every request. The protocol layer resolves it per request
7
- * and formats the `Authorization: Bearer <apiKey>` header.
6
+ * and formats the `Authorization` header.
7
+ *
8
+ * Alchemy and `flyctl` read `FLY_API_TOKEN`. `FLY_IO_API_KEY` is kept as a
9
+ * fallback for older distilled consumers. Optional `FLY_API_HOSTNAME`
10
+ * overrides the Machines API host (default `https://api.machines.dev`).
11
+ *
12
+ * Managed REST (MPG), GraphQL add-ons (Tigris, Redis), and Sprites all
13
+ * reuse this token. Sprites never reads a separate env var: the protocol
14
+ * mints a Sprites bearer from `FLY_API_TOKEN` (see `SpritesProtocol`).
8
15
  */
9
16
  import { ConfigError } from "@distilled.cloud/core/errors";
10
17
  import * as EffectConfig from "effect/Config";
@@ -13,7 +20,33 @@ import * as Effect from "effect/Effect";
13
20
  import * as Layer from "effect/Layer";
14
21
  import * as Redacted from "effect/Redacted";
15
22
 
16
- export const DEFAULT_API_BASE_URL = "https://api.machines.dev/v1";
23
+ /**
24
+ * Machines API host. The generated Machines routes carry the `/v1` prefix
25
+ * (`/v1/apps/{app_name}/machines`), as the upstream OpenAPI spells them, so
26
+ * the base URL must not.
27
+ */
28
+ export const DEFAULT_API_BASE_URL = "https://api.machines.dev";
29
+
30
+ /** UI-EX REST + GraphQL host (MPG, Tigris, Redis). Not overridable via an invented env var. */
31
+ export const DEFAULT_FLY_API_BASE_URL = "https://api.fly.io";
32
+
33
+ /** Sprites REST root. Auth is a bearer minted from `FLY_API_TOKEN` — never `SPRITES_TOKEN`. */
34
+ export const DEFAULT_SPRITES_API_BASE_URL = "https://api.sprites.dev/v1";
35
+
36
+ /**
37
+ * Normalize a Fly API hostname into the Machines API base URL.
38
+ *
39
+ * - unset / empty → `https://api.machines.dev`
40
+ * - trailing slashes stripped
41
+ * - a trailing `/v1` is dropped: `flyctl` and older consumers set
42
+ * `FLY_API_HOSTNAME` to the `/v1` root, and the routes already carry it
43
+ */
44
+ export const normalizeApiBaseUrl = (hostname?: string): string => {
45
+ if (hostname === undefined) return DEFAULT_API_BASE_URL;
46
+ const trimmed = hostname.trim().replace(/\/+$/, "");
47
+ if (trimmed.length === 0) return DEFAULT_API_BASE_URL;
48
+ return trimmed.endsWith("/v1") ? trimmed.slice(0, -3) : trimmed;
49
+ };
17
50
 
18
51
  export interface Config {
19
52
  readonly apiKey: Redacted.Redacted<string>;
@@ -26,7 +59,12 @@ export class Credentials extends Context.Service<
26
59
  >()("Fly-ioCredentials") {}
27
60
 
28
61
  const envConfig = EffectConfig.all({
29
- apiKey: EffectConfig.string("FLY_IO_API_KEY"),
62
+ apiKey: EffectConfig.String("FLY_API_TOKEN").pipe(
63
+ EffectConfig.orElse(() => EffectConfig.String("FLY_IO_API_KEY")),
64
+ ),
65
+ apiBaseUrl: EffectConfig.String("FLY_API_HOSTNAME").pipe(
66
+ EffectConfig.withDefault(""),
67
+ ),
30
68
  });
31
69
 
32
70
  export const CredentialsFromEnv = Layer.succeed(
@@ -35,13 +73,27 @@ export const CredentialsFromEnv = Layer.succeed(
35
73
  Effect.mapError(
36
74
  () =>
37
75
  new ConfigError({
38
- message: "FLY_IO_API_KEY environment variable is required",
76
+ message:
77
+ "FLY_API_TOKEN (or FLY_IO_API_KEY) environment variable is required",
39
78
  }),
40
79
  ),
41
- Effect.map(({ apiKey }) => ({
80
+ Effect.map(({ apiKey, apiBaseUrl }) => ({
42
81
  apiKey: Redacted.make(apiKey),
43
- apiBaseUrl: DEFAULT_API_BASE_URL,
82
+ apiBaseUrl: normalizeApiBaseUrl(apiBaseUrl || undefined),
44
83
  })),
45
84
  Effect.orDie,
46
85
  ),
47
86
  );
87
+
88
+ /** Convenience layer from a plain API token + optional base URL. */
89
+ export const credentials = (config: {
90
+ readonly apiKey: string;
91
+ readonly apiBaseUrl?: string;
92
+ }): Layer.Layer<Credentials> =>
93
+ Layer.succeed(
94
+ Credentials,
95
+ Effect.succeed({
96
+ apiKey: Redacted.make(config.apiKey),
97
+ apiBaseUrl: normalizeApiBaseUrl(config.apiBaseUrl),
98
+ }),
99
+ );
package/src/errors.ts CHANGED
@@ -29,12 +29,13 @@ import type { DefaultErrors as CoreDefaultErrors } from "@distilled.cloud/core/e
29
29
 
30
30
  import * as Schema from "effect/Schema";
31
31
  import * as Category from "@distilled.cloud/core/category";
32
+ import { applyErrorMatchers } from "@distilled.cloud/core/trait";
32
33
 
33
34
  /**
34
35
  * Unknown Fly.io error — returned when a failure matches no status-mapped
35
36
  * error class. Carries the raw body for later cataloging.
36
37
  */
37
- export class UnknownFlyIoError extends Schema.TaggedErrorClass<UnknownFlyIoError>()(
38
+ export class UnknownFlyIoError extends Schema.TaggedError<UnknownFlyIoError>()(
38
39
  "UnknownFlyIoError",
39
40
  {
40
41
  code: Schema.optional(Schema.String),
@@ -44,7 +45,7 @@ export class UnknownFlyIoError extends Schema.TaggedErrorClass<UnknownFlyIoError
44
45
  ).pipe(Category.withServerError) {}
45
46
 
46
47
  /** Schema parse error wrapper. */
47
- export class FlyIoParseError extends Schema.TaggedErrorClass<FlyIoParseError>()(
48
+ export class FlyIoParseError extends Schema.TaggedError<FlyIoParseError>()(
48
49
  "FlyIoParseError",
49
50
  {
50
51
  body: Schema.Unknown,
@@ -52,6 +53,44 @@ export class FlyIoParseError extends Schema.TaggedErrorClass<FlyIoParseError>()(
52
53
  },
53
54
  ).pipe(Category.withParseError) {}
54
55
 
56
+ /**
57
+ * Sprites is not enabled for the Fly organization that owns `FLY_API_TOKEN`.
58
+ *
59
+ * Returned by `POST /v1/organizations/{org}/tokens` as HTTP 401 with a
60
+ * message matching `sprites not enabled`. Sprite CRUD never sees a
61
+ * `SPRITES_TOKEN` — this is the mint-time entitlement signal.
62
+ */
63
+ export class SpritesNotEnabled extends Schema.TaggedError<SpritesNotEnabled>()(
64
+ "SpritesNotEnabled",
65
+ {
66
+ code: Schema.optional(Schema.Int),
67
+ message: Schema.optional(Schema.String),
68
+ },
69
+ ).pipe(Category.withAuthError) {}
70
+ applyErrorMatchers(SpritesNotEnabled, [
71
+ { status: 401, message: { matches: "[Ss]prites not enabled" } },
72
+ ]);
73
+
74
+ /**
75
+ * The Fly token cannot record add-on provider ToS agreement
76
+ * (`createExtensionTosAgreement`). GraphQL returns this as a 200
77
+ * with `Not authorized to access this createextensiontosagreement`.
78
+ */
79
+ export class CreateExtensionTosAgreementNotAuthorized extends Schema.TaggedError<CreateExtensionTosAgreementNotAuthorized>()(
80
+ "CreateExtensionTosAgreementNotAuthorized",
81
+ {
82
+ code: Schema.optional(Schema.Int),
83
+ message: Schema.optional(Schema.String),
84
+ },
85
+ ).pipe(Category.withAuthError) {}
86
+ applyErrorMatchers(CreateExtensionTosAgreementNotAuthorized, [
87
+ {
88
+ message: {
89
+ matches: "[Nn]ot authorized to access this createextensiontosagreement",
90
+ },
91
+ },
92
+ ]);
93
+
55
94
  /**
56
95
  * Errors any Fly.io operation may surface in addition to the status-mapped
57
96
  * per-operation errors.
package/src/index.ts CHANGED
@@ -4,14 +4,45 @@
4
4
  * `./services` is generated by `scripts/generate.ts` from the Smithy model
5
5
  * written by `scripts/convert.ts` (OpenAPI → Smithy via the shared core
6
6
  * converter). Everything else in this folder is hand-written.
7
+ *
8
+ * The generated barrel is re-exported at the package root, same as every
9
+ * other distilled SDK's service modules:
10
+ *
11
+ * @example Package namespace
12
+ * ```ts
13
+ * import * as Fly from "@distilled.cloud/fly-io";
14
+ *
15
+ * yield* Fly.machines.listApps({ org_slug });
16
+ * yield* Fly.mpg.createCluster({
17
+ * name, region, org_slug, plan, pg_major_version: "16", storage_in_gb: 10,
18
+ * });
19
+ * yield* Fly.addons.createAddOn({
20
+ * input: { type: "tigris", name, options: { website: { domain_name: "" } } },
21
+ * });
22
+ * yield* Fly.sprites.createSprite({ name, labels: ["alchemy"] });
23
+ * ```
24
+ *
25
+ * @example Per-service path
26
+ * ```ts
27
+ * import * as Machines from "@distilled.cloud/fly-io/machines";
28
+ *
29
+ * yield* Machines.listApps({ org_slug });
30
+ * ```
7
31
  */
8
32
  export * from "./credentials.ts";
9
33
  export * from "./errors.ts";
10
34
  export * as T from "./traits.ts";
11
35
  export {
12
36
  FlyIoProtocol,
37
+ FlyApiProtocol,
38
+ FlyGraphqlProtocol,
39
+ SpritesProtocol,
40
+ MachineIdentity,
13
41
  type FlyIoOpError,
14
42
  type FlyIoOpContext,
43
+ type SpritesOpError,
44
+ type SpritesOpContext,
15
45
  } from "./protocol.ts";
16
46
  export * as Retry from "./retry.ts";
17
- export * as Services from "./services/index.ts";
47
+ export * as Pagination from "./pagination.ts";
48
+ export * from "./services/index.ts";
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Fly.io pagination — cursor (Sprites list) and Relay (GraphQL add-ons).
3
+ */
4
+ export {
5
+ paginateCursor,
6
+ paginateRelay,
7
+ extractItems,
8
+ getItems,
9
+ getPath,
10
+ type PaginatedTrait,
11
+ type PaginationStrategy,
12
+ } from "@distilled.cloud/core/pagination";