adonia 0.1.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 (140) hide show
  1. package/README.md +64 -0
  2. package/build/adonis_peers.d.ts +14 -0
  3. package/build/adonis_peers.js +56 -0
  4. package/build/cli.d.ts +2 -0
  5. package/build/cli.js +111 -0
  6. package/build/commands/add.d.ts +18 -0
  7. package/build/commands/add.js +246 -0
  8. package/build/commands/check.d.ts +4 -0
  9. package/build/commands/check.js +159 -0
  10. package/build/commands/diff.d.ts +2 -0
  11. package/build/commands/diff.js +74 -0
  12. package/build/commands/init.d.ts +6 -0
  13. package/build/commands/init.js +124 -0
  14. package/build/commands/list.d.ts +2 -0
  15. package/build/commands/list.js +34 -0
  16. package/build/config_merge.d.ts +10 -0
  17. package/build/config_merge.js +71 -0
  18. package/build/constants_merge.d.ts +4 -0
  19. package/build/constants_merge.js +85 -0
  20. package/build/copy.d.ts +8 -0
  21. package/build/copy.js +33 -0
  22. package/build/host.d.ts +15 -0
  23. package/build/host.js +85 -0
  24. package/build/registry/index.d.ts +26 -0
  25. package/build/registry/index.js +116 -0
  26. package/build/registry/plan.d.ts +53 -0
  27. package/build/registry/plan.js +159 -0
  28. package/build/schema.d.ts +136 -0
  29. package/build/schema.js +58 -0
  30. package/build/types.d.ts +21 -0
  31. package/build/types.js +1 -0
  32. package/build/wire.d.ts +16 -0
  33. package/build/wire.js +162 -0
  34. package/package.json +51 -0
  35. package/registry/README.md +86 -0
  36. package/registry/account/contracts/avatar_storage.ts +7 -0
  37. package/registry/account/contracts/index.ts +7 -0
  38. package/registry/account/contracts/types.ts +23 -0
  39. package/registry/account/events.ts +14 -0
  40. package/registry/account/module.json +31 -0
  41. package/registry/account/options.ts +11 -0
  42. package/registry/account/service.ts +155 -0
  43. package/registry/account/stubs/adapters/account.ts +21 -0
  44. package/registry/account/stubs/adapters/drive_avatar_storage.ts +15 -0
  45. package/registry/account/stubs/controllers/account_controller.ts +190 -0
  46. package/registry/account/stubs/routes/account.ts +53 -0
  47. package/registry/account/stubs/validators/account.ts +37 -0
  48. package/registry/account/tests/account_service.spec.ts +132 -0
  49. package/registry/account/tests/fakes/memory_avatar_storage.ts +12 -0
  50. package/registry/api/envelope.ts +66 -0
  51. package/registry/api/exception.ts +38 -0
  52. package/registry/api/exception_handler.ts +54 -0
  53. package/registry/api/module.json +27 -0
  54. package/registry/api/provider.ts +129 -0
  55. package/registry/api/service.ts +88 -0
  56. package/registry/api/tests/emit_safe.spec.ts +107 -0
  57. package/registry/api/tests/respond.spec.ts +40 -0
  58. package/registry/auth/contracts/index.ts +18 -0
  59. package/registry/auth/contracts/password_reset_store.ts +21 -0
  60. package/registry/auth/contracts/session_manager.ts +19 -0
  61. package/registry/auth/contracts/types.ts +32 -0
  62. package/registry/auth/events.ts +21 -0
  63. package/registry/auth/module.json +45 -0
  64. package/registry/auth/options.ts +23 -0
  65. package/registry/auth/service.ts +150 -0
  66. package/registry/auth/stubs/adapters/auth.ts +21 -0
  67. package/registry/auth/stubs/adapters/lucid_access_token_session.ts +33 -0
  68. package/registry/auth/stubs/adapters/lucid_password_reset_store.ts +68 -0
  69. package/registry/auth/stubs/adapters/lucid_user_store.ts +86 -0
  70. package/registry/auth/stubs/adapters/map_user.ts +19 -0
  71. package/registry/auth/stubs/controllers/auth_controller.ts +126 -0
  72. package/registry/auth/stubs/migrations/add_pending_email_to_users_table.ts +17 -0
  73. package/registry/auth/stubs/migrations/create_password_resets_table.ts +27 -0
  74. package/registry/auth/stubs/migrations/create_users_table.ts +31 -0
  75. package/registry/auth/stubs/models/password_reset.ts +29 -0
  76. package/registry/auth/stubs/models/user.ts +99 -0
  77. package/registry/auth/stubs/providers/vine_provider.ts +43 -0
  78. package/registry/auth/stubs/routes/auth.ts +36 -0
  79. package/registry/auth/stubs/start/limiter.ts +17 -0
  80. package/registry/auth/stubs/validators/auth.ts +48 -0
  81. package/registry/auth/stubs/validators/rules/exists.ts +21 -0
  82. package/registry/auth/stubs/validators/rules/unique.ts +21 -0
  83. package/registry/auth/stubs/validators/rules/valid_password.ts +20 -0
  84. package/registry/auth/stubs/validators/rules/valid_token.ts +27 -0
  85. package/registry/auth/stubs/validators/vine.d.ts +10 -0
  86. package/registry/auth/tests/auth_service.spec.ts +145 -0
  87. package/registry/auth/tests/auth_update_password.spec.ts +99 -0
  88. package/registry/auth/tests/fakes/index.ts +3 -0
  89. package/registry/auth/tests/fakes/memory_password_reset_store.ts +71 -0
  90. package/registry/auth/tests/fakes/memory_session_manager.ts +23 -0
  91. package/registry/auth/tests/fakes/memory_user_store.ts +89 -0
  92. package/registry/constants/exceptions.ts +64 -0
  93. package/registry/constants/index.ts +12 -0
  94. package/registry/constants/responseCodes.ts +87 -0
  95. package/registry/contracts/index.ts +5 -0
  96. package/registry/contracts/user.ts +78 -0
  97. package/registry/creem/contracts/creem_client.ts +34 -0
  98. package/registry/creem/contracts/index.ts +8 -0
  99. package/registry/creem/contracts/types.ts +30 -0
  100. package/registry/creem/events.ts +9 -0
  101. package/registry/creem/module.json +28 -0
  102. package/registry/creem/service.ts +87 -0
  103. package/registry/creem/stubs/adapters/creem.ts +23 -0
  104. package/registry/creem/stubs/adapters/creem_io_client.ts +70 -0
  105. package/registry/creem/tests/fakes/fake_creem_client.ts +68 -0
  106. package/registry/notification/contracts/app_notification_store.ts +8 -0
  107. package/registry/notification/contracts/index.ts +9 -0
  108. package/registry/notification/contracts/mail_transport.ts +7 -0
  109. package/registry/notification/contracts/types.ts +32 -0
  110. package/registry/notification/module.json +23 -0
  111. package/registry/notification/options.ts +11 -0
  112. package/registry/notification/service.ts +103 -0
  113. package/registry/notification/stubs/adapters/adonis_mail_transport.ts +15 -0
  114. package/registry/notification/stubs/adapters/lucid_app_notification_store.ts +21 -0
  115. package/registry/notification/stubs/adapters/notification.ts +36 -0
  116. package/registry/notification/stubs/migrations/create_notifications_table.ts +23 -0
  117. package/registry/notification/stubs/models/app_notification.ts +45 -0
  118. package/registry/notification/tests/fakes/memory_app_notification_store.ts +19 -0
  119. package/registry/notification/tests/fakes/memory_mail_transport.ts +16 -0
  120. package/registry/notification/tests/notification_service.spec.ts +63 -0
  121. package/registry/registry.json +4 -0
  122. package/registry/subscription/contracts/index.ts +9 -0
  123. package/registry/subscription/contracts/subscription_store.ts +15 -0
  124. package/registry/subscription/contracts/types.ts +39 -0
  125. package/registry/subscription/events.ts +13 -0
  126. package/registry/subscription/module.json +31 -0
  127. package/registry/subscription/options.ts +14 -0
  128. package/registry/subscription/service.ts +140 -0
  129. package/registry/subscription/stubs/adapters/lucid_subscription_store.ts +69 -0
  130. package/registry/subscription/stubs/adapters/subscription.ts +21 -0
  131. package/registry/subscription/stubs/migrations/create_subscriptions_table.ts +26 -0
  132. package/registry/subscription/stubs/migrations/subscriptions_user_creem_unique.ts +19 -0
  133. package/registry/subscription/stubs/models/subscription.ts +45 -0
  134. package/registry/subscription/tests/billing_service.spec.ts +189 -0
  135. package/registry/subscription/tests/fakes/memory_subscription_store.ts +63 -0
  136. package/registry/types/api.ts +41 -0
  137. package/registry/types/constants.ts +7 -0
  138. package/registry/types/index.ts +6 -0
  139. package/registry/types/models.ts +32 -0
  140. package/schema/adonia.schema.json +39 -0
@@ -0,0 +1,129 @@
1
+ import type { ApplicationService } from '@adonisjs/core/types'
2
+ import { HttpContext } from '@adonisjs/core/http'
3
+ import { BaseSerializer } from '@adonisjs/core/transformers'
4
+ import { type SimplePaginatorMetaKeys } from '@adonisjs/lucid/types/querybuilder'
5
+ import {
6
+ isApiError,
7
+ isApiResponse,
8
+ isPaginatedResponse,
9
+ } from '#modules/api/envelope'
10
+ import type {
11
+ ApiResponse,
12
+ ApiResult,
13
+ PaginatedResponse,
14
+ } from '#modules/types/api'
15
+
16
+ /**
17
+ * Custom serializer for API responses that ensures consistent JSON structure
18
+ * across all API endpoints. Wraps response data in a 'data' property and handles
19
+ * pagination metadata for Lucid ORM query results.
20
+ */
21
+ class ApiSerializer extends BaseSerializer<{
22
+ Wrap: 'data'
23
+ PaginationMetaData: SimplePaginatorMetaKeys
24
+ }> {
25
+ /**
26
+ * Wraps all serialized data under this key in the response object.
27
+ * Example: { data: [...] } instead of returning raw arrays/objects
28
+ */
29
+ wrap: 'data' = 'data'
30
+
31
+ /**
32
+ * Validates and defines pagination metadata structure for paginated responses.
33
+ * Ensures that pagination info from Lucid queries is properly formatted.
34
+ *
35
+ * @throws Error if metadata doesn't match Lucid's pagination structure
36
+ */
37
+ definePaginationMetaData(metaData: unknown): SimplePaginatorMetaKeys {
38
+ if (!this.isLucidPaginatorMetaData(metaData)) {
39
+ throw new Error(
40
+ 'Invalid pagination metadata. Expected metadata to contain Lucid pagination keys'
41
+ )
42
+ }
43
+ return metaData
44
+ }
45
+ }
46
+
47
+ /**
48
+ * Single instance of ApiSerializer used across the application
49
+ */
50
+ const serializer = new ApiSerializer()
51
+
52
+ const serialize = Object.assign(
53
+ function (this: HttpContext, ...[data, resolver]: Parameters<ApiSerializer['serialize']>) {
54
+ return serializer.serialize(data, resolver ?? this.containerResolver)
55
+ },
56
+ {
57
+ withoutWrapping(
58
+ this: HttpContext,
59
+ ...[data, resolver]: Parameters<ApiSerializer['serializeWithoutWrapping']>
60
+ ) {
61
+ return serializer.serializeWithoutWrapping(data, resolver ?? this.containerResolver)
62
+ },
63
+ }
64
+ ) as ApiSerializer['serialize'] & { withoutWrapping: ApiSerializer['serializeWithoutWrapping'] }
65
+
66
+ type Respondable =
67
+ | ApiResponse<unknown>
68
+ | ApiResult<unknown>
69
+ | PaginatedResponse<unknown>
70
+
71
+ /**
72
+ * Bridges ApiService envelopes to HTTP JSON without double-wrapping `data`.
73
+ * Serializes the payload via transformers, then restores the shared envelope.
74
+ */
75
+ export async function respond(this: HttpContext, result: Respondable) {
76
+ if (isApiError(result)) {
77
+ this.response.status(result.status ?? 400)
78
+ return result
79
+ }
80
+
81
+ if (isPaginatedResponse(result)) {
82
+ const data = await serializer.serializeWithoutWrapping(
83
+ result.data,
84
+ this.containerResolver
85
+ )
86
+ return {
87
+ success: true as const,
88
+ message: result.message,
89
+ data,
90
+ meta: result.meta,
91
+ }
92
+ }
93
+
94
+ if (isApiResponse(result)) {
95
+ const data = await serializer.serializeWithoutWrapping(
96
+ result.data,
97
+ this.containerResolver
98
+ )
99
+ return {
100
+ success: true as const,
101
+ message: result.message,
102
+ data,
103
+ }
104
+ }
105
+
106
+ return result
107
+ }
108
+
109
+ /**
110
+ * Registers HTTP helpers used by all API controllers.
111
+ */
112
+ export default class ApiProvider {
113
+ constructor(protected app: ApplicationService) {}
114
+
115
+ async boot() {
116
+ HttpContext.instanceProperty('serialize', serialize)
117
+ HttpContext.instanceProperty('respond', respond)
118
+ }
119
+ }
120
+
121
+ /**
122
+ * Module augmentation for HttpContext API helpers.
123
+ */
124
+ declare module '@adonisjs/core/http' {
125
+ export interface HttpContext {
126
+ serialize: typeof serialize
127
+ respond: typeof respond
128
+ }
129
+ }
@@ -0,0 +1,88 @@
1
+ /*
2
+ * Domain base for feature modules.
3
+ *
4
+ * Envelope helpers (prepareResponse / prepareError / preparePaginatedResponse)
5
+ * are for controllers and hosts — domain services under modules/ return DTOs
6
+ * and throw ApiException instead of wrapping results.
7
+ *
8
+ * HTTP serialization lives on HttpContext via the api provider (ctx.respond).
9
+ */
10
+ import emitter from '@adonisjs/core/services/emitter'
11
+ import logger from '@adonisjs/core/services/logger'
12
+ import config from '@adonisjs/core/services/config'
13
+ import type { EventsList } from '@adonisjs/core/types'
14
+ import { ModelsTypes, ApiTypes } from '#modules/types'
15
+ import { prepareError } from '#modules/api/envelope'
16
+
17
+ export default class ApiService {
18
+ namespace: ModelsTypes.NameSpace = null
19
+
20
+ resolveConfig() {
21
+ if (!this.namespace) {
22
+ return null
23
+ }
24
+ return config.get<ModelsTypes.ModuleActionConfig>(`modules.${this.namespace}`)
25
+ }
26
+
27
+ /**
28
+ * Build a success envelope. Prefer calling this from controllers/hosts,
29
+ * not from domain services under modules/.
30
+ */
31
+ prepareResponse<T>(data: T, message: string | null = null): ApiTypes.ApiResponse<T> {
32
+ return {
33
+ data,
34
+ message,
35
+ success: true,
36
+ }
37
+ }
38
+
39
+ prepareError(message: string, status?: number): ApiTypes.ApiResult<never> {
40
+ return prepareError(message, status)
41
+ }
42
+
43
+ /**
44
+ * Build a paginated success envelope with meta. Controllers/hosts only.
45
+ */
46
+ preparePaginatedResponse<T>(
47
+ data: T[],
48
+ total: number,
49
+ params: ApiTypes.PaginationParams = {}
50
+ ): ApiTypes.PaginatedResponse<T> {
51
+ const page = params.page ?? 1
52
+ const pageSize = params.pageSize ?? data.length
53
+ return {
54
+ data,
55
+ message: null,
56
+ success: true,
57
+ meta: {
58
+ total,
59
+ page,
60
+ pageSize,
61
+ totalPages: pageSize > 0 ? Math.ceil(total / pageSize) : 0,
62
+ },
63
+ }
64
+ }
65
+
66
+ /**
67
+ * Emit a typed domain event when listed in config/modules.ts.
68
+ * Types come from EventsList augmentations imported by each feature module.
69
+ */
70
+ public async emitSafe<K extends keyof EventsList>(
71
+ eventName: K,
72
+ payload: EventsList[K]
73
+ ): Promise<void> {
74
+ const actionConfig = this.resolveConfig()
75
+ if (!actionConfig) {
76
+ logger.warn(`No modules.${this.namespace} config; skipping ${String(eventName)}`)
77
+ return
78
+ }
79
+ if (!actionConfig.emits.includes(eventName as string)) {
80
+ return
81
+ }
82
+ try {
83
+ await emitter.emit(eventName, payload)
84
+ } catch (err) {
85
+ logger.error(`Event emit failed for ${String(eventName)}: %o`, err)
86
+ }
87
+ }
88
+ }
@@ -0,0 +1,107 @@
1
+ import { test } from '@japa/runner'
2
+ import assert from 'node:assert/strict'
3
+ import emitter from '@adonisjs/core/services/emitter'
4
+ import config from '@adonisjs/core/services/config'
5
+ import { AuthService } from '#modules/auth/service'
6
+ import type { User, UserStore } from '#modules/contracts/index'
7
+ import type { PasswordResetStore } from '#modules/auth/contracts/index'
8
+ import '#modules/auth/events'
9
+
10
+ function makeUser(): User {
11
+ return {
12
+ id: 1,
13
+ email: 'user@test.com',
14
+ pendingEmail: null,
15
+ authMethod: 'email',
16
+ firstName: 'Test',
17
+ lastName: 'User',
18
+ avatarKey: null,
19
+ emailVerifiedAt: new Date(),
20
+ emailVerificationToken: null,
21
+ }
22
+ }
23
+
24
+ function makeUserStore(): UserStore {
25
+ return {
26
+ createEmailUser: async () => makeUser(),
27
+ findOrFail: async () => makeUser(),
28
+ findByEmail: async () => null,
29
+ findByEmailOrFail: async () => makeUser(),
30
+ findByVerificationToken: async () => null,
31
+ verifyCredentials: async () => makeUser(),
32
+ verifyPassword: async () => true,
33
+ save: async (u) => u,
34
+ updatePassword: async (u) => u,
35
+ delete: async () => {},
36
+ }
37
+ }
38
+
39
+ function makePasswordResetStore(): PasswordResetStore {
40
+ return {
41
+ createForUser: async () => ({ id: 1, userId: 1, token: 't', isExpired: false }),
42
+ findByToken: async () => null,
43
+ deleteForUser: async () => {},
44
+ refreshToken: async (r) => r,
45
+ findUserByReset: async () => makeUser(),
46
+ }
47
+ }
48
+
49
+ test.group('ApiService emitSafe', () => {
50
+ test('emits listed events and skips unlisted ones', async () => {
51
+ const service = new AuthService(makeUserStore(), makePasswordResetStore())
52
+ const emitted: string[] = []
53
+ const originalEmit = emitter.emit.bind(emitter)
54
+ const originalGet = config.get.bind(config)
55
+
56
+ ;(emitter as any).emit = async (event: string, payload: unknown) => {
57
+ emitted.push(event)
58
+ return originalEmit(event as any, payload as any)
59
+ }
60
+
61
+ ;(config as any).get = (key: string) => {
62
+ if (key === 'modules.auth') {
63
+ return {
64
+ description: 'test',
65
+ emits: ['Auth:Logout'],
66
+ }
67
+ }
68
+ return originalGet(key)
69
+ }
70
+
71
+ try {
72
+ await service.emitSafe('Auth:Logout', null)
73
+ await service.emitSafe('Auth:Login', { user: makeUser() })
74
+ assert.deepEqual(emitted, ['Auth:Logout'])
75
+ } finally {
76
+ ;(emitter as any).emit = originalEmit
77
+ ;(config as any).get = originalGet
78
+ }
79
+ })
80
+
81
+ test('resolves when a listener throws', async () => {
82
+ const service = new AuthService(makeUserStore(), makePasswordResetStore())
83
+ const originalEmit = emitter.emit.bind(emitter)
84
+ const originalGet = config.get.bind(config)
85
+
86
+ ;(config as any).get = (key: string) => {
87
+ if (key === 'modules.auth') {
88
+ return {
89
+ description: 'test',
90
+ emits: ['Auth:Logout'],
91
+ }
92
+ }
93
+ return originalGet(key)
94
+ }
95
+
96
+ ;(emitter as any).emit = async () => {
97
+ throw new Error('listener boom')
98
+ }
99
+
100
+ try {
101
+ await service.emitSafe('Auth:Logout', null)
102
+ } finally {
103
+ ;(emitter as any).emit = originalEmit
104
+ ;(config as any).get = originalGet
105
+ }
106
+ })
107
+ })
@@ -0,0 +1,40 @@
1
+ import { test } from '@japa/runner'
2
+ import assert from 'node:assert/strict'
3
+ import type { HttpContext } from '@adonisjs/core/http'
4
+ import { respond } from '#modules/api/provider'
5
+ import { prepareError } from '#modules/api/envelope'
6
+
7
+ test.group('ctx.respond error status', () => {
8
+ test('sets HTTP status from ApiErrorBody', async () => {
9
+ let statusCode = 200
10
+ const ctx = {
11
+ response: {
12
+ status(code: number) {
13
+ statusCode = code
14
+ return this
15
+ },
16
+ },
17
+ } as unknown as HttpContext
18
+
19
+ const body = prepareError('E_X', 409)
20
+ const result = await respond.call(ctx, body)
21
+
22
+ assert.equal(statusCode, 409)
23
+ assert.deepEqual(result, { success: false, message: 'E_X', status: 409 })
24
+ })
25
+
26
+ test('defaults to 400 when status is omitted', async () => {
27
+ let statusCode = 200
28
+ const ctx = {
29
+ response: {
30
+ status(code: number) {
31
+ statusCode = code
32
+ return this
33
+ },
34
+ },
35
+ } as unknown as HttpContext
36
+
37
+ await respond.call(ctx, prepareError('E_X'))
38
+ assert.equal(statusCode, 400)
39
+ })
40
+ })
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Auth module contracts.
3
+ * Shared User / UserStore: #modules/contracts
4
+ */
5
+ export type {
6
+ AuthPasswordReset,
7
+ LoginCredentials,
8
+ LoginResult,
9
+ UpdatePasswordInput,
10
+ TokenDuration,
11
+ SessionResult,
12
+ } from './types.ts'
13
+
14
+ export type { PasswordResetStore } from './password_reset_store.ts'
15
+ export type { SessionManager } from './session_manager.ts'
16
+
17
+ /** Re-export shared user port for convenience inside the auth module. */
18
+ export type { AuthMethod, User, RegisterUserInput, UserStore } from '#modules/contracts/index'
@@ -0,0 +1,21 @@
1
+ import type { User } from '#modules/contracts/index'
2
+ import type { AuthPasswordReset, TokenDuration } from './types.ts'
3
+
4
+ /**
5
+ * Host must implement this for password-reset flows.
6
+ */
7
+ export interface PasswordResetStore {
8
+ /** Invalidate existing reset rows for the user, then create a new token. */
9
+ createForUser(userId: number, duration: TokenDuration): Promise<AuthPasswordReset>
10
+
11
+ findByToken(token: string): Promise<AuthPasswordReset | null>
12
+
13
+ deleteForUser(userId: number): Promise<void>
14
+
15
+ /** Rotate/replace the token with a new expiry window. */
16
+ refreshToken(reset: AuthPasswordReset, duration: TokenDuration): Promise<AuthPasswordReset>
17
+
18
+ findUserByReset(reset: AuthPasswordReset): Promise<User>
19
+ }
20
+
21
+ export type { AuthPasswordReset, TokenDuration }
@@ -0,0 +1,19 @@
1
+ import type { User } from '#modules/contracts/index'
2
+
3
+ /**
4
+ * Result of opening a session. Access-token hosts return token + expiry;
5
+ * cookie hosts may return {}.
6
+ */
7
+ export type SessionResult = {
8
+ token?: string
9
+ expiresAt?: Date
10
+ }
11
+
12
+ /**
13
+ * Host HTTP/session (or access-token) bridge.
14
+ * Controllers pass an implementation; AuthService stays HTTP-free.
15
+ */
16
+ export interface SessionManager {
17
+ login(user: User): Promise<SessionResult>
18
+ logout(): Promise<void>
19
+ }
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Auth-only DTOs and input types.
3
+ * Shared User / UserStore live in #modules/contracts.
4
+ */
5
+ import type { User } from '#modules/contracts/index'
6
+ import type { SessionResult } from './session_manager.ts'
7
+
8
+ export type AuthPasswordReset = {
9
+ id: number
10
+ userId: number
11
+ token: string
12
+ isExpired: boolean
13
+ }
14
+
15
+ export type LoginCredentials = {
16
+ email: string
17
+ password: string
18
+ }
19
+
20
+ export type UpdatePasswordInput = {
21
+ token: string
22
+ password: string
23
+ }
24
+
25
+ export type TokenDuration = { hours: number } | { minutes: number }
26
+
27
+ export type { SessionResult }
28
+
29
+ export type LoginResult = {
30
+ user: User
31
+ session: SessionResult
32
+ }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Auth module events. Import this file so the EventsList augmentation loads.
3
+ */
4
+ import type { User } from '#modules/contracts/index'
5
+
6
+ type RequestPasswordReset = {
7
+ user: User
8
+ token: string
9
+ }
10
+
11
+ declare module '@adonisjs/core/types' {
12
+ interface EventsList {
13
+ 'Auth:RegisterUser': User
14
+ 'Auth:CreateNewVerificationToken': User
15
+ 'Auth:ActivateUserAccount': User
16
+ 'Auth:RequestPasswordReset': RequestPasswordReset
17
+ 'Auth:ResetPassword': { user: User }
18
+ 'Auth:Login': { user: User }
19
+ 'Auth:Logout': null
20
+ }
21
+ }
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "auth",
3
+ "description": "Email registration, login, verification, password reset",
4
+ "files": [
5
+ "service.ts",
6
+ "events.ts",
7
+ "options.ts",
8
+ "contracts/**",
9
+ "module.json"
10
+ ],
11
+ "stubs": [
12
+ "stubs/models/user.ts",
13
+ "stubs/models/password_reset.ts",
14
+ "stubs/migrations/*.ts",
15
+ "stubs/controllers/auth_controller.ts",
16
+ "stubs/validators/**/*",
17
+ "stubs/providers/**/*",
18
+ "stubs/start/**/*",
19
+ "stubs/adapters/**/*",
20
+ "stubs/routes/auth.ts"
21
+ ],
22
+ "dependencies": {},
23
+ "registryDependencies": ["api"],
24
+ "peerModels": ["#models/user", "#models/password_reset"],
25
+ "configKeys": ["modules.auth"],
26
+ "env": ["APP_KEY"],
27
+ "events": [
28
+ "Auth:RegisterUser",
29
+ "Auth:CreateNewVerificationToken",
30
+ "Auth:ActivateUserAccount",
31
+ "Auth:RequestPasswordReset",
32
+ "Auth:ResetPassword",
33
+ "Auth:Login",
34
+ "Auth:Logout"
35
+ ],
36
+ "hostFacingExceptions": [
37
+ "INVALID_CREDENTIALS",
38
+ "UNAUTHENTICATED",
39
+ "SESSION_EXPIRED",
40
+ "FORBIDDEN",
41
+ "TOO_MANY_ATTEMPTS",
42
+ "TOO_MANY_REQUESTS"
43
+ ],
44
+ "hostTests": ["tests/integration/lucid_adapters.spec.ts"]
45
+ }
@@ -0,0 +1,23 @@
1
+ import type { TokenDuration } from '#modules/auth/contracts/index'
2
+
3
+ /**
4
+ * Host-editable defaults for AuthService.
5
+ * Do not read env here — pass values in when constructing the service.
6
+ */
7
+ export type AuthOptions = {
8
+ /** Duration passed to encryption.encrypt for email verification tokens. */
9
+ verificationTtl: string
10
+ /** Lifetime of a newly requested password-reset token. */
11
+ passwordResetTtl: TokenDuration
12
+ /** Lifetime after validatePasswordResetToken rotates the token. */
13
+ passwordResetValidateTtl: TokenDuration
14
+ /** Byte length for string.generateRandom in LucidPasswordResetStore. */
15
+ passwordResetTokenBytes: number
16
+ }
17
+
18
+ export const defaultAuthOptions: AuthOptions = {
19
+ verificationTtl: '2 Hours',
20
+ passwordResetTtl: { hours: 2 },
21
+ passwordResetValidateTtl: { minutes: 5 },
22
+ passwordResetTokenBytes: 40,
23
+ }