@promigence/sdk 0.1.0-beta.12

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 (104) hide show
  1. package/NOTICE +14 -0
  2. package/README.md +54 -0
  3. package/dist/blake3.d.ts +10 -0
  4. package/dist/blake3.js +111 -0
  5. package/dist/bundle.d.ts +96 -0
  6. package/dist/bundle.js +227 -0
  7. package/dist/ca-guard.d.ts +1 -0
  8. package/dist/ca-guard.js +166 -0
  9. package/dist/caller.d.ts +73 -0
  10. package/dist/caller.js +47 -0
  11. package/dist/cjs/blake3.d.ts +10 -0
  12. package/dist/cjs/blake3.js +116 -0
  13. package/dist/cjs/bundle.d.ts +96 -0
  14. package/dist/cjs/bundle.js +242 -0
  15. package/dist/cjs/ca-guard.d.ts +1 -0
  16. package/dist/cjs/ca-guard.js +174 -0
  17. package/dist/cjs/caller.d.ts +73 -0
  18. package/dist/cjs/caller.js +57 -0
  19. package/dist/cjs/client.d.ts +3015 -0
  20. package/dist/cjs/client.js +2617 -0
  21. package/dist/cjs/command-errors.d.ts +41 -0
  22. package/dist/cjs/command-errors.js +43 -0
  23. package/dist/cjs/context.d.ts +119 -0
  24. package/dist/cjs/context.js +598 -0
  25. package/dist/cjs/core.d.ts +285 -0
  26. package/dist/cjs/core.js +290 -0
  27. package/dist/cjs/credstore.d.ts +90 -0
  28. package/dist/cjs/credstore.js +219 -0
  29. package/dist/cjs/dispatcher.d.ts +58 -0
  30. package/dist/cjs/dispatcher.js +91 -0
  31. package/dist/cjs/github.d.ts +158 -0
  32. package/dist/cjs/github.js +84 -0
  33. package/dist/cjs/gitlab.d.ts +104 -0
  34. package/dist/cjs/gitlab.js +24 -0
  35. package/dist/cjs/handles.d.ts +82 -0
  36. package/dist/cjs/handles.js +139 -0
  37. package/dist/cjs/hint.d.ts +1 -0
  38. package/dist/cjs/hint.js +10 -0
  39. package/dist/cjs/http2.d.ts +206 -0
  40. package/dist/cjs/http2.js +1932 -0
  41. package/dist/cjs/index.d.ts +34 -0
  42. package/dist/cjs/index.js +31 -0
  43. package/dist/cjs/keyed.gen.d.ts +1 -0
  44. package/dist/cjs/keyed.gen.js +10 -0
  45. package/dist/cjs/models.gen.d.ts +6162 -0
  46. package/dist/cjs/models.gen.js +2 -0
  47. package/dist/cjs/package.json +1 -0
  48. package/dist/cjs/proxy.d.ts +40 -0
  49. package/dist/cjs/proxy.js +257 -0
  50. package/dist/cjs/pty.d.ts +171 -0
  51. package/dist/cjs/pty.js +504 -0
  52. package/dist/cjs/sandbox.d.ts +537 -0
  53. package/dist/cjs/sandbox.js +736 -0
  54. package/dist/cjs/ssh.d.ts +25 -0
  55. package/dist/cjs/ssh.js +117 -0
  56. package/dist/cjs/trace.d.ts +33 -0
  57. package/dist/cjs/trace.js +88 -0
  58. package/dist/cjs/transport-worker.d.ts +1 -0
  59. package/dist/cjs/transport-worker.js +468 -0
  60. package/dist/cjs/warm.d.ts +1 -0
  61. package/dist/cjs/warm.js +43 -0
  62. package/dist/client.d.ts +3015 -0
  63. package/dist/client.js +2583 -0
  64. package/dist/command-errors.d.ts +41 -0
  65. package/dist/command-errors.js +36 -0
  66. package/dist/context.d.ts +119 -0
  67. package/dist/context.js +588 -0
  68. package/dist/core.d.ts +285 -0
  69. package/dist/core.js +266 -0
  70. package/dist/credstore.d.ts +90 -0
  71. package/dist/credstore.js +206 -0
  72. package/dist/dispatcher.d.ts +58 -0
  73. package/dist/dispatcher.js +86 -0
  74. package/dist/github.d.ts +158 -0
  75. package/dist/github.js +78 -0
  76. package/dist/gitlab.d.ts +104 -0
  77. package/dist/gitlab.js +20 -0
  78. package/dist/handles.d.ts +82 -0
  79. package/dist/handles.js +135 -0
  80. package/dist/hint.d.ts +1 -0
  81. package/dist/hint.js +7 -0
  82. package/dist/http2.d.ts +206 -0
  83. package/dist/http2.js +1921 -0
  84. package/dist/index.d.ts +34 -0
  85. package/dist/index.js +15 -0
  86. package/dist/keyed.gen.d.ts +1 -0
  87. package/dist/keyed.gen.js +7 -0
  88. package/dist/models.gen.d.ts +6162 -0
  89. package/dist/models.gen.js +1 -0
  90. package/dist/proxy.d.ts +40 -0
  91. package/dist/proxy.js +249 -0
  92. package/dist/pty.d.ts +171 -0
  93. package/dist/pty.js +496 -0
  94. package/dist/sandbox.d.ts +537 -0
  95. package/dist/sandbox.js +725 -0
  96. package/dist/ssh.d.ts +25 -0
  97. package/dist/ssh.js +114 -0
  98. package/dist/trace.d.ts +33 -0
  99. package/dist/trace.js +80 -0
  100. package/dist/transport-worker.d.ts +1 -0
  101. package/dist/transport-worker.js +466 -0
  102. package/dist/warm.d.ts +1 -0
  103. package/dist/warm.js +40 -0
  104. package/package.json +54 -0
package/dist/ssh.d.ts ADDED
@@ -0,0 +1,25 @@
1
+ export interface SshTunnelOpts {
2
+ /** `https://api…/v1/sandboxes/:id/ssh/connect` */
3
+ url: string;
4
+ /** A `prom_ssh_` access credential, or an API key. */
5
+ token: string;
6
+ userAgent: string;
7
+ caller?: string;
8
+ timeoutMs?: number;
9
+ /** Bytes from the sandbox's SSH server. */
10
+ onData: (data: Uint8Array) => void;
11
+ /** The tunnel closed. */
12
+ onClose: () => void;
13
+ /** Build the error to reject with when the server does not switch protocols. */
14
+ refuse: (status: number, text: string) => Error;
15
+ }
16
+ export interface SshTunnel {
17
+ /** Send bytes to the sandbox's SSH server. */
18
+ write(data: Uint8Array): void;
19
+ /** Close the tunnel. */
20
+ close(): void;
21
+ /** Resolves when the tunnel is finished. */
22
+ done: Promise<void>;
23
+ }
24
+ /** Open the tunnel. Resolves once the socket has switched protocols. */
25
+ export declare function connectSshTunnel(opts: SshTunnelOpts): Promise<SshTunnel>;
package/dist/ssh.js ADDED
@@ -0,0 +1,114 @@
1
+ import { randomBytes } from "node:crypto";
2
+ import { CALLER_HEADER } from "./caller.js";
3
+ import { requestVia } from "./proxy.js";
4
+ import { FrameReader, encodeFrame, wsAccept } from "./pty.js";
5
+ export function connectSshTunnel(opts) {
6
+ const url = new URL(opts.url);
7
+ const key = randomBytes(16).toString("base64");
8
+ const req = requestVia(url, {
9
+ method: "GET",
10
+ agent: false,
11
+ headers: {
12
+ connection: "Upgrade",
13
+ upgrade: "websocket",
14
+ "sec-websocket-version": "13",
15
+ "sec-websocket-key": key,
16
+ authorization: `Bearer ${opts.token}`,
17
+ "user-agent": opts.userAgent,
18
+ ...(opts.caller ? { [CALLER_HEADER]: opts.caller } : {}),
19
+ },
20
+ });
21
+ return new Promise((resolve, reject) => {
22
+ let settled = false;
23
+ const fail = (e) => {
24
+ if (!settled) {
25
+ settled = true;
26
+ reject(e);
27
+ }
28
+ };
29
+ const timer = setTimeout(() => {
30
+ req.destroy();
31
+ fail(opts.refuse(504, JSON.stringify({
32
+ error: {
33
+ code: "timeout",
34
+ message: `the SSH tunnel to ${url.host} did not open within ${opts.timeoutMs ?? 30_000} ms`,
35
+ fix: "Retry; if it repeats, check the sandbox is ready.",
36
+ },
37
+ })));
38
+ }, opts.timeoutMs ?? 30_000);
39
+ req.on("error", (e) => {
40
+ clearTimeout(timer);
41
+ fail(opts.refuse(0, JSON.stringify({
42
+ error: {
43
+ code: "unreachable",
44
+ message: `cannot reach ${url.host}: ${e.code ?? e.message}`,
45
+ },
46
+ })));
47
+ });
48
+ req.on("response", (res) => {
49
+ clearTimeout(timer);
50
+ const parts = [];
51
+ res.on("data", (d) => parts.push(d));
52
+ res.on("end", () => fail(opts.refuse(res.statusCode ?? 0, Buffer.concat(parts).toString("utf8"))));
53
+ });
54
+ req.on("upgrade", (res, socket, head) => {
55
+ clearTimeout(timer);
56
+ if (res.headers["sec-websocket-accept"] !== wsAccept(key)) {
57
+ socket.destroy();
58
+ fail(opts.refuse(502, JSON.stringify({
59
+ error: {
60
+ code: "internal",
61
+ message: "the tunnel answered the WebSocket handshake with the wrong accept key",
62
+ },
63
+ })));
64
+ return;
65
+ }
66
+ socket.setNoDelay(true);
67
+ const reader = new FrameReader();
68
+ let resolveDone;
69
+ const done = new Promise((r) => {
70
+ resolveDone = r;
71
+ });
72
+ let finished = false;
73
+ const finish = () => {
74
+ if (finished)
75
+ return;
76
+ finished = true;
77
+ opts.onClose();
78
+ resolveDone();
79
+ };
80
+ const onFrames = (chunk) => {
81
+ for (const f of reader.push(chunk)) {
82
+ if (f.opcode === 0x2 || f.opcode === 0x1) {
83
+ opts.onData(new Uint8Array(f.payload));
84
+ }
85
+ else if (f.opcode === 0x9) {
86
+ socket.write(encodeFrame(0xa, f.payload));
87
+ }
88
+ else if (f.opcode === 0x8) {
89
+ if (!socket.destroyed)
90
+ socket.end(encodeFrame(0x8, f.payload.subarray(0, 2)));
91
+ }
92
+ }
93
+ };
94
+ socket.on("data", onFrames);
95
+ socket.on("close", finish);
96
+ socket.on("error", finish);
97
+ if (head.length)
98
+ onFrames(head);
99
+ settled = true;
100
+ resolve({
101
+ write(data) {
102
+ if (!socket.destroyed)
103
+ socket.write(encodeFrame(0x2, data));
104
+ },
105
+ close() {
106
+ if (!socket.destroyed)
107
+ socket.end(encodeFrame(0x8, Buffer.from([0x03, 0xe8])));
108
+ },
109
+ done,
110
+ });
111
+ });
112
+ req.end();
113
+ });
114
+ }
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Per-request phase stamps for measuring the SDK's own client-side cost.
3
+ *
4
+ * Off unless `PROMIGENCE_SDK_TRACE=1`, in which case every `request()` records `performance.now()`
5
+ * at each phase it passes through and the process prints one JSON line per request to stderr
6
+ * when it exits (buffered: writing in the hot path would be the skew being measured). Nothing
7
+ * here is part of the API.
8
+ */
9
+ export interface TraceStamp {
10
+ seq: number;
11
+ method: string;
12
+ path: string;
13
+ /** `performance.now()` at each phase, by name. */
14
+ t: Record<string, number>;
15
+ /** How the request travelled: "h2" or "fetch". */
16
+ via?: string;
17
+ /** The server's wall stamps (unix ns) when the answer carried them (`x-promigence-rx-ns` / `-tx-ns`). */
18
+ rx?: string;
19
+ tx?: string;
20
+ status?: number;
21
+ /** Over the transport thread: which of its connections (0-based, in the order they came up). */
22
+ conn?: number;
23
+ }
24
+ export declare const TRACE_ON: boolean;
25
+ /** Run `fn` with tracing off. */
26
+ export declare function untraced<T>(fn: () => T): T;
27
+ /** Start a stamp for one request, or `undefined` when tracing is off (the common case: one branch). */
28
+ export declare function traceBegin(method: string, path: string): TraceStamp | undefined;
29
+ export declare function mark(s: TraceStamp | undefined, phase: string): void;
30
+ /** A one-off process event (a constructor, a handshake step), for the same output. */
31
+ export declare function traceEvent(name: string): void;
32
+ /** A process event that happened at `t` (`performance.now()` terms), recorded now: one another thread reported. */
33
+ export declare function traceEventAt(name: string, t: number): void;
package/dist/trace.js ADDED
@@ -0,0 +1,80 @@
1
+ import { writeSync } from "node:fs";
2
+ import { VERSION } from "./core.js";
3
+ export const TRACE_ON = (() => {
4
+ try {
5
+ return typeof process === "object" && process.env?.["PROMIGENCE_SDK_TRACE"] === "1";
6
+ }
7
+ catch {
8
+ return false;
9
+ }
10
+ })();
11
+ const stamps = [];
12
+ let seq = 0;
13
+ let hooked = false;
14
+ let muted = 0;
15
+ export function untraced(fn) {
16
+ muted++;
17
+ try {
18
+ return fn();
19
+ }
20
+ finally {
21
+ muted--;
22
+ }
23
+ }
24
+ export function traceBegin(method, path) {
25
+ if (!TRACE_ON || muted > 0)
26
+ return undefined;
27
+ const s = { seq: seq++, method, path, t: { call: performance.now() } };
28
+ stamps.push(s);
29
+ if (!hooked) {
30
+ hooked = true;
31
+ process.once("exit", flush);
32
+ }
33
+ return s;
34
+ }
35
+ export function mark(s, phase) {
36
+ if (s !== undefined)
37
+ s.t[phase] = performance.now();
38
+ }
39
+ const events = [];
40
+ export function traceEvent(name) {
41
+ if (!TRACE_ON || muted > 0)
42
+ return;
43
+ events.push([name, performance.now()]);
44
+ if (!hooked) {
45
+ hooked = true;
46
+ process.once("exit", flush);
47
+ }
48
+ }
49
+ export function traceEventAt(name, t) {
50
+ if (!TRACE_ON || muted > 0)
51
+ return;
52
+ events.push([name, t]);
53
+ if (!hooked) {
54
+ hooked = true;
55
+ process.once("exit", flush);
56
+ }
57
+ }
58
+ function modulePath() {
59
+ const frame = (new Error().stack ?? "").split("\n")[1] ?? "";
60
+ const m = /\((.*):\d+:\d+\)\s*$/.exec(frame) ?? /at (.*):\d+:\d+\s*$/.exec(frame);
61
+ return m?.[1] ?? "";
62
+ }
63
+ function flush() {
64
+ const head = {
65
+ trace: "promigence-sdk",
66
+ version: VERSION,
67
+ node: process.versions.node,
68
+ timeOrigin: performance.timeOrigin,
69
+ module: modulePath(),
70
+ requests: stamps.length,
71
+ events,
72
+ };
73
+ let out = `PROMIGENCE_SDK_TRACE ${JSON.stringify(head)}\n`;
74
+ for (const s of stamps)
75
+ out += `PROMIGENCE_SDK_TRACE ${JSON.stringify(s)}\n`;
76
+ try {
77
+ writeSync(2, out);
78
+ }
79
+ catch { }
80
+ }
@@ -0,0 +1 @@
1
+ export {};