generator-kodly-react-app 1.0.15 → 1.0.17

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 (106) hide show
  1. package/generators/app/index.js +15 -1
  2. package/generators/app/templates/.env.sandbox +4 -3
  3. package/generators/app/templates/.node-version +1 -0
  4. package/generators/app/templates/.pnpmfile.cjs +14 -0
  5. package/generators/app/templates/.prettierignore +13 -0
  6. package/generators/app/templates/AGENTS.md +14 -0
  7. package/generators/app/templates/I18N_MIGRATION.md +13 -13
  8. package/generators/app/templates/STRUCTURE.md +26 -26
  9. package/generators/app/templates/TESTING.md +30 -0
  10. package/generators/app/templates/index.html +6 -14
  11. package/generators/app/templates/openapi-ts.config.ts +16 -12
  12. package/generators/app/templates/oxlint.config.ts +72 -0
  13. package/generators/app/templates/package.json +66 -52
  14. package/generators/app/templates/pnpm-workspace.yaml +19 -0
  15. package/generators/app/templates/scripts/check-duplicates.mjs +28 -0
  16. package/generators/app/templates/scripts/generated-files.mjs +21 -0
  17. package/generators/app/templates/src/app.tsx +20 -20
  18. package/generators/app/templates/src/components/layout/language-switcher.tsx +20 -16
  19. package/generators/app/templates/src/components/layout/page-layout.tsx +31 -0
  20. package/generators/app/templates/src/components/layout/theme-switcher.tsx +16 -15
  21. package/generators/app/templates/src/components/theme/theme-provider.tsx +20 -13
  22. package/generators/app/templates/src/components/ui/button.tsx +15 -14
  23. package/generators/app/templates/src/components/ui/card.tsx +23 -16
  24. package/generators/app/templates/src/components/ui/field.tsx +35 -35
  25. package/generators/app/templates/src/components/ui/form.tsx +66 -30
  26. package/generators/app/templates/src/components/ui/input-group.tsx +22 -28
  27. package/generators/app/templates/src/components/ui/input.tsx +8 -8
  28. package/generators/app/templates/src/components/ui/label.tsx +9 -9
  29. package/generators/app/templates/src/components/ui/select.tsx +0 -1
  30. package/generators/app/templates/src/components/ui/separator.tsx +10 -10
  31. package/generators/app/templates/src/components/ui/textarea.tsx +7 -7
  32. package/generators/app/templates/src/index.css +78 -68
  33. package/generators/app/templates/src/lib/i18n.ts +40 -31
  34. package/generators/app/templates/src/lib/routes.ts +2 -3
  35. package/generators/app/templates/src/lib/utils/error-handler.ts +21 -14
  36. package/generators/app/templates/src/lib/utils.ts +3 -3
  37. package/generators/app/templates/src/locales/index.ts +12 -12
  38. package/generators/app/templates/src/locales/ja/theme.json +0 -1
  39. package/generators/app/templates/src/main.tsx +10 -12
  40. package/generators/app/templates/src/modules/app/layouts/app-layout.tsx +14 -25
  41. package/generators/app/templates/src/modules/app/locales/app-en.json +0 -1
  42. package/generators/app/templates/src/modules/app/locales/app-ja.json +0 -1
  43. package/generators/app/templates/src/modules/auth/components/auth-form.tsx +86 -0
  44. package/generators/app/templates/src/modules/auth/components/forgot-password-form.tsx +27 -52
  45. package/generators/app/templates/src/modules/auth/components/login-form.tsx +42 -72
  46. package/generators/app/templates/src/modules/auth/components/login-link.tsx +12 -0
  47. package/generators/app/templates/src/modules/auth/components/reset-password-form.tsx +46 -92
  48. package/generators/app/templates/src/modules/auth/components/signup-form.tsx +35 -71
  49. package/generators/app/templates/src/modules/auth/contexts/auth-context.tsx +10 -6
  50. package/generators/app/templates/src/modules/auth/hooks/use-auth-hook.ts +54 -39
  51. package/generators/app/templates/src/modules/auth/layouts/auth-layout.tsx +12 -15
  52. package/generators/app/templates/src/modules/auth/locales/auth-en.json +0 -1
  53. package/generators/app/templates/src/modules/auth/locales/auth-ja.json +0 -1
  54. package/generators/app/templates/src/modules/auth/schemas/form-schemas.ts +14 -10
  55. package/generators/app/templates/src/modules/landing/components/auth-hero.tsx +20 -18
  56. package/generators/app/templates/src/modules/landing/components/welcome-hero.tsx +13 -11
  57. package/generators/app/templates/src/modules/landing/landing-page-layout.tsx +1 -24
  58. package/generators/app/templates/src/modules/landing/landing-page.tsx +11 -6
  59. package/generators/app/templates/src/modules/landing/layouts/landing-page-layout.tsx +2 -21
  60. package/generators/app/templates/src/modules/landing/locales/landing-en.json +0 -1
  61. package/generators/app/templates/src/openapi-client-config.ts +1 -1
  62. package/generators/app/templates/src/routeTree.gen.ts +188 -188
  63. package/generators/app/templates/src/router.tsx +4 -4
  64. package/generators/app/templates/src/routes/$.tsx +0 -1
  65. package/generators/app/templates/src/routes/__root.tsx +3 -3
  66. package/generators/app/templates/src/routes/_landing/index.tsx +3 -3
  67. package/generators/app/templates/src/routes/_landing/route.tsx +3 -3
  68. package/generators/app/templates/src/routes/app/index.tsx +6 -6
  69. package/generators/app/templates/src/routes/app/route.tsx +4 -4
  70. package/generators/app/templates/src/routes/auth/forgot-password.tsx +1 -1
  71. package/generators/app/templates/src/routes/auth/login.tsx +3 -3
  72. package/generators/app/templates/src/routes/auth/reset-password.tsx +3 -3
  73. package/generators/app/templates/src/routes/auth/route.tsx +16 -8
  74. package/generators/app/templates/src/routes/auth/signup.tsx +1 -2
  75. package/generators/app/templates/src/sdk/@tanstack/react-query.gen.ts +157 -76
  76. package/generators/app/templates/src/sdk/client/client.gen.ts +35 -37
  77. package/generators/app/templates/src/sdk/client/index.ts +8 -8
  78. package/generators/app/templates/src/sdk/client/types.gen.ts +22 -19
  79. package/generators/app/templates/src/sdk/client/utils.gen.ts +53 -45
  80. package/generators/app/templates/src/sdk/client.gen.ts +14 -5
  81. package/generators/app/templates/src/sdk/core/auth.gen.ts +6 -6
  82. package/generators/app/templates/src/sdk/core/bodySerializer.gen.ts +25 -27
  83. package/generators/app/templates/src/sdk/core/params.gen.ts +12 -12
  84. package/generators/app/templates/src/sdk/core/pathSerializer.gen.ts +40 -41
  85. package/generators/app/templates/src/sdk/core/queryKeySerializer.gen.ts +12 -29
  86. package/generators/app/templates/src/sdk/core/serverSentEvents.gen.ts +26 -24
  87. package/generators/app/templates/src/sdk/core/types.gen.ts +17 -15
  88. package/generators/app/templates/src/sdk/core/utils.gen.ts +18 -18
  89. package/generators/app/templates/src/sdk/index.ts +40 -2
  90. package/generators/app/templates/src/sdk/schemas.gen.ts +108 -166
  91. package/generators/app/templates/src/sdk/sdk.gen.ts +145 -63
  92. package/generators/app/templates/src/sdk/types.gen.ts +90 -84
  93. package/generators/app/templates/src/sdk/zod.gen.ts +57 -74
  94. package/generators/app/templates/src/types/i18n.d.ts +0 -1
  95. package/generators/app/templates/stylelint.config.js +55 -0
  96. package/generators/app/templates/tailwind.config.js +0 -1
  97. package/generators/app/templates/tests/form-controls.test.tsx +39 -0
  98. package/generators/app/templates/tests/sdk.test.ts +49 -0
  99. package/generators/app/templates/tests/setup.ts +5 -0
  100. package/generators/app/templates/tsconfig.app.json +0 -2
  101. package/generators/app/templates/tsconfig.json +2 -2
  102. package/generators/app/templates/tsr.config.json +4 -0
  103. package/generators/app/templates/vite.config.js +14 -16
  104. package/generators/app/templates/vitest.config.ts +14 -0
  105. package/package.json +9 -10
  106. package/generators/app/templates/postcss.config.js +0 -6
@@ -1,158 +1,164 @@
1
1
  // This file is auto-generated by @hey-api/openapi-ts
2
2
 
3
3
  export type ClientOptions = {
4
- baseURL: 'https://sandbox.beta.kodly.dev/proxy/95-2' | (string & {});
4
+ baseURL?: string;
5
5
  };
6
6
 
7
7
  export type AuthResponseDtoUserDetailDto = {
8
- token?: string | null;
9
- data?: UserDetailDto;
10
- roleName?: string | null;
11
- modulePermissions?: Array<ModulePermission> | null;
8
+ token?: string | null;
9
+ data?: UserDetailDto;
10
+ roleName?: string | null;
11
+ modulePermissions?: Array<ModulePermission> | null;
12
12
  };
13
13
 
14
14
  export type ModuleDefinition = unknown;
15
15
 
16
16
  export type ModulePermission = {
17
- module: ModuleDefinition;
18
- permissions: Array<PermissionDefinition>;
17
+ module: ModuleDefinition;
18
+ permissions: Array<PermissionDefinition>;
19
19
  };
20
20
 
21
21
  export type PermissionDefinition = unknown;
22
22
 
23
23
  export type RestResponseAuthResponseDtoUserDetailDto = {
24
- message?: string | null;
25
- status?: boolean | null;
26
- data?: AuthResponseDtoUserDetailDto;
24
+ message?: string | null;
25
+ status?: boolean | null;
26
+ data?: AuthResponseDtoUserDetailDto;
27
27
  };
28
28
 
29
29
  export type UserDetailDto = {
30
- id: string;
31
- slug: string;
32
- email: string;
30
+ id: string;
31
+ slug: string;
32
+ email: string;
33
33
  };
34
34
 
35
35
  export type RestResponseString = {
36
- message?: string | null;
37
- status?: boolean | null;
38
- data?: string | null;
36
+ message?: string | null;
37
+ status?: boolean | null;
38
+ data?: string | null;
39
39
  };
40
40
 
41
41
  export type UserResetPasswordDto = {
42
- email: string;
43
- password: string;
44
- otp: string;
42
+ email: string;
43
+ password: string;
44
+ otp: string;
45
45
  };
46
46
 
47
47
  export type UserSignupDto = {
48
- password: string;
49
- email: string;
48
+ password: string;
49
+ email: string;
50
50
  };
51
51
 
52
52
  export type UserLoginDto = {
53
- email: string;
54
- password: string;
53
+ email: string;
54
+ password: string;
55
55
  };
56
56
 
57
57
  export type ValidateTokenUserAuthData = {
58
- body?: never;
59
- path?: never;
60
- query?: never;
61
- url: '/api/v1/auth/user/validate-token';
58
+ body?: never;
59
+ path?: never;
60
+ query?: never;
61
+ url: "/api/v1/auth/user/validate-token";
62
62
  };
63
63
 
64
64
  export type ValidateTokenUserAuthResponses = {
65
- /**
66
- * OK
67
- */
68
- 200: RestResponseAuthResponseDtoUserDetailDto;
65
+ /**
66
+ * OK
67
+ */
68
+ 200: RestResponseAuthResponseDtoUserDetailDto;
69
69
  };
70
70
 
71
- export type ValidateTokenUserAuthResponse = ValidateTokenUserAuthResponses[keyof ValidateTokenUserAuthResponses];
71
+ export type ValidateTokenUserAuthResponse =
72
+ ValidateTokenUserAuthResponses[keyof ValidateTokenUserAuthResponses];
72
73
 
73
74
  export type SendOtpUserAuthData = {
74
- body?: never;
75
- path?: never;
76
- query: {
77
- authId: string;
78
- };
79
- url: '/api/v1/auth/user/send-otp';
75
+ body?: never;
76
+ path?: never;
77
+ query: {
78
+ authId: string;
79
+ };
80
+ url: "/api/v1/auth/user/send-otp";
80
81
  };
81
82
 
82
83
  export type SendOtpUserAuthResponses = {
83
- /**
84
- * OK
85
- */
86
- 200: RestResponseString;
84
+ /**
85
+ * OK
86
+ */
87
+ 200: RestResponseString;
87
88
  };
88
89
 
89
- export type SendOtpUserAuthResponse = SendOtpUserAuthResponses[keyof SendOtpUserAuthResponses];
90
+ export type SendOtpUserAuthResponse =
91
+ SendOtpUserAuthResponses[keyof SendOtpUserAuthResponses];
90
92
 
91
93
  export type ResetPasswordUserAuthData = {
92
- body: UserResetPasswordDto;
93
- path?: never;
94
- query?: never;
95
- url: '/api/v1/auth/user/reset';
94
+ body: UserResetPasswordDto;
95
+ path?: never;
96
+ query?: never;
97
+ url: "/api/v1/auth/user/reset";
96
98
  };
97
99
 
98
100
  export type ResetPasswordUserAuthResponses = {
99
- /**
100
- * OK
101
- */
102
- 200: RestResponseString;
101
+ /**
102
+ * OK
103
+ */
104
+ 200: RestResponseString;
103
105
  };
104
106
 
105
- export type ResetPasswordUserAuthResponse = ResetPasswordUserAuthResponses[keyof ResetPasswordUserAuthResponses];
107
+ export type ResetPasswordUserAuthResponse =
108
+ ResetPasswordUserAuthResponses[keyof ResetPasswordUserAuthResponses];
106
109
 
107
110
  export type RegisterUserAuthData = {
108
- body: UserSignupDto;
109
- path?: never;
110
- query?: never;
111
- url: '/api/v1/auth/user/register';
111
+ body: UserSignupDto;
112
+ path?: never;
113
+ query?: never;
114
+ url: "/api/v1/auth/user/register";
112
115
  };
113
116
 
114
117
  export type RegisterUserAuthResponses = {
115
- /**
116
- * OK
117
- */
118
- 200: RestResponseAuthResponseDtoUserDetailDto;
118
+ /**
119
+ * OK
120
+ */
121
+ 200: RestResponseAuthResponseDtoUserDetailDto;
119
122
  };
120
123
 
121
- export type RegisterUserAuthResponse = RegisterUserAuthResponses[keyof RegisterUserAuthResponses];
124
+ export type RegisterUserAuthResponse =
125
+ RegisterUserAuthResponses[keyof RegisterUserAuthResponses];
122
126
 
123
127
  export type LogoutUserAuthData = {
124
- body?: never;
125
- headers?: {
126
- 'x-auth-token'?: string;
127
- };
128
- path?: never;
129
- query?: never;
130
- url: '/api/v1/auth/user/logout';
128
+ body?: never;
129
+ headers?: {
130
+ "x-auth-token"?: string;
131
+ };
132
+ path?: never;
133
+ query?: never;
134
+ url: "/api/v1/auth/user/logout";
131
135
  };
132
136
 
133
137
  export type LogoutUserAuthResponses = {
134
- /**
135
- * OK
136
- */
137
- 200: {
138
- [key: string]: unknown;
139
- };
138
+ /**
139
+ * OK
140
+ */
141
+ 200: {
142
+ [key: string]: unknown;
143
+ };
140
144
  };
141
145
 
142
- export type LogoutUserAuthResponse = LogoutUserAuthResponses[keyof LogoutUserAuthResponses];
146
+ export type LogoutUserAuthResponse =
147
+ LogoutUserAuthResponses[keyof LogoutUserAuthResponses];
143
148
 
144
149
  export type LoginUserAuthData = {
145
- body: UserLoginDto;
146
- path?: never;
147
- query?: never;
148
- url: '/api/v1/auth/user/login';
150
+ body: UserLoginDto;
151
+ path?: never;
152
+ query?: never;
153
+ url: "/api/v1/auth/user/login";
149
154
  };
150
155
 
151
156
  export type LoginUserAuthResponses = {
152
- /**
153
- * OK
154
- */
155
- 200: RestResponseAuthResponseDtoUserDetailDto;
157
+ /**
158
+ * OK
159
+ */
160
+ 200: RestResponseAuthResponseDtoUserDetailDto;
156
161
  };
157
162
 
158
- export type LoginUserAuthResponse = LoginUserAuthResponses[keyof LoginUserAuthResponses];
163
+ export type LoginUserAuthResponse =
164
+ LoginUserAuthResponses[keyof LoginUserAuthResponses];
@@ -1,98 +1,78 @@
1
1
  // This file is auto-generated by @hey-api/openapi-ts
2
2
 
3
- import { z } from 'zod';
3
+ import { z } from "zod";
4
4
 
5
5
  export const zModuleDefinition = z.unknown();
6
6
 
7
7
  export const zPermissionDefinition = z.unknown();
8
8
 
9
9
  export const zModulePermission = z.object({
10
- module: zModuleDefinition,
11
- permissions: z.array(zPermissionDefinition).min(0).max(512)
10
+ module: zModuleDefinition,
11
+ permissions: z.array(zPermissionDefinition).min(0).max(512),
12
12
  });
13
13
 
14
14
  export const zUserDetailDto = z.object({
15
- id: z.string(),
16
- slug: z.string(),
17
- email: z.email().min(1).max(256)
15
+ id: z.string(),
16
+ slug: z.string(),
17
+ email: z.email().min(1).max(256),
18
18
  });
19
19
 
20
20
  export const zAuthResponseDtoUserDetailDto = z.object({
21
- token: z.optional(z.union([
22
- z.string(),
23
- z.null()
24
- ])),
25
- data: z.optional(zUserDetailDto),
26
- roleName: z.optional(z.union([
27
- z.string(),
28
- z.null()
29
- ])),
30
- modulePermissions: z.optional(z.union([
31
- z.array(zModulePermission),
32
- z.null()
33
- ]))
21
+ token: z.optional(z.union([z.string(), z.null()])),
22
+ data: z.optional(zUserDetailDto),
23
+ roleName: z.optional(z.union([z.string(), z.null()])),
24
+ modulePermissions: z.optional(
25
+ z.union([z.array(zModulePermission), z.null()]),
26
+ ),
34
27
  });
35
28
 
36
- export const zRestResponseAuthResponseDtoUserDetailDto = z.object({
37
- message: z.optional(z.union([
38
- z.string(),
39
- z.null()
40
- ])),
41
- status: z.optional(z.union([
42
- z.boolean(),
43
- z.null()
44
- ])),
45
- data: z.optional(zAuthResponseDtoUserDetailDto)
29
+ const zRestResponse = z.object({
30
+ message: z.string().nullable().optional(),
31
+ status: z.boolean().nullable().optional(),
46
32
  });
47
33
 
48
- export const zRestResponseString = z.object({
49
- message: z.optional(z.union([
50
- z.string(),
51
- z.null()
52
- ])),
53
- status: z.optional(z.union([
54
- z.boolean(),
55
- z.null()
56
- ])),
57
- data: z.optional(z.union([
58
- z.string(),
59
- z.null()
60
- ]))
34
+ export const zRestResponseAuthResponseDtoUserDetailDto = zRestResponse.extend({
35
+ data: zAuthResponseDtoUserDetailDto.optional(),
36
+ });
37
+
38
+ export const zRestResponseString = zRestResponse.extend({
39
+ data: z.string().nullable().optional(),
61
40
  });
62
41
 
63
42
  export const zUserResetPasswordDto = z.object({
64
- email: z.email().min(1).max(256),
65
- password: z.string().min(6).max(32),
66
- otp: z.string().min(4).max(12)
43
+ email: z.email().min(1).max(256),
44
+ password: z.string().min(6).max(32),
45
+ otp: z.string().min(4).max(12),
67
46
  });
68
47
 
69
48
  export const zUserSignupDto = z.object({
70
- password: z.string(),
71
- email: z.email().min(1).max(256)
49
+ password: z.string(),
50
+ email: z.email().min(1).max(256),
72
51
  });
73
52
 
74
53
  export const zUserLoginDto = z.object({
75
- email: z.email().min(1).max(256),
76
- password: z.string().min(6).max(32)
54
+ email: z.email().min(1).max(256),
55
+ password: z.string().min(6).max(32),
77
56
  });
78
57
 
79
58
  export const zValidateTokenUserAuthData = z.object({
80
- body: z.optional(z.never()),
81
- path: z.optional(z.never()),
82
- query: z.optional(z.never())
59
+ body: z.optional(z.never()),
60
+ path: z.optional(z.never()),
61
+ query: z.optional(z.never()),
83
62
  });
84
63
 
85
64
  /**
86
65
  * OK
87
66
  */
88
- export const zValidateTokenUserAuthResponse = zRestResponseAuthResponseDtoUserDetailDto;
67
+ export const zValidateTokenUserAuthResponse =
68
+ zRestResponseAuthResponseDtoUserDetailDto;
89
69
 
90
70
  export const zSendOtpUserAuthData = z.object({
91
- body: z.optional(z.never()),
92
- path: z.optional(z.never()),
93
- query: z.object({
94
- authId: z.string()
95
- })
71
+ body: z.optional(z.never()),
72
+ path: z.optional(z.never()),
73
+ query: z.object({
74
+ authId: z.string(),
75
+ }),
96
76
  });
97
77
 
98
78
  /**
@@ -101,9 +81,9 @@ export const zSendOtpUserAuthData = z.object({
101
81
  export const zSendOtpUserAuthResponse = zRestResponseString;
102
82
 
103
83
  export const zResetPasswordUserAuthData = z.object({
104
- body: zUserResetPasswordDto,
105
- path: z.optional(z.never()),
106
- query: z.optional(z.never())
84
+ body: zUserResetPasswordDto,
85
+ path: z.optional(z.never()),
86
+ query: z.optional(z.never()),
107
87
  });
108
88
 
109
89
  /**
@@ -112,23 +92,26 @@ export const zResetPasswordUserAuthData = z.object({
112
92
  export const zResetPasswordUserAuthResponse = zRestResponseString;
113
93
 
114
94
  export const zRegisterUserAuthData = z.object({
115
- body: zUserSignupDto,
116
- path: z.optional(z.never()),
117
- query: z.optional(z.never())
95
+ body: zUserSignupDto,
96
+ path: z.optional(z.never()),
97
+ query: z.optional(z.never()),
118
98
  });
119
99
 
120
100
  /**
121
101
  * OK
122
102
  */
123
- export const zRegisterUserAuthResponse = zRestResponseAuthResponseDtoUserDetailDto;
103
+ export const zRegisterUserAuthResponse =
104
+ zRestResponseAuthResponseDtoUserDetailDto;
124
105
 
125
106
  export const zLogoutUserAuthData = z.object({
126
- body: z.optional(z.never()),
127
- path: z.optional(z.never()),
128
- query: z.optional(z.never()),
129
- headers: z.optional(z.object({
130
- 'x-auth-token': z.optional(z.string()).default('')
131
- }))
107
+ body: z.optional(z.never()),
108
+ path: z.optional(z.never()),
109
+ query: z.optional(z.never()),
110
+ headers: z.optional(
111
+ z.object({
112
+ "x-auth-token": z.optional(z.string()).default(""),
113
+ }),
114
+ ),
132
115
  });
133
116
 
134
117
  /**
@@ -137,9 +120,9 @@ export const zLogoutUserAuthData = z.object({
137
120
  export const zLogoutUserAuthResponse = z.record(z.string(), z.unknown());
138
121
 
139
122
  export const zLoginUserAuthData = z.object({
140
- body: zUserLoginDto,
141
- path: z.optional(z.never()),
142
- query: z.optional(z.never())
123
+ body: zUserLoginDto,
124
+ path: z.optional(z.never()),
125
+ query: z.optional(z.never()),
143
126
  });
144
127
 
145
128
  /**
@@ -5,4 +5,3 @@ declare module "i18next" {
5
5
  returnNull: false;
6
6
  }
7
7
  }
8
-
@@ -0,0 +1,55 @@
1
+ export default {
2
+ extends: ["stylelint-config-standard"],
3
+ plugins: ["stylelint-declaration-strict-value"],
4
+ rules: {
5
+ "at-rule-prelude-no-invalid": [
6
+ true,
7
+ {
8
+ ignoreAtRules: [
9
+ "apply",
10
+ "theme",
11
+ "custom-variant",
12
+ "utility",
13
+ "variant",
14
+ "source",
15
+ "plugin",
16
+ "config",
17
+ "reference",
18
+ ],
19
+ },
20
+ ],
21
+ "at-rule-no-unknown": [
22
+ true,
23
+ {
24
+ ignoreAtRules: [
25
+ "theme",
26
+ "utility",
27
+ "variant",
28
+ "custom-variant",
29
+ "apply",
30
+ "source",
31
+ "plugin",
32
+ "config",
33
+ "reference",
34
+ ],
35
+ },
36
+ ],
37
+ "import-notation": "string",
38
+ "scale-unlimited/declaration-strict-value": [
39
+ ["/color$/", "fill", "stroke"],
40
+ {
41
+ ignoreValues: [
42
+ "inherit",
43
+ "initial",
44
+ "unset",
45
+ "revert",
46
+ "transparent",
47
+ "currentColor",
48
+ "none",
49
+ ],
50
+ ignoreFunctions: false,
51
+ disableFix: true,
52
+ },
53
+ ],
54
+ },
55
+ };
@@ -6,4 +6,3 @@ export default {
6
6
  },
7
7
  plugins: [],
8
8
  };
9
-
@@ -0,0 +1,39 @@
1
+ import { describe, expect, it, vi } from "vitest";
2
+ import { render, screen } from "@testing-library/react";
3
+ import userEvent from "@testing-library/user-event";
4
+ import { Input } from "@/components/ui/input";
5
+ import { Button } from "@/components/ui/button";
6
+
7
+ describe("form controls", () => {
8
+ it("accepts keyboard input and submits its value", async () => {
9
+ const user = userEvent.setup();
10
+ const save = vi.fn();
11
+ render(
12
+ <form
13
+ onSubmit={(event) => {
14
+ event.preventDefault();
15
+ save(new FormData(event.currentTarget).get("name"));
16
+ }}
17
+ >
18
+ <label htmlFor="name">Name</label>
19
+ <Input id="name" name="name" required />
20
+ <Button type="submit">Save</Button>
21
+ </form>,
22
+ );
23
+ await user.type(screen.getByRole("textbox", { name: "Name" }), "Ada");
24
+ await user.click(screen.getByRole("button", { name: "Save" }));
25
+ expect(save).toHaveBeenCalledWith("Ada");
26
+ });
27
+
28
+ it("does not submit a disabled action", async () => {
29
+ const user = userEvent.setup();
30
+ const save = vi.fn();
31
+ render(
32
+ <Button disabled onClick={save}>
33
+ Save
34
+ </Button>,
35
+ );
36
+ await user.click(screen.getByRole("button", { name: "Save" }));
37
+ expect(save).not.toHaveBeenCalled();
38
+ });
39
+ });
@@ -0,0 +1,49 @@
1
+ import { test } from "vitest";
2
+ import assert from "node:assert/strict";
3
+ import {
4
+ formDataBodySerializer,
5
+ urlSearchParamsBodySerializer,
6
+ jsonBodySerializer,
7
+ } from "../src/sdk/core/bodySerializer.gen";
8
+ import { serializeQueryKeyValue } from "../src/sdk/core/queryKeySerializer.gen";
9
+
10
+ test("API serialization preserves values and omits absent fields", () => {
11
+ const body = {
12
+ title: "hello",
13
+ count: 3,
14
+ tags: ["a", "b"],
15
+ absent: null,
16
+ missing: undefined,
17
+ date: new Date("2026-10-20T00:00:00Z"),
18
+ nested: { enabled: true },
19
+ };
20
+ const form = formDataBodySerializer.bodySerializer(body);
21
+ assert.deepEqual(form.getAll("tags"), ["a", "b"]);
22
+ assert.equal(form.get("date"), body.date.toISOString());
23
+ assert.equal(form.get("nested"), '{"enabled":true}');
24
+ assert.equal(form.has("absent"), false);
25
+ assert.equal(form.has("missing"), false);
26
+ const params = new URLSearchParams(
27
+ urlSearchParamsBodySerializer.bodySerializer(body),
28
+ );
29
+ assert.deepEqual(params.getAll("tags"), ["a", "b"]);
30
+ assert.equal(params.get("count"), "3");
31
+ assert.equal(jsonBodySerializer.bodySerializer({ id: 23n }), '{"id":"23"}');
32
+ });
33
+
34
+ test("query cache keys preserve dates and have stable parameter ordering", () => {
35
+ assert.equal(serializeQueryKeyValue(23n), "23");
36
+ assert.equal(
37
+ serializeQueryKeyValue(new Date("2026-10-20T00:00:00Z")),
38
+ "2026-10-20T00:00:00.000Z",
39
+ );
40
+ assert.equal(serializeQueryKeyValue(Symbol("omitted")), undefined);
41
+ assert.equal(
42
+ serializeQueryKeyValue(() => 1),
43
+ undefined,
44
+ );
45
+ assert.deepEqual(serializeQueryKeyValue(new URLSearchParams("z=1&a=2&a=3")), {
46
+ a: ["2", "3"],
47
+ z: "1",
48
+ });
49
+ });
@@ -0,0 +1,5 @@
1
+ import "@testing-library/jest-dom/vitest";
2
+ import { afterEach } from "vitest";
3
+ import { cleanup } from "@testing-library/react";
4
+
5
+ afterEach(cleanup);
@@ -1,9 +1,7 @@
1
1
  {
2
2
  "compilerOptions": {
3
- "baseUrl": ".",
4
3
  "paths": {
5
4
  "@/*": ["./src/*"]
6
5
  }
7
6
  }
8
7
  }
9
-
@@ -20,10 +20,10 @@
20
20
  "noUnusedParameters": true,
21
21
  "noFallthroughCasesInSwitch": true,
22
22
  "noUncheckedSideEffectImports": true,
23
- "baseUrl": ".",
23
+ "allowJs": true,
24
+ "noUncheckedIndexedAccess": true,
24
25
  "paths": {
25
26
  "@/*": ["./src/*"]
26
27
  }
27
28
  }
28
29
  }
29
-
@@ -0,0 +1,4 @@
1
+ {
2
+ "quoteStyle": "double",
3
+ "semicolons": true
4
+ }