@molecule/api-code-sandbox-flyio 1.3.8 → 1.3.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +72 -139
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@ AUTO-GENERATED — DO NOT EDIT THIS FILE.
|
|
|
3
3
|
Generated by `mlcl sync-docs` from the package's src/index.ts JSDoc + mlcl/registry.json.
|
|
4
4
|
Edits here are overwritten on the next commit (molecule's pre-commit hook regenerates).
|
|
5
5
|
To change this document, edit the module-level JSDoc in src/index.ts.
|
|
6
|
-
Generated: 2026-11-
|
|
6
|
+
Generated: 2026-11-04T14:19:55.149Z
|
|
7
7
|
-->
|
|
8
8
|
|
|
9
9
|
# @molecule/api-code-sandbox-flyio
|
|
@@ -484,169 +484,95 @@ Every option is also readable from an environment variable (see
|
|
|
484
484
|
|
|
485
485
|
```typescript
|
|
486
486
|
interface FlyioConfig {
|
|
487
|
-
/**
|
|
488
|
-
* Fly API token (sent as `Authorization: Bearer <token>`). Falls back to
|
|
489
|
-
* `FLY_API_TOKEN`, then `FLY_ACCESS_TOKEN`. Required — the provider throws a
|
|
490
|
-
* named error on the first API call if none is resolvable.
|
|
491
|
-
*/
|
|
487
|
+
/** Fly API token (sent as `Authorization: Bearer <token>`). */
|
|
492
488
|
apiToken?: string
|
|
493
|
-
/**
|
|
494
|
-
* Machines API base URL, INCLUDING the `/v1` path segment. Defaults to
|
|
495
|
-
* `FLY_API_HOSTNAME` (with `/v1` appended when the value has no path) or
|
|
496
|
-
* `https://api.machines.dev/v1`. From inside a Fly private network the
|
|
497
|
-
* documented internal endpoint is `http://_api.internal:4280/v1`.
|
|
498
|
-
*/
|
|
489
|
+
/** Machines API base URL, INCLUDING the `/v1` path segment. */
|
|
499
490
|
apiUrl?: string
|
|
500
|
-
/**
|
|
501
|
-
* Fly organization slug that owns the sandbox apps. Falls back to
|
|
502
|
-
* `FLY_ORG_SLUG`, then `personal`. Required for app creation and for
|
|
503
|
-
* {@link FlyioConfig.appPerProject} listing.
|
|
504
|
-
*/
|
|
491
|
+
/** Fly organization slug that owns the sandbox apps. */
|
|
505
492
|
orgSlug?: string
|
|
506
|
-
/**
|
|
507
|
-
* Shared Fly app that holds every sandbox Machine. Only used when
|
|
508
|
-
* `appPerProject` is `false`. Falls back to `FLY_SANDBOX_APP`.
|
|
509
|
-
*
|
|
510
|
-
* A shared app puts every tenant on ONE 6PN private network, where each
|
|
511
|
-
* sandbox can reach every other sandbox's dev-server ports by private IPv6.
|
|
512
|
-
* That is the same cross-tenant exposure the Docker bond's `bridge` network
|
|
513
|
-
* has, so this mode is REFUSED in production.
|
|
514
|
-
*/
|
|
493
|
+
/** Shared Fly app that holds every sandbox Machine. */
|
|
515
494
|
appName?: string
|
|
516
|
-
/**
|
|
517
|
-
* Name prefix for the per-project Fly app when `appPerProject` is `true`
|
|
518
|
-
* (default). The app is `<appPrefix>-<sanitized projectId>`. Falls back to
|
|
519
|
-
* `FLY_SANDBOX_APP_PREFIX`, then `mol-sandbox`.
|
|
520
|
-
*/
|
|
495
|
+
/** Name prefix for the per-project Fly app when `appPerProject` is `true` (default). */
|
|
521
496
|
appPrefix?: string
|
|
522
|
-
/**
|
|
523
|
-
* Create one Fly app — on its own custom 6PN private network — per project,
|
|
524
|
-
* so tenants are network-isolated from each other. Defaults to `true`.
|
|
525
|
-
* Set `false` (or `FLY_SANDBOX_APP_PER_PROJECT=false`) only for a
|
|
526
|
-
* single-tenant deployment; it is refused in production.
|
|
527
|
-
*/
|
|
497
|
+
/** Create one Fly app — on its own custom 6PN private network — per project, so tenants are network-isolated from each other. */
|
|
528
498
|
appPerProject?: boolean
|
|
529
|
-
/**
|
|
530
|
-
* Custom 6PN network name for a per-project app. Defaults to the app name, so
|
|
531
|
-
* every project lands on its own private network. Ignored when
|
|
532
|
-
* `appPerProject` is `false`. A Fly app's network CANNOT be changed after
|
|
533
|
-
* creation.
|
|
534
|
-
*/
|
|
499
|
+
/** Custom 6PN network name for a per-project app. */
|
|
535
500
|
network?: string
|
|
536
|
-
/**
|
|
537
|
-
* Default Fly region for Machines and volumes (e.g. `iad`). Defaults to
|
|
538
|
-
* `iad`; `SandboxConfig.region` overrides it for one recorded project create.
|
|
539
|
-
* The API Machine's own `FLY_REGION` is never a tenant-placement fallback.
|
|
540
|
-
*/
|
|
501
|
+
/** Default Fly region for Machines and volumes (e.g. `iad`). */
|
|
541
502
|
region?: string
|
|
542
|
-
/**
|
|
543
|
-
* OCI image every sandbox Machine runs. Must be pullable by Fly — a tag in
|
|
544
|
-
* the org's `registry.fly.io` repository or a public registry. A LOCAL
|
|
545
|
-
* `molecule-sandbox:latest` is not reachable by Fly; push it first. Falls
|
|
546
|
-
* back to `FLY_SANDBOX_IMAGE`, then `registry.fly.io/molecule-sandbox:latest`.
|
|
547
|
-
*/
|
|
503
|
+
/** OCI image every sandbox Machine runs. */
|
|
548
504
|
baseImage?: string
|
|
549
|
-
/** Default vCPU count (`guest.cpus`).
|
|
505
|
+
/** Default vCPU count (`guest.cpus`). */
|
|
550
506
|
defaultCpu?: number
|
|
551
|
-
/** Default `guest.cpu_kind` — `shared` or `performance`.
|
|
507
|
+
/** Default `guest.cpu_kind` — `shared` or `performance`. */
|
|
552
508
|
defaultCpuKind?: string
|
|
553
|
-
/** Default memory in MB (`guest.memory_mb`).
|
|
509
|
+
/** Default memory in MB (`guest.memory_mb`). */
|
|
554
510
|
defaultMemoryMB?: number
|
|
555
|
-
/**
|
|
556
|
-
* Size in GB of the volume created for a sandbox's `/workspace` when
|
|
557
|
-
* `SandboxConfig.volumeName` is set. Fly volumes are sized in whole GB, so the
|
|
558
|
-
* core's `resources.diskMB` is rounded UP to the next GB. Defaults to 10.
|
|
559
|
-
*/
|
|
511
|
+
/** Size in GB of the volume created for a sandbox's `/workspace` when `SandboxConfig.volumeName` is set. */
|
|
560
512
|
defaultVolumeGB?: number
|
|
561
|
-
/** Internal port the preview service forwards to (the Vite dev server).
|
|
513
|
+
/** Internal port the preview service forwards to (the Vite dev server). */
|
|
562
514
|
previewPort?: number
|
|
563
|
-
/**
|
|
564
|
-
* Preview URL template. Placeholders `{app}`, `{machineId}` and `{port}` are
|
|
565
|
-
* all replaced globally. Defaults to `https://{app}.fly.dev`.
|
|
566
|
-
*
|
|
567
|
-
* For a control plane that runs on the SAME Fly 6PN, the private form
|
|
568
|
-
* `http://{machineId}.vm.{app}.internal:{port}` reaches the Machine with no
|
|
569
|
-
* public exposure at all — but it does NOT work across custom 6PNs, which is
|
|
570
|
-
* exactly what `appPerProject` creates. See the module `@remarks`.
|
|
571
|
-
*/
|
|
515
|
+
/** Preview URL template. */
|
|
572
516
|
previewUrlTemplate?: string
|
|
573
|
-
/**
|
|
574
|
-
* Attach a public Fly Proxy service (`80` → http, `443` → tls+http) forwarding
|
|
575
|
-
* to {@link FlyioConfig.previewPort}. Defaults to `true`. Set `false` for a
|
|
576
|
-
* fully private sandbox reached only over 6PN/Flycast.
|
|
577
|
-
*/
|
|
517
|
+
/** Attach a public Fly Proxy service (`80` → http, `443` → tls+http) forwarding to {@link FlyioConfig.previewPort}. */
|
|
578
518
|
publicService?: boolean
|
|
579
|
-
/**
|
|
580
|
-
* Fly Proxy idle behaviour for the preview service. Defaults to `'off'` —
|
|
581
|
-
* never idle the Machine — because the autostop timer counts the PROXY
|
|
582
|
-
* service's idle time, not the workload's, so a sandbox with nobody looking at
|
|
583
|
-
* its preview is suspended out from under a build that is still running.
|
|
584
|
-
* `suspend` is the scale-to-zero mapping (resume from a memory snapshot on the
|
|
585
|
-
* next request) and `stop` is a full stop with a cold boot on wake; opt into
|
|
586
|
-
* either deliberately.
|
|
587
|
-
*
|
|
588
|
-
* This is the provider's STEADY-STATE policy, reported as
|
|
589
|
-
* `SandboxProvider.defaultIdleAction`. A caller can override it for one sandbox
|
|
590
|
-
* with `SandboxConfig.idleAction` and restore this value afterwards with
|
|
591
|
-
* `Sandbox.setIdleAction` — which is what a production deploy does so its
|
|
592
|
-
* destination cannot suspend mid-copy.
|
|
593
|
-
*/
|
|
519
|
+
/** Fly Proxy idle behaviour for the preview service. */
|
|
594
520
|
autostop?: 'off' | 'stop' | 'suspend'
|
|
595
|
-
/**
|
|
596
|
-
* Allocate a shared Anycast IPv4 for a newly-created app so `<app>.fly.dev`
|
|
597
|
-
* serves traffic. Defaults to `false` (opt-in). See the module `@remarks` —
|
|
598
|
-
* the accepted `type` values for the IP-assignment endpoint are NOT enumerated
|
|
599
|
-
* in Fly's OpenAPI specification.
|
|
600
|
-
*/
|
|
521
|
+
/** Allocate a shared Anycast IPv4 for a newly-created app so `<app>.fly.dev` serves traffic. */
|
|
601
522
|
assignSharedIpv4?: boolean
|
|
602
|
-
/** IP type requested when {@link FlyioConfig.assignSharedIpv4} is on.
|
|
523
|
+
/** IP type requested when {@link FlyioConfig.assignSharedIpv4} is on. */
|
|
603
524
|
ipAssignmentType?: string
|
|
604
|
-
/** Prefix for the Machine metadata keys this provider owns.
|
|
525
|
+
/** Prefix for the Machine metadata keys this provider owns. */
|
|
605
526
|
metadataPrefix?: string
|
|
606
|
-
/** Durable create-attempt ownership.
|
|
527
|
+
/** Durable create-attempt ownership. */
|
|
607
528
|
createAttemptJournal?: FlyCreateAttemptJournal
|
|
608
|
-
/** Timeout for a single Machines API request, in ms.
|
|
529
|
+
/** Timeout for a single Machines API request, in ms. */
|
|
609
530
|
requestTimeoutMs?: number
|
|
610
|
-
/**
|
|
611
|
-
* TOTAL budget, in seconds, that `create()`/`start()`/`wake()` block waiting
|
|
612
|
-
* for the Machine to actually reach `started`. Fly's `GET .../wait` blocks
|
|
613
|
-
* for at most 60 seconds per call, so a larger budget is spent as consecutive
|
|
614
|
-
* wait rounds. Defaults to 180 — a Machine whose image is not yet cached on
|
|
615
|
-
* its host (every first boot after an image push) pulls it before starting,
|
|
616
|
-
* and that alone can exceed a single 60 s round.
|
|
617
|
-
*
|
|
618
|
-
* Without this wait, `start()` resolves the moment Fly ACCEPTS the request,
|
|
619
|
-
* and the caller's very next `exec` hits a Machine that is not running yet.
|
|
620
|
-
*/
|
|
531
|
+
/** TOTAL budget, in seconds, that `create()`/`start()`/`wake()` block waiting for the Machine to actually reach `started`. */
|
|
621
532
|
startTimeoutSeconds?: number
|
|
622
|
-
/**
|
|
623
|
-
* Ports a sandbox Machine may open outbound connections on. Setting this makes
|
|
624
|
-
* the provider apply a Fly **network policy** to every app it provisions;
|
|
625
|
-
* leaving it unset applies no policy at all, and `verifyEgress()` will then
|
|
626
|
-
* observe (correctly) that egress is `open`. Falls back to
|
|
627
|
-
* `FLY_SANDBOX_EGRESS_ALLOWED_PORTS` (`tcp:3128,udp:53`).
|
|
628
|
-
*
|
|
629
|
-
* Read {@link https://fly.io/docs/machines/guides-examples/network-policies/}
|
|
630
|
-
* before choosing a value, because the mechanism is narrower than it looks:
|
|
631
|
-
* rules match protocol and port ONLY — no host, no CIDR, no ranges — so this
|
|
632
|
-
* can never be a host allowlist. `tcp:443` lets a sandbox reach EVERY host on
|
|
633
|
-
* the internet that listens on 443. To get a host allowlist, allow only the
|
|
634
|
-
* port of an egress proxy you control and route sandbox traffic through it.
|
|
635
|
-
*
|
|
636
|
-
* An empty array is rejected rather than treated as "deny all": Fly documents
|
|
637
|
-
* the deny default as a consequence of an `allow` rule existing, and says
|
|
638
|
-
* nothing about a rule with no ports.
|
|
639
|
-
*/
|
|
533
|
+
/** Ports a sandbox Machine may open outbound connections on. */
|
|
640
534
|
egressAllowedPorts?: FlyNetworkPolicyPort[]
|
|
641
|
-
/** Name of the egress policy this provider owns on each app.
|
|
535
|
+
/** Name of the egress policy this provider owns on each app. */
|
|
642
536
|
egressPolicyName?: string
|
|
643
|
-
/**
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
537
|
+
/** Apps every sandbox must be able to reach ACROSS its per-project 6PN — the tenant Postgres cluster and the control plane's egress proxy. */
|
|
538
|
+
privateServices?: FlyPrivateService[]
|
|
539
|
+
/** Per-create regional overrides for {@link FlyioConfig.privateServices}. */
|
|
540
|
+
privateServicesByRegion?: Record<string, FlyPrivateService[]>
|
|
541
|
+
/** `type` sent to `POST /apps/{app}/ip_assignments` when allocating a Flycast address. */
|
|
542
|
+
privateIpAssignmentType?: string
|
|
543
|
+
/** Literal `ip:port` targets `verifyEgress()` attempts raw TCP connections to. */
|
|
544
|
+
egressProbeTargets?: string[]
|
|
545
|
+
/** Per-connection timeout for the egress probe, in ms. */
|
|
546
|
+
egressProbeTimeoutMs?: number
|
|
547
|
+
/** Image the throwaway `verifyEgress()` probe Machine runs. */
|
|
548
|
+
egressProbeImage?: string
|
|
549
|
+
/** Bucket holding sandbox templates. */
|
|
550
|
+
templateBucket?: string
|
|
551
|
+
/** S3 endpoint for {@link FlyioConfig.templateBucket}, e.g. Tigris's `https://t3.storage.dev`. */
|
|
552
|
+
templateEndpoint?: string
|
|
553
|
+
/** Region used to sign template-store requests. */
|
|
554
|
+
templateRegion?: string
|
|
555
|
+
/** Access key for the template store. */
|
|
556
|
+
templateAccessKeyId?: string
|
|
557
|
+
/** Secret key for the template store. */
|
|
558
|
+
templateSecretAccessKey?: string
|
|
559
|
+
/** Session token for temporary template-store credentials. */
|
|
560
|
+
templateSessionToken?: string
|
|
561
|
+
/** Key prefix every template object lives under. */
|
|
562
|
+
templatePrefix?: string
|
|
563
|
+
/** Address the template bucket path-style (`https://endpoint/bucket/key`) instead of virtual-host style. */
|
|
564
|
+
templateForcePathStyle?: boolean
|
|
565
|
+
/** Lifetime of the presigned capture/restore URL handed to a sandbox, in seconds. */
|
|
566
|
+
templateUrlExpirySeconds?: number
|
|
567
|
+
/** Wall-clock budget for one capture or restore transfer, in ms. */
|
|
568
|
+
templateTransferTimeoutMs?: number
|
|
569
|
+
/** Largest template archive this provider will store, in bytes. */
|
|
570
|
+
templateMaxArchiveBytes?: number
|
|
571
|
+
}
|
|
648
572
|
```
|
|
649
573
|
|
|
574
|
+
_(Member comments are shortened to their first sentence to fit; the full declaration is in `node_modules/@molecule/api-code-sandbox-flyio/dist/types.d.ts`.)_
|
|
575
|
+
|
|
650
576
|
#### `ProcessEnv`
|
|
651
577
|
|
|
652
578
|
Environment variables the Fly.io sandbox provider reads. Every one is
|
|
@@ -1605,8 +1531,15 @@ its own 6PN: under a policy allowing only `udp:53`, `molecule-pg-tenant.flycast`
|
|
|
1605
1531
|
and `molecule-api.flycast` both RESOLVED and every TCP connect to them was
|
|
1606
1532
|
dropped; re-applying the policy with `tcp:443` opened 443 and nothing else.
|
|
1607
1533
|
Fly's sentence is about INGRESS — a Machine's egress TOWARD a Flycast address
|
|
1608
|
-
|
|
1609
|
-
|
|
1534
|
+
is filtered like any other. Drop a declared service's port and every database
|
|
1535
|
+
connection in the fleet goes with it.
|
|
1536
|
+
|
|
1537
|
+
The cost of each derived port, stated plainly because a Fly policy has no
|
|
1538
|
+
destination field of any kind (also measured — see the `egress.ts` module
|
|
1539
|
+
description): the port is opened to EVERY host on the internet, not only to
|
|
1540
|
+
the private service it was derived for. That residual cannot be closed at this
|
|
1541
|
+
layer; it is named in `verifyEgress()`'s verdict and in
|
|
1542
|
+
`docs/sandbox-egress-enforcement.md`.
|
|
1610
1543
|
|
|
1611
1544
|
```typescript
|
|
1612
1545
|
function mergeEgressPorts(
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@molecule/api-code-sandbox-flyio",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.9",
|
|
4
4
|
"description": "Fly.io Machines (Firecracker microVM) code sandbox provider",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"license": "Apache-2.0",
|
|
32
32
|
"devDependencies": {
|
|
33
33
|
"@molecule/api-bond": "1.0.4",
|
|
34
|
-
"@molecule/api-code-sandbox": "1.
|
|
34
|
+
"@molecule/api-code-sandbox": "1.6.1",
|
|
35
35
|
"@types/node": "26.6.5",
|
|
36
36
|
"typescript": "6.0.3",
|
|
37
37
|
"vitest": "4.1.12"
|