@sylphx/lens-server 4.0.0 → 4.1.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.js CHANGED
@@ -39,12 +39,15 @@ import {
39
39
  collectModelsFromRouter,
40
40
  createEmit,
41
41
  createResolverFromEntity,
42
+ firstValueFrom,
42
43
  flattenRouter,
43
44
  hashValue,
45
+ isError,
44
46
  isLiveQueryDef,
45
47
  isModelDef,
46
48
  isMutationDef,
47
49
  isQueryDef,
50
+ isSnapshot,
48
51
  isSubscriptionDef,
49
52
  mergeModelCollections,
50
53
  toOps,
@@ -515,7 +518,7 @@ class LensServerImpl {
515
518
  observer.complete?.();
516
519
  return;
517
520
  }
518
- const publisher = subscriber({ input, ctx: context });
521
+ const publisher = subscriber({ args: input, ctx: context });
519
522
  if (publisher) {
520
523
  const emit = createEmit((command) => {
521
524
  if (cancelled)
@@ -1009,353 +1012,91 @@ class LensServerImpl {
1009
1012
  getPluginManager() {
1010
1013
  return this.pluginManager;
1011
1014
  }
1012
- }
1013
- function createApp(config) {
1014
- const server = new LensServerImpl(config);
1015
- return server;
1016
- }
1017
- // src/sse/handler.ts
1018
- class SSEHandler {
1019
- heartbeatInterval;
1020
- onConnectCallback;
1021
- onDisconnectCallback;
1022
- clients = new Map;
1023
- clientCounter = 0;
1024
- constructor(config = {}) {
1025
- this.heartbeatInterval = config.heartbeatInterval ?? 30000;
1026
- this.onConnectCallback = config.onConnect;
1027
- this.onDisconnectCallback = config.onDisconnect;
1028
- }
1029
- handleConnection(_req) {
1030
- const clientId = `sse_${++this.clientCounter}_${Date.now()}`;
1031
- const encoder = new TextEncoder;
1032
- const stream = new ReadableStream({
1033
- start: (controller) => {
1034
- const heartbeat = setInterval(() => {
1035
- try {
1036
- controller.enqueue(encoder.encode(`: heartbeat ${Date.now()}
1037
-
1038
- `));
1039
- } catch {
1040
- this.removeClient(clientId);
1041
- }
1042
- }, this.heartbeatInterval);
1043
- this.clients.set(clientId, { controller, heartbeat, encoder });
1044
- controller.enqueue(encoder.encode(`event: connected
1045
- data: ${JSON.stringify({ clientId })}
1046
-
1047
- `));
1048
- const client = {
1049
- id: clientId,
1050
- send: (message) => this.send(clientId, message),
1051
- sendEvent: (event, data) => this.sendEvent(clientId, event, data),
1052
- close: () => this.closeClient(clientId)
1053
- };
1054
- this.onConnectCallback?.(client);
1055
- },
1056
- cancel: () => {
1057
- this.removeClient(clientId);
1058
- }
1059
- });
1060
- return new Response(stream, {
1061
- headers: {
1062
- "Content-Type": "text/event-stream",
1063
- "Cache-Control": "no-cache",
1064
- Connection: "keep-alive",
1065
- "Access-Control-Allow-Origin": "*"
1066
- }
1067
- });
1068
- }
1069
- send(clientId, message) {
1070
- const client = this.clients.get(clientId);
1071
- if (!client)
1072
- return false;
1073
- try {
1074
- const data = `data: ${JSON.stringify(message)}
1075
-
1076
- `;
1077
- client.controller.enqueue(client.encoder.encode(data));
1078
- return true;
1079
- } catch {
1080
- this.removeClient(clientId);
1081
- return false;
1082
- }
1083
- }
1084
- sendEvent(clientId, event, data) {
1085
- const client = this.clients.get(clientId);
1086
- if (!client)
1087
- return false;
1088
- if (/[\r\n:]/.test(event)) {
1089
- return false;
1090
- }
1091
- try {
1092
- const message = `event: ${event}
1093
- data: ${JSON.stringify(data)}
1094
-
1095
- `;
1096
- client.controller.enqueue(client.encoder.encode(message));
1097
- return true;
1098
- } catch {
1099
- this.removeClient(clientId);
1100
- return false;
1101
- }
1102
- }
1103
- broadcast(message) {
1104
- for (const clientId of this.clients.keys()) {
1105
- this.send(clientId, message);
1106
- }
1107
- }
1108
- removeClient(clientId) {
1109
- const client = this.clients.get(clientId);
1110
- if (client) {
1111
- clearInterval(client.heartbeat);
1112
- this.clients.delete(clientId);
1113
- this.onDisconnectCallback?.(clientId);
1114
- }
1115
- }
1116
- closeClient(clientId) {
1117
- const client = this.clients.get(clientId);
1118
- if (client) {
1119
- try {
1120
- client.controller.close();
1121
- } catch {}
1122
- this.removeClient(clientId);
1123
- }
1124
- }
1125
- getClientCount() {
1126
- return this.clients.size;
1127
- }
1128
- getClientIds() {
1129
- return Array.from(this.clients.keys());
1130
- }
1131
- hasClient(clientId) {
1132
- return this.clients.has(clientId);
1133
- }
1134
- closeAll() {
1135
- for (const clientId of this.clients.keys()) {
1136
- this.closeClient(clientId);
1137
- }
1138
- }
1139
- }
1140
- function createSSEHandler(config = {}) {
1141
- return new SSEHandler(config);
1142
- }
1143
-
1144
- // src/handlers/http.ts
1145
- import { firstValueFrom, isError, isSnapshot } from "@sylphx/lens-core";
1146
- function sanitizeError(error, isDevelopment) {
1147
- if (isDevelopment) {
1148
- return error.message;
1149
- }
1150
- const message = error.message;
1151
- const safePatterns = [
1152
- /^Invalid input:/,
1153
- /^Missing operation/,
1154
- /^Not found/,
1155
- /^Unauthorized/,
1156
- /^Forbidden/,
1157
- /^Bad request/,
1158
- /^Validation failed/
1159
- ];
1160
- if (safePatterns.some((pattern) => pattern.test(message))) {
1161
- return message;
1162
- }
1163
- const sensitivePatterns = [
1164
- /\/[^\s]+\.(ts|js|json)/,
1165
- /at\s+[^\s]+\s+\(/,
1166
- /ENOENT|EACCES|ECONNREFUSED/,
1167
- /SELECT|INSERT|UPDATE|DELETE|FROM|WHERE/i,
1168
- /password|secret|token|key|auth/i
1169
- ];
1170
- if (sensitivePatterns.some((pattern) => pattern.test(message))) {
1171
- return "An internal error occurred";
1172
- }
1173
- if (message.length < 100 && !message.includes(`
1174
- `)) {
1175
- return message;
1176
- }
1177
- return "An internal error occurred";
1178
- }
1179
- function createHTTPHandler(server, options = {}) {
1180
- const { pathPrefix = "", cors, errors, health } = options;
1181
- const isDevelopment = errors?.development ?? false;
1182
- const healthEnabled = health?.enabled !== false;
1183
- const healthPath = health?.path ?? "/__lens/health";
1184
- const startTime = Date.now();
1185
- const sanitize = (error) => {
1186
- if (errors?.sanitize) {
1187
- return errors.sanitize(error);
1188
- }
1189
- return sanitizeError(error, isDevelopment);
1190
- };
1191
- const allowedOrigin = cors?.origin ? Array.isArray(cors.origin) ? cors.origin.join(", ") : cors.origin : isDevelopment ? "*" : "";
1192
- const baseHeaders = {
1193
- "Content-Type": "application/json",
1194
- "X-Content-Type-Options": "nosniff",
1195
- "X-Frame-Options": "DENY",
1196
- "Access-Control-Allow-Methods": cors?.methods?.join(", ") ?? "GET, POST, OPTIONS",
1197
- "Access-Control-Allow-Headers": cors?.headers?.join(", ") ?? "Content-Type, Authorization"
1198
- };
1199
- if (allowedOrigin) {
1200
- baseHeaders["Access-Control-Allow-Origin"] = allowedOrigin;
1201
- }
1202
- const handler = async (request) => {
1015
+ fetch = async (request) => {
1203
1016
  const url = new URL(request.url);
1204
1017
  const pathname = url.pathname;
1018
+ const baseHeaders = {
1019
+ "Content-Type": "application/json",
1020
+ "X-Content-Type-Options": "nosniff",
1021
+ "X-Frame-Options": "DENY",
1022
+ "Access-Control-Allow-Origin": "*",
1023
+ "Access-Control-Allow-Methods": "GET, POST, OPTIONS",
1024
+ "Access-Control-Allow-Headers": "Content-Type, Authorization"
1025
+ };
1205
1026
  if (request.method === "OPTIONS") {
1206
- return new Response(null, {
1207
- status: 204,
1208
- headers: baseHeaders
1209
- });
1027
+ return new Response(null, { status: 204, headers: baseHeaders });
1210
1028
  }
1211
- const fullHealthPath = `${pathPrefix}${healthPath}`;
1212
- if (healthEnabled && request.method === "GET" && pathname === fullHealthPath) {
1213
- const metadata = server.getMetadata();
1214
- const uptimeSeconds = Math.floor((Date.now() - startTime) / 1000);
1215
- let customChecks = {};
1216
- let hasFailure = false;
1217
- if (health?.checks) {
1218
- try {
1219
- customChecks = await health.checks();
1220
- hasFailure = Object.values(customChecks).some((c) => c.status === "fail");
1221
- } catch (error) {
1222
- customChecks.healthCheck = {
1223
- status: "fail",
1224
- message: error instanceof Error ? error.message : "Health check failed"
1225
- };
1226
- hasFailure = true;
1227
- }
1228
- }
1229
- const response = {
1230
- status: hasFailure ? "degraded" : "healthy",
1029
+ if (request.method === "GET" && pathname === "/__lens/health") {
1030
+ const metadata = this.getMetadata();
1031
+ return new Response(JSON.stringify({
1032
+ status: "healthy",
1231
1033
  service: "lens-server",
1232
1034
  version: metadata.version,
1233
- uptime: uptimeSeconds,
1234
1035
  timestamp: new Date().toISOString()
1235
- };
1236
- if (Object.keys(customChecks).length > 0) {
1237
- response.checks = customChecks;
1238
- }
1239
- return new Response(JSON.stringify(response), {
1240
- status: hasFailure ? 503 : 200,
1036
+ }), {
1241
1037
  headers: {
1242
- "Content-Type": "application/json",
1243
- "Cache-Control": "no-cache, no-store, must-revalidate",
1244
- ...baseHeaders
1038
+ ...baseHeaders,
1039
+ "Cache-Control": "no-cache, no-store, must-revalidate"
1245
1040
  }
1246
1041
  });
1247
1042
  }
1248
- const metadataPath = `${pathPrefix}/__lens/metadata`;
1249
- if (request.method === "GET" && pathname === metadataPath) {
1250
- return new Response(JSON.stringify(server.getMetadata()), {
1251
- headers: {
1252
- "Content-Type": "application/json",
1253
- ...baseHeaders
1254
- }
1043
+ if (request.method === "GET" && pathname === "/__lens/metadata") {
1044
+ return new Response(JSON.stringify(this.getMetadata()), {
1045
+ headers: baseHeaders
1255
1046
  });
1256
1047
  }
1257
- const operationPath = pathPrefix || "/";
1258
- if (request.method === "POST" && (pathname === operationPath || pathname === `${pathPrefix}/`)) {
1048
+ if (request.method === "POST" && (pathname === "/" || pathname === "")) {
1259
1049
  let body;
1260
1050
  try {
1261
1051
  body = await request.json();
1262
1052
  } catch {
1263
1053
  return new Response(JSON.stringify({ error: "Invalid JSON in request body" }), {
1264
1054
  status: 400,
1265
- headers: {
1266
- "Content-Type": "application/json",
1267
- ...baseHeaders
1268
- }
1055
+ headers: baseHeaders
1056
+ });
1057
+ }
1058
+ if (!body.path) {
1059
+ return new Response(JSON.stringify({ error: "Missing operation path" }), {
1060
+ status: 400,
1061
+ headers: baseHeaders
1269
1062
  });
1270
1063
  }
1271
1064
  try {
1272
- if (!body.path) {
1273
- return new Response(JSON.stringify({ error: "Missing operation path" }), {
1274
- status: 400,
1275
- headers: {
1276
- "Content-Type": "application/json",
1277
- ...baseHeaders
1278
- }
1279
- });
1280
- }
1281
- const result2 = await firstValueFrom(server.execute({
1282
- path: body.path,
1283
- input: body.input
1284
- }));
1285
- if (isError(result2)) {
1286
- return new Response(JSON.stringify({ error: result2.error }), {
1065
+ const result = await firstValueFrom(this.execute({ path: body.path, input: body.input }));
1066
+ if (isError(result)) {
1067
+ return new Response(JSON.stringify({ error: result.error }), {
1287
1068
  status: 500,
1288
- headers: {
1289
- "Content-Type": "application/json",
1290
- ...baseHeaders
1291
- }
1069
+ headers: baseHeaders
1292
1070
  });
1293
1071
  }
1294
- if (isSnapshot(result2)) {
1295
- return new Response(JSON.stringify({ data: result2.data }), {
1296
- headers: {
1297
- "Content-Type": "application/json",
1298
- ...baseHeaders
1299
- }
1072
+ if (isSnapshot(result)) {
1073
+ return new Response(JSON.stringify({ data: result.data }), {
1074
+ headers: baseHeaders
1300
1075
  });
1301
1076
  }
1302
- return new Response(JSON.stringify(result2), {
1303
- headers: {
1304
- "Content-Type": "application/json",
1305
- ...baseHeaders
1306
- }
1307
- });
1077
+ return new Response(JSON.stringify(result), { headers: baseHeaders });
1308
1078
  } catch (error) {
1309
- const err = error instanceof Error ? error : new Error(String(error));
1310
- return new Response(JSON.stringify({ error: sanitize(err) }), {
1079
+ const errMsg = error instanceof Error ? error.message : String(error);
1080
+ return new Response(JSON.stringify({ error: errMsg }), {
1311
1081
  status: 500,
1312
- headers: {
1313
- "Content-Type": "application/json",
1314
- ...baseHeaders
1315
- }
1082
+ headers: baseHeaders
1316
1083
  });
1317
1084
  }
1318
1085
  }
1319
1086
  return new Response(JSON.stringify({ error: "Not found" }), {
1320
1087
  status: 404,
1321
- headers: {
1322
- "Content-Type": "application/json",
1323
- ...baseHeaders
1324
- }
1088
+ headers: baseHeaders
1325
1089
  });
1326
1090
  };
1327
- const result = handler;
1328
- result.handle = handler;
1329
- return result;
1330
1091
  }
1331
-
1332
- // src/handlers/unified.ts
1333
- function createHandler(server, options = {}) {
1334
- const { ssePath = "/__lens/sse", heartbeatInterval, ...httpOptions } = options;
1335
- const pathPrefix = httpOptions.pathPrefix ?? "";
1336
- const fullSsePath = `${pathPrefix}${ssePath}`;
1337
- const httpHandler = createHTTPHandler(server, httpOptions);
1338
- const pluginManager = server.getPluginManager();
1339
- const sseHandler = new SSEHandler({
1340
- ...heartbeatInterval !== undefined && { heartbeatInterval },
1341
- onConnect: (client) => {
1342
- pluginManager.runOnConnect({ clientId: client.id });
1343
- },
1344
- onDisconnect: (clientId) => {
1345
- pluginManager.runOnDisconnect({ clientId, subscriptionCount: 0 });
1346
- }
1347
- });
1348
- const handler = async (request) => {
1349
- const url = new URL(request.url);
1350
- if (request.method === "GET" && url.pathname === fullSsePath) {
1351
- return sseHandler.handleConnection(request);
1352
- }
1353
- return httpHandler(request);
1354
- };
1355
- const result = handler;
1356
- result.handle = handler;
1357
- result.sse = sseHandler;
1358
- return result;
1092
+ function createApp(config) {
1093
+ const server = new LensServerImpl(config);
1094
+ const app = (request) => server.fetch(request);
1095
+ app.fetch = server.fetch;
1096
+ app.execute = server.execute.bind(server);
1097
+ app.getMetadata = server.getMetadata.bind(server);
1098
+ app.getPluginManager = server.getPluginManager.bind(server);
1099
+ return app;
1359
1100
  }
1360
1101
  // src/handlers/framework.ts
1361
1102
  import { firstValueFrom as firstValueFrom2, isError as isError2, isSnapshot as isSnapshot2 } from "@sylphx/lens-core";
@@ -1514,6 +1255,132 @@ function createFrameworkHandler(server, options = {}) {
1514
1255
  return new Response("Method not allowed", { status: 405 });
1515
1256
  };
1516
1257
  }
1258
+ // src/sse/handler.ts
1259
+ class SSEHandler {
1260
+ heartbeatInterval;
1261
+ onConnectCallback;
1262
+ onDisconnectCallback;
1263
+ clients = new Map;
1264
+ clientCounter = 0;
1265
+ constructor(config = {}) {
1266
+ this.heartbeatInterval = config.heartbeatInterval ?? 30000;
1267
+ this.onConnectCallback = config.onConnect;
1268
+ this.onDisconnectCallback = config.onDisconnect;
1269
+ }
1270
+ handleConnection(_req) {
1271
+ const clientId = `sse_${++this.clientCounter}_${Date.now()}`;
1272
+ const encoder = new TextEncoder;
1273
+ const stream = new ReadableStream({
1274
+ start: (controller) => {
1275
+ const heartbeat = setInterval(() => {
1276
+ try {
1277
+ controller.enqueue(encoder.encode(`: heartbeat ${Date.now()}
1278
+
1279
+ `));
1280
+ } catch {
1281
+ this.removeClient(clientId);
1282
+ }
1283
+ }, this.heartbeatInterval);
1284
+ this.clients.set(clientId, { controller, heartbeat, encoder });
1285
+ controller.enqueue(encoder.encode(`event: connected
1286
+ data: ${JSON.stringify({ clientId })}
1287
+
1288
+ `));
1289
+ const client = {
1290
+ id: clientId,
1291
+ send: (message) => this.send(clientId, message),
1292
+ sendEvent: (event, data) => this.sendEvent(clientId, event, data),
1293
+ close: () => this.closeClient(clientId)
1294
+ };
1295
+ this.onConnectCallback?.(client);
1296
+ },
1297
+ cancel: () => {
1298
+ this.removeClient(clientId);
1299
+ }
1300
+ });
1301
+ return new Response(stream, {
1302
+ headers: {
1303
+ "Content-Type": "text/event-stream",
1304
+ "Cache-Control": "no-cache",
1305
+ Connection: "keep-alive",
1306
+ "Access-Control-Allow-Origin": "*"
1307
+ }
1308
+ });
1309
+ }
1310
+ send(clientId, message) {
1311
+ const client = this.clients.get(clientId);
1312
+ if (!client)
1313
+ return false;
1314
+ try {
1315
+ const data = `data: ${JSON.stringify(message)}
1316
+
1317
+ `;
1318
+ client.controller.enqueue(client.encoder.encode(data));
1319
+ return true;
1320
+ } catch {
1321
+ this.removeClient(clientId);
1322
+ return false;
1323
+ }
1324
+ }
1325
+ sendEvent(clientId, event, data) {
1326
+ const client = this.clients.get(clientId);
1327
+ if (!client)
1328
+ return false;
1329
+ if (/[\r\n:]/.test(event)) {
1330
+ return false;
1331
+ }
1332
+ try {
1333
+ const message = `event: ${event}
1334
+ data: ${JSON.stringify(data)}
1335
+
1336
+ `;
1337
+ client.controller.enqueue(client.encoder.encode(message));
1338
+ return true;
1339
+ } catch {
1340
+ this.removeClient(clientId);
1341
+ return false;
1342
+ }
1343
+ }
1344
+ broadcast(message) {
1345
+ for (const clientId of this.clients.keys()) {
1346
+ this.send(clientId, message);
1347
+ }
1348
+ }
1349
+ removeClient(clientId) {
1350
+ const client = this.clients.get(clientId);
1351
+ if (client) {
1352
+ clearInterval(client.heartbeat);
1353
+ this.clients.delete(clientId);
1354
+ this.onDisconnectCallback?.(clientId);
1355
+ }
1356
+ }
1357
+ closeClient(clientId) {
1358
+ const client = this.clients.get(clientId);
1359
+ if (client) {
1360
+ try {
1361
+ client.controller.close();
1362
+ } catch {}
1363
+ this.removeClient(clientId);
1364
+ }
1365
+ }
1366
+ getClientCount() {
1367
+ return this.clients.size;
1368
+ }
1369
+ getClientIds() {
1370
+ return Array.from(this.clients.keys());
1371
+ }
1372
+ hasClient(clientId) {
1373
+ return this.clients.has(clientId);
1374
+ }
1375
+ closeAll() {
1376
+ for (const clientId of this.clients.keys()) {
1377
+ this.closeClient(clientId);
1378
+ }
1379
+ }
1380
+ }
1381
+ function createSSEHandler(config = {}) {
1382
+ return new SSEHandler(config);
1383
+ }
1517
1384
  // src/handlers/ws.ts
1518
1385
  import {
1519
1386
  firstValueFrom as firstValueFrom3,
@@ -2961,8 +2828,6 @@ export {
2961
2828
  createServerClientProxy,
2962
2829
  createSSEHandler,
2963
2830
  createPluginManager,
2964
- createHandler,
2965
- createHTTPHandler,
2966
2831
  createFrameworkHandler,
2967
2832
  createContext,
2968
2833
  createApp,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sylphx/lens-server",
3
- "version": "4.0.0",
3
+ "version": "4.1.0",
4
4
  "description": "Server runtime for Lens API framework",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -30,7 +30,7 @@
30
30
  "author": "SylphxAI",
31
31
  "license": "MIT",
32
32
  "dependencies": {
33
- "@sylphx/lens-core": "^4.0.1"
33
+ "@sylphx/lens-core": "^4.1.0"
34
34
  },
35
35
  "devDependencies": {
36
36
  "typescript": "^5.9.3",
@@ -68,7 +68,7 @@ describe("E2E - Basic Operations", () => {
68
68
 
69
69
  it("query with input", async () => {
70
70
  const getUser = query()
71
- .input(z.object({ id: z.string() }))
71
+ .args(z.object({ id: z.string() }))
72
72
  .returns(User)
73
73
  .resolve(({ args }) => {
74
74
  const user = mockUsers.find((u) => u.id === args.id);
@@ -96,7 +96,7 @@ describe("E2E - Basic Operations", () => {
96
96
 
97
97
  it("mutation", async () => {
98
98
  const createUser = mutation()
99
- .input(z.object({ name: z.string(), email: z.string() }))
99
+ .args(z.object({ name: z.string(), email: z.string() }))
100
100
  .returns(User)
101
101
  .resolve(({ args }) => ({
102
102
  id: "user-new",
@@ -130,7 +130,7 @@ describe("E2E - Basic Operations", () => {
130
130
 
131
131
  it("handles query errors", async () => {
132
132
  const failingQuery = query()
133
- .input(z.object({ id: z.string() }))
133
+ .args(z.object({ id: z.string() }))
134
134
  .resolve(() => {
135
135
  throw new Error("Query failed");
136
136
  });
@@ -178,7 +178,7 @@ describe("E2E - Context", () => {
178
178
  let capturedContext: unknown = null;
179
179
 
180
180
  const getUser = query()
181
- .input(z.object({ id: z.string() }))
181
+ .args(z.object({ id: z.string() }))
182
182
  .resolve(({ ctx }) => {
183
183
  capturedContext = ctx;
184
184
  return mockUsers[0];
@@ -206,7 +206,7 @@ describe("E2E - Context", () => {
206
206
  let capturedContext: unknown = null;
207
207
 
208
208
  const getUser = query()
209
- .input(z.object({ id: z.string() }))
209
+ .args(z.object({ id: z.string() }))
210
210
  .resolve(({ ctx }) => {
211
211
  capturedContext = ctx;
212
212
  return mockUsers[0];
@@ -240,7 +240,7 @@ describe("E2E - Context", () => {
240
240
  describe("E2E - Selection", () => {
241
241
  it("applies $select to filter fields", async () => {
242
242
  const getUser = query()
243
- .input(z.object({ id: z.string() }))
243
+ .args(z.object({ id: z.string() }))
244
244
  .returns(User)
245
245
  .resolve(({ args }) => {
246
246
  const user = mockUsers.find((u) => u.id === args.id);
@@ -278,7 +278,7 @@ describe("E2E - Selection", () => {
278
278
 
279
279
  it("includes id by default in selection", async () => {
280
280
  const getUser = query()
281
- .input(z.object({ id: z.string() }))
281
+ .args(z.object({ id: z.string() }))
282
282
  .returns(User)
283
283
  .resolve(({ args }) => mockUsers.find((u) => u.id === args.id)!);
284
284
 
@@ -340,7 +340,7 @@ describe("E2E - Entity Resolvers", () => {
340
340
  }));
341
341
 
342
342
  const getUser = query()
343
- .input(z.object({ id: z.string() }))
343
+ .args(z.object({ id: z.string() }))
344
344
  .returns(UserWithPosts)
345
345
  .resolve(({ args }) => {
346
346
  const user = users.find((u) => u.id === args.id);
@@ -460,12 +460,12 @@ describe("E2E - Entity Resolvers", () => {
460
460
  describe("E2E - Metadata", () => {
461
461
  it("returns correct metadata structure", () => {
462
462
  const getUser = query()
463
- .input(z.object({ id: z.string() }))
463
+ .args(z.object({ id: z.string() }))
464
464
  .returns(User)
465
465
  .resolve(({ args }) => mockUsers.find((u) => u.id === args.id)!);
466
466
 
467
467
  const createUser = mutation()
468
- .input(z.object({ name: z.string() }))
468
+ .args(z.object({ name: z.string() }))
469
469
  .returns(User)
470
470
  .resolve(({ args }) => ({ id: "new", name: args.name, email: "", status: "" }));
471
471
 
@@ -489,12 +489,12 @@ describe("E2E - Metadata", () => {
489
489
 
490
490
  it("auto-derives optimistic hints from naming with plugin", () => {
491
491
  const updateUser = mutation()
492
- .input(z.object({ id: z.string(), name: z.string() }))
492
+ .args(z.object({ id: z.string(), name: z.string() }))
493
493
  .returns(User)
494
494
  .resolve(({ args }) => ({ ...mockUsers[0], name: args.name }));
495
495
 
496
496
  const deleteUser = mutation()
497
- .input(z.object({ id: z.string() }))
497
+ .args(z.object({ id: z.string() }))
498
498
  .resolve(() => ({ success: true }));
499
499
 
500
500
  const server = createApp({
@@ -13,14 +13,14 @@ import { createHTTPHandler } from "./http.js";
13
13
  // =============================================================================
14
14
 
15
15
  const getUser = query()
16
- .input(z.object({ id: z.string() }))
16
+ .args(z.object({ id: z.string() }))
17
17
  .resolve(({ args }) => ({
18
18
  id: args.id,
19
19
  name: "Test User",
20
20
  }));
21
21
 
22
22
  const createUser = mutation()
23
- .input(z.object({ name: z.string() }))
23
+ .args(z.object({ name: z.string() }))
24
24
  .resolve(({ args }) => ({
25
25
  id: "new-id",
26
26
  name: args.name,