stitchkit 0.59.1 → 0.59.3
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 +44 -4
- package/dist/agent-runtime-openrouter.js +0 -1
- package/dist/agent-runtime.js +0 -1
- package/dist/application/activity.d.ts +70 -0
- package/dist/application/activity.d.ts.map +1 -0
- package/dist/application/events.d.ts +65 -0
- package/dist/application/events.d.ts.map +1 -0
- package/dist/application/grammy.d.ts +35 -0
- package/dist/application/grammy.d.ts.map +1 -0
- package/dist/application/graph.d.ts +11 -0
- package/dist/application/graph.d.ts.map +1 -0
- package/dist/application/health.d.ts +13 -0
- package/dist/application/health.d.ts.map +1 -0
- package/dist/application/kernel.d.ts +31 -0
- package/dist/application/kernel.d.ts.map +1 -0
- package/dist/application/latest-sink.d.ts +39 -0
- package/dist/application/latest-sink.d.ts.map +1 -0
- package/dist/application/resource.d.ts +30 -0
- package/dist/application/resource.d.ts.map +1 -0
- package/dist/application/schedule.d.ts +112 -0
- package/dist/application/schedule.d.ts.map +1 -0
- package/dist/application/schemas.d.ts +160 -0
- package/dist/application/schemas.d.ts.map +1 -0
- package/dist/application/server-resource.d.ts +12 -0
- package/dist/application/server-resource.d.ts.map +1 -0
- package/dist/application-grammy.d.ts +2 -0
- package/dist/application-grammy.d.ts.map +1 -0
- package/dist/application-grammy.js +164 -0
- package/dist/application.d.ts +10 -0
- package/dist/application.d.ts.map +1 -0
- package/dist/application.js +1369 -0
- package/dist/cli.js +0 -1
- package/dist/files.js +0 -1
- package/dist/{index-9zn9fb4e.js → index-0tszzfxp.js} +10 -218
- package/dist/index-dk6e56g0.js +211 -0
- package/dist/index-yr276yz0.js +6 -0
- package/dist/internal/fetch-port.d.ts +2 -0
- package/dist/internal/fetch-port.d.ts.map +1 -0
- package/dist/node.js +115 -14
- package/dist/observability/index.js +0 -1
- package/dist/remote.js +0 -1
- package/dist/server/index.js +8 -7
- package/dist/server/node.d.ts.map +1 -1
- package/dist/server/process-signals.d.ts +10 -8
- package/dist/server/process-signals.d.ts.map +1 -1
- package/dist/server/socket-io.d.ts.map +1 -1
- package/dist/testing.js +0 -1
- package/dist/tools.js +0 -1
- package/llms-full.txt +379 -0
- package/llms.txt +1 -0
- package/package.json +15 -2
- package/dist/index-1bx83sw4.js +0 -4
package/dist/cli.js
CHANGED
package/dist/files.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ShutdownOptionsSchema
|
|
3
|
+
} from "./index-dk6e56g0.js";
|
|
1
4
|
import {
|
|
2
5
|
DEFAULT_PROCESS_SIGNALS,
|
|
3
6
|
RUNTIME_CONTEXT_RESERVED_KEYS,
|
|
@@ -38,9 +41,6 @@ import {
|
|
|
38
41
|
isRecord,
|
|
39
42
|
transportResult
|
|
40
43
|
} from "./index-smpbdg6k.js";
|
|
41
|
-
import {
|
|
42
|
-
__require
|
|
43
|
-
} from "./index-1bx83sw4.js";
|
|
44
44
|
|
|
45
45
|
// src/server/multipart.ts
|
|
46
46
|
var DEFAULT_MAX_REQUEST_BYTES = 25 * 1024 * 1024;
|
|
@@ -1457,216 +1457,6 @@ function json(data, status, cors, req) {
|
|
|
1457
1457
|
return Response.json(data, { status, headers: corsHeaders2(cors, req) });
|
|
1458
1458
|
}
|
|
1459
1459
|
|
|
1460
|
-
// src/server/shutdown.ts
|
|
1461
|
-
import { z } from "zod";
|
|
1462
|
-
var ShutdownStateSchema = z.enum([
|
|
1463
|
-
"running",
|
|
1464
|
-
"draining-http",
|
|
1465
|
-
"closing-realtime",
|
|
1466
|
-
"stopping-runtime",
|
|
1467
|
-
"clean",
|
|
1468
|
-
"forced"
|
|
1469
|
-
]);
|
|
1470
|
-
var ShutdownOptionsSchema = z.object({
|
|
1471
|
-
gracePeriodMs: z.number().int().nonnegative().default(30000),
|
|
1472
|
-
forceTimeoutMs: z.number().int().nonnegative().default(5000),
|
|
1473
|
-
retryAfterSeconds: z.number().int().nonnegative().default(5),
|
|
1474
|
-
signal: z.custom((value) => typeof value === "object" && value !== null && ("aborted" in value) && ("addEventListener" in value), "Expected an AbortSignal").optional()
|
|
1475
|
-
});
|
|
1476
|
-
var ShutdownStatusSchema = z.object({
|
|
1477
|
-
state: ShutdownStateSchema,
|
|
1478
|
-
acceptedRequests: z.number().int().nonnegative(),
|
|
1479
|
-
completedRequests: z.number().int().nonnegative(),
|
|
1480
|
-
pendingRequests: z.number().int().nonnegative(),
|
|
1481
|
-
pendingWebSockets: z.number().int().nonnegative()
|
|
1482
|
-
});
|
|
1483
|
-
var ShutdownResultSchema = z.object({
|
|
1484
|
-
outcome: z.enum(["clean", "forced"]),
|
|
1485
|
-
reason: z.enum(["deadline", "signal"]).optional(),
|
|
1486
|
-
acceptedRequests: z.number().int().nonnegative(),
|
|
1487
|
-
completedRequests: z.number().int().nonnegative(),
|
|
1488
|
-
pendingRequests: z.number().int().nonnegative(),
|
|
1489
|
-
pendingWebSockets: z.number().int().nonnegative(),
|
|
1490
|
-
pendingRequestsAtForce: z.number().int().nonnegative(),
|
|
1491
|
-
pendingWebSocketsAtForce: z.number().int().nonnegative(),
|
|
1492
|
-
abortedRequests: z.number().int().nonnegative(),
|
|
1493
|
-
forcedWebSockets: z.number().int().nonnegative(),
|
|
1494
|
-
durationMs: z.number().nonnegative()
|
|
1495
|
-
});
|
|
1496
|
-
function rejectedResponse(retryAfterSeconds) {
|
|
1497
|
-
return Response.json({ error: { code: "SERVER_SHUTTING_DOWN", message: "Server is shutting down" } }, {
|
|
1498
|
-
status: 503,
|
|
1499
|
-
headers: {
|
|
1500
|
-
Connection: "close",
|
|
1501
|
-
"Retry-After": String(retryAfterSeconds)
|
|
1502
|
-
}
|
|
1503
|
-
});
|
|
1504
|
-
}
|
|
1505
|
-
function waitForZero(read, signal) {
|
|
1506
|
-
if (read() === 0)
|
|
1507
|
-
return Promise.resolve();
|
|
1508
|
-
return new Promise((resolve) => {
|
|
1509
|
-
const check = () => {
|
|
1510
|
-
if (read() === 0 || signal.aborted) {
|
|
1511
|
-
clearInterval(timer);
|
|
1512
|
-
signal.removeEventListener("abort", check);
|
|
1513
|
-
resolve();
|
|
1514
|
-
}
|
|
1515
|
-
};
|
|
1516
|
-
const timer = setInterval(check, 5);
|
|
1517
|
-
signal.addEventListener("abort", check, { once: true });
|
|
1518
|
-
});
|
|
1519
|
-
}
|
|
1520
|
-
function untilAbort(signal) {
|
|
1521
|
-
if (signal.aborted)
|
|
1522
|
-
return Promise.resolve();
|
|
1523
|
-
return new Promise((resolve) => signal.addEventListener("abort", () => resolve(), { once: true }));
|
|
1524
|
-
}
|
|
1525
|
-
function withTimeout(promise, timeoutMs, message) {
|
|
1526
|
-
return new Promise((resolve, reject) => {
|
|
1527
|
-
const timer = setTimeout(() => reject(new Error(message)), timeoutMs);
|
|
1528
|
-
promise.then((value) => {
|
|
1529
|
-
clearTimeout(timer);
|
|
1530
|
-
resolve(value);
|
|
1531
|
-
}, (error) => {
|
|
1532
|
-
clearTimeout(timer);
|
|
1533
|
-
reject(error);
|
|
1534
|
-
});
|
|
1535
|
-
});
|
|
1536
|
-
}
|
|
1537
|
-
function createServerLifecycle(getAdapter) {
|
|
1538
|
-
let state = "running";
|
|
1539
|
-
let acceptedRequests = 0;
|
|
1540
|
-
let completedRequests = 0;
|
|
1541
|
-
let pendingApplicationRequests = 0;
|
|
1542
|
-
let retryAfterSeconds = 5;
|
|
1543
|
-
let shutdownPromise;
|
|
1544
|
-
const status = () => {
|
|
1545
|
-
const adapter = getAdapter();
|
|
1546
|
-
return ShutdownStatusSchema.parse({
|
|
1547
|
-
state,
|
|
1548
|
-
acceptedRequests,
|
|
1549
|
-
completedRequests,
|
|
1550
|
-
pendingRequests: adapter.pendingRequests(),
|
|
1551
|
-
pendingWebSockets: adapter.pendingWebSockets()
|
|
1552
|
-
});
|
|
1553
|
-
};
|
|
1554
|
-
const wrapFetch = (handler) => {
|
|
1555
|
-
return async (request, server) => {
|
|
1556
|
-
if (state !== "running")
|
|
1557
|
-
return rejectedResponse(retryAfterSeconds);
|
|
1558
|
-
acceptedRequests += 1;
|
|
1559
|
-
pendingApplicationRequests += 1;
|
|
1560
|
-
try {
|
|
1561
|
-
return await handler(request, server);
|
|
1562
|
-
} finally {
|
|
1563
|
-
pendingApplicationRequests -= 1;
|
|
1564
|
-
completedRequests += 1;
|
|
1565
|
-
}
|
|
1566
|
-
};
|
|
1567
|
-
};
|
|
1568
|
-
const shutdown = (options) => {
|
|
1569
|
-
if (shutdownPromise)
|
|
1570
|
-
return shutdownPromise;
|
|
1571
|
-
const parsed = ShutdownOptionsSchema.parse(options ?? {});
|
|
1572
|
-
retryAfterSeconds = parsed.retryAfterSeconds;
|
|
1573
|
-
const startedAt = performance.now();
|
|
1574
|
-
const adapter = getAdapter();
|
|
1575
|
-
state = "draining-http";
|
|
1576
|
-
adapter.beginShutdown(retryAfterSeconds);
|
|
1577
|
-
shutdownPromise = new Promise((resolve, reject) => {
|
|
1578
|
-
const phaseAbort = new AbortController;
|
|
1579
|
-
let forcedReason;
|
|
1580
|
-
let phaseError;
|
|
1581
|
-
const force = (reason) => {
|
|
1582
|
-
if (forcedReason)
|
|
1583
|
-
return;
|
|
1584
|
-
forcedReason = reason;
|
|
1585
|
-
phaseAbort.abort();
|
|
1586
|
-
};
|
|
1587
|
-
const timer = setTimeout(() => force("deadline"), parsed.gracePeriodMs);
|
|
1588
|
-
const onExternalAbort = () => force("signal");
|
|
1589
|
-
parsed.signal?.addEventListener("abort", onExternalAbort, { once: true });
|
|
1590
|
-
if (parsed.signal?.aborted)
|
|
1591
|
-
force("signal");
|
|
1592
|
-
const cleanup = () => {
|
|
1593
|
-
clearTimeout(timer);
|
|
1594
|
-
parsed.signal?.removeEventListener("abort", onExternalAbort);
|
|
1595
|
-
};
|
|
1596
|
-
(async () => {
|
|
1597
|
-
try {
|
|
1598
|
-
await waitForZero(() => pendingApplicationRequests, phaseAbort.signal);
|
|
1599
|
-
if (!forcedReason) {
|
|
1600
|
-
state = "closing-realtime";
|
|
1601
|
-
await Promise.race([adapter.closeRealtime(), untilAbort(phaseAbort.signal)]);
|
|
1602
|
-
}
|
|
1603
|
-
if (!forcedReason) {
|
|
1604
|
-
state = "stopping-runtime";
|
|
1605
|
-
await Promise.race([adapter.stopGracefully(), untilAbort(phaseAbort.signal)]);
|
|
1606
|
-
}
|
|
1607
|
-
} catch (error) {
|
|
1608
|
-
if (!forcedReason) {
|
|
1609
|
-
phaseError = error;
|
|
1610
|
-
force("error");
|
|
1611
|
-
}
|
|
1612
|
-
}
|
|
1613
|
-
let pendingRequestsAtForce = 0;
|
|
1614
|
-
let pendingWebSocketsAtForce = 0;
|
|
1615
|
-
if (forcedReason) {
|
|
1616
|
-
state = "stopping-runtime";
|
|
1617
|
-
pendingRequestsAtForce = adapter.pendingRequests();
|
|
1618
|
-
pendingWebSocketsAtForce = adapter.pendingWebSockets();
|
|
1619
|
-
let forceError;
|
|
1620
|
-
let forceFailed = false;
|
|
1621
|
-
try {
|
|
1622
|
-
await withTimeout(adapter.forceStop(), parsed.forceTimeoutMs, `[stitchkit] forced shutdown did not complete within ${parsed.forceTimeoutMs}ms`);
|
|
1623
|
-
} catch (error) {
|
|
1624
|
-
forceFailed = true;
|
|
1625
|
-
forceError = error;
|
|
1626
|
-
} finally {
|
|
1627
|
-
state = "forced";
|
|
1628
|
-
}
|
|
1629
|
-
if (forcedReason === "error") {
|
|
1630
|
-
if (forceFailed) {
|
|
1631
|
-
throw new AggregateError([phaseError, forceError], "[stitchkit] graceful shutdown failed and forced cleanup also failed", { cause: phaseError });
|
|
1632
|
-
}
|
|
1633
|
-
throw phaseError;
|
|
1634
|
-
}
|
|
1635
|
-
if (forceFailed)
|
|
1636
|
-
throw forceError;
|
|
1637
|
-
} else {
|
|
1638
|
-
state = "clean";
|
|
1639
|
-
}
|
|
1640
|
-
cleanup();
|
|
1641
|
-
resolve(ShutdownResultSchema.parse({
|
|
1642
|
-
outcome: forcedReason ? "forced" : "clean",
|
|
1643
|
-
...forcedReason && { reason: forcedReason },
|
|
1644
|
-
acceptedRequests,
|
|
1645
|
-
completedRequests,
|
|
1646
|
-
pendingRequests: adapter.pendingRequests(),
|
|
1647
|
-
pendingWebSockets: adapter.pendingWebSockets(),
|
|
1648
|
-
pendingRequestsAtForce,
|
|
1649
|
-
pendingWebSocketsAtForce,
|
|
1650
|
-
abortedRequests: pendingRequestsAtForce,
|
|
1651
|
-
forcedWebSockets: pendingWebSocketsAtForce,
|
|
1652
|
-
durationMs: performance.now() - startedAt
|
|
1653
|
-
}));
|
|
1654
|
-
})().catch((error) => {
|
|
1655
|
-
cleanup();
|
|
1656
|
-
reject(error);
|
|
1657
|
-
});
|
|
1658
|
-
});
|
|
1659
|
-
return shutdownPromise;
|
|
1660
|
-
};
|
|
1661
|
-
return {
|
|
1662
|
-
wrapFetch,
|
|
1663
|
-
get status() {
|
|
1664
|
-
return status();
|
|
1665
|
-
},
|
|
1666
|
-
shutdown
|
|
1667
|
-
};
|
|
1668
|
-
}
|
|
1669
|
-
|
|
1670
1460
|
// src/server/process-signals.ts
|
|
1671
1461
|
var bound = new WeakSet;
|
|
1672
1462
|
function bindProcessSignals(handle, options = {}) {
|
|
@@ -1775,9 +1565,9 @@ function bindProcessSignals(handle, options = {}) {
|
|
|
1775
1565
|
}
|
|
1776
1566
|
|
|
1777
1567
|
// src/realtime/rejection.ts
|
|
1778
|
-
import { z
|
|
1568
|
+
import { z } from "zod";
|
|
1779
1569
|
function realtimeContractViolation(options) {
|
|
1780
|
-
const issues = options.cause instanceof
|
|
1570
|
+
const issues = options.cause instanceof z.ZodError ? zodIssues(options.cause) : undefined;
|
|
1781
1571
|
const reason = options.reason.replaceAll("-", " ");
|
|
1782
1572
|
const error = new AppError("REALTIME_CONTRACT_VIOLATION", `Realtime event "${options.event}" (${options.direction}, ${options.phase}): ${reason}`, 500, {
|
|
1783
1573
|
event: options.event,
|
|
@@ -2053,6 +1843,8 @@ function composeWebSocketHandlers(lanes, config) {
|
|
|
2053
1843
|
}
|
|
2054
1844
|
|
|
2055
1845
|
// src/server/socket-io.ts
|
|
1846
|
+
var SOCKET_IO_SERVER = "socket.io";
|
|
1847
|
+
var SOCKET_IO_BUN_ENGINE = "@socket.io/bun-engine";
|
|
2056
1848
|
var noop = () => {};
|
|
2057
1849
|
function isModuleNotFound(err) {
|
|
2058
1850
|
if (typeof err !== "object" || err === null)
|
|
@@ -2147,7 +1939,7 @@ async function createSocketIOServer(config) {
|
|
|
2147
1939
|
});
|
|
2148
1940
|
checkRequest(webRequest).then(() => done(null, true), (error) => done(error instanceof Error ? error.message : "Request rejected", false));
|
|
2149
1941
|
};
|
|
2150
|
-
const { Server } = await importPeer(() => import(
|
|
1942
|
+
const { Server } = await importPeer(() => import(SOCKET_IO_SERVER).then((module) => module), SOCKET_IO_SERVER);
|
|
2151
1943
|
const io = new Server({
|
|
2152
1944
|
...config.serverOptions,
|
|
2153
1945
|
path,
|
|
@@ -2174,7 +1966,7 @@ async function createSocketIOServer(config) {
|
|
|
2174
1966
|
}
|
|
2175
1967
|
};
|
|
2176
1968
|
if (onBun) {
|
|
2177
|
-
const { Server: Engine } = await importPeer(() => import(
|
|
1969
|
+
const { Server: Engine } = await importPeer(() => import(SOCKET_IO_BUN_ENGINE).then((module) => module), SOCKET_IO_BUN_ENGINE);
|
|
2178
1970
|
const engineOpts = {
|
|
2179
1971
|
path,
|
|
2180
1972
|
cors,
|
|
@@ -2227,4 +2019,4 @@ function socketIoLane(websocket) {
|
|
|
2227
2019
|
});
|
|
2228
2020
|
}
|
|
2229
2021
|
|
|
2230
|
-
export { parseMultipart, createHandler,
|
|
2022
|
+
export { parseMultipart, createHandler, bindProcessSignals, bindRealtimeServer, webSocketLane, composeWebSocketHandlers, createSocketIOServer, socketIoLane };
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
// src/server/shutdown.ts
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
var ShutdownStateSchema = z.enum([
|
|
4
|
+
"running",
|
|
5
|
+
"draining-http",
|
|
6
|
+
"closing-realtime",
|
|
7
|
+
"stopping-runtime",
|
|
8
|
+
"clean",
|
|
9
|
+
"forced"
|
|
10
|
+
]);
|
|
11
|
+
var ShutdownOptionsSchema = z.object({
|
|
12
|
+
gracePeriodMs: z.number().int().nonnegative().default(30000),
|
|
13
|
+
forceTimeoutMs: z.number().int().nonnegative().default(5000),
|
|
14
|
+
retryAfterSeconds: z.number().int().nonnegative().default(5),
|
|
15
|
+
signal: z.custom((value) => typeof value === "object" && value !== null && ("aborted" in value) && ("addEventListener" in value), "Expected an AbortSignal").optional()
|
|
16
|
+
});
|
|
17
|
+
var ShutdownStatusSchema = z.object({
|
|
18
|
+
state: ShutdownStateSchema,
|
|
19
|
+
acceptedRequests: z.number().int().nonnegative(),
|
|
20
|
+
completedRequests: z.number().int().nonnegative(),
|
|
21
|
+
pendingRequests: z.number().int().nonnegative(),
|
|
22
|
+
pendingWebSockets: z.number().int().nonnegative()
|
|
23
|
+
});
|
|
24
|
+
var ShutdownResultSchema = z.object({
|
|
25
|
+
outcome: z.enum(["clean", "forced"]),
|
|
26
|
+
reason: z.enum(["deadline", "signal"]).optional(),
|
|
27
|
+
acceptedRequests: z.number().int().nonnegative(),
|
|
28
|
+
completedRequests: z.number().int().nonnegative(),
|
|
29
|
+
pendingRequests: z.number().int().nonnegative(),
|
|
30
|
+
pendingWebSockets: z.number().int().nonnegative(),
|
|
31
|
+
pendingRequestsAtForce: z.number().int().nonnegative(),
|
|
32
|
+
pendingWebSocketsAtForce: z.number().int().nonnegative(),
|
|
33
|
+
abortedRequests: z.number().int().nonnegative(),
|
|
34
|
+
forcedWebSockets: z.number().int().nonnegative(),
|
|
35
|
+
durationMs: z.number().nonnegative()
|
|
36
|
+
});
|
|
37
|
+
function rejectedResponse(retryAfterSeconds) {
|
|
38
|
+
return Response.json({ error: { code: "SERVER_SHUTTING_DOWN", message: "Server is shutting down" } }, {
|
|
39
|
+
status: 503,
|
|
40
|
+
headers: {
|
|
41
|
+
Connection: "close",
|
|
42
|
+
"Retry-After": String(retryAfterSeconds)
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
function waitForZero(read, signal) {
|
|
47
|
+
if (read() === 0)
|
|
48
|
+
return Promise.resolve();
|
|
49
|
+
return new Promise((resolve) => {
|
|
50
|
+
const check = () => {
|
|
51
|
+
if (read() === 0 || signal.aborted) {
|
|
52
|
+
clearInterval(timer);
|
|
53
|
+
signal.removeEventListener("abort", check);
|
|
54
|
+
resolve();
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
const timer = setInterval(check, 5);
|
|
58
|
+
signal.addEventListener("abort", check, { once: true });
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
function untilAbort(signal) {
|
|
62
|
+
if (signal.aborted)
|
|
63
|
+
return Promise.resolve();
|
|
64
|
+
return new Promise((resolve) => signal.addEventListener("abort", () => resolve(), { once: true }));
|
|
65
|
+
}
|
|
66
|
+
function withTimeout(promise, timeoutMs, message) {
|
|
67
|
+
return new Promise((resolve, reject) => {
|
|
68
|
+
const timer = setTimeout(() => reject(new Error(message)), timeoutMs);
|
|
69
|
+
promise.then((value) => {
|
|
70
|
+
clearTimeout(timer);
|
|
71
|
+
resolve(value);
|
|
72
|
+
}, (error) => {
|
|
73
|
+
clearTimeout(timer);
|
|
74
|
+
reject(error);
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
function createServerLifecycle(getAdapter) {
|
|
79
|
+
let state = "running";
|
|
80
|
+
let acceptedRequests = 0;
|
|
81
|
+
let completedRequests = 0;
|
|
82
|
+
let pendingApplicationRequests = 0;
|
|
83
|
+
let retryAfterSeconds = 5;
|
|
84
|
+
let shutdownPromise;
|
|
85
|
+
const status = () => {
|
|
86
|
+
const adapter = getAdapter();
|
|
87
|
+
return ShutdownStatusSchema.parse({
|
|
88
|
+
state,
|
|
89
|
+
acceptedRequests,
|
|
90
|
+
completedRequests,
|
|
91
|
+
pendingRequests: adapter.pendingRequests(),
|
|
92
|
+
pendingWebSockets: adapter.pendingWebSockets()
|
|
93
|
+
});
|
|
94
|
+
};
|
|
95
|
+
const wrapFetch = (handler) => {
|
|
96
|
+
return async (request, server) => {
|
|
97
|
+
if (state !== "running")
|
|
98
|
+
return rejectedResponse(retryAfterSeconds);
|
|
99
|
+
acceptedRequests += 1;
|
|
100
|
+
pendingApplicationRequests += 1;
|
|
101
|
+
try {
|
|
102
|
+
return await handler(request, server);
|
|
103
|
+
} finally {
|
|
104
|
+
pendingApplicationRequests -= 1;
|
|
105
|
+
completedRequests += 1;
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
};
|
|
109
|
+
const shutdown = (options) => {
|
|
110
|
+
if (shutdownPromise)
|
|
111
|
+
return shutdownPromise;
|
|
112
|
+
const parsed = ShutdownOptionsSchema.parse(options ?? {});
|
|
113
|
+
retryAfterSeconds = parsed.retryAfterSeconds;
|
|
114
|
+
const startedAt = performance.now();
|
|
115
|
+
const adapter = getAdapter();
|
|
116
|
+
state = "draining-http";
|
|
117
|
+
adapter.beginShutdown(retryAfterSeconds);
|
|
118
|
+
shutdownPromise = new Promise((resolve, reject) => {
|
|
119
|
+
const phaseAbort = new AbortController;
|
|
120
|
+
let forcedReason;
|
|
121
|
+
let phaseError;
|
|
122
|
+
const force = (reason) => {
|
|
123
|
+
if (forcedReason)
|
|
124
|
+
return;
|
|
125
|
+
forcedReason = reason;
|
|
126
|
+
phaseAbort.abort();
|
|
127
|
+
};
|
|
128
|
+
const timer = setTimeout(() => force("deadline"), parsed.gracePeriodMs);
|
|
129
|
+
const onExternalAbort = () => force("signal");
|
|
130
|
+
parsed.signal?.addEventListener("abort", onExternalAbort, { once: true });
|
|
131
|
+
if (parsed.signal?.aborted)
|
|
132
|
+
force("signal");
|
|
133
|
+
const cleanup = () => {
|
|
134
|
+
clearTimeout(timer);
|
|
135
|
+
parsed.signal?.removeEventListener("abort", onExternalAbort);
|
|
136
|
+
};
|
|
137
|
+
(async () => {
|
|
138
|
+
try {
|
|
139
|
+
await waitForZero(() => pendingApplicationRequests, phaseAbort.signal);
|
|
140
|
+
if (!forcedReason) {
|
|
141
|
+
state = "closing-realtime";
|
|
142
|
+
await Promise.race([adapter.closeRealtime(), untilAbort(phaseAbort.signal)]);
|
|
143
|
+
}
|
|
144
|
+
if (!forcedReason) {
|
|
145
|
+
state = "stopping-runtime";
|
|
146
|
+
await Promise.race([adapter.stopGracefully(), untilAbort(phaseAbort.signal)]);
|
|
147
|
+
}
|
|
148
|
+
} catch (error) {
|
|
149
|
+
if (!forcedReason) {
|
|
150
|
+
phaseError = error;
|
|
151
|
+
force("error");
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
let pendingRequestsAtForce = 0;
|
|
155
|
+
let pendingWebSocketsAtForce = 0;
|
|
156
|
+
if (forcedReason) {
|
|
157
|
+
state = "stopping-runtime";
|
|
158
|
+
pendingRequestsAtForce = adapter.pendingRequests();
|
|
159
|
+
pendingWebSocketsAtForce = adapter.pendingWebSockets();
|
|
160
|
+
let forceError;
|
|
161
|
+
let forceFailed = false;
|
|
162
|
+
try {
|
|
163
|
+
await withTimeout(adapter.forceStop(), parsed.forceTimeoutMs, `[stitchkit] forced shutdown did not complete within ${parsed.forceTimeoutMs}ms`);
|
|
164
|
+
} catch (error) {
|
|
165
|
+
forceFailed = true;
|
|
166
|
+
forceError = error;
|
|
167
|
+
} finally {
|
|
168
|
+
state = "forced";
|
|
169
|
+
}
|
|
170
|
+
if (forcedReason === "error") {
|
|
171
|
+
if (forceFailed) {
|
|
172
|
+
throw new AggregateError([phaseError, forceError], "[stitchkit] graceful shutdown failed and forced cleanup also failed", { cause: phaseError });
|
|
173
|
+
}
|
|
174
|
+
throw phaseError;
|
|
175
|
+
}
|
|
176
|
+
if (forceFailed)
|
|
177
|
+
throw forceError;
|
|
178
|
+
} else {
|
|
179
|
+
state = "clean";
|
|
180
|
+
}
|
|
181
|
+
cleanup();
|
|
182
|
+
resolve(ShutdownResultSchema.parse({
|
|
183
|
+
outcome: forcedReason ? "forced" : "clean",
|
|
184
|
+
...forcedReason && { reason: forcedReason },
|
|
185
|
+
acceptedRequests,
|
|
186
|
+
completedRequests,
|
|
187
|
+
pendingRequests: adapter.pendingRequests(),
|
|
188
|
+
pendingWebSockets: adapter.pendingWebSockets(),
|
|
189
|
+
pendingRequestsAtForce,
|
|
190
|
+
pendingWebSocketsAtForce,
|
|
191
|
+
abortedRequests: pendingRequestsAtForce,
|
|
192
|
+
forcedWebSockets: pendingWebSocketsAtForce,
|
|
193
|
+
durationMs: performance.now() - startedAt
|
|
194
|
+
}));
|
|
195
|
+
})().catch((error) => {
|
|
196
|
+
cleanup();
|
|
197
|
+
reject(error);
|
|
198
|
+
});
|
|
199
|
+
});
|
|
200
|
+
return shutdownPromise;
|
|
201
|
+
};
|
|
202
|
+
return {
|
|
203
|
+
wrapFetch,
|
|
204
|
+
get status() {
|
|
205
|
+
return status();
|
|
206
|
+
},
|
|
207
|
+
shutdown
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
export { ShutdownStateSchema, ShutdownOptionsSchema, ShutdownStatusSchema, ShutdownResultSchema, createServerLifecycle };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fetch-port.d.ts","sourceRoot":"","sources":["../../src/internal/fetch-port.ts"],"names":[],"mappings":"AAaA,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAExD"}
|
package/dist/node.js
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import {
|
|
2
|
-
ShutdownOptionsSchema,
|
|
3
|
-
ShutdownResultSchema,
|
|
4
|
-
ShutdownStateSchema,
|
|
5
|
-
ShutdownStatusSchema,
|
|
6
2
|
bindProcessSignals,
|
|
7
3
|
bindRealtimeServer,
|
|
8
4
|
createHandler,
|
|
9
|
-
createServerLifecycle,
|
|
10
5
|
createSocketIOServer
|
|
11
|
-
} from "./index-
|
|
6
|
+
} from "./index-0tszzfxp.js";
|
|
7
|
+
import {
|
|
8
|
+
ShutdownOptionsSchema,
|
|
9
|
+
ShutdownResultSchema,
|
|
10
|
+
ShutdownStateSchema,
|
|
11
|
+
ShutdownStatusSchema,
|
|
12
|
+
createServerLifecycle
|
|
13
|
+
} from "./index-dk6e56g0.js";
|
|
12
14
|
import {
|
|
13
15
|
createImplement,
|
|
14
16
|
createImplementRegistry,
|
|
@@ -33,9 +35,99 @@ import {
|
|
|
33
35
|
import"./index-6k1937bx.js";
|
|
34
36
|
import"./index-y2rb7dwx.js";
|
|
35
37
|
import"./index-smpbdg6k.js";
|
|
36
|
-
import"./index-1bx83sw4.js";
|
|
37
38
|
// src/server/node.ts
|
|
38
39
|
import { serve } from "srvx/node";
|
|
40
|
+
|
|
41
|
+
// src/internal/fetch-port.ts
|
|
42
|
+
var FETCH_BLOCKED_PORTS = new Set([
|
|
43
|
+
1,
|
|
44
|
+
7,
|
|
45
|
+
9,
|
|
46
|
+
11,
|
|
47
|
+
13,
|
|
48
|
+
15,
|
|
49
|
+
17,
|
|
50
|
+
19,
|
|
51
|
+
20,
|
|
52
|
+
21,
|
|
53
|
+
22,
|
|
54
|
+
23,
|
|
55
|
+
25,
|
|
56
|
+
37,
|
|
57
|
+
42,
|
|
58
|
+
43,
|
|
59
|
+
53,
|
|
60
|
+
69,
|
|
61
|
+
77,
|
|
62
|
+
79,
|
|
63
|
+
87,
|
|
64
|
+
95,
|
|
65
|
+
101,
|
|
66
|
+
102,
|
|
67
|
+
103,
|
|
68
|
+
104,
|
|
69
|
+
109,
|
|
70
|
+
110,
|
|
71
|
+
111,
|
|
72
|
+
113,
|
|
73
|
+
115,
|
|
74
|
+
117,
|
|
75
|
+
119,
|
|
76
|
+
123,
|
|
77
|
+
135,
|
|
78
|
+
137,
|
|
79
|
+
139,
|
|
80
|
+
143,
|
|
81
|
+
161,
|
|
82
|
+
179,
|
|
83
|
+
389,
|
|
84
|
+
427,
|
|
85
|
+
465,
|
|
86
|
+
512,
|
|
87
|
+
513,
|
|
88
|
+
514,
|
|
89
|
+
515,
|
|
90
|
+
526,
|
|
91
|
+
530,
|
|
92
|
+
531,
|
|
93
|
+
532,
|
|
94
|
+
540,
|
|
95
|
+
548,
|
|
96
|
+
554,
|
|
97
|
+
556,
|
|
98
|
+
563,
|
|
99
|
+
587,
|
|
100
|
+
601,
|
|
101
|
+
636,
|
|
102
|
+
989,
|
|
103
|
+
990,
|
|
104
|
+
993,
|
|
105
|
+
995,
|
|
106
|
+
1719,
|
|
107
|
+
1720,
|
|
108
|
+
1723,
|
|
109
|
+
2049,
|
|
110
|
+
3659,
|
|
111
|
+
4045,
|
|
112
|
+
4190,
|
|
113
|
+
5060,
|
|
114
|
+
5061,
|
|
115
|
+
6000,
|
|
116
|
+
6566,
|
|
117
|
+
6665,
|
|
118
|
+
6666,
|
|
119
|
+
6667,
|
|
120
|
+
6668,
|
|
121
|
+
6669,
|
|
122
|
+
6679,
|
|
123
|
+
6697,
|
|
124
|
+
10080
|
|
125
|
+
]);
|
|
126
|
+
function isFetchBlockedPort(port) {
|
|
127
|
+
return FETCH_BLOCKED_PORTS.has(port);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// src/server/node.ts
|
|
39
131
|
async function serveNode(config) {
|
|
40
132
|
const { port = 3000, hostname, socket, wrapFetch, ...handlerConfig } = config;
|
|
41
133
|
const handler = createHandler(handlerConfig);
|
|
@@ -101,14 +193,23 @@ async function serveNode(config) {
|
|
|
101
193
|
const lifecycle = createServerLifecycle(() => adapter);
|
|
102
194
|
const consumerFetch = wrapFetch ? wrapFetch(handler) : handler;
|
|
103
195
|
const fetch = lifecycle.wrapFetch(consumerFetch);
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
196
|
+
for (;; ) {
|
|
197
|
+
runtime = serve({ port, hostname, fetch, gracefulShutdown: false });
|
|
198
|
+
await runtime.ready();
|
|
199
|
+
const candidate = runtime.node?.server;
|
|
200
|
+
if (!candidate || !("maxRequestsPerSocket" in candidate)) {
|
|
201
|
+
await runtime.close(true);
|
|
202
|
+
throw new Error("[stitchkit] serveNode: expected a node:http.Server for the managed lifecycle.");
|
|
203
|
+
}
|
|
204
|
+
const candidateUrl = runtime.url ?? `http://${hostname ?? "localhost"}:${port}`;
|
|
205
|
+
const candidatePort = Number(new URL(candidateUrl).port) || port;
|
|
206
|
+
if (port === 0 && isFetchBlockedPort(candidatePort)) {
|
|
207
|
+
await runtime.close(true);
|
|
208
|
+
continue;
|
|
209
|
+
}
|
|
210
|
+
nodeServer = candidate;
|
|
211
|
+
break;
|
|
110
212
|
}
|
|
111
|
-
nodeServer = candidate;
|
|
112
213
|
nodeServer.on("connection", (activeSocket) => {
|
|
113
214
|
sockets.add(activeSocket);
|
|
114
215
|
activeSocket.once("close", () => {
|