Skip to content

Commit 5312d52

Browse files
committed
Allow arbitrary suffix
1 parent d015b98 commit 5312d52

2 files changed

Lines changed: 61 additions & 41 deletions

File tree

packages/core/src/actions/postActivity.ts

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,20 @@ const postActivityActionSchema = pipe(
1616

1717
const middlewareActionSchemas = createMiddlewareActionSchemas(
1818
POST_ACTIVITY,
19+
['FULFILLED', 'IMPEDED', 'PENDING'],
1920
pipe(object({ activity: custom<WebChatActivity>(() => true) }), readonly()),
2021
pipe(object({ clientActivityID: string(), method: string() }), readonly())
2122
);
2223

23-
const POST_ACTIVITY_FULFILLED = middlewareActionSchemas.fulfilled.name;
24-
const POST_ACTIVITY_IMPEDED = middlewareActionSchemas.impeded.name;
25-
const POST_ACTIVITY_PENDING = middlewareActionSchemas.pending.name;
26-
const POST_ACTIVITY_REJECTED = middlewareActionSchemas.rejected.name;
24+
const POST_ACTIVITY_FULFILLED = middlewareActionSchemas.FULFILLED.name;
25+
const POST_ACTIVITY_IMPEDED = middlewareActionSchemas.IMPEDED.name;
26+
const POST_ACTIVITY_PENDING = middlewareActionSchemas.PENDING.name;
27+
const POST_ACTIVITY_REJECTED = middlewareActionSchemas.REJECTED.name;
2728

28-
const postActivityFulfilledActionSchema = middlewareActionSchemas.fulfilled.schema;
29-
const postActivityImpededActionSchema = middlewareActionSchemas.impeded.schema;
30-
const postActivityPendingActionSchema = middlewareActionSchemas.pending.schema;
31-
const postActivityRejectedActionSchema = middlewareActionSchemas.rejected.schema;
29+
const postActivityFulfilledActionSchema = middlewareActionSchemas.FULFILLED.schema;
30+
const postActivityImpededActionSchema = middlewareActionSchemas.IMPEDED.schema;
31+
const postActivityPendingActionSchema = middlewareActionSchemas.PENDING.schema;
32+
const postActivityRejectedActionSchema = middlewareActionSchemas.REJECTED.schema;
3233

3334
type PostActivityAction = InferOutput<typeof postActivityActionSchema>;
3435
type PostActivityFulfilledAction = InferOutput<typeof postActivityFulfilledActionSchema>;

packages/core/src/actions/private/createMiddlewareActionSchemas.ts

Lines changed: 52 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,71 @@
1-
import { instance, literal, object, pipe, readonly, type BaseIssue, type BaseSchema } from 'valibot';
1+
import {
2+
array,
3+
instance,
4+
literal,
5+
object,
6+
parse,
7+
picklist,
8+
pipe,
9+
readonly,
10+
type BaseIssue,
11+
type BaseSchema,
12+
type InferOutput
13+
} from 'valibot';
14+
15+
// No dangerous value such as: constructor, prototype, etc.
16+
const allowedSuffixSchema = picklist(['FULFILLED', 'IMPEDED', 'PENDING']);
17+
18+
type AllowedSuffix = InferOutput<typeof allowedSuffixSchema>;
19+
20+
const suffixesSchema = array(allowedSuffixSchema);
221

322
export default function createMiddlewareActionSchemas<
423
const TName extends string,
524
const TPayloadSchema extends BaseSchema<unknown, unknown, BaseIssue<unknown>>,
6-
const TMetaSchema extends BaseSchema<unknown, unknown, BaseIssue<unknown>>
7-
>(actionName: TName, payloadSchema: TPayloadSchema, metaSchema: TMetaSchema) {
8-
return Object.freeze({
9-
fulfilled: {
10-
name: `${actionName}_FULFILLED` as const,
11-
schema: pipe(
12-
object({
13-
meta: metaSchema,
14-
payload: payloadSchema,
15-
type: literal(`${actionName}_FULFILLED`)
16-
}),
17-
readonly()
18-
)
19-
},
20-
impeded: {
21-
name: `${actionName}_IMPEDED` as const,
22-
schema: pipe(
23-
object({
24-
meta: metaSchema,
25-
payload: payloadSchema,
26-
type: literal(`${actionName}_IMPEDED`)
27-
}),
28-
readonly()
29-
)
30-
},
31-
pending: {
32-
name: `${actionName}_PENDING` as const,
25+
const TMetaSchema extends BaseSchema<unknown, unknown, BaseIssue<unknown>>,
26+
const TSuffix extends AllowedSuffix
27+
>(prefix: TName, suffixes: readonly TSuffix[], payloadSchema: TPayloadSchema, metaSchema: TMetaSchema) {
28+
const result: {
29+
[K in TSuffix]: Readonly<{
30+
name: `${TName}_${K}`;
31+
schema: BaseSchema<
32+
unknown,
33+
{
34+
meta: InferOutput<typeof metaSchema>;
35+
payload: InferOutput<typeof payloadSchema>;
36+
type: `${TName}_${K}`;
37+
},
38+
BaseIssue<unknown>
39+
>;
40+
}>;
41+
} = {} as any;
42+
43+
for (const suffix of parse(suffixesSchema, suffixes)) {
44+
// We use allowlist to filter the suffix.
45+
// eslint-disable-next-line security/detect-object-injection
46+
result[suffix] = {
47+
name: `${prefix}_${suffix}` as const,
3348
schema: pipe(
3449
object({
3550
meta: metaSchema,
3651
payload: payloadSchema,
37-
type: literal(`${actionName}_PENDING`)
52+
type: literal(`${prefix}_${suffix}`)
3853
}),
3954
readonly()
4055
)
41-
},
42-
rejected: {
43-
name: `${actionName}_REJECTED` as const,
56+
};
57+
}
58+
59+
return Object.freeze({
60+
...result,
61+
REJECTED: {
62+
name: `${prefix}_REJECTED` as const,
4463
schema: pipe(
4564
object({
4665
error: literal(true),
4766
meta: metaSchema,
4867
payload: instance(Error),
49-
type: literal(`${actionName}_REJECTED`)
68+
type: literal(`${prefix}_REJECTED`)
5069
}),
5170
readonly()
5271
)

0 commit comments

Comments
 (0)