@spikard/node 0.11.0 → 0.12.0
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.mts +16 -1
- package/dist/index.d.ts +16 -1
- package/dist/index.js +131 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +131 -0
- package/dist/index.mjs.map +1 -1
- package/index.js +52 -52
- package/package.json +4 -4
- package/spikard-node.linux-x64-gnu.node +0 -0
package/dist/index.d.mts
CHANGED
|
@@ -117,6 +117,12 @@ interface OpenApiConfig {
|
|
|
117
117
|
servers?: ServerInfo[];
|
|
118
118
|
securitySchemes?: Record<string, SecuritySchemeInfo>;
|
|
119
119
|
}
|
|
120
|
+
interface JsonRpcConfig {
|
|
121
|
+
enabled?: boolean;
|
|
122
|
+
endpointPath?: string;
|
|
123
|
+
enableBatch?: boolean;
|
|
124
|
+
maxBatchSize?: number;
|
|
125
|
+
}
|
|
120
126
|
interface StaticFilesConfig {
|
|
121
127
|
directory: string;
|
|
122
128
|
routePrefix: string;
|
|
@@ -138,6 +144,7 @@ interface ServerConfig {
|
|
|
138
144
|
gracefulShutdown?: boolean;
|
|
139
145
|
shutdownTimeout?: number;
|
|
140
146
|
openapi?: OpenApiConfig | null;
|
|
147
|
+
jsonrpc?: JsonRpcConfig | null;
|
|
141
148
|
}
|
|
142
149
|
|
|
143
150
|
interface ServerOptions {
|
|
@@ -292,6 +299,13 @@ interface WebSocketTestConnection {
|
|
|
292
299
|
close(): Promise<void>;
|
|
293
300
|
}
|
|
294
301
|
type TestResponse = NativeTestResponse;
|
|
302
|
+
interface GraphQLSubscriptionResult {
|
|
303
|
+
operationId: string;
|
|
304
|
+
acknowledged: boolean;
|
|
305
|
+
event: unknown | null;
|
|
306
|
+
errors: unknown[];
|
|
307
|
+
completeReceived: boolean;
|
|
308
|
+
}
|
|
295
309
|
interface MultipartFile {
|
|
296
310
|
name: string;
|
|
297
311
|
filename?: string;
|
|
@@ -330,6 +344,7 @@ declare class TestClient {
|
|
|
330
344
|
headers: string;
|
|
331
345
|
bodyText: string;
|
|
332
346
|
}>;
|
|
347
|
+
graphqlSubscription(query: string, variables?: Record<string, unknown> | null, operationName?: string | null, path?: string): Promise<GraphQLSubscriptionResult>;
|
|
333
348
|
cleanup(): Promise<void>;
|
|
334
349
|
}
|
|
335
350
|
|
|
@@ -397,4 +412,4 @@ interface SpikardApp {
|
|
|
397
412
|
dependencies?: Record<string, unknown>;
|
|
398
413
|
}
|
|
399
414
|
|
|
400
|
-
export { type ApiKeyConfig, type Base64EncodedBody, type Body, type CompressionConfig, type ContactInfo, type CorsConfig, type DependencyFactory, type DependencyOptions, type DependencyValue, type FileParam, GrpcError, type GrpcHandler, type GrpcMetadata, type GrpcRequest, type GrpcResponse, type GrpcServiceConfig, GrpcStatusCode, type HandlerFunction, type HandlerResult, type JsonPrimitive, type JsonRecord, type JsonSchema, type JsonValue, type JwtConfig, type LicenseInfo, type LifecycleHookFunction, type LifecycleHooks, type MaybePromise, type NativeHandlerFunction, type OpenApiConfig, type Path, type Query, QueryDefault, type RateLimitConfig, type Request, type RouteMetadata, type RouteOptions, type SecuritySchemeInfo, type ServerConfig, type ServerInfo, type ServerOptions, Spikard, type SpikardApp, type StaticFilesConfig, StreamingResponse, type StreamingResponseInit, type StructuredHandlerResponse, TestClient, type TestResponse, UploadFile, type WebSocketHandler, type WebSocketOptions, background, createServiceHandler, createUnaryHandler, del, get, patch, post, put, route, runServer, wrapBodyHandler, wrapHandler };
|
|
415
|
+
export { type ApiKeyConfig, type Base64EncodedBody, type Body, type CompressionConfig, type ContactInfo, type CorsConfig, type DependencyFactory, type DependencyOptions, type DependencyValue, type FileParam, GrpcError, type GrpcHandler, type GrpcMetadata, type GrpcRequest, type GrpcResponse, type GrpcServiceConfig, GrpcStatusCode, type HandlerFunction, type HandlerResult, type JsonPrimitive, type JsonRecord, type JsonRpcConfig, type JsonSchema, type JsonValue, type JwtConfig, type LicenseInfo, type LifecycleHookFunction, type LifecycleHooks, type MaybePromise, type NativeHandlerFunction, type OpenApiConfig, type Path, type Query, QueryDefault, type RateLimitConfig, type Request, type RouteMetadata, type RouteOptions, type SecuritySchemeInfo, type ServerConfig, type ServerInfo, type ServerOptions, Spikard, type SpikardApp, type StaticFilesConfig, StreamingResponse, type StreamingResponseInit, type StructuredHandlerResponse, TestClient, type TestResponse, UploadFile, type WebSocketHandler, type WebSocketOptions, background, createServiceHandler, createUnaryHandler, del, get, patch, post, put, route, runServer, wrapBodyHandler, wrapHandler };
|
package/dist/index.d.ts
CHANGED
|
@@ -117,6 +117,12 @@ interface OpenApiConfig {
|
|
|
117
117
|
servers?: ServerInfo[];
|
|
118
118
|
securitySchemes?: Record<string, SecuritySchemeInfo>;
|
|
119
119
|
}
|
|
120
|
+
interface JsonRpcConfig {
|
|
121
|
+
enabled?: boolean;
|
|
122
|
+
endpointPath?: string;
|
|
123
|
+
enableBatch?: boolean;
|
|
124
|
+
maxBatchSize?: number;
|
|
125
|
+
}
|
|
120
126
|
interface StaticFilesConfig {
|
|
121
127
|
directory: string;
|
|
122
128
|
routePrefix: string;
|
|
@@ -138,6 +144,7 @@ interface ServerConfig {
|
|
|
138
144
|
gracefulShutdown?: boolean;
|
|
139
145
|
shutdownTimeout?: number;
|
|
140
146
|
openapi?: OpenApiConfig | null;
|
|
147
|
+
jsonrpc?: JsonRpcConfig | null;
|
|
141
148
|
}
|
|
142
149
|
|
|
143
150
|
interface ServerOptions {
|
|
@@ -292,6 +299,13 @@ interface WebSocketTestConnection {
|
|
|
292
299
|
close(): Promise<void>;
|
|
293
300
|
}
|
|
294
301
|
type TestResponse = NativeTestResponse;
|
|
302
|
+
interface GraphQLSubscriptionResult {
|
|
303
|
+
operationId: string;
|
|
304
|
+
acknowledged: boolean;
|
|
305
|
+
event: unknown | null;
|
|
306
|
+
errors: unknown[];
|
|
307
|
+
completeReceived: boolean;
|
|
308
|
+
}
|
|
295
309
|
interface MultipartFile {
|
|
296
310
|
name: string;
|
|
297
311
|
filename?: string;
|
|
@@ -330,6 +344,7 @@ declare class TestClient {
|
|
|
330
344
|
headers: string;
|
|
331
345
|
bodyText: string;
|
|
332
346
|
}>;
|
|
347
|
+
graphqlSubscription(query: string, variables?: Record<string, unknown> | null, operationName?: string | null, path?: string): Promise<GraphQLSubscriptionResult>;
|
|
333
348
|
cleanup(): Promise<void>;
|
|
334
349
|
}
|
|
335
350
|
|
|
@@ -397,4 +412,4 @@ interface SpikardApp {
|
|
|
397
412
|
dependencies?: Record<string, unknown>;
|
|
398
413
|
}
|
|
399
414
|
|
|
400
|
-
export { type ApiKeyConfig, type Base64EncodedBody, type Body, type CompressionConfig, type ContactInfo, type CorsConfig, type DependencyFactory, type DependencyOptions, type DependencyValue, type FileParam, GrpcError, type GrpcHandler, type GrpcMetadata, type GrpcRequest, type GrpcResponse, type GrpcServiceConfig, GrpcStatusCode, type HandlerFunction, type HandlerResult, type JsonPrimitive, type JsonRecord, type JsonSchema, type JsonValue, type JwtConfig, type LicenseInfo, type LifecycleHookFunction, type LifecycleHooks, type MaybePromise, type NativeHandlerFunction, type OpenApiConfig, type Path, type Query, QueryDefault, type RateLimitConfig, type Request, type RouteMetadata, type RouteOptions, type SecuritySchemeInfo, type ServerConfig, type ServerInfo, type ServerOptions, Spikard, type SpikardApp, type StaticFilesConfig, StreamingResponse, type StreamingResponseInit, type StructuredHandlerResponse, TestClient, type TestResponse, UploadFile, type WebSocketHandler, type WebSocketOptions, background, createServiceHandler, createUnaryHandler, del, get, patch, post, put, route, runServer, wrapBodyHandler, wrapHandler };
|
|
415
|
+
export { type ApiKeyConfig, type Base64EncodedBody, type Body, type CompressionConfig, type ContactInfo, type CorsConfig, type DependencyFactory, type DependencyOptions, type DependencyValue, type FileParam, GrpcError, type GrpcHandler, type GrpcMetadata, type GrpcRequest, type GrpcResponse, type GrpcServiceConfig, GrpcStatusCode, type HandlerFunction, type HandlerResult, type JsonPrimitive, type JsonRecord, type JsonRpcConfig, type JsonSchema, type JsonValue, type JwtConfig, type LicenseInfo, type LifecycleHookFunction, type LifecycleHooks, type MaybePromise, type NativeHandlerFunction, type OpenApiConfig, type Path, type Query, QueryDefault, type RateLimitConfig, type Request, type RouteMetadata, type RouteOptions, type SecuritySchemeInfo, type ServerConfig, type ServerInfo, type ServerOptions, Spikard, type SpikardApp, type StaticFilesConfig, StreamingResponse, type StreamingResponseInit, type StructuredHandlerResponse, TestClient, type TestResponse, UploadFile, type WebSocketHandler, type WebSocketOptions, background, createServiceHandler, createUnaryHandler, del, get, patch, post, put, route, runServer, wrapBodyHandler, wrapHandler };
|
package/dist/index.js
CHANGED
|
@@ -954,6 +954,36 @@ var import_promises = __toESM(require("fs/promises"));
|
|
|
954
954
|
var import_node_module3 = require("module");
|
|
955
955
|
var import_node_path = __toESM(require("path"));
|
|
956
956
|
var import_node_zlib = require("zlib");
|
|
957
|
+
var GRAPHQL_WS_TIMEOUT_MS = 2e3;
|
|
958
|
+
var GRAPHQL_WS_MAX_CONTROL_MESSAGES = 32;
|
|
959
|
+
var withTimeout = async (promise, timeoutMs, context) => {
|
|
960
|
+
let timer;
|
|
961
|
+
try {
|
|
962
|
+
return await Promise.race([
|
|
963
|
+
promise,
|
|
964
|
+
new Promise((_resolve, reject) => {
|
|
965
|
+
timer = setTimeout(() => reject(new Error(`Timed out waiting for ${context}`)), timeoutMs);
|
|
966
|
+
})
|
|
967
|
+
]);
|
|
968
|
+
} finally {
|
|
969
|
+
if (timer) {
|
|
970
|
+
clearTimeout(timer);
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
};
|
|
974
|
+
var decodeGraphqlWsMessage = (value) => {
|
|
975
|
+
if (typeof value === "string") {
|
|
976
|
+
const parsed = JSON.parse(value);
|
|
977
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
978
|
+
return parsed;
|
|
979
|
+
}
|
|
980
|
+
throw new Error("Expected GraphQL WebSocket JSON object message");
|
|
981
|
+
}
|
|
982
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
983
|
+
return value;
|
|
984
|
+
}
|
|
985
|
+
throw new Error("Expected GraphQL WebSocket message object");
|
|
986
|
+
};
|
|
957
987
|
var MockWebSocketConnection = class {
|
|
958
988
|
handler;
|
|
959
989
|
queue = [];
|
|
@@ -1667,6 +1697,107 @@ var TestClient = class {
|
|
|
1667
1697
|
bodyText: response.text()
|
|
1668
1698
|
};
|
|
1669
1699
|
}
|
|
1700
|
+
/**
|
|
1701
|
+
* Send a GraphQL subscription over WebSocket and return the first event payload.
|
|
1702
|
+
*/
|
|
1703
|
+
async graphqlSubscription(query, variables, operationName, path2 = "/graphql") {
|
|
1704
|
+
const operationId = "spikard-subscription-1";
|
|
1705
|
+
const subscriptionPayload = { query };
|
|
1706
|
+
if (variables !== null && variables !== void 0) {
|
|
1707
|
+
subscriptionPayload.variables = variables;
|
|
1708
|
+
}
|
|
1709
|
+
if (operationName !== null && operationName !== void 0) {
|
|
1710
|
+
subscriptionPayload.operationName = operationName;
|
|
1711
|
+
}
|
|
1712
|
+
const ws = await this.websocketConnect(path2);
|
|
1713
|
+
try {
|
|
1714
|
+
await ws.sendJson({ type: "connection_init" });
|
|
1715
|
+
let acknowledged = false;
|
|
1716
|
+
for (let i = 0; i < GRAPHQL_WS_MAX_CONTROL_MESSAGES; i++) {
|
|
1717
|
+
const message = decodeGraphqlWsMessage(
|
|
1718
|
+
await withTimeout(ws.receiveJson(), GRAPHQL_WS_TIMEOUT_MS, "GraphQL connection_ack")
|
|
1719
|
+
);
|
|
1720
|
+
const messageType = typeof message.type === "string" ? message.type : "";
|
|
1721
|
+
if (messageType === "connection_ack") {
|
|
1722
|
+
acknowledged = true;
|
|
1723
|
+
break;
|
|
1724
|
+
}
|
|
1725
|
+
if (messageType === "ping") {
|
|
1726
|
+
const pong = { type: "pong" };
|
|
1727
|
+
if ("payload" in message) {
|
|
1728
|
+
pong.payload = message.payload;
|
|
1729
|
+
}
|
|
1730
|
+
await ws.sendJson(pong);
|
|
1731
|
+
continue;
|
|
1732
|
+
}
|
|
1733
|
+
if (messageType === "connection_error" || messageType === "error") {
|
|
1734
|
+
throw new Error(`GraphQL subscription rejected during init: ${JSON.stringify(message)}`);
|
|
1735
|
+
}
|
|
1736
|
+
}
|
|
1737
|
+
if (!acknowledged) {
|
|
1738
|
+
throw new Error("No GraphQL connection_ack received");
|
|
1739
|
+
}
|
|
1740
|
+
await ws.sendJson({
|
|
1741
|
+
id: operationId,
|
|
1742
|
+
type: "subscribe",
|
|
1743
|
+
payload: subscriptionPayload
|
|
1744
|
+
});
|
|
1745
|
+
let event = null;
|
|
1746
|
+
const errors = [];
|
|
1747
|
+
let completeReceived = false;
|
|
1748
|
+
for (let i = 0; i < GRAPHQL_WS_MAX_CONTROL_MESSAGES; i++) {
|
|
1749
|
+
const message = decodeGraphqlWsMessage(
|
|
1750
|
+
await withTimeout(ws.receiveJson(), GRAPHQL_WS_TIMEOUT_MS, "GraphQL subscription message")
|
|
1751
|
+
);
|
|
1752
|
+
const messageType = typeof message.type === "string" ? message.type : "";
|
|
1753
|
+
const messageId = typeof message.id === "string" ? message.id : void 0;
|
|
1754
|
+
const idMatches = messageId === void 0 || messageId === operationId;
|
|
1755
|
+
if (messageType === "next" && idMatches) {
|
|
1756
|
+
event = "payload" in message ? message.payload : null;
|
|
1757
|
+
await ws.sendJson({ id: operationId, type: "complete" });
|
|
1758
|
+
try {
|
|
1759
|
+
const maybeComplete = decodeGraphqlWsMessage(
|
|
1760
|
+
await withTimeout(ws.receiveJson(), GRAPHQL_WS_TIMEOUT_MS, "GraphQL complete message")
|
|
1761
|
+
);
|
|
1762
|
+
const completeType = typeof maybeComplete.type === "string" ? maybeComplete.type : "";
|
|
1763
|
+
const completeId = typeof maybeComplete.id === "string" ? maybeComplete.id : void 0;
|
|
1764
|
+
if (completeType === "complete" && (completeId === void 0 || completeId === operationId)) {
|
|
1765
|
+
completeReceived = true;
|
|
1766
|
+
}
|
|
1767
|
+
} catch {
|
|
1768
|
+
}
|
|
1769
|
+
break;
|
|
1770
|
+
}
|
|
1771
|
+
if (messageType === "error") {
|
|
1772
|
+
errors.push("payload" in message ? message.payload : message);
|
|
1773
|
+
break;
|
|
1774
|
+
}
|
|
1775
|
+
if (messageType === "complete" && idMatches) {
|
|
1776
|
+
completeReceived = true;
|
|
1777
|
+
break;
|
|
1778
|
+
}
|
|
1779
|
+
if (messageType === "ping") {
|
|
1780
|
+
const pong = { type: "pong" };
|
|
1781
|
+
if ("payload" in message) {
|
|
1782
|
+
pong.payload = message.payload;
|
|
1783
|
+
}
|
|
1784
|
+
await ws.sendJson(pong);
|
|
1785
|
+
}
|
|
1786
|
+
}
|
|
1787
|
+
if (event === null && errors.length === 0 && !completeReceived) {
|
|
1788
|
+
throw new Error("No GraphQL subscription event received before timeout");
|
|
1789
|
+
}
|
|
1790
|
+
return {
|
|
1791
|
+
operationId,
|
|
1792
|
+
acknowledged,
|
|
1793
|
+
event,
|
|
1794
|
+
errors,
|
|
1795
|
+
completeReceived
|
|
1796
|
+
};
|
|
1797
|
+
} finally {
|
|
1798
|
+
await ws.close();
|
|
1799
|
+
}
|
|
1800
|
+
}
|
|
1670
1801
|
/**
|
|
1671
1802
|
* Cleanup resources when test client is done
|
|
1672
1803
|
*/
|