kitcn 0.16.0 → 0.17.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.
Files changed (38) hide show
  1. package/dist/aggregate/index.d.ts +1 -1
  2. package/dist/auth/client/index.js +1 -1
  3. package/dist/auth/index.js +19 -21
  4. package/dist/auth/nextjs/index.d.ts +1 -1
  5. package/dist/auth/nextjs/index.js +4 -4
  6. package/dist/{auth-store-ssZDPa37.js → auth-store-BnGZxmnY.js} +4 -1
  7. package/dist/{backend-core-DqPydYyx.mjs → backend-core-BsKP1LVg.mjs} +204 -164
  8. package/dist/{builder-DBgto1yn.js → builder-f4F_NRvK.js} +245 -153
  9. package/dist/{caller-factory-NEfgD5E0.js → caller-factory-DHywSoGZ.js} +7 -5
  10. package/dist/cli.mjs +14 -7
  11. package/dist/crpc/index.js +1 -127
  12. package/dist/{middleware-Bg-PdtrI.js → middleware-Cgrv2jIu.js} +1 -1
  13. package/dist/orm/index.d.ts +1 -1
  14. package/dist/orm/index.js +486 -121
  15. package/dist/plugins/index.js +1 -1
  16. package/dist/{procedure-caller-9m6NBxQu.js → procedure-caller-Rj6z3ai7.js} +1 -1
  17. package/dist/{procedure-name-Cy1AxayA.d.ts → procedure-name-Bo5KMcqc.d.ts} +15 -3
  18. package/dist/{query-context-ydn9kb6P.js → query-context-C90vNlc9.js} +131 -30
  19. package/dist/query-options-C_eBSIXG.js +247 -0
  20. package/dist/ratelimit/index.d.ts +26 -6
  21. package/dist/ratelimit/index.js +427 -100
  22. package/dist/ratelimit/react/index.d.ts +14 -0
  23. package/dist/ratelimit/react/index.js +149 -16
  24. package/dist/react/index.d.ts +3 -1
  25. package/dist/react/index.js +48 -15
  26. package/dist/rsc/index.js +22 -33
  27. package/dist/server/index.d.ts +1 -1
  28. package/dist/server/index.js +3 -3
  29. package/dist/solid/index.js +19 -5
  30. package/dist/watcher.mjs +2 -2
  31. package/dist/{where-clause-compiler-WF9UcrAB.d.ts → where-clause-compiler-BRhLW1dp.d.ts} +51 -0
  32. package/package.json +1 -1
  33. package/skills/kitcn/SKILL.md +1 -0
  34. package/skills/kitcn/references/features/create-plugins.md +1 -1
  35. package/skills/kitcn/references/features/orm.md +11 -1
  36. package/skills/kitcn/references/features/ratelimit.md +105 -0
  37. package/skills/kitcn/references/setup/server.md +1 -1
  38. package/dist/query-options-C96zLANM.js +0 -121
@@ -745,6 +745,20 @@ var CRPCError = class extends ConvexError {
745
745
  function isOrmNotFoundErrorLike(cause) {
746
746
  return cause instanceof Error && cause.name === "OrmNotFoundError";
747
747
  }
748
+ function isConvexErrorLike(cause) {
749
+ return cause instanceof Error && "data" in cause;
750
+ }
751
+ /**
752
+ * `ctx.runQuery`/`ctx.runMutation` never rethrow the original error object:
753
+ * Convex builds a fresh `ConvexError` from the message and re-attaches `.data`.
754
+ * A cRPC error therefore arrives as a plain `ConvexError` whose `data` still
755
+ * carries the original `code`/`message`.
756
+ */
757
+ function isCRPCErrorData(data) {
758
+ if (!data || typeof data !== "object" || Array.isArray(data)) return false;
759
+ const { code, message } = data;
760
+ return typeof code === "string" && code in CRPC_ERROR_CODES_BY_KEY && (message === void 0 || typeof message === "string");
761
+ }
748
762
  function isApiErrorLike(cause) {
749
763
  return cause instanceof Error && cause.name === "APIError" && typeof cause.statusCode === "number";
750
764
  }
@@ -785,6 +799,17 @@ function getApiErrorMessage(cause) {
785
799
  function toCRPCError(cause) {
786
800
  if (cause instanceof CRPCError) return cause;
787
801
  if (cause instanceof Error && cause.name === "CRPCError") return cause;
802
+ if (isConvexErrorLike(cause) && isCRPCErrorData(cause.data)) {
803
+ const { code, message, ...data } = cause.data;
804
+ const err = new CRPCError({
805
+ code,
806
+ message,
807
+ cause,
808
+ data
809
+ });
810
+ if (cause.stack) err.stack = cause.stack;
811
+ return err;
812
+ }
788
813
  if (isOrmNotFoundErrorLike(cause)) {
789
814
  const err = new CRPCError({
790
815
  code: "NOT_FOUND",
@@ -845,6 +870,44 @@ function isCRPCError(error) {
845
870
  return error instanceof CRPCError;
846
871
  }
847
872
 
873
+ //#endregion
874
+ //#region src/server/middleware-runner.ts
875
+ /** Run middleware around a terminal procedure resolver. */
876
+ const executeMiddlewares = async (middlewares, ctx, meta, procedure, input, getRawInput, resolve, index = 0) => {
877
+ if (index >= middlewares.length) return {
878
+ marker: void 0,
879
+ ctx,
880
+ input,
881
+ output: await resolve({
882
+ ctx,
883
+ input
884
+ })
885
+ };
886
+ const middleware = middlewares[index];
887
+ let currentInput = input;
888
+ let innerResult;
889
+ const next = async (opts) => {
890
+ const nextCtx = opts?.ctx ?? ctx;
891
+ if (opts?.input !== void 0) currentInput = opts.input;
892
+ innerResult = await executeMiddlewares(middlewares, nextCtx, meta, procedure, currentInput, getRawInput, resolve, index + 1);
893
+ return innerResult;
894
+ };
895
+ const result = await middleware({
896
+ ctx,
897
+ meta,
898
+ procedure,
899
+ input,
900
+ getRawInput,
901
+ next
902
+ });
903
+ return {
904
+ marker: void 0,
905
+ ctx: result.ctx ?? ctx,
906
+ input: result.input ?? innerResult?.input ?? currentInput,
907
+ output: result.output ?? innerResult?.output
908
+ };
909
+ };
910
+
848
911
  //#endregion
849
912
  //#region src/server/http-builder.ts
850
913
  function extractPathParams(path) {
@@ -865,29 +928,41 @@ function matchPathParams(template, pathname) {
865
928
  return params;
866
929
  }
867
930
  function handleHttpError(error) {
868
- if (error instanceof CRPCError) {
869
- const status = {
870
- BAD_REQUEST: 400,
871
- UNAUTHORIZED: 401,
872
- FORBIDDEN: 403,
873
- NOT_FOUND: 404,
874
- METHOD_NOT_SUPPORTED: 405,
875
- CONFLICT: 409,
876
- UNPROCESSABLE_CONTENT: 422,
877
- TOO_MANY_REQUESTS: 429,
878
- INTERNAL_SERVER_ERROR: 500
879
- }[error.code] ?? 500;
880
- return Response.json({ error: {
881
- code: error.code,
882
- message: error.message
883
- } }, { status });
884
- }
931
+ const crpcError = toCRPCError(error);
932
+ if (crpcError) return Response.json({ error: {
933
+ code: crpcError.code,
934
+ message: crpcError.message
935
+ } }, { status: getHTTPStatusCodeFromError(crpcError) });
885
936
  console.error("Unhandled HTTP error:", error);
886
937
  return Response.json({ error: {
887
938
  code: "INTERNAL_SERVER_ERROR",
888
939
  message: "An unexpected error occurred"
889
940
  } }, { status: 500 });
890
941
  }
942
+ /** Read a JSON body, reporting parse failures as client errors. */
943
+ async function readJsonBody(request) {
944
+ try {
945
+ return await request.json();
946
+ } catch (cause) {
947
+ throw new CRPCError({
948
+ code: "BAD_REQUEST",
949
+ message: "Invalid JSON body",
950
+ cause
951
+ });
952
+ }
953
+ }
954
+ /** Read a form body, reporting parse failures as client errors. */
955
+ async function readFormDataBody(request) {
956
+ try {
957
+ return await request.formData();
958
+ } catch (cause) {
959
+ throw new CRPCError({
960
+ code: "BAD_REQUEST",
961
+ message: "Invalid form data",
962
+ cause
963
+ });
964
+ }
965
+ }
891
966
  function getBaseSchema(schema) {
892
967
  if (schema instanceof z.ZodOptional || schema instanceof z.ZodNullable) return getBaseSchema(schema.unwrap());
893
968
  if (schema instanceof z.ZodDefault) return getBaseSchema(schema._def.innerType);
@@ -949,109 +1024,86 @@ function createProcedure(def, handler, _type) {
949
1024
  try {
950
1025
  const url = new URL(request.url);
951
1026
  const pathParams = c.req.param() ?? matchPathParams(def.route.path, url.pathname) ?? {};
952
- let ctx = def.functionConfig.createContext(convexCtx);
1027
+ const initialCtx = def.functionConfig.createContext(convexCtx);
953
1028
  const getRawInput = async () => {
954
- if ((request.headers.get("content-type") ?? "").includes("application/json")) return request.clone().json();
1029
+ if ((request.headers.get("content-type") ?? "").includes("application/json")) return readJsonBody(request.clone());
955
1030
  return null;
956
1031
  };
957
- let currentInput;
958
- for (const middleware of def.middlewares) {
959
- const result = await middleware({
960
- ctx,
961
- procedure: middlewareProcedure,
962
- input: currentInput,
963
- getRawInput,
964
- next: async (opts) => {
965
- if (opts?.ctx) ctx = {
966
- ...ctx,
967
- ...opts.ctx
968
- };
969
- if (opts?.input !== void 0) currentInput = opts.input;
970
- return {
971
- ctx,
972
- marker: void 0
973
- };
974
- },
975
- meta: def.meta
976
- });
977
- if (result?.ctx) ctx = {
978
- ...ctx,
979
- ...result.ctx
980
- };
981
- }
982
- let parsedParams;
983
- if (def.paramsSchema) try {
984
- parsedParams = def.paramsSchema.parse(pathParams);
985
- } catch (error) {
986
- if (error instanceof z.ZodError) throw new CRPCError({
987
- code: "BAD_REQUEST",
988
- message: "Invalid path params",
989
- cause: error
990
- });
991
- throw error;
992
- }
993
- let parsedQuery;
994
- if (def.querySchema) {
995
- const queryParams = parseQueryParams(url, def.querySchema);
996
- try {
997
- parsedQuery = def.querySchema.parse(queryParams);
1032
+ return (await executeMiddlewares(def.middlewares, initialCtx, def.meta, middlewareProcedure, void 0, getRawInput, async ({ ctx }) => {
1033
+ let parsedParams;
1034
+ if (def.paramsSchema) try {
1035
+ parsedParams = def.paramsSchema.parse(pathParams);
998
1036
  } catch (error) {
999
1037
  if (error instanceof z.ZodError) throw new CRPCError({
1000
1038
  code: "BAD_REQUEST",
1001
- message: "Invalid query params",
1039
+ message: "Invalid path params",
1002
1040
  cause: error
1003
1041
  });
1004
1042
  throw error;
1005
1043
  }
1006
- }
1007
- let parsedInput;
1008
- if (def.inputSchema && request.method !== "GET") {
1009
- const contentType = request.headers.get("content-type") ?? "";
1010
- let body;
1011
- if (contentType.includes("application/json")) body = await request.json();
1012
- else if (contentType.includes("application/x-www-form-urlencoded")) {
1013
- const formData = await request.formData();
1014
- body = Object.fromEntries(formData.entries());
1015
- } else body = await request.json().catch(() => ({}));
1016
- try {
1017
- parsedInput = def.inputSchema.parse(def.functionConfig.transformer.input.deserialize(body));
1018
- } catch (error) {
1019
- if (error instanceof z.ZodError) throw new CRPCError({
1020
- code: "BAD_REQUEST",
1021
- message: "Invalid input",
1022
- cause: error
1023
- });
1024
- throw error;
1044
+ let parsedQuery;
1045
+ if (def.querySchema) {
1046
+ const queryParams = parseQueryParams(url, def.querySchema);
1047
+ try {
1048
+ parsedQuery = def.querySchema.parse(queryParams);
1049
+ } catch (error) {
1050
+ if (error instanceof z.ZodError) throw new CRPCError({
1051
+ code: "BAD_REQUEST",
1052
+ message: "Invalid query params",
1053
+ cause: error
1054
+ });
1055
+ throw error;
1056
+ }
1025
1057
  }
1026
- }
1027
- let parsedForm;
1028
- if (def.formSchema && request.method !== "GET") {
1029
- const formData = await request.formData();
1030
- const formObj = {};
1031
- for (const [key, value] of formData.entries()) formObj[key] = value;
1032
- try {
1033
- parsedForm = def.formSchema.parse(formObj);
1034
- } catch (error) {
1035
- if (error instanceof z.ZodError) throw new CRPCError({
1036
- code: "BAD_REQUEST",
1037
- message: "Invalid form data",
1038
- cause: error
1039
- });
1040
- throw error;
1058
+ let parsedInput;
1059
+ if (def.inputSchema && request.method !== "GET") {
1060
+ const contentType = request.headers.get("content-type") ?? "";
1061
+ let body;
1062
+ if (contentType.includes("application/json")) body = await readJsonBody(request);
1063
+ else if (contentType.includes("application/x-www-form-urlencoded")) {
1064
+ const formData = await readFormDataBody(request);
1065
+ body = Object.fromEntries(formData.entries());
1066
+ } else body = await request.json().catch(() => ({}));
1067
+ try {
1068
+ parsedInput = def.inputSchema.parse(def.functionConfig.transformer.input.deserialize(body));
1069
+ } catch (error) {
1070
+ if (error instanceof z.ZodError) throw new CRPCError({
1071
+ code: "BAD_REQUEST",
1072
+ message: "Invalid input",
1073
+ cause: error
1074
+ });
1075
+ throw error;
1076
+ }
1041
1077
  }
1042
- }
1043
- const handlerOpts = {
1044
- ctx,
1045
- c
1046
- };
1047
- if (parsedInput !== void 0) handlerOpts.input = parsedInput;
1048
- if (parsedParams !== void 0) handlerOpts.params = parsedParams;
1049
- if (parsedQuery !== void 0) handlerOpts.searchParams = parsedQuery;
1050
- if (parsedForm !== void 0) handlerOpts.form = parsedForm;
1051
- const result = await handler(handlerOpts);
1052
- if (result instanceof Response) return result;
1053
- const output = def.outputSchema ? def.outputSchema.parse(result) : result;
1054
- return c.json(def.functionConfig.transformer.output.serialize(output));
1078
+ let parsedForm;
1079
+ if (def.formSchema && request.method !== "GET") {
1080
+ const formData = await readFormDataBody(request);
1081
+ const formObj = {};
1082
+ for (const [key, value] of formData.entries()) formObj[key] = value;
1083
+ try {
1084
+ parsedForm = def.formSchema.parse(formObj);
1085
+ } catch (error) {
1086
+ if (error instanceof z.ZodError) throw new CRPCError({
1087
+ code: "BAD_REQUEST",
1088
+ message: "Invalid form data",
1089
+ cause: error
1090
+ });
1091
+ throw error;
1092
+ }
1093
+ }
1094
+ const handlerOpts = {
1095
+ ctx,
1096
+ c
1097
+ };
1098
+ if (parsedInput !== void 0) handlerOpts.input = parsedInput;
1099
+ if (parsedParams !== void 0) handlerOpts.params = parsedParams;
1100
+ if (parsedQuery !== void 0) handlerOpts.searchParams = parsedQuery;
1101
+ if (parsedForm !== void 0) handlerOpts.form = parsedForm;
1102
+ const result = await handler(handlerOpts);
1103
+ if (result instanceof Response) return result;
1104
+ const output = def.outputSchema ? def.outputSchema.parse(result) : result;
1105
+ return c.json(def.functionConfig.transformer.output.serialize(output));
1106
+ })).output;
1055
1107
  } catch (error) {
1056
1108
  return handleHttpError(error);
1057
1109
  }
@@ -1541,34 +1593,6 @@ const resolveProcedureInfo = (type, procedureName, procedureFn) => {
1541
1593
  name: (procedureFn && typeof procedureFn === "object" && typeof procedureFn[FUNCTION_NAME_SYMBOL] === "string" ? procedureFn[FUNCTION_NAME_SYMBOL] : void 0) ?? procedureName
1542
1594
  };
1543
1595
  };
1544
- /** Execute middleware chain recursively with input access */
1545
- async function executeMiddlewares(middlewares, ctx, meta, procedure, input, getRawInput, index = 0) {
1546
- if (index >= middlewares.length) return {
1547
- marker: void 0,
1548
- ctx,
1549
- input
1550
- };
1551
- const middleware = middlewares[index];
1552
- let currentInput = input;
1553
- const next = async (opts) => {
1554
- const nextCtx = opts?.ctx ?? ctx;
1555
- const nextInput = opts?.input ?? currentInput;
1556
- if (opts?.input !== void 0) currentInput = opts.input;
1557
- return await executeMiddlewares(middlewares, nextCtx, meta, procedure, nextInput, getRawInput, index + 1);
1558
- };
1559
- return {
1560
- marker: void 0,
1561
- ctx: (await middleware({
1562
- ctx,
1563
- meta,
1564
- procedure,
1565
- input,
1566
- getRawInput,
1567
- next
1568
- })).ctx ?? ctx,
1569
- input: currentInput
1570
- };
1571
- }
1572
1596
  const isPlainObject = (value) => !!value && typeof value === "object" && !Array.isArray(value) && !(value instanceof Date);
1573
1597
  const toConvexSafeValue = (value) => {
1574
1598
  if (value instanceof Date) return value.getTime();
@@ -1686,22 +1710,92 @@ const replaceUnencodableInputTypes = (schema) => {
1686
1710
  if (schema instanceof z.ZodDefault) return replaceUnencodableInputTypes(schema.removeDefault());
1687
1711
  return schema;
1688
1712
  };
1713
+ /**
1714
+ * Rebuild a shape from the Convex validator it produces.
1715
+ *
1716
+ * The result is structurally identical (so the generated Convex validator is
1717
+ * unchanged) but carries no checks, transforms, or defaults. cRPC's own
1718
+ * `.input()` parse stays the single authoritative one, so refinements and
1719
+ * transforms never run twice.
1720
+ */
1721
+ const toWireShape = (shape) => {
1722
+ try {
1723
+ return convexToZodFields(zodToConvexFields(shape));
1724
+ } catch {
1725
+ return shape;
1726
+ }
1727
+ };
1689
1728
  const resolveConvexArgsShape = (inputShape) => {
1690
1729
  if (!inputShape) return;
1691
1730
  const rawSchema = z.object(inputShape);
1692
1731
  try {
1693
1732
  zodToConvex(rawSchema);
1694
- return inputShape;
1733
+ return toWireShape(inputShape);
1695
1734
  } catch {
1696
1735
  const compatibleSchema = replaceUnencodableInputTypes(rawSchema);
1697
1736
  try {
1698
1737
  zodToConvex(compatibleSchema);
1699
- return compatibleSchema.shape;
1738
+ return toWireShape(compatibleSchema.shape);
1700
1739
  } catch {
1701
1740
  return Object.fromEntries(Object.keys(inputShape).map((key) => [key, z.any()]));
1702
1741
  }
1703
1742
  }
1704
1743
  };
1744
+ /**
1745
+ * Strip the field validators for keys a later `.input()` redeclares.
1746
+ *
1747
+ * The keys stay on the schema so its object-level checks still see them - and
1748
+ * read the value their owner parsed - while only the last declaration validates
1749
+ * them. `safeExtend` is the one zod object operation that rewrites keys on a
1750
+ * schema carrying object-level checks; `omit` and `extend` both refuse.
1751
+ */
1752
+ const relaxSupersededKeys = (schema, superseded) => {
1753
+ if (superseded.length === 0) return schema;
1754
+ try {
1755
+ return schema.safeExtend(Object.fromEntries(superseded.map((key) => [key, z.any()])));
1756
+ } catch {
1757
+ return schema;
1758
+ }
1759
+ };
1760
+ /**
1761
+ * Parse the wire payload through every `.input()` schema.
1762
+ *
1763
+ * Each schema parses only the keys it owns - the last `.input()` to declare a
1764
+ * key wins, matching the merged shape the Convex arg validator is built from -
1765
+ * so object-level checks run against the shape they were written for without an
1766
+ * earlier, superseded declaration vetoing the payload.
1767
+ */
1768
+ const parseInput = (inputSchemas, value) => {
1769
+ try {
1770
+ if (inputSchemas.length === 1) return inputSchemas[0].parse(value);
1771
+ const ownerOf = /* @__PURE__ */ new Map();
1772
+ inputSchemas.forEach((schema, index) => {
1773
+ for (const key of Object.keys(schema.shape)) ownerOf.set(key, index);
1774
+ });
1775
+ const source = isPlainObject(value) ? value : {};
1776
+ const parsed = {};
1777
+ for (let index = inputSchemas.length - 1; index >= 0; index -= 1) {
1778
+ const schema = inputSchemas[index];
1779
+ const keys = Object.keys(schema.shape);
1780
+ const superseded = new Set(keys.filter((key) => ownerOf.get(key) !== index));
1781
+ const scoped = relaxSupersededKeys(schema, [...superseded]);
1782
+ const narrowed = {};
1783
+ for (const key of keys) {
1784
+ if (superseded.has(key)) {
1785
+ if (key in parsed) narrowed[key] = parsed[key];
1786
+ continue;
1787
+ }
1788
+ if (Object.hasOwn(source, key)) narrowed[key] = source[key];
1789
+ }
1790
+ const result = scoped.parse(narrowed);
1791
+ for (const key of keys) if (ownerOf.get(key) === index && key in result) parsed[key] = result[key];
1792
+ }
1793
+ return parsed;
1794
+ } catch (cause) {
1795
+ if (cause instanceof z.ZodError) throw new ConvexError({ ZodError: JSON.parse(JSON.stringify(cause.issues, null, 2)) });
1796
+ throw cause;
1797
+ }
1798
+ };
1705
1799
  const resolveConvexReturnsSchema = (schema) => {
1706
1800
  if (!schema) return;
1707
1801
  try {
@@ -1744,7 +1838,7 @@ var ProcedureBuilder = class {
1744
1838
  _input(schema) {
1745
1839
  return {
1746
1840
  ...this._def,
1747
- inputSchemas: [...this._def.inputSchemas, schema.shape]
1841
+ inputSchemas: [...this._def.inputSchemas, schema]
1748
1842
  };
1749
1843
  }
1750
1844
  /** Define output schema - to be overridden by subclasses */
@@ -1771,17 +1865,15 @@ var ProcedureBuilder = class {
1771
1865
  procedureName: value
1772
1866
  };
1773
1867
  }
1774
- /** Merge all input schemas into one */
1868
+ /** Merge every `.input()` shape - used to build the Convex arg validator */
1775
1869
  _getMergedInput() {
1776
1870
  const { inputSchemas } = this._def;
1777
1871
  if (inputSchemas.length === 0) return;
1778
- return Object.assign({}, ...inputSchemas);
1872
+ return Object.assign({}, ...inputSchemas.map((schema) => schema.shape));
1779
1873
  }
1780
1874
  _createFunction(handler, baseFunction, customFn, fnType) {
1781
- const { middlewares, outputSchema, meta, procedureName, functionConfig, isInternal } = this._def;
1782
- const mergedInput = this._getMergedInput();
1783
- const inputSchema = mergedInput ? z.object(mergedInput) : void 0;
1784
- const convexArgs = resolveConvexArgsShape(mergedInput);
1875
+ const { middlewares, inputSchemas, outputSchema, meta, procedureName, functionConfig, isInternal } = this._def;
1876
+ const convexArgs = resolveConvexArgsShape(this._getMergedInput());
1785
1877
  const customFunction = customFn(baseFunction, customCtx(async (_ctx) => withConvexSafeRunners(await functionConfig.createContext(_ctx))));
1786
1878
  const returnsSchema = resolveConvexReturnsSchema(outputSchema);
1787
1879
  const typedReturnsSchema = returnsSchema;
@@ -1794,16 +1886,16 @@ var ProcedureBuilder = class {
1794
1886
  ...typedReturnsSchema ? { returns: typedReturnsSchema } : {},
1795
1887
  handler: async (ctx, rawInput) => {
1796
1888
  const decodedInput = functionConfig.transformer.input.deserialize(rawInput);
1797
- const parsedInput = inputSchema ? inputSchema.parse(decodedInput) : decodedInput;
1889
+ const parsedInput = inputSchemas.length > 0 ? parseInput(inputSchemas, decodedInput) : decodedInput;
1798
1890
  const getRawInput = async () => parsedInput;
1799
1891
  try {
1800
- const result = await executeMiddlewares(middlewares, ctx, meta, resolveProcedureInfo(fnType, resolvedProcedureName, fn), parsedInput, getRawInput);
1801
- const handlerInput = result.input === parsedInput ? parsedInput : functionConfig.transformer.input.deserialize(result.input ?? parsedInput);
1802
- const output = await handler({
1803
- ctx: result.ctx,
1804
- input: handlerInput
1892
+ const result = await executeMiddlewares(middlewares, ctx, meta, resolveProcedureInfo(fnType, resolvedProcedureName, fn), parsedInput, getRawInput, async ({ ctx: resolvedCtx, input: resolvedInput }) => {
1893
+ return await handler({
1894
+ ctx: resolvedCtx,
1895
+ input: resolvedInput === parsedInput ? parsedInput : functionConfig.transformer.input.deserialize(resolvedInput ?? parsedInput)
1896
+ });
1805
1897
  });
1806
- const validatedOutput = shouldValidateOutputWithZod ? outputSchema.parse(output) : output;
1898
+ const validatedOutput = shouldValidateOutputWithZod ? outputSchema.parse(result.output) : result.output;
1807
1899
  return functionConfig.transformer.output.serialize(validatedOutput);
1808
1900
  } catch (cause) {
1809
1901
  const err = toCRPCError(cause);
@@ -1868,7 +1960,7 @@ var QueryProcedureBuilder = class QueryProcedureBuilder extends ProcedureBuilder
1868
1960
  });
1869
1961
  return new QueryProcedureBuilder({
1870
1962
  ...this._def,
1871
- inputSchemas: [...this._def.inputSchemas, paginationSchemaWithDefault.shape],
1963
+ inputSchemas: [...this._def.inputSchemas, paginationSchemaWithDefault],
1872
1964
  outputSchema,
1873
1965
  meta: {
1874
1966
  ...this._def.meta,
@@ -1,3 +1,4 @@
1
+ import { n as defaultIsUnauthorized } from "./error-Bvo7YEhk.js";
1
2
  import { i as getFunctionType, n as getFuncRef, t as buildMetaIndex } from "./meta-utils-D9K4fICl.js";
2
3
  import { s as getTransformer } from "./transformer-C6pGVHqx.js";
3
4
  import { fetchAction, fetchMutation, fetchQuery } from "convex/nextjs";
@@ -147,15 +148,16 @@ function createCallerFactory(opts) {
147
148
  const siteUrl = parseConvexSiteUrl(opts.convexSiteUrl);
148
149
  const convexUrl = getConvexUrl(siteUrl, opts.convexUrl);
149
150
  const getToken = opts.auth?.getToken ?? noAuthGetToken;
150
- const isUnauthorized = opts.auth?.isUnauthorized;
151
+ const isRetryableAuthError = opts.auth ? opts.auth.isUnauthorized ?? defaultIsUnauthorized : void 0;
152
+ const shouldReturnNullOnUnauthorized = opts.auth?.isUnauthorized;
151
153
  const crpcMeta = buildMetaIndex(opts.api);
152
154
  const callWithTokenAndRetry = async (fn, tokenResult, headers) => {
153
- const shouldRetryWithFreshToken = !!opts.auth && !tokenResult.isFresh;
155
+ const canRefreshToken = !!opts.auth && !tokenResult.isFresh;
154
156
  try {
155
157
  return await fn(tokenResult.token);
156
158
  } catch (error) {
157
- if (!shouldRetryWithFreshToken) {
158
- if (isUnauthorized?.(error)) return null;
159
+ if (!(canRefreshToken && isRetryableAuthError?.(error))) {
160
+ if (shouldReturnNullOnUnauthorized?.(error)) return null;
159
161
  throw error;
160
162
  }
161
163
  const newToken = await getToken(siteUrl, headers, {
@@ -165,7 +167,7 @@ function createCallerFactory(opts) {
165
167
  try {
166
168
  return await fn(newToken.token);
167
169
  } catch (retryError) {
168
- if (isUnauthorized?.(retryError)) return null;
170
+ if (shouldReturnNullOnUnauthorized?.(retryError)) return null;
169
171
  throw retryError;
170
172
  }
171
173
  }
package/dist/cli.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { $ as promptForScaffoldTemplateSelection, A as resolveCodegenTrimSegments, At as highlighter, B as runConfiguredCodegen, C as isEntryPoint, Ct as formatDependencyInstallCommand, D as parseInitCommandArgs, E as parseBackendRunJson, Et as stripConvexCommandNoise, F as resolveRunDeps, G as runMigrationFlow, H as runDevSchemaBackfillIfNeeded, I as runAfterScaffoldScript, J as withWorkingDirectory, K as trackProcess, L as runAggregateBackfillFlow, M as resolveDocTopic, N as resolveInitProjectDir, O as readPackageVersions, P as resolveMigrationConfig, Q as promptForPluginSelection, R as runAggregatePruneFlow, S as isConvexDevPreRunConflictFlag, St as detectPackageManager, T as parseArgs, Tt as serializeEnvValue, U as runInitCommandFlow, V as runConvexInitIfNeeded, W as runMigrationCreate, X as collectPluginScaffoldTemplates, Y as createSpinner, Z as filterScaffoldTemplatePathMap, _ as formatInfoOutput, _t as applyPlanningDependencyInstall, a as cleanup, at as getPluginCatalogEntry, b as getDevAggregateBackfillStatePath, bt as resolveSupportedDependencyWarnings, c as createCommandEnv, ct as buildPluginInstallPlan, d as extractBackfillCliOptions, dt as collectInstalledPluginKeys, et as resolveAddTemplateDefaults, f as extractConcaveRunTargetArgs, ft as getPluginLockfilePath, g as formatDocsOutput, gt as applyDependencyHintsInstall, h as extractResetCliOptions, ht as resolveSchemaInstalledPlugins, i as buildInitializationPlan, it as resolveTemplatesByIdOrThrow, j as resolveConfiguredBackend, k as resolveBackfillConfig, kt as logger, l as ensureConvexGitignoreEntry, lt as resolvePluginScaffoldRoots, m as extractMigrationDownOptions, mt as readPluginLockfile, n as applyPluginInstallPlanFiles, nt as resolvePresetScaffoldTemplates, o as createBackendAdapter, ot as getSupportedPluginKeys, p as extractMigrationCliOptions, pt as getSchemaFilePath, q as withLocalCodegenEnv, r as assertNoRemovedDevPreRunFlag, rt as resolveTemplateSelectionSource, s as createBackendCommandEnv, st as isSupportedPluginKey, t as applyDependencyInstallPlan, tt as resolvePluginPreset, u as extractBackendRunTargetArgs, ut as assertSchemaFileExists, v as getAggregateBackfillDeploymentKey, vt as applyPluginDependencyInstall, w as isInitialized, wt as resolveAuthEnvState, x as hasRemoteConvexDeploymentEnv, xt as resolveProjectScaffoldContext, y as getConvexDeploymentCommandEnv, yt as inspectPluginDependencyInstall, z as runBackendFunction } from "./backend-core-DqPydYyx.mjs";
2
+ import { $ as promptForScaffoldTemplateSelection, A as resolveCodegenTrimSegments, B as runConfiguredCodegen, C as isEntryPoint, Ct as formatDependencyInstallCommand, D as parseInitCommandArgs, E as parseBackendRunJson, Et as stripConvexCommandNoise, F as resolveRunDeps, G as runMigrationFlow, H as runDevSchemaBackfillIfNeeded, I as runAfterScaffoldScript, J as withWorkingDirectory, K as trackProcess, L as runAggregateBackfillFlow, M as resolveDocTopic, N as resolveInitProjectDir, O as readPackageVersions, P as resolveMigrationConfig, Q as promptForPluginSelection, R as runAggregatePruneFlow, S as isConvexDevPreRunConflictFlag, St as detectPackageManager, T as parseArgs, Tt as serializeEnvValue, U as runInitCommandFlow, V as runConvexInitIfNeeded, W as runMigrationCreate, X as collectPluginScaffoldTemplates, Y as createSpinner, Z as filterScaffoldTemplatePathMap, _ as formatInfoOutput, _t as applyPlanningDependencyInstall, a as cleanup, at as getPluginCatalogEntry, b as getDevAggregateBackfillStatePath, bt as resolveSupportedDependencyWarnings, c as createCommandEnv, ct as buildPluginInstallPlan, d as extractBackfillCliOptions, dt as collectInstalledPluginKeys, et as resolveAddTemplateDefaults, f as extractConcaveRunTargetArgs, ft as getPluginLockfilePath, g as formatDocsOutput, gt as applyDependencyHintsInstall, h as extractResetCliOptions, ht as resolveSchemaInstalledPlugins, i as buildInitializationPlan, it as resolveTemplatesByIdOrThrow, j as resolveConfiguredBackend, jt as highlighter, k as resolveBackfillConfig, kt as logger, l as ensureConvexGitignoreEntry, lt as resolvePluginScaffoldRoots, m as extractMigrationDownOptions, mt as readPluginLockfile, n as applyPluginInstallPlanFiles, nt as resolvePresetScaffoldTemplates, o as createBackendAdapter, ot as getSupportedPluginKeys, p as extractMigrationCliOptions, pt as getSchemaFilePath, q as withLocalCodegenEnv, r as assertNoRemovedDevPreRunFlag, rt as resolveTemplateSelectionSource, s as createBackendCommandEnv, st as isSupportedPluginKey, t as applyDependencyInstallPlan, tt as resolvePluginPreset, u as extractBackendRunTargetArgs, ut as assertSchemaFileExists, v as getAggregateBackfillDeploymentKey, vt as applyPluginDependencyInstall, w as isInitialized, wt as resolveAuthEnvState, x as hasRemoteConvexDeploymentEnv, xt as resolveProjectScaffoldContext, y as getConvexDeploymentCommandEnv, yt as inspectPluginDependencyInstall, z as runBackendFunction } from "./backend-core-BsKP1LVg.mjs";
3
3
  import fs, { existsSync, readFileSync } from "node:fs";
4
4
  import path, { delimiter, dirname, join, relative, resolve } from "node:path";
5
5
  import { fileURLToPath } from "node:url";
@@ -1471,16 +1471,22 @@ const handleAddCommand = async (argv, deps = {}) => {
1471
1471
  created: applyResult.created,
1472
1472
  manualActions: applyResult.manualActions,
1473
1473
  updated: applyResult.updated,
1474
- skipped: applyResult.skipped
1474
+ skipped: applyResult.skipped,
1475
+ refused: applyResult.refused,
1476
+ complete: applyResult.refused.length === 0
1475
1477
  };
1478
+ const resultLine = `${selectedPlugin} scaffold results: ${applyResult.created.length} created, ${applyResult.updated.length} updated, ${applyResult.skipped.length} skipped, ${applyResult.refused.length} refused.`;
1476
1479
  if (addArgs.json) console.info(JSON.stringify(payload));
1477
1480
  else {
1478
- logger.success(`✔ ${selectedPlugin} scaffold results: ${applyResult.created.length} created, ${applyResult.updated.length} updated, ${applyResult.skipped.length} skipped.`);
1481
+ if (applyResult.refused.length > 0) logger.error(`✖ ${resultLine}`);
1482
+ else logger.success(`✔ ${resultLine}`);
1479
1483
  if (applyResult.created.length > 0) logger.write(`Created files:\n${applyResult.created.map((file) => ` - ${file}`).join("\n")}`);
1480
1484
  if (applyResult.updated.length > 0) logger.write(`Updated files:\n${applyResult.updated.map((file) => ` - ${file}`).join("\n")}`);
1481
- if (applyResult.skipped.length > 0) {
1482
- logger.write(`Skipped files:\n${applyResult.skipped.map((file) => ` - ${file}`).join("\n")}`);
1483
- if (!addArgs.schema && !addArgs.overwrite) logger.info("Re-run with --overwrite to replace changed files.");
1485
+ if (applyResult.skipped.length > 0) logger.write(`Skipped files (already up to date):\n${applyResult.skipped.map((file) => ` - ${file}`).join("\n")}`);
1486
+ if (applyResult.refused.length > 0) {
1487
+ logger.write(`Refused files (your changes were kept):\n${applyResult.refused.map((file) => ` - ${file}`).join("\n")}`);
1488
+ logger.info("Re-run with --overwrite to replace these files, or merge the changes yourself.");
1489
+ logger.error(`${selectedPlugin} is only partially installed.`);
1484
1490
  }
1485
1491
  if (applyResult.manualActions.length > 0) {
1486
1492
  logger.info("Manual actions:");
@@ -1551,7 +1557,7 @@ const handleAddCommand = async (argv, deps = {}) => {
1551
1557
  });
1552
1558
  if (hookExitCode !== 0) return hookExitCode;
1553
1559
  }
1554
- return 0;
1560
+ return applyResult.refused.length > 0 ? 1 : 0;
1555
1561
  };
1556
1562
 
1557
1563
  //#endregion
@@ -2240,6 +2246,7 @@ const handleInitCommand = async (argv, deps = {}) => {
2240
2246
  created: result.created,
2241
2247
  updated: result.updated,
2242
2248
  skipped: result.skipped,
2249
+ refused: result.refused,
2243
2250
  usedShadcn: result.usedShadcn,
2244
2251
  template: result.template,
2245
2252
  codegen: result.codegen,