Skip to content

Commit e8932bb

Browse files
committedApr 19, 2024··
fix: prevent sharing metadata between actions
Remove private property `#metadata` and instead pass metadata from `metadata` method to `schema`, `bindArgsSchemas` and `action` methods. This prevents sharing and potentially overwriting metadata between actions, for example when multiple actions are declared in one file.
1 parent aa11577 commit e8932bb

File tree

1 file changed

+30
-16
lines changed

1 file changed

+30
-16
lines changed
 

‎packages/next-safe-action/src/index.ts

+30-16
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ class SafeActionClient<const ServerError, const Ctx = null, const Metadata = nul
3737
>;
3838

3939
#middlewareFns: MiddlewareFn<ServerError, any, any, Metadata>[];
40-
#metadata = null as Metadata;
4140

4241
constructor(
4342
opts: { middlewareFns: MiddlewareFn<ServerError, any, any, Metadata>[] } & Omit<
@@ -84,33 +83,43 @@ class SafeActionClient<const ServerError, const Ctx = null, const Metadata = nul
8483
* @returns {Function} Define a new action
8584
*/
8685
public metadata(data: Metadata) {
87-
this.#metadata = data;
88-
8986
return {
9087
schema: <const S extends Schema | undefined = undefined, const FVE = ValidationErrors<S>>(
9188
schema?: S,
9289
utils?: {
9390
formatValidationErrors?: FormatValidationErrorsFn<S, FVE>;
9491
}
95-
) => this.schema<S, FVE, Metadata>(schema, utils),
92+
) =>
93+
this.#schema<S, FVE, Metadata>({
94+
schema,
95+
formatValidationErrors: utils?.formatValidationErrors,
96+
metadata: data,
97+
}),
9698
};
9799
}
98-
99100
/**
100101
* Pass an input schema to define safe action arguments.
101102
* @param schema An input schema supported by [TypeSchema](https://typeschema.com/#coverage).
102103
* @returns {Function} The `define` function, which is used to define a new safe action.
103104
*/
104-
public schema<
105-
const S extends Schema | undefined = undefined,
106-
const FVE = ValidationErrors<S>,
107-
const MD = null,
108-
>(
105+
public schema<const S extends Schema | undefined = undefined, const FVE = ValidationErrors<S>>(
109106
schema?: S,
110107
utils?: {
111108
formatValidationErrors?: FormatValidationErrorsFn<S, FVE>;
112109
}
113110
) {
111+
return this.#schema<S, FVE, null>({
112+
schema,
113+
formatValidationErrors: utils?.formatValidationErrors,
114+
metadata: null,
115+
});
116+
}
117+
118+
#schema<
119+
const S extends Schema | undefined = undefined,
120+
const FVE = ValidationErrors<S>,
121+
const MD = null,
122+
>(args: { schema?: S; formatValidationErrors?: FormatValidationErrorsFn<S, FVE>; metadata: MD }) {
114123
return {
115124
bindArgsSchemas: <
116125
const BAS extends readonly Schema[],
@@ -122,17 +131,19 @@ class SafeActionClient<const ServerError, const Ctx = null, const Metadata = nul
122131
}
123132
) =>
124133
this.#bindArgsSchemas<S, BAS, FVE, FBAVE, MD>({
125-
mainSchema: schema,
134+
mainSchema: args.schema,
126135
bindArgsSchemas,
127-
formatValidationErrors: utils?.formatValidationErrors,
136+
formatValidationErrors: args.formatValidationErrors,
128137
formatBindArgsValidationErrors: bindArgsUtils?.formatBindArgsValidationErrors,
138+
metadata: args.metadata,
129139
}),
130140
action: <const Data = null>(serverCodeFn: ServerCodeFn<S, [], Data, Ctx, MD>) =>
131141
this.#action({
132-
schema,
142+
schema: args.schema,
133143
bindArgsSchemas: [],
134144
serverCodeFn,
135-
formatValidationErrors: utils?.formatValidationErrors,
145+
formatValidationErrors: args.formatValidationErrors,
146+
metadata: args.metadata,
136147
}),
137148
};
138149
}
@@ -148,6 +159,7 @@ class SafeActionClient<const ServerError, const Ctx = null, const Metadata = nul
148159
bindArgsSchemas: BAS;
149160
formatValidationErrors?: FormatValidationErrorsFn<S, FVE>;
150161
formatBindArgsValidationErrors?: FormatBindArgsValidationErrorsFn<BAS, FBAVE>;
162+
metadata: MD;
151163
}) {
152164
return {
153165
action: <const Data = null>(serverCodeFn: ServerCodeFn<S, BAS, Data, Ctx, MD>) =>
@@ -157,6 +169,7 @@ class SafeActionClient<const ServerError, const Ctx = null, const Metadata = nul
157169
serverCodeFn,
158170
formatValidationErrors: args.formatValidationErrors,
159171
formatBindArgsValidationErrors: args.formatBindArgsValidationErrors,
172+
metadata: args.metadata,
160173
}),
161174
};
162175
}
@@ -179,6 +192,7 @@ class SafeActionClient<const ServerError, const Ctx = null, const Metadata = nul
179192
serverCodeFn: ServerCodeFn<S, BAS, Data, Ctx, MD>;
180193
formatValidationErrors?: FormatValidationErrorsFn<S, FVE>;
181194
formatBindArgsValidationErrors?: FormatBindArgsValidationErrorsFn<BAS, FBAVE>;
195+
metadata: MD;
182196
}): SafeActionFn<ServerError, S, BAS, FVE, FBAVE, Data> {
183197
return async (...clientInputs) => {
184198
let prevCtx: any = null;
@@ -205,7 +219,7 @@ class SafeActionClient<const ServerError, const Ctx = null, const Metadata = nul
205219
clientInput: clientInputs.at(-1), // pass raw client input
206220
bindArgsClientInputs: args.bindArgsSchemas.length ? clientInputs.slice(0, -1) : [],
207221
ctx: prevCtx,
208-
metadata: this.#metadata,
222+
metadata: args.metadata as Metadata | null,
209223
next: async ({ ctx }) => {
210224
prevCtx = ctx;
211225
await executeMiddlewareChain(idx + 1);
@@ -285,7 +299,7 @@ class SafeActionClient<const ServerError, const Ctx = null, const Metadata = nul
285299
parsedInput: parsedInputDatas.at(-1) as S extends Schema ? Infer<S> : undefined,
286300
bindArgsParsedInputs: parsedInputDatas.slice(0, -1) as InferArray<BAS>,
287301
ctx: prevCtx,
288-
metadata: this.#metadata as any as MD,
302+
metadata: args.metadata,
289303
})) ?? null;
290304

291305
middlewareResult.success = true;

0 commit comments

Comments
 (0)
Please sign in to comment.