@arcote.tech/arc-auth 0.4.10 → 0.5.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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@arcote.tech/arc-auth",
3
3
  "type": "module",
4
- "version": "0.4.10",
4
+ "version": "0.5.0",
5
5
  "private": false,
6
6
  "description": "Reusable authentication module for Arc framework — aggregate-based auth with factory pattern",
7
7
  "main": "./src/index.ts",
@@ -10,7 +10,7 @@
10
10
  "type-check": "tsc --noEmit"
11
11
  },
12
12
  "peerDependencies": {
13
- "@arcote.tech/arc": "^0.4.10",
13
+ "@arcote.tech/arc": "^0.5.0",
14
14
  "react": "^18.0.0 || ^19.0.0",
15
15
  "typescript": "^5.0.0"
16
16
  },
@@ -3,8 +3,8 @@ import {
3
3
  aggregate,
4
4
  boolean,
5
5
  date,
6
+ mergeUnsafe,
6
7
  string,
7
- type $type,
8
8
  type ArcRawShape,
9
9
  } from "@arcote.tech/arc";
10
10
  import type { AccountId } from "../ids/account";
@@ -41,9 +41,17 @@ export const createAccountAggregate = <
41
41
  const { accountId, token, customFields } = data;
42
42
  const tokenFields = data.tokenFields ?? [];
43
43
 
44
+ const name = data.name as Data["name"];
45
+
44
46
  /** Build JWT params from account — includes accountId + tokenFields */
45
- const buildTokenParams = (account: any) => {
46
- const params: any = { accountId: account._id };
47
+ const buildTokenParams = (account: {
48
+ _id: unknown;
49
+ [key: string]: unknown;
50
+ }) => {
51
+ const params = { accountId: account._id as string } as Record<
52
+ string,
53
+ unknown
54
+ > & { accountId: string };
47
55
  for (const field of tokenFields) {
48
56
  params[field] = account[field];
49
57
  }
@@ -51,70 +59,65 @@ export const createAccountAggregate = <
51
59
  };
52
60
 
53
61
  return (
54
- aggregate(`${data.name}Accounts`, accountId, {
55
- email: string().email(),
56
- isEmailVerified: boolean(),
57
- passwordHash: string().optional(),
58
- authMethod: string(),
59
- registeredAt: date(),
60
- lastSignedInAt: date().optional(),
61
- ...customFields,
62
- })
62
+ aggregate(
63
+ `${name}Accounts`,
64
+ accountId,
65
+ mergeUnsafe(
66
+ {
67
+ email: string().email(),
68
+ isEmailVerified: boolean(),
69
+ passwordHash: string().optional(),
70
+ authMethod: string(),
71
+ registeredAt: date(),
72
+ lastSignedInAt: date().optional(),
73
+ },
74
+ customFields,
75
+ ),
76
+ )
63
77
  // --- Public Events ---
64
78
 
65
79
  .publicEvent(
66
80
  "accountRegistered",
67
- {
68
- accountId,
69
- email: string().email(),
70
- passwordHash: string(),
71
- ...customFields,
72
- },
81
+ mergeUnsafe(
82
+ {
83
+ accountId,
84
+ email: string().email(),
85
+ passwordHash: string(),
86
+ },
87
+ customFields,
88
+ ),
73
89
  async (ctx, event) => {
74
- const {
75
- accountId: id,
76
- email,
77
- passwordHash,
78
- ...customData
79
- } = event.payload as any;
80
- await ctx.set(id, {
81
- email,
90
+ event.payload;
91
+ await ctx.set(event.payload.accountId, {
82
92
  isEmailVerified: false,
83
- passwordHash,
84
93
  authMethod: "email",
85
94
  registeredAt: event.createdAt,
86
- lastSignedInAt: null,
87
- ...customData,
88
- } as any);
95
+ lastSignedInAt: undefined,
96
+ ...event.payload,
97
+ });
89
98
  },
90
99
  )
91
100
 
92
101
  .publicEvent(
93
102
  "accountRegisteredViaOAuth",
94
- {
95
- accountId,
96
- email: string().email(),
97
- provider: string(),
98
- providerUserId: string(),
99
- ...customFields,
100
- },
103
+ mergeUnsafe(
104
+ {
105
+ accountId,
106
+ email: string().email(),
107
+ provider: string(),
108
+ providerUserId: string(),
109
+ },
110
+ customFields,
111
+ ),
101
112
  async (ctx, event) => {
102
- const {
103
- accountId: id,
104
- email,
105
- provider: _provider,
106
- providerUserId: _providerUserId,
107
- ...customData
108
- } = event.payload as any;
109
- await ctx.set(id, {
110
- email,
113
+ await ctx.set(event.payload.accountId, {
111
114
  isEmailVerified: true,
112
- passwordHash: null,
115
+ passwordHash: undefined,
113
116
  authMethod: "oauth",
114
117
  registeredAt: event.createdAt,
115
118
  lastSignedInAt: event.createdAt,
116
- ...customData,
117
- } as any);
119
+ ...event.payload,
120
+ });
118
121
  },
119
122
  )
120
123
 
@@ -122,192 +125,180 @@ export const createAccountAggregate = <
122
125
  "signedIn",
123
126
  { accountId, email: string().email() },
124
127
  async (ctx, event) => {
125
- await ctx.modify(
126
- event.payload.accountId as any,
127
- {
128
- lastSignedInAt: event.createdAt,
129
- } as any,
130
- );
128
+ await ctx.modify(event.payload.accountId, {
129
+ lastSignedInAt: event.createdAt,
130
+ });
131
131
  },
132
132
  )
133
133
 
134
134
  .publicEvent("emailVerified", { accountId }, async (ctx, event) => {
135
- await ctx.modify(
136
- event.payload.accountId as any,
137
- {
138
- isEmailVerified: true,
139
- } as any,
140
- );
135
+ await ctx.modify(event.payload.accountId, {
136
+ isEmailVerified: true,
137
+ });
141
138
  })
142
139
 
143
140
  // --- Mutate Methods ---
144
141
 
145
- /**
146
- * register — server-only. Hashes password, emits accountRegistered.
147
- */
148
- .mutateMethod(
149
- "register",
150
- {
151
- params: {
152
- email: string().email(),
153
- password: string().minLength(6).maxLength(32),
154
- ...customFields,
155
- },
156
- },
157
- ONLY_SERVER &&
158
- (async (ctx: any, params: any) => {
159
- const existing = await ctx.$query.findOne({ email: params.email });
160
- if (existing) {
161
- return { error: "EMAIL_ALREADY_TAKEN" as const };
162
- }
163
-
164
- const id = accountId.generate();
165
- const pwHash = await hashPassword(params.password);
166
- const { email, password: _pw, ...custom } = params;
167
-
168
- await ctx.accountRegistered.emit({
169
- accountId: id,
170
- email,
171
- passwordHash: pwHash,
172
- ...custom,
173
- });
174
-
175
- return { accountId: id };
176
- }),
142
+ .mutateMethod("register", (fn) =>
143
+ fn
144
+ .withParams(
145
+ mergeUnsafe(
146
+ {
147
+ email: string().email(),
148
+ password: string().minLength(6).maxLength(32),
149
+ },
150
+ customFields,
151
+ ),
152
+ )
153
+ .handle(
154
+ ONLY_SERVER &&
155
+ (async (ctx, params) => {
156
+ const existing = await ctx.$query.findOne({
157
+ email: params.email,
158
+ });
159
+ if (existing) {
160
+ return { error: "EMAIL_ALREADY_TAKEN" as const };
161
+ }
162
+
163
+ const id = accountId.generate();
164
+ const pwHash = await hashPassword(params.password);
165
+
166
+ await ctx.accountRegistered.emit({
167
+ ...params,
168
+ accountId: id,
169
+ passwordHash: pwHash,
170
+ });
171
+
172
+ return { accountId: id };
173
+ }),
174
+ ),
177
175
  )
178
176
 
179
- /**
180
- * signIn — server-only. Verifies password, checks email verification, returns JWT.
181
- */
182
- .mutateMethod(
183
- "signIn",
184
- {
185
- params: {
177
+ .mutateMethod("signIn", (fn) =>
178
+ fn
179
+ .withParams({
186
180
  email: string().email(),
187
181
  password: string().minLength(6).maxLength(32),
188
- },
189
- },
190
- ONLY_SERVER &&
191
- (async (ctx: any, params: any) => {
192
- const account = await ctx.$query.findOne({ email: params.email });
193
-
194
- if (!account) {
195
- return { error: "INVALID_EMAIL_OR_PASSWORD" as const };
196
- }
197
-
198
- const isValid = await verifyPassword(
199
- params.password,
200
- account.passwordHash,
201
- );
202
- if (!isValid) {
203
- return { error: "INVALID_EMAIL_OR_PASSWORD" as const };
204
- }
205
-
206
- if (!account.isEmailVerified) {
207
- return {
208
- error: "EMAIL_NOT_VERIFIED" as const,
209
- email: params.email,
210
- };
211
- }
212
-
213
- const jwtToken = token.generateJWT(buildTokenParams(account));
214
-
215
- await ctx.signedIn.emit({
216
- accountId: account._id,
217
- email: params.email,
218
- });
219
-
220
- return { token: jwtToken };
221
- }),
182
+ })
183
+ .handle(
184
+ ONLY_SERVER &&
185
+ (async (ctx, params) => {
186
+ const account = await ctx.$query.findOne({
187
+ email: params.email,
188
+ });
189
+
190
+ if (!account) {
191
+ return { error: "INVALID_EMAIL_OR_PASSWORD" as const };
192
+ }
193
+
194
+ const isValid = await verifyPassword(
195
+ params.password,
196
+ account.passwordHash!,
197
+ );
198
+ if (!isValid) {
199
+ return { error: "INVALID_EMAIL_OR_PASSWORD" as const };
200
+ }
201
+
202
+ if (!account.isEmailVerified) {
203
+ return {
204
+ error: "EMAIL_NOT_VERIFIED" as const,
205
+ email: params.email,
206
+ };
207
+ }
208
+
209
+ const jwtToken = token.generateJWT(buildTokenParams(account));
210
+
211
+ await ctx.signedIn.emit({
212
+ accountId: account._id,
213
+ email: params.email,
214
+ });
215
+
216
+ return { token: jwtToken };
217
+ }),
218
+ ),
222
219
  )
223
220
 
224
- /**
225
- * registerViaOAuth — server-only. Creates account from OAuth provider data.
226
- */
227
- .mutateMethod(
228
- "registerViaOAuth",
229
- {
230
- params: {
231
- email: string().email(),
232
- provider: string(),
233
- providerUserId: string(),
234
- ...customFields,
235
- },
236
- result: {} as
237
- | { accountId: $type<typeof accountId>; token: string }
238
- | {
239
- error: "EMAIL_ALREADY_TAKEN";
240
- accountId: $type<typeof accountId>;
241
- token: string;
221
+ .mutateMethod("registerViaOAuth", (fn) =>
222
+ fn
223
+ .withParams(
224
+ mergeUnsafe(
225
+ {
226
+ email: string().email(),
227
+ provider: string(),
228
+ providerUserId: string(),
242
229
  },
243
- },
244
- ONLY_SERVER &&
245
- (async (ctx: any, params: any) => {
246
- const existing = await ctx.$query.findOne({ email: params.email });
247
- if (existing) {
248
- return {
249
- error: "EMAIL_ALREADY_TAKEN" as const,
250
- accountId: existing._id,
251
- token: token.generateJWT(buildTokenParams(existing)),
252
- };
253
- }
254
-
255
- const id = accountId.generate();
256
- const { email, provider, providerUserId, ...custom } = params;
257
-
258
- await ctx.accountRegisteredViaOAuth.emit({
259
- accountId: id,
260
- email,
261
- provider,
262
- providerUserId,
263
- ...custom,
264
- });
265
-
266
- // Fetch newly created account to get defaults (e.g. role)
267
- const newAccount = await ctx.$query.findOne({ _id: id });
268
- return {
269
- accountId: id,
270
- token: token.generateJWT(buildTokenParams(newAccount ?? { _id: id })),
271
- };
272
- }),
230
+ customFields,
231
+ ),
232
+ )
233
+ .handle(
234
+ ONLY_SERVER &&
235
+ (async (ctx, params) => {
236
+ const existing = await ctx.$query.findOne({
237
+ email: params.email,
238
+ });
239
+ if (existing) {
240
+ return {
241
+ error: "EMAIL_ALREADY_TAKEN" as const,
242
+ accountId: existing._id,
243
+ token: token.generateJWT(buildTokenParams(existing)),
244
+ };
245
+ }
246
+
247
+ const id = accountId.generate();
248
+
249
+ await ctx.accountRegisteredViaOAuth.emit({
250
+ ...params,
251
+ accountId: id,
252
+ });
253
+
254
+ const newAccount = await ctx.$query.findOne({ _id: id });
255
+ return {
256
+ accountId: id,
257
+ token: token.generateJWT(
258
+ buildTokenParams(newAccount ?? { _id: id }),
259
+ ),
260
+ };
261
+ }),
262
+ ),
273
263
  )
274
264
 
275
- /**
276
- * signInViaOAuth — server-only. Signs in via OAuth (no password check).
277
- * Identity already verified by the OAuth provider.
278
- */
279
- .mutateMethod(
280
- "signInViaOAuth",
281
- {
282
- params: {
265
+ .mutateMethod("signInViaOAuth", (fn) =>
266
+ fn
267
+ .withParams({
283
268
  email: string().email(),
284
269
  provider: string(),
285
270
  providerUserId: string(),
286
- },
287
- result: {} as { token: string } | { error: "ACCOUNT_NOT_FOUND" },
288
- },
289
- ONLY_SERVER &&
290
- (async (ctx: any, params: any) => {
291
- const account = await ctx.$query.findOne({ email: params.email });
292
-
293
- if (!account) {
294
- return { error: "ACCOUNT_NOT_FOUND" as const };
295
- }
296
-
297
- const jwtToken = token.generateJWT(buildTokenParams(account));
298
-
299
- await ctx.signedIn.emit({
300
- accountId: account._id,
301
- email: params.email,
302
- });
303
-
304
- return { token: jwtToken };
305
- }),
271
+ })
272
+ .handle(
273
+ ONLY_SERVER &&
274
+ (async (ctx, params) => {
275
+ const account = await ctx.$query.findOne({
276
+ email: params.email,
277
+ });
278
+
279
+ if (!account) {
280
+ return { error: "ACCOUNT_NOT_FOUND" as const };
281
+ }
282
+
283
+ const jwtToken = token.generateJWT(buildTokenParams(account));
284
+
285
+ await ctx.signedIn.emit({
286
+ accountId: account._id,
287
+ email: params.email,
288
+ });
289
+
290
+ return { token: jwtToken };
291
+ }),
292
+ ),
306
293
  )
307
294
 
308
- .protectBy(token, (params: any) => ({ _id: params.accountId }))
309
- .clientQuery("getAll", async (ctx) => ctx.$query.find({}))
310
- .clientQuery("getMe", async (ctx) => ctx.$query.findOne({}))
295
+ .protectBy(token, (params) => ({ _id: params.accountId }))
296
+ .clientQuery("getAll", (fn) =>
297
+ fn.handle(async (ctx) => ctx.$query.find({})),
298
+ )
299
+ .clientQuery("getMe", (fn) =>
300
+ fn.handle(async (ctx) => ctx.$query.findOne({})),
301
+ )
311
302
  );
312
303
  };
313
304
 
@@ -1,6 +1,6 @@
1
1
  import { aggregate, date, string } from "@arcote.tech/arc";
2
- import type { OAuthIdentityId } from "../ids/oauth-identity";
3
2
  import type { AccountId } from "../ids/account";
3
+ import type { OAuthIdentityId } from "../ids/oauth-identity";
4
4
 
5
5
  export type OAuthIdentityAggregateData = {
6
6
  name: string;
@@ -14,8 +14,9 @@ export const createOAuthIdentityAggregate = <
14
14
  data: Data,
15
15
  ) => {
16
16
  const { oauthIdentityId, accountId } = data;
17
+ const name = data.name as Data["name"];
17
18
 
18
- return aggregate(`${data.name}OAuthIdentities`, oauthIdentityId, {
19
+ return aggregate(`${name}OAuthIdentities`, oauthIdentityId, {
19
20
  accountId,
20
21
  provider: string(),
21
22
  providerUserId: string(),
@@ -39,15 +40,15 @@ export const createOAuthIdentityAggregate = <
39
40
  provider,
40
41
  providerUserId,
41
42
  providerEmail,
42
- } = event.payload as any;
43
+ } = event.payload;
43
44
  await ctx.set(id, {
44
45
  accountId: accId,
45
46
  provider,
46
47
  providerUserId,
47
48
  providerEmail,
48
49
  linkedAt: event.createdAt,
49
- lastUsedAt: null,
50
- } as any);
50
+ lastUsedAt: undefined,
51
+ });
51
52
  },
52
53
  )
53
54
 
@@ -55,9 +56,9 @@ export const createOAuthIdentityAggregate = <
55
56
  "oauthIdentityUsed",
56
57
  { oauthIdentityId },
57
58
  async (ctx, event) => {
58
- await ctx.modify(event.payload.oauthIdentityId as any, {
59
+ await ctx.modify(event.payload.oauthIdentityId, {
59
60
  lastUsedAt: event.createdAt,
60
- } as any);
61
+ });
61
62
  },
62
63
  )
63
64
 
@@ -65,65 +66,68 @@ export const createOAuthIdentityAggregate = <
65
66
  "oauthIdentityUnlinked",
66
67
  { oauthIdentityId },
67
68
  async (ctx, event) => {
68
- await ctx.remove(event.payload.oauthIdentityId as any);
69
+ await ctx.remove(event.payload.oauthIdentityId);
69
70
  },
70
71
  )
71
72
 
72
- .mutateMethod(
73
- "linkIdentity",
74
- {
75
- params: {
73
+ .mutateMethod("linkIdentity", (fn) =>
74
+ fn
75
+ .withParams({
76
76
  accountId,
77
77
  provider: string(),
78
78
  providerUserId: string(),
79
79
  providerEmail: string().email(),
80
- },
81
- },
82
- ONLY_SERVER &&
83
- (async (ctx: any, params: any) => {
84
- // Check for duplicate (same provider + providerUserId)
85
- const existing = await ctx.$query.findOne({
86
- provider: params.provider,
87
- providerUserId: params.providerUserId,
88
- });
89
- if (existing) {
90
- return { error: "OAUTH_IDENTITY_ALREADY_LINKED" as const };
91
- }
80
+ })
81
+ .handle(
82
+ ONLY_SERVER &&
83
+ (async (ctx, params) => {
84
+ const existing = await ctx.$query.findOne({
85
+ provider: params.provider,
86
+ providerUserId: params.providerUserId,
87
+ });
88
+ if (existing) {
89
+ return { error: "OAUTH_IDENTITY_ALREADY_LINKED" as const };
90
+ }
92
91
 
93
- const id = oauthIdentityId.generate();
92
+ const id = oauthIdentityId.generate();
94
93
 
95
- await ctx.oauthIdentityLinked.emit({
96
- oauthIdentityId: id,
97
- accountId: params.accountId,
98
- provider: params.provider,
99
- providerUserId: params.providerUserId,
100
- providerEmail: params.providerEmail,
101
- });
94
+ await ctx.oauthIdentityLinked.emit({
95
+ oauthIdentityId: id,
96
+ accountId: params.accountId,
97
+ provider: params.provider,
98
+ providerUserId: params.providerUserId,
99
+ providerEmail: params.providerEmail,
100
+ });
102
101
 
103
- return { oauthIdentityId: id };
104
- }),
102
+ return { oauthIdentityId: id };
103
+ }),
104
+ ),
105
105
  )
106
106
 
107
- .mutateMethod(
108
- "markUsed",
109
- { params: { oauthIdentityId } },
110
- ONLY_SERVER &&
111
- (async (ctx: any, params: any) => {
112
- await ctx.oauthIdentityUsed.emit({
113
- oauthIdentityId: params.oauthIdentityId,
114
- });
115
- }),
107
+ .mutateMethod("markUsed", (fn) =>
108
+ fn.withParams({ oauthIdentityId }).handle(
109
+ ONLY_SERVER &&
110
+ (async (ctx, params) => {
111
+ await ctx["oauthIdentityUsed"].emit({
112
+ oauthIdentityId: params.oauthIdentityId,
113
+ });
114
+ }),
115
+ ),
116
116
  )
117
- .clientQuery("getAll", async (ctx) => ctx.$query.find({}))
118
- .clientQuery(
119
- "findByProvider",
120
- async (ctx, params: { provider: string; providerUserId: string }) =>
121
- ctx.$query.findOne({
122
- provider: params.provider,
123
- providerUserId: params.providerUserId,
124
- }),
117
+ .clientQuery("getAll", (fn) =>
118
+ fn.handle(async (ctx) => ctx.$query.find({})),
125
119
  )
126
- ;
120
+ .clientQuery("findByProvider", (fn) =>
121
+ fn
122
+ .withParams({ provider: string(), providerUserId: string() })
123
+ .handle(
124
+ async (ctx, params: { provider: string; providerUserId: string }) =>
125
+ ctx.$query.findOne({
126
+ provider: params.provider,
127
+ providerUserId: params.providerUserId,
128
+ }),
129
+ ),
130
+ );
127
131
  };
128
132
 
129
133
  export type OAuthIdentityAggregate<
@@ -1,23 +1,26 @@
1
1
  import {
2
2
  context,
3
3
  route,
4
- type ArcAggregateElement,
5
4
  type ArcContextElement,
6
5
  type ArcRawShape,
7
6
  } from "@arcote.tech/arc";
7
+ import type { AccountAggregate } from "./aggregates/account";
8
+ import type { OAuthIdentityAggregate } from "./aggregates/oauth-identity";
8
9
  import { createAccountAggregate } from "./aggregates/account";
9
10
  import { createOAuthIdentityAggregate } from "./aggregates/oauth-identity";
10
11
  import { createAccountId } from "./ids/account";
11
12
  import { createOAuthIdentityId } from "./ids/oauth-identity";
12
13
  import { createToken } from "./tokens/token";
13
14
  import { createOAuthRoutes } from "./routes/oauth-routes";
15
+ import type { AccountId } from "./ids/account";
14
16
  import type { OAuthProvidersConfig } from "./providers/types";
17
+ import type { Token } from "./tokens/token";
15
18
 
16
19
  export class AuthBuilder<
17
- AccId,
18
- Tok,
19
- Account extends ArcAggregateElement<any, any, any, any, any, any>,
20
- OAuthIdentity extends ArcAggregateElement<any, any, any, any, any, any> | undefined,
20
+ AccId extends AccountId,
21
+ Tok extends Token,
22
+ Account extends AccountAggregate,
23
+ OAuthIdentity extends OAuthIdentityAggregate | undefined,
21
24
  EnabledProviders extends string[],
22
25
  Elements extends ArcContextElement<any>[],
23
26
  > {
@@ -39,7 +42,7 @@ export class AuthBuilder<
39
42
  const OAuthIdentity = createOAuthIdentityAggregate({
40
43
  name: this._name,
41
44
  oauthIdentityId,
42
- accountId: this.accountId as any,
45
+ accountId: this.accountId,
43
46
  });
44
47
 
45
48
  const hasProviders = config.providers && config.baseUrl;
@@ -47,7 +50,7 @@ export class AuthBuilder<
47
50
  ? createOAuthRoutes({
48
51
  providers: config.providers!,
49
52
  baseUrl: config.baseUrl!,
50
- token: this.token as any,
53
+ token: this.token,
51
54
  accountElement: this.Account,
52
55
  oauthIdentityElement: OAuthIdentity,
53
56
  })
@@ -248,9 +248,13 @@ export function createOAuthRoutes(data: OAuthRoutesData) {
248
248
  const targetUrl = new URL(decodedRedirect, baseUrl);
249
249
  targetUrl.searchParams.set("token", jwtToken);
250
250
 
251
- // Clear state cookie
251
+ // Set auth cookie + clear state cookie
252
252
  const response = Response.redirect(targetUrl.toString(), 302);
253
253
  const headers = new Headers(response.headers);
254
+ headers.append(
255
+ "Set-Cookie",
256
+ `arc_token=${encodeURIComponent(jwtToken)}; HttpOnly; SameSite=Lax; Path=/; Max-Age=604800`,
257
+ );
254
258
  headers.append(
255
259
  "Set-Cookie",
256
260
  `oauth_state=; HttpOnly; SameSite=Lax; Path=/; Max-Age=0`,
@@ -10,7 +10,7 @@ export const createToken = <const Data extends TokenData>(data: Data) =>
10
10
  token(`${data.name}Account`, {
11
11
  accountId: string(),
12
12
  ...(data.extraParams ?? {}),
13
- } as any).secret(data.secret);
13
+ }).secret(data.secret);
14
14
 
15
15
  export type Token<Data extends TokenData = TokenData> = ReturnType<
16
16
  typeof createToken<Data>