better-auth-devtools 0.1.1-alpha.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 (55) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +12 -0
  3. package/dist/client-plugin.d.ts +74 -0
  4. package/dist/client-plugin.d.ts.map +1 -0
  5. package/dist/client-plugin.js +41 -0
  6. package/dist/client-plugin.js.map +1 -0
  7. package/dist/endpoints.d.ts +9 -0
  8. package/dist/endpoints.d.ts.map +1 -0
  9. package/dist/endpoints.js +9 -0
  10. package/dist/endpoints.js.map +1 -0
  11. package/dist/errors.d.ts +17 -0
  12. package/dist/errors.d.ts.map +1 -0
  13. package/dist/errors.js +20 -0
  14. package/dist/errors.js.map +1 -0
  15. package/dist/guards.d.ts +2 -0
  16. package/dist/guards.d.ts.map +1 -0
  17. package/dist/guards.js +7 -0
  18. package/dist/guards.js.map +1 -0
  19. package/dist/index.d.ts +9 -0
  20. package/dist/index.d.ts.map +1 -0
  21. package/dist/index.js +7 -0
  22. package/dist/index.js.map +1 -0
  23. package/dist/payloads.d.ts +30 -0
  24. package/dist/payloads.d.ts.map +1 -0
  25. package/dist/payloads.js +2 -0
  26. package/dist/payloads.js.map +1 -0
  27. package/dist/plugin.d.ts +2 -0
  28. package/dist/plugin.d.ts.map +1 -0
  29. package/dist/plugin.js +2 -0
  30. package/dist/plugin.js.map +1 -0
  31. package/dist/react/devtools-panel.d.ts +12 -0
  32. package/dist/react/devtools-panel.d.ts.map +1 -0
  33. package/dist/react/devtools-panel.js +184 -0
  34. package/dist/react/devtools-panel.js.map +1 -0
  35. package/dist/react/index.d.ts +3 -0
  36. package/dist/react/index.d.ts.map +1 -0
  37. package/dist/react/index.js +2 -0
  38. package/dist/react/index.js.map +1 -0
  39. package/dist/react/styles.d.ts +3 -0
  40. package/dist/react/styles.d.ts.map +1 -0
  41. package/dist/react/styles.js +215 -0
  42. package/dist/react/styles.js.map +1 -0
  43. package/dist/server-plugin.d.ts +178 -0
  44. package/dist/server-plugin.d.ts.map +1 -0
  45. package/dist/server-plugin.js +285 -0
  46. package/dist/server-plugin.js.map +1 -0
  47. package/dist/types.d.ts +56 -0
  48. package/dist/types.d.ts.map +1 -0
  49. package/dist/types.js +2 -0
  50. package/dist/types.js.map +1 -0
  51. package/dist/validation.d.ts +7 -0
  52. package/dist/validation.d.ts.map +1 -0
  53. package/dist/validation.js +18 -0
  54. package/dist/validation.js.map +1 -0
  55. package/package.json +68 -0
@@ -0,0 +1,215 @@
1
+ export const styles = {
2
+ container: {
3
+ position: "fixed",
4
+ zIndex: 99999,
5
+ fontFamily: 'ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace',
6
+ fontSize: "13px",
7
+ },
8
+ trigger: {
9
+ background: "#1a1a2e",
10
+ color: "#e0e0e0",
11
+ border: "1px solid #333",
12
+ borderRadius: "8px",
13
+ padding: "8px 16px",
14
+ cursor: "pointer",
15
+ fontSize: "12px",
16
+ fontFamily: "inherit",
17
+ boxShadow: "0 2px 8px rgba(0,0,0,0.3)",
18
+ },
19
+ panel: {
20
+ width: "360px",
21
+ maxHeight: "520px",
22
+ overflowY: "auto",
23
+ background: "#1a1a2e",
24
+ color: "#e0e0e0",
25
+ border: "1px solid #333",
26
+ borderRadius: "12px",
27
+ boxShadow: "0 4px 24px rgba(0,0,0,0.4)",
28
+ },
29
+ header: {
30
+ display: "flex",
31
+ justifyContent: "space-between",
32
+ alignItems: "center",
33
+ padding: "12px 16px",
34
+ borderBottom: "1px solid #333",
35
+ },
36
+ headerTitle: {
37
+ fontWeight: 600,
38
+ fontSize: "14px",
39
+ color: "#fff",
40
+ },
41
+ closeButton: {
42
+ background: "transparent",
43
+ color: "#888",
44
+ border: "none",
45
+ cursor: "pointer",
46
+ fontSize: "16px",
47
+ padding: "0 4px",
48
+ fontFamily: "inherit",
49
+ },
50
+ section: {
51
+ padding: "12px 16px",
52
+ borderBottom: "1px solid #2a2a3e",
53
+ },
54
+ sectionTitle: {
55
+ fontSize: "11px",
56
+ fontWeight: 600,
57
+ textTransform: "uppercase",
58
+ color: "#888",
59
+ marginBottom: "8px",
60
+ letterSpacing: "0.5px",
61
+ display: "flex",
62
+ justifyContent: "space-between",
63
+ alignItems: "center",
64
+ },
65
+ templateGrid: {
66
+ display: "flex",
67
+ gap: "6px",
68
+ flexWrap: "wrap",
69
+ },
70
+ templateButton: {
71
+ background: "#2a2a3e",
72
+ color: "#a0c4ff",
73
+ border: "1px solid #3a3a5e",
74
+ borderRadius: "6px",
75
+ padding: "4px 10px",
76
+ cursor: "pointer",
77
+ fontSize: "12px",
78
+ fontFamily: "inherit",
79
+ },
80
+ searchInput: {
81
+ width: "100%",
82
+ background: "#2a2a3e",
83
+ color: "#e0e0e0",
84
+ border: "1px solid #3a3a5e",
85
+ borderRadius: "6px",
86
+ padding: "6px 10px",
87
+ fontSize: "12px",
88
+ marginBottom: "8px",
89
+ fontFamily: "inherit",
90
+ boxSizing: "border-box",
91
+ },
92
+ userList: {
93
+ display: "flex",
94
+ flexDirection: "column",
95
+ gap: "4px",
96
+ },
97
+ userRow: {
98
+ display: "flex",
99
+ justifyContent: "space-between",
100
+ alignItems: "center",
101
+ padding: "6px 8px",
102
+ background: "#2a2a3e",
103
+ borderRadius: "6px",
104
+ },
105
+ userInfo: {
106
+ flex: 1,
107
+ minWidth: 0,
108
+ },
109
+ userLabel: {
110
+ fontWeight: 500,
111
+ color: "#fff",
112
+ fontSize: "13px",
113
+ },
114
+ userEmail: {
115
+ color: "#888",
116
+ fontSize: "11px",
117
+ overflow: "hidden",
118
+ textOverflow: "ellipsis",
119
+ whiteSpace: "nowrap",
120
+ },
121
+ loginButton: {
122
+ background: "#3a5a8a",
123
+ color: "#fff",
124
+ border: "none",
125
+ borderRadius: "4px",
126
+ padding: "4px 10px",
127
+ cursor: "pointer",
128
+ fontSize: "11px",
129
+ fontFamily: "inherit",
130
+ marginLeft: "8px",
131
+ flexShrink: 0,
132
+ },
133
+ sessionFields: {
134
+ display: "flex",
135
+ flexDirection: "column",
136
+ gap: "4px",
137
+ },
138
+ fieldRow: {
139
+ display: "flex",
140
+ justifyContent: "space-between",
141
+ padding: "4px 8px",
142
+ background: "#2a2a3e",
143
+ borderRadius: "4px",
144
+ },
145
+ fieldKey: {
146
+ color: "#a0c4ff",
147
+ fontWeight: 500,
148
+ },
149
+ fieldValue: {
150
+ color: "#e0e0e0",
151
+ textAlign: "right",
152
+ maxWidth: "60%",
153
+ overflow: "hidden",
154
+ textOverflow: "ellipsis",
155
+ whiteSpace: "nowrap",
156
+ },
157
+ editFieldRow: {
158
+ marginBottom: "8px",
159
+ },
160
+ editFieldLabel: {
161
+ display: "block",
162
+ fontSize: "11px",
163
+ color: "#888",
164
+ marginBottom: "4px",
165
+ },
166
+ editInput: {
167
+ width: "100%",
168
+ background: "#2a2a3e",
169
+ color: "#e0e0e0",
170
+ border: "1px solid #3a3a5e",
171
+ borderRadius: "4px",
172
+ padding: "6px 8px",
173
+ fontSize: "12px",
174
+ fontFamily: "inherit",
175
+ boxSizing: "border-box",
176
+ },
177
+ saveButton: {
178
+ width: "100%",
179
+ background: "#3a8a5a",
180
+ color: "#fff",
181
+ border: "none",
182
+ borderRadius: "6px",
183
+ padding: "8px",
184
+ cursor: "pointer",
185
+ fontSize: "12px",
186
+ fontFamily: "inherit",
187
+ marginTop: "4px",
188
+ },
189
+ refreshButton: {
190
+ background: "transparent",
191
+ color: "#a0c4ff",
192
+ border: "none",
193
+ cursor: "pointer",
194
+ fontSize: "11px",
195
+ fontFamily: "inherit",
196
+ padding: "0",
197
+ },
198
+ errorBanner: {
199
+ background: "#3a1a1a",
200
+ color: "#ff8080",
201
+ padding: "8px 16px",
202
+ fontSize: "12px",
203
+ borderBottom: "1px solid #4a2a2a",
204
+ },
205
+ errorText: {
206
+ color: "#ff8080",
207
+ fontSize: "12px",
208
+ },
209
+ muted: {
210
+ color: "#666",
211
+ fontSize: "12px",
212
+ fontStyle: "italic",
213
+ },
214
+ };
215
+ //# sourceMappingURL=styles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"styles.js","sourceRoot":"","sources":["../../src/react/styles.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,178 @@
1
+ import type { DevtoolsPluginConfig } from "./types.js";
2
+ export declare const devtoolsPlugin: (config: DevtoolsPluginConfig) => {
3
+ id: "better-auth-devtools";
4
+ schema: {
5
+ devtoolsUser: {
6
+ fields: {
7
+ userId: {
8
+ type: "string";
9
+ required: true;
10
+ };
11
+ templateKey: {
12
+ type: "string";
13
+ required: true;
14
+ };
15
+ label: {
16
+ type: "string";
17
+ required: true;
18
+ };
19
+ email: {
20
+ type: "string";
21
+ required: true;
22
+ };
23
+ createdAt: {
24
+ type: "date";
25
+ required: true;
26
+ };
27
+ updatedAt: {
28
+ type: "date";
29
+ required: true;
30
+ };
31
+ };
32
+ modelName: string;
33
+ };
34
+ };
35
+ endpoints: {
36
+ listDevtoolsUsers: import("better-auth").StrictEndpoint<"/better-auth-devtools/users", {
37
+ method: "GET";
38
+ }, {
39
+ error: {
40
+ readonly code: "FEATURE_DISABLED";
41
+ readonly message: "DevTools is disabled. Set DEV_AUTH_ENABLED=true in a non-production environment.";
42
+ };
43
+ } | {
44
+ id: unknown;
45
+ userId: unknown;
46
+ templateKey: unknown;
47
+ label: unknown;
48
+ email: unknown;
49
+ createdAt: unknown;
50
+ }[]>;
51
+ createDevtoolsUser: import("better-auth").StrictEndpoint<"/better-auth-devtools/users", {
52
+ method: "POST";
53
+ }, {
54
+ error: {
55
+ readonly code: "FEATURE_DISABLED";
56
+ readonly message: "DevTools is disabled. Set DEV_AUTH_ENABLED=true in a non-production environment.";
57
+ };
58
+ } | {
59
+ error: {
60
+ code: "INVALID_TEMPLATE";
61
+ message: string;
62
+ };
63
+ } | {
64
+ user: {
65
+ id: any;
66
+ userId: any;
67
+ templateKey: any;
68
+ label: any;
69
+ email: any;
70
+ createdAt: any;
71
+ };
72
+ } | {
73
+ error: {
74
+ code: "CREATION_FAILED";
75
+ message: string;
76
+ };
77
+ }>;
78
+ devtoolsLogin: import("better-auth").StrictEndpoint<"/better-auth-devtools/login", {
79
+ method: "POST";
80
+ }, {
81
+ error: {
82
+ readonly code: "FEATURE_DISABLED";
83
+ readonly message: "DevTools is disabled. Set DEV_AUTH_ENABLED=true in a non-production environment.";
84
+ };
85
+ } | {
86
+ error: {
87
+ code: "USER_NOT_FOUND";
88
+ message: string;
89
+ };
90
+ } | {
91
+ error: {
92
+ code: "UNMANAGED_USER";
93
+ message: string;
94
+ };
95
+ } | {
96
+ error: {
97
+ code: "SESSION_CREATION_FAILED";
98
+ message: string;
99
+ };
100
+ } | {
101
+ session: import("./types.js").DevtoolsSessionView;
102
+ }>;
103
+ getDevtoolsSession: import("better-auth").StrictEndpoint<"/better-auth-devtools/session", {
104
+ method: "GET";
105
+ use: ((inputContext: import("better-auth").MiddlewareInputContext<import("better-auth").MiddlewareOptions>) => Promise<{
106
+ session: {
107
+ session: Record<string, any> & {
108
+ id: string;
109
+ createdAt: Date;
110
+ updatedAt: Date;
111
+ userId: string;
112
+ expiresAt: Date;
113
+ token: string;
114
+ ipAddress?: string | null | undefined;
115
+ userAgent?: string | null | undefined;
116
+ };
117
+ user: Record<string, any> & {
118
+ id: string;
119
+ createdAt: Date;
120
+ updatedAt: Date;
121
+ email: string;
122
+ emailVerified: boolean;
123
+ name: string;
124
+ image?: string | null | undefined;
125
+ };
126
+ };
127
+ }>)[];
128
+ }, {
129
+ error: {
130
+ readonly code: "FEATURE_DISABLED";
131
+ readonly message: "DevTools is disabled. Set DEV_AUTH_ENABLED=true in a non-production environment.";
132
+ };
133
+ } | {
134
+ session: import("./types.js").DevtoolsSessionView;
135
+ } | {
136
+ session: null;
137
+ }>;
138
+ updateDevtoolsSession: import("better-auth").StrictEndpoint<"/better-auth-devtools/update-session", {
139
+ method: "POST";
140
+ use: ((inputContext: import("better-auth").MiddlewareInputContext<import("better-auth").MiddlewareOptions>) => Promise<{
141
+ session: {
142
+ session: Record<string, any> & {
143
+ id: string;
144
+ createdAt: Date;
145
+ updatedAt: Date;
146
+ userId: string;
147
+ expiresAt: Date;
148
+ token: string;
149
+ ipAddress?: string | null | undefined;
150
+ userAgent?: string | null | undefined;
151
+ };
152
+ user: Record<string, any> & {
153
+ id: string;
154
+ createdAt: Date;
155
+ updatedAt: Date;
156
+ email: string;
157
+ emailVerified: boolean;
158
+ name: string;
159
+ image?: string | null | undefined;
160
+ };
161
+ };
162
+ }>)[];
163
+ }, {
164
+ error: {
165
+ readonly code: "FEATURE_DISABLED";
166
+ readonly message: "DevTools is disabled. Set DEV_AUTH_ENABLED=true in a non-production environment.";
167
+ };
168
+ } | {
169
+ error: {
170
+ code: "INVALID_PATCH";
171
+ message: string;
172
+ };
173
+ } | {
174
+ session: import("./types.js").DevtoolsSessionView;
175
+ }>;
176
+ };
177
+ };
178
+ //# sourceMappingURL=server-plugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server-plugin.d.ts","sourceRoot":"","sources":["../src/server-plugin.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAkBvD,eAAO,MAAM,cAAc,GAAI,QAAQ,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iCAmD/C,CAAH;iCAA6C,CAAA;;;;;;;;;6BAMgB,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;iCAN3D,CAAH;iCAA6C,CAAA;;;;;;;;;6BAMgB,CAAC;;;;;;;;;;;;;;;;;;CAyTtE,CAAC"}
@@ -0,0 +1,285 @@
1
+ import { createAuthEndpoint, sessionMiddleware } from "better-auth/api";
2
+ import { setSessionCookie } from "better-auth/cookies";
3
+ import { ENDPOINTS } from "./endpoints.js";
4
+ import { filterAllowedPatchKeys, isValidTemplateKey } from "./validation.js";
5
+ import { ErrorCode } from "./errors.js";
6
+ import { isDevtoolsEnabled } from "./guards.js";
7
+ function guardCheck() {
8
+ if (!isDevtoolsEnabled()) {
9
+ return {
10
+ enabled: false,
11
+ error: {
12
+ code: ErrorCode.FEATURE_DISABLED,
13
+ message: "DevTools is disabled. Set DEV_AUTH_ENABLED=true in a non-production environment.",
14
+ },
15
+ };
16
+ }
17
+ return { enabled: true };
18
+ }
19
+ export const devtoolsPlugin = (config) => {
20
+ return {
21
+ id: "better-auth-devtools",
22
+ schema: {
23
+ devtoolsUser: {
24
+ fields: {
25
+ userId: { type: "string", required: true },
26
+ templateKey: { type: "string", required: true },
27
+ label: { type: "string", required: true },
28
+ email: { type: "string", required: true },
29
+ createdAt: { type: "date", required: true },
30
+ updatedAt: { type: "date", required: true },
31
+ },
32
+ modelName: "devtoolsUser",
33
+ },
34
+ },
35
+ endpoints: {
36
+ listDevtoolsUsers: createAuthEndpoint(ENDPOINTS.LIST_USERS, { method: "GET" }, async (ctx) => {
37
+ const guard = guardCheck();
38
+ if (!guard.enabled) {
39
+ return ctx.json({ error: guard.error }, { status: 403 });
40
+ }
41
+ const users = await ctx.context.adapter.findMany({
42
+ model: "devtoolsUser",
43
+ });
44
+ return ctx.json(users.map((u) => ({
45
+ id: u.id,
46
+ userId: u.userId,
47
+ templateKey: u.templateKey,
48
+ label: u.label,
49
+ email: u.email,
50
+ createdAt: u.createdAt,
51
+ })));
52
+ }),
53
+ createDevtoolsUser: createAuthEndpoint(ENDPOINTS.CREATE_USER, { method: "POST" }, async (ctx) => {
54
+ const guard = guardCheck();
55
+ if (!guard.enabled) {
56
+ return ctx.json({ error: guard.error }, { status: 403 });
57
+ }
58
+ const body = ctx.body;
59
+ const templateKey = body?.template;
60
+ if (!templateKey || !isValidTemplateKey(templateKey, config.templates)) {
61
+ return ctx.json({
62
+ error: {
63
+ code: ErrorCode.INVALID_TEMPLATE,
64
+ message: `Invalid template key: ${templateKey}. Available: ${Object.keys(config.templates).join(", ")}`,
65
+ },
66
+ }, { status: 400 });
67
+ }
68
+ const template = config.templates[templateKey];
69
+ // Count existing users for this template to generate unique email
70
+ const existing = await ctx.context.adapter.findMany({
71
+ model: "devtoolsUser",
72
+ where: [{ field: "templateKey", value: templateKey }],
73
+ });
74
+ const nextNum = existing.length + 1;
75
+ const email = template.emailPattern
76
+ ? template.emailPattern.replace("{{n}}", String(nextNum))
77
+ : `${templateKey}+${nextNum}@test.local`;
78
+ try {
79
+ const result = await config.createManagedUser({
80
+ templateKey,
81
+ template,
82
+ email,
83
+ });
84
+ const now = new Date();
85
+ const record = await ctx.context.adapter.create({
86
+ model: "devtoolsUser",
87
+ data: {
88
+ userId: result.userId,
89
+ templateKey,
90
+ label: result.label ?? template.label,
91
+ email: result.email ?? email,
92
+ createdAt: now,
93
+ updatedAt: now,
94
+ },
95
+ });
96
+ return ctx.json({
97
+ user: {
98
+ id: record.id,
99
+ userId: record.userId,
100
+ templateKey: record.templateKey,
101
+ label: record.label,
102
+ email: record.email,
103
+ createdAt: record.createdAt,
104
+ },
105
+ });
106
+ }
107
+ catch (e) {
108
+ return ctx.json({
109
+ error: {
110
+ code: ErrorCode.CREATION_FAILED,
111
+ message: e instanceof Error ? e.message : "Failed to create managed user",
112
+ },
113
+ }, { status: 500 });
114
+ }
115
+ }),
116
+ devtoolsLogin: createAuthEndpoint(ENDPOINTS.LOGIN, { method: "POST" }, async (ctx) => {
117
+ const guard = guardCheck();
118
+ if (!guard.enabled) {
119
+ return ctx.json({ error: guard.error }, { status: 403 });
120
+ }
121
+ const body = ctx.body;
122
+ const userId = body?.userId;
123
+ if (!userId) {
124
+ return ctx.json({
125
+ error: {
126
+ code: ErrorCode.USER_NOT_FOUND,
127
+ message: "userId is required",
128
+ },
129
+ }, { status: 400 });
130
+ }
131
+ // Verify user is devtools-managed
132
+ const managed = await ctx.context.adapter.findMany({
133
+ model: "devtoolsUser",
134
+ where: [{ field: "userId", value: userId }],
135
+ });
136
+ if (!managed || managed.length === 0) {
137
+ return ctx.json({
138
+ error: {
139
+ code: ErrorCode.UNMANAGED_USER,
140
+ message: "User is not a devtools-managed test user. Only managed test users can be switched to.",
141
+ },
142
+ }, { status: 403 });
143
+ }
144
+ try {
145
+ const user = await ctx.context.internalAdapter.findUserById(userId);
146
+ if (!user) {
147
+ return ctx.json({
148
+ error: {
149
+ code: ErrorCode.USER_NOT_FOUND,
150
+ message: "Managed test user no longer exists",
151
+ },
152
+ }, { status: 404 });
153
+ }
154
+ // Create a new session using Better Auth's internal adapter
155
+ const session = await ctx.context.internalAdapter.createSession(userId);
156
+ if (!session) {
157
+ return ctx.json({
158
+ error: {
159
+ code: ErrorCode.SESSION_CREATION_FAILED,
160
+ message: "Failed to create session",
161
+ },
162
+ }, { status: 500 });
163
+ }
164
+ await setSessionCookie(ctx, {
165
+ session,
166
+ user,
167
+ });
168
+ // Get session view from host
169
+ const sessionView = await config.getSessionView({
170
+ userId,
171
+ sessionId: session.id,
172
+ });
173
+ return ctx.json({ session: sessionView });
174
+ }
175
+ catch (e) {
176
+ return ctx.json({
177
+ error: {
178
+ code: ErrorCode.SESSION_CREATION_FAILED,
179
+ message: e instanceof Error
180
+ ? e.message
181
+ : "Failed to create session for user",
182
+ },
183
+ }, { status: 500 });
184
+ }
185
+ }),
186
+ getDevtoolsSession: createAuthEndpoint(ENDPOINTS.SESSION, {
187
+ method: "GET",
188
+ use: [sessionMiddleware],
189
+ }, async (ctx) => {
190
+ const guard = guardCheck();
191
+ if (!guard.enabled) {
192
+ return ctx.json({ error: guard.error }, { status: 403 });
193
+ }
194
+ const session = ctx.context.session;
195
+ try {
196
+ const sessionView = await config.getSessionView({
197
+ userId: session.user.id,
198
+ sessionId: session.session.id,
199
+ });
200
+ return ctx.json({ session: sessionView });
201
+ }
202
+ catch {
203
+ return ctx.json({ session: null });
204
+ }
205
+ }),
206
+ updateDevtoolsSession: createAuthEndpoint(ENDPOINTS.UPDATE_SESSION, {
207
+ method: "POST",
208
+ use: [sessionMiddleware],
209
+ }, async (ctx) => {
210
+ const guard = guardCheck();
211
+ if (!guard.enabled) {
212
+ return ctx.json({ error: guard.error }, { status: 403 });
213
+ }
214
+ const body = ctx.body;
215
+ const patch = body?.patch;
216
+ if (!patch || typeof patch !== "object") {
217
+ return ctx.json({
218
+ error: {
219
+ code: ErrorCode.INVALID_PATCH,
220
+ message: "patch object is required",
221
+ },
222
+ }, { status: 400 });
223
+ }
224
+ if (!config.editableFields || config.editableFields.length === 0) {
225
+ return ctx.json({
226
+ error: {
227
+ code: ErrorCode.INVALID_PATCH,
228
+ message: "No editable fields configured",
229
+ },
230
+ }, { status: 400 });
231
+ }
232
+ const { allowed, disallowed } = filterAllowedPatchKeys(patch, config.editableFields);
233
+ if (disallowed.length > 0) {
234
+ return ctx.json({
235
+ error: {
236
+ code: ErrorCode.INVALID_PATCH,
237
+ message: `Disallowed patch keys: ${disallowed.join(", ")}`,
238
+ },
239
+ }, { status: 400 });
240
+ }
241
+ if (Object.keys(allowed).length === 0) {
242
+ return ctx.json({
243
+ error: {
244
+ code: ErrorCode.INVALID_PATCH,
245
+ message: "No valid patch keys provided",
246
+ },
247
+ }, { status: 400 });
248
+ }
249
+ // Validate individual field values
250
+ for (const field of config.editableFields) {
251
+ if (field.key in allowed && field.validate) {
252
+ if (!field.validate(allowed[field.key])) {
253
+ return ctx.json({
254
+ error: {
255
+ code: ErrorCode.INVALID_PATCH,
256
+ message: `Invalid value for field: ${field.key}`,
257
+ },
258
+ }, { status: 400 });
259
+ }
260
+ }
261
+ }
262
+ const session = ctx.context.session;
263
+ try {
264
+ const sessionView = await config.patchSession({
265
+ userId: session.user.id,
266
+ sessionId: session.session.id,
267
+ patch: allowed,
268
+ });
269
+ return ctx.json({ session: sessionView });
270
+ }
271
+ catch (e) {
272
+ return ctx.json({
273
+ error: {
274
+ code: ErrorCode.INVALID_PATCH,
275
+ message: e instanceof Error
276
+ ? e.message
277
+ : "Failed to update session",
278
+ },
279
+ }, { status: 500 });
280
+ }
281
+ }),
282
+ },
283
+ };
284
+ };
285
+ //# sourceMappingURL=server-plugin.js.map