@miosa/sdk 3.3.1 → 3.4.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.
- package/dist/index.d.ts +194 -11
- package/dist/index.js +306 -46
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as ws from 'ws';
|
|
2
2
|
import EventEmitter from 'node:events';
|
|
3
|
+
import * as http2 from 'node:http2';
|
|
3
4
|
|
|
4
5
|
interface RequestOptions {
|
|
5
6
|
method?: string;
|
|
@@ -2243,6 +2244,13 @@ interface MiosaClientConfig {
|
|
|
2243
2244
|
region?: string;
|
|
2244
2245
|
/** Overrides `miosa.ai` - for self-hosted / test deployments. */
|
|
2245
2246
|
baseDomain?: string;
|
|
2247
|
+
/**
|
|
2248
|
+
* Pin each runner session group to one resolved IPv4 address, so
|
|
2249
|
+
* `run-<region>.miosa.ai`'s several A records are all used. Set `false`
|
|
2250
|
+
* to dial the hostname and let the OS resolver choose instead.
|
|
2251
|
+
* Defaults to `true`.
|
|
2252
|
+
*/
|
|
2253
|
+
pinAddresses?: boolean;
|
|
2246
2254
|
};
|
|
2247
2255
|
}
|
|
2248
2256
|
|
|
@@ -8855,8 +8863,22 @@ interface RunnerClientOptions {
|
|
|
8855
8863
|
tenant?: string;
|
|
8856
8864
|
/** Sessions opened per resolved region address. C6 default: 8. */
|
|
8857
8865
|
sessionsPerAddress?: number;
|
|
8866
|
+
/**
|
|
8867
|
+
* Pin each session group to one resolved runner address (C6), so creates
|
|
8868
|
+
* spread over every host behind `run-<region>.miosa.ai`. Set `false` to
|
|
8869
|
+
* dial the hostname and let the OS resolver choose instead. Defaults to
|
|
8870
|
+
* `true`; only consulted when `transport` is not injected.
|
|
8871
|
+
*/
|
|
8872
|
+
pinAddresses?: boolean;
|
|
8858
8873
|
/** Injectable for tests; defaults to the best available transport. */
|
|
8859
8874
|
transport?: RunnerTransport;
|
|
8875
|
+
/**
|
|
8876
|
+
* Race HTTP/3 against HTTP/2 per region host. Default false: HTTP/2 only.
|
|
8877
|
+
* See transport-factory.ts for why the race is opt-in - on a cold burst the
|
|
8878
|
+
* promotion can land requests on HTTP/3 sessions that are not yet carrying
|
|
8879
|
+
* traffic, which costs several times what HTTP/2 does.
|
|
8880
|
+
*/
|
|
8881
|
+
http3?: boolean;
|
|
8860
8882
|
/**
|
|
8861
8883
|
* Called for a create the runner doesn't serve (C2: template, image,
|
|
8862
8884
|
* snapshot, cwd, persistent, non-xs shapes) - wired by `Miosa` to
|
|
@@ -9003,6 +9025,13 @@ declare class RunnerClient {
|
|
|
9003
9025
|
private readonly addressIndexByTag;
|
|
9004
9026
|
/** sandbox id -> tag, set only once a 421 corrects the id-derived guess. */
|
|
9005
9027
|
private readonly correctedTag;
|
|
9028
|
+
/**
|
|
9029
|
+
* Rotating start address for creates, so a cold burst spreads over every
|
|
9030
|
+
* resolved runner address instead of all of it landing on address 0.
|
|
9031
|
+
* Advanced once per create; the retry on `429 runtime_busy`/connect
|
|
9032
|
+
* failure still walks the other addresses from there.
|
|
9033
|
+
*/
|
|
9034
|
+
private createCursor;
|
|
9006
9035
|
constructor(options: RunnerClientOptions);
|
|
9007
9036
|
get protocol(): RunnerProtocol;
|
|
9008
9037
|
/** The tag a 421 has corrected sandboxId to, if any. */
|
|
@@ -9510,17 +9539,32 @@ declare function sandboxTag(sandboxId: string): string;
|
|
|
9510
9539
|
/** Resolves a hostname to the list of IP addresses it should be reached at. */
|
|
9511
9540
|
interface AddressResolver {
|
|
9512
9541
|
resolve(hostname: string): Promise<string[]>;
|
|
9542
|
+
/**
|
|
9543
|
+
* Forgets anything cached for `hostname`, so the next `resolve` asks the
|
|
9544
|
+
* OS resolver again. The transports call this after a per-address connect
|
|
9545
|
+
* failure: a runner host that has moved, or whose address has gone away,
|
|
9546
|
+
* is re-resolved rather than retried at a stale address for the rest of
|
|
9547
|
+
* the cache window. Optional - a resolver with nothing to cache omits it.
|
|
9548
|
+
*/
|
|
9549
|
+
invalidate?(hostname: string): void;
|
|
9513
9550
|
}
|
|
9551
|
+
/** Resolves a hostname straight to its list of IPv4 addresses, in resolver order. */
|
|
9552
|
+
type AddressLookup = (hostname: string) => Promise<string[]>;
|
|
9514
9553
|
/**
|
|
9515
|
-
* Default resolver:
|
|
9516
|
-
*
|
|
9517
|
-
*
|
|
9554
|
+
* Default resolver: every IPv4 address of the hostname, cached for a short
|
|
9555
|
+
* TTL (60 s - the runners' advertised A-record TTL) so a burst of requests
|
|
9556
|
+
* resolves once instead of hitting the resolver per request. IP literals
|
|
9557
|
+
* and `localhost` are passed through unchanged so tests and self-hosted
|
|
9558
|
+
* runners can point the transport straight at a fixed address without a
|
|
9559
|
+
* resolver.
|
|
9518
9560
|
*/
|
|
9519
9561
|
declare class DnsAddressResolver implements AddressResolver {
|
|
9520
9562
|
private readonly ttlMs;
|
|
9563
|
+
private readonly lookupAddresses;
|
|
9521
9564
|
private readonly cache;
|
|
9522
|
-
constructor(ttlMs?: number);
|
|
9565
|
+
constructor(ttlMs?: number, lookupAddresses?: AddressLookup);
|
|
9523
9566
|
resolve(hostname: string): Promise<string[]>;
|
|
9567
|
+
invalidate(hostname: string): void;
|
|
9524
9568
|
}
|
|
9525
9569
|
/** A fixed-table resolver, for tests and for pinning to known runner IPs (C1). */
|
|
9526
9570
|
declare class StaticAddressResolver implements AddressResolver {
|
|
@@ -9551,8 +9595,23 @@ declare class StaticAddressResolver implements AddressResolver {
|
|
|
9551
9595
|
* coalescing: the cert covers `run-<region>.miosa.ai` and
|
|
9552
9596
|
* `*.run-<region>.miosa.ai`, and a per-host name's one A record is the
|
|
9553
9597
|
* same IP already in this pool - see transport.ts's doc comment).
|
|
9598
|
+
*
|
|
9599
|
+
* Pinning is what makes the dial target explicit: the hostname is resolved
|
|
9600
|
+
* once, and every session dials its own resolved IP while SNI and the
|
|
9601
|
+
* HTTP/2 `:authority` stay the hostname, so a name with several A records
|
|
9602
|
+
* spreads over all of them deterministically instead of wherever the OS
|
|
9603
|
+
* resolver happens to point. `pinAddresses: false` turns this off and dials
|
|
9604
|
+
* the hostname itself, letting the OS resolver choose (one address, the
|
|
9605
|
+
* pre-pinning behaviour). A per-address connect failure drops that
|
|
9606
|
+
* address's sessions, invalidates the resolver's cache and re-resolves, so
|
|
9607
|
+
* a host that has moved is not retried at a stale address.
|
|
9554
9608
|
*/
|
|
9555
9609
|
|
|
9610
|
+
/**
|
|
9611
|
+
* The dial itself, injectable so tests can observe (and selectively fail)
|
|
9612
|
+
* which address a session is opened against without a real socket.
|
|
9613
|
+
*/
|
|
9614
|
+
type Http2Connector = (authority: string, options: http2.SecureClientSessionOptions) => http2.ClientHttp2Session;
|
|
9556
9615
|
interface Http2TransportOptions {
|
|
9557
9616
|
/** Sessions opened per address when no explicit count is given. C6 default: 8. */
|
|
9558
9617
|
defaultSessionsPerAddress?: number;
|
|
@@ -9562,6 +9621,17 @@ interface Http2TransportOptions {
|
|
|
9562
9621
|
resolver?: AddressResolver;
|
|
9563
9622
|
/** Default per-request timeout when the caller doesn't set one. */
|
|
9564
9623
|
defaultTimeoutMs?: number;
|
|
9624
|
+
/**
|
|
9625
|
+
* Pin every session group to one resolved IPv4 address (C6), so a name
|
|
9626
|
+
* with several A records is dialled at all of them deliberately. Set
|
|
9627
|
+
* `false` to dial the hostname itself and let the OS resolver pick - the
|
|
9628
|
+
* pre-pinning behaviour, one address only. Defaults to `true`.
|
|
9629
|
+
*/
|
|
9630
|
+
pinAddresses?: boolean;
|
|
9631
|
+
/** Skips TLS certificate verification. Test-only - never set true in production. */
|
|
9632
|
+
insecure?: boolean;
|
|
9633
|
+
/** Injectable for tests; defaults to `node:http2`'s connect. */
|
|
9634
|
+
connect?: Http2Connector;
|
|
9565
9635
|
}
|
|
9566
9636
|
declare class Http2Transport implements RunnerTransport {
|
|
9567
9637
|
readonly protocol: "h2";
|
|
@@ -9570,7 +9640,16 @@ declare class Http2Transport implements RunnerTransport {
|
|
|
9570
9640
|
private readonly port;
|
|
9571
9641
|
private readonly resolver;
|
|
9572
9642
|
private readonly defaultTimeoutMs;
|
|
9643
|
+
private readonly pinAddresses;
|
|
9644
|
+
private readonly insecure;
|
|
9645
|
+
private readonly dial;
|
|
9573
9646
|
private readonly pools;
|
|
9647
|
+
/**
|
|
9648
|
+
* Requests in flight per session. A pooled session is unref'd while idle so
|
|
9649
|
+
* a process that only imported the client (or finished its last request)
|
|
9650
|
+
* still exits; it is ref'd again for exactly as long as it carries a request.
|
|
9651
|
+
*/
|
|
9652
|
+
private readonly inFlight;
|
|
9574
9653
|
constructor(options?: Http2TransportOptions);
|
|
9575
9654
|
prewarm(regionHostname: string, sessionsPerAddress?: number): void;
|
|
9576
9655
|
addressCount(regionHostname: string): Promise<number>;
|
|
@@ -9582,7 +9661,40 @@ declare class Http2Transport implements RunnerTransport {
|
|
|
9582
9661
|
close(): Promise<void>;
|
|
9583
9662
|
private poolFor;
|
|
9584
9663
|
private buildPool;
|
|
9664
|
+
/**
|
|
9665
|
+
* The addresses this pool pins to. With pinning on, every IPv4 address
|
|
9666
|
+
* the hostname resolves to; with it off, the hostname itself - one entry,
|
|
9667
|
+
* dialled as-is so the OS resolver chooses.
|
|
9668
|
+
*/
|
|
9669
|
+
private resolveAddresses;
|
|
9670
|
+
/**
|
|
9671
|
+
* Opens `sessionsPerAddress` sessions against one address, in parallel.
|
|
9672
|
+
* sessionsPerAddress: 0 is a deliberate "open nothing" (e.g. a count-only
|
|
9673
|
+
* probe).
|
|
9674
|
+
*/
|
|
9675
|
+
private openGroup;
|
|
9676
|
+
/** Closes a session slot once it connects, ignoring one that never did. */
|
|
9677
|
+
private closeSlot;
|
|
9678
|
+
/**
|
|
9679
|
+
* A session pinned to `address` failed to connect. Mark that address's
|
|
9680
|
+
* group for reopening and re-resolve in the background (single-flight),
|
|
9681
|
+
* so one dead address never costs every concurrent failure its own DNS
|
|
9682
|
+
* lookup. Never blocks or fails the request that is already on its way
|
|
9683
|
+
* out - the caller retries another index (C6's next-IP retry).
|
|
9684
|
+
*/
|
|
9685
|
+
private noteAddressFailure;
|
|
9686
|
+
/**
|
|
9687
|
+
* Re-resolves `regionHostname` and redistributes the pool over the fresh
|
|
9688
|
+
* addresses: the failed address's sessions are dropped and reopened, a
|
|
9689
|
+
* newly advertised address gets a group of its own, an address DNS no
|
|
9690
|
+
* longer lists loses its sessions, and every healthy address keeps the
|
|
9691
|
+
* sessions it already has - so a failure on one host never costs the rest
|
|
9692
|
+
* their warm connections.
|
|
9693
|
+
*/
|
|
9694
|
+
private rebuildPool;
|
|
9585
9695
|
private connectSession;
|
|
9696
|
+
private retain;
|
|
9697
|
+
private release;
|
|
9586
9698
|
private sendRequest;
|
|
9587
9699
|
private sendStreamRequest;
|
|
9588
9700
|
}
|
|
@@ -9611,6 +9723,12 @@ interface Http3Availability {
|
|
|
9611
9723
|
declare function detectHttp3Support(): Http3Availability;
|
|
9612
9724
|
/** Exposed for tests - clears the cached load result and availability. */
|
|
9613
9725
|
declare function resetHttp3DetectionCache(): void;
|
|
9726
|
+
/**
|
|
9727
|
+
* The connection handshake, injectable so tests can observe (and
|
|
9728
|
+
* selectively fail) which address a connection is opened against without a
|
|
9729
|
+
* native QUIC listener.
|
|
9730
|
+
*/
|
|
9731
|
+
type Http3Connector = (address: string, servername: string, port: number, insecure: boolean, connectTimeoutMs: number) => Promise<number>;
|
|
9614
9732
|
interface Http3TransportOptions {
|
|
9615
9733
|
/** Sessions opened per address when no explicit count is given. C6: 4. */
|
|
9616
9734
|
defaultSessionsPerAddress?: number;
|
|
@@ -9626,6 +9744,17 @@ interface Http3TransportOptions {
|
|
|
9626
9744
|
/** Skips certificate verification. Test-only - never set true in production. */
|
|
9627
9745
|
insecure?: boolean;
|
|
9628
9746
|
port?: number;
|
|
9747
|
+
/**
|
|
9748
|
+
* Pin every connection group to one resolved IPv4 address (C6), so a name
|
|
9749
|
+
* with several A records is dialled at all of them deliberately. Set
|
|
9750
|
+
* `false` to use only the hostname's first resolved address and let the
|
|
9751
|
+
* OS resolver pick which that is - one target, the pre-pinning shape (the
|
|
9752
|
+
* native addon dials a literal address, so a hostname cannot be passed
|
|
9753
|
+
* through here). Defaults to `true`.
|
|
9754
|
+
*/
|
|
9755
|
+
pinAddresses?: boolean;
|
|
9756
|
+
/** Injectable for tests; defaults to the native addon's connect. */
|
|
9757
|
+
connect?: Http3Connector;
|
|
9629
9758
|
}
|
|
9630
9759
|
declare class Http3Transport implements RunnerTransport {
|
|
9631
9760
|
readonly protocol: "h3";
|
|
@@ -9636,6 +9765,8 @@ declare class Http3Transport implements RunnerTransport {
|
|
|
9636
9765
|
private readonly connectTimeoutMs;
|
|
9637
9766
|
private readonly insecure;
|
|
9638
9767
|
private readonly port;
|
|
9768
|
+
private readonly pinAddresses;
|
|
9769
|
+
private readonly dial;
|
|
9639
9770
|
private readonly pools;
|
|
9640
9771
|
constructor(options?: Http3TransportOptions);
|
|
9641
9772
|
prewarm(regionHostname: string, sessionsPerAddress?: number): void;
|
|
@@ -9654,23 +9785,67 @@ declare class Http3Transport implements RunnerTransport {
|
|
|
9654
9785
|
close(): Promise<void>;
|
|
9655
9786
|
private poolFor;
|
|
9656
9787
|
private buildPool;
|
|
9788
|
+
/**
|
|
9789
|
+
* The addresses this pool pins to. With pinning on, every IPv4 address
|
|
9790
|
+
* the hostname resolves to. With it off, the hostname is resolved once
|
|
9791
|
+
* and only its first address is kept - one target, chosen by the OS
|
|
9792
|
+
* resolver, which is the closest this transport can get to HTTP/2's
|
|
9793
|
+
* hostname dial: the native addon takes a literal socket address, never
|
|
9794
|
+
* a hostname.
|
|
9795
|
+
*/
|
|
9796
|
+
private resolveAddresses;
|
|
9797
|
+
/** Opens `sessionsPerAddress` connections against one address, in parallel. */
|
|
9798
|
+
private openGroup;
|
|
9799
|
+
/** Closes a connection slot once it connects, ignoring one that never did. */
|
|
9800
|
+
private closeSlot;
|
|
9801
|
+
/**
|
|
9802
|
+
* A connection pinned to `address` failed to connect. Mark that address's
|
|
9803
|
+
* group for reopening and re-resolve in the background (single-flight),
|
|
9804
|
+
* so one dead address never costs every concurrent failure its own DNS
|
|
9805
|
+
* lookup. Never blocks or fails the request already on its way out.
|
|
9806
|
+
*/
|
|
9807
|
+
private noteAddressFailure;
|
|
9808
|
+
/**
|
|
9809
|
+
* Re-resolves `regionHostname` and redistributes the pool over the fresh
|
|
9810
|
+
* addresses: the failed address's connections are dropped and reopened, a
|
|
9811
|
+
* newly advertised address gets a group of its own, an address DNS no
|
|
9812
|
+
* longer lists loses its connections, and every healthy address keeps the
|
|
9813
|
+
* connections it already has.
|
|
9814
|
+
*/
|
|
9815
|
+
private rebuildPool;
|
|
9657
9816
|
private connectSession;
|
|
9658
9817
|
private sendRequest;
|
|
9659
9818
|
}
|
|
9660
9819
|
|
|
9661
9820
|
/**
|
|
9662
|
-
* Picks the
|
|
9663
|
-
*
|
|
9664
|
-
*
|
|
9665
|
-
*
|
|
9666
|
-
*
|
|
9667
|
-
*
|
|
9668
|
-
* HTTP/2
|
|
9821
|
+
* Picks the transport for a region host.
|
|
9822
|
+
*
|
|
9823
|
+
* HTTP/2 unless the caller opts into racing HTTP/3 against it. A platform
|
|
9824
|
+
* with no native HTTP/3 addon is always HTTP/2 with zero QUIC probing
|
|
9825
|
+
* either way - see http3-transport.ts.
|
|
9826
|
+
*
|
|
9827
|
+
* Why HTTP/2 is the default rather than the race: on a cold burst the race
|
|
9828
|
+
* costs several times what HTTP/2 does. The promotion to HTTP/3 is decided
|
|
9829
|
+
* by address 0's *connection* being ready, while every request for that host
|
|
9830
|
+
* is then spread over all of its sessions, so a burst is dispatched onto
|
|
9831
|
+
* HTTP/3 sessions that have not carried a request yet. Measured on one region
|
|
9832
|
+
* host at c=100, alternating order, three runs each: TTI p50 203 / 221 / 267 ms
|
|
9833
|
+
* on the race against 51 / 53 / 50 ms on HTTP/2 at 4 sessions per address, and
|
|
9834
|
+
* 28 / 55 / 235 / 250 ms against 43 / 57 / 52 / 66 ms at the default 8. Once the
|
|
9835
|
+
* pool is genuinely warm HTTP/3 is the faster of the two, so it stays available
|
|
9836
|
+
* for callers who can pre-warm it; it is just not a safe default for the first
|
|
9837
|
+
* burst, and a first burst is what a latency benchmark measures.
|
|
9669
9838
|
*/
|
|
9670
9839
|
|
|
9671
9840
|
interface BestTransportOptions {
|
|
9672
9841
|
http2?: Http2TransportOptions;
|
|
9673
9842
|
http3?: Http3TransportOptions;
|
|
9843
|
+
/**
|
|
9844
|
+
* Race HTTP/3 against HTTP/2 per region host. Default false, for the reason
|
|
9845
|
+
* in this module's doc comment. HTTP/3 still only ever promotes a host for
|
|
9846
|
+
* *future* requests, so opting in never delays a request in flight.
|
|
9847
|
+
*/
|
|
9848
|
+
raceHttp3?: boolean | undefined;
|
|
9674
9849
|
}
|
|
9675
9850
|
interface BestTransportResult {
|
|
9676
9851
|
transport: RunnerTransport;
|
|
@@ -9766,6 +9941,14 @@ declare class RunnerError extends Error {
|
|
|
9766
9941
|
* two carries it.
|
|
9767
9942
|
*/
|
|
9768
9943
|
get isBusy(): boolean;
|
|
9944
|
+
/**
|
|
9945
|
+
* `429 rate_limited`: the key's own window on this runner has no room.
|
|
9946
|
+
*
|
|
9947
|
+
* Separate from `isBusy`, which means this runner's admission is full for
|
|
9948
|
+
* everyone. The limiter counts per key per runner, so a refusal here says
|
|
9949
|
+
* nothing about the next address, and `createSandbox` may try that one.
|
|
9950
|
+
*/
|
|
9951
|
+
get isRateLimited(): boolean;
|
|
9769
9952
|
/** C2: the runner doesn't serve this create shape at all - send it to api.miosa.ai instead. */
|
|
9770
9953
|
get isUnsupportedRequest(): boolean;
|
|
9771
9954
|
}
|