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.
- package/dist/aggregate/index.d.ts +1 -1
- package/dist/auth/client/index.js +1 -1
- package/dist/auth/index.js +19 -21
- package/dist/auth/nextjs/index.d.ts +1 -1
- package/dist/auth/nextjs/index.js +4 -4
- package/dist/{auth-store-ssZDPa37.js → auth-store-BnGZxmnY.js} +4 -1
- package/dist/{backend-core-DqPydYyx.mjs → backend-core-BsKP1LVg.mjs} +204 -164
- package/dist/{builder-DBgto1yn.js → builder-f4F_NRvK.js} +245 -153
- package/dist/{caller-factory-NEfgD5E0.js → caller-factory-DHywSoGZ.js} +7 -5
- package/dist/cli.mjs +14 -7
- package/dist/crpc/index.js +1 -127
- package/dist/{middleware-Bg-PdtrI.js → middleware-Cgrv2jIu.js} +1 -1
- package/dist/orm/index.d.ts +1 -1
- package/dist/orm/index.js +486 -121
- package/dist/plugins/index.js +1 -1
- package/dist/{procedure-caller-9m6NBxQu.js → procedure-caller-Rj6z3ai7.js} +1 -1
- package/dist/{procedure-name-Cy1AxayA.d.ts → procedure-name-Bo5KMcqc.d.ts} +15 -3
- package/dist/{query-context-ydn9kb6P.js → query-context-C90vNlc9.js} +131 -30
- package/dist/query-options-C_eBSIXG.js +247 -0
- package/dist/ratelimit/index.d.ts +26 -6
- package/dist/ratelimit/index.js +427 -100
- package/dist/ratelimit/react/index.d.ts +14 -0
- package/dist/ratelimit/react/index.js +149 -16
- package/dist/react/index.d.ts +3 -1
- package/dist/react/index.js +48 -15
- package/dist/rsc/index.js +22 -33
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.js +3 -3
- package/dist/solid/index.js +19 -5
- package/dist/watcher.mjs +2 -2
- package/dist/{where-clause-compiler-WF9UcrAB.d.ts → where-clause-compiler-BRhLW1dp.d.ts} +51 -0
- package/package.json +1 -1
- package/skills/kitcn/SKILL.md +1 -0
- package/skills/kitcn/references/features/create-plugins.md +1 -1
- package/skills/kitcn/references/features/orm.md +11 -1
- package/skills/kitcn/references/features/ratelimit.md +105 -0
- package/skills/kitcn/references/setup/server.md +1 -1
- 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
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
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
|
-
|
|
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()
|
|
1029
|
+
if ((request.headers.get("content-type") ?? "").includes("application/json")) return readJsonBody(request.clone());
|
|
955
1030
|
return null;
|
|
956
1031
|
};
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
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
|
|
1039
|
+
message: "Invalid path params",
|
|
1002
1040
|
cause: error
|
|
1003
1041
|
});
|
|
1004
1042
|
throw error;
|
|
1005
1043
|
}
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
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
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
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
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
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
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
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
|
|
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
|
|
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
|
|
155
|
+
const canRefreshToken = !!opts.auth && !tokenResult.isFresh;
|
|
154
156
|
try {
|
|
155
157
|
return await fn(tokenResult.token);
|
|
156
158
|
} catch (error) {
|
|
157
|
-
if (!
|
|
158
|
-
if (
|
|
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 (
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
1483
|
-
|
|
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,
|