···1+/**
2+ * This file is automatically generated.
3+ * DO NOT EDIT manually
4+ */
5+6+/// <reference path="./manifest.d.ts" />
7+import type { InferData, InferVariants } from '@adonisjs/core/types/transformers'
8+import type { InferSharedProps } from '@adonisjs/inertia/types'
9+import type UserTransformer from '#transformers/user_transformer'
10+import type InertiaMiddleware from '#middleware/inertia_middleware'
11+12+export namespace Data {
13+ export type User = InferData<UserTransformer>
14+ export namespace User {
15+ export type Variants = InferVariants<UserTransformer>
16+ }
17+ export type SharedProps = InferSharedProps<InertiaMiddleware>
18+}
+10
.adonisjs/client/manifest.d.ts
···0000000000
···1+/**
2+ * This file is automatically generated.
3+ * DO NOT EDIT manually
4+ */
5+6+/// <reference path="../../adonisrc.ts" />
7+/// <reference path="../../config/atproto_oauth.ts" />
8+/// <reference path="../../config/auth.ts" />
9+/// <reference path="../../config/hash.ts" />
10+/// <reference path="../../config/logger.ts" />
···1+# the name by which the project can be referenced within Serena
2+project_name: "ATlast"
3+4+5+# list of languages for which language servers are started; choose from:
6+# al bash clojure cpp csharp
7+# csharp_omnisharp dart elixir elm erlang
8+# fortran fsharp go groovy haskell
9+# java julia kotlin lua markdown
10+# matlab nix pascal perl php
11+# php_phpactor powershell python python_jedi r
12+# rego ruby ruby_solargraph rust scala
13+# swift terraform toml typescript typescript_vts
14+# vue yaml zig
15+# (This list may be outdated. For the current list, see values of Language enum here:
16+# https://github.com/oraios/serena/blob/main/src/solidlsp/ls_config.py
17+# For some languages, there are alternative language servers, e.g. csharp_omnisharp, ruby_solargraph.)
18+# Note:
19+# - For C, use cpp
20+# - For JavaScript, use typescript
21+# - For Free Pascal/Lazarus, use pascal
22+# Special requirements:
23+# Some languages require additional setup/installations.
24+# See here for details: https://oraios.github.io/serena/01-about/020_programming-languages.html#language-servers
25+# When using multiple languages, the first language server that supports a given file will be used for that file.
26+# The first language is the default language and the respective language server will be used as a fallback.
27+# Note that when using the JetBrains backend, language servers are not used and this list is correspondingly ignored.
28+languages:
29+- vue
30+31+# the encoding used by text files in the project
32+# For a list of possible encodings, see https://docs.python.org/3.11/library/codecs.html#standard-encodings
33+encoding: "utf-8"
34+35+# The language backend to use for this project.
36+# If not set, the global setting from serena_config.yml is used.
37+# Valid values: LSP, JetBrains
38+# Note: the backend is fixed at startup. If a project with a different backend
39+# is activated post-init, an error will be returned.
40+language_backend:
41+42+# whether to use project's .gitignore files to ignore files
43+ignore_all_files_in_gitignore: true
44+45+# list of additional paths to ignore in this project.
46+# Same syntax as gitignore, so you can use * and **.
47+# Note: global ignored_paths from serena_config.yml are also applied additively.
48+ignored_paths: []
49+50+# whether the project is in read-only mode
51+# If set to true, all editing tools will be disabled and attempts to use them will result in an error
52+# Added on 2025-04-18
53+read_only: false
54+55+# list of tool names to exclude. We recommend not excluding any tools, see the readme for more details.
56+# Below is the complete list of tools for convenience.
57+# To make sure you have the latest list of tools, and to view their descriptions,
58+# execute `uv run scripts/print_tool_overview.py`.
59+#
60+# * `activate_project`: Activates a project by name.
61+# * `check_onboarding_performed`: Checks whether project onboarding was already performed.
62+# * `create_text_file`: Creates/overwrites a file in the project directory.
63+# * `delete_lines`: Deletes a range of lines within a file.
64+# * `delete_memory`: Deletes a memory from Serena's project-specific memory store.
65+# * `execute_shell_command`: Executes a shell command.
66+# * `find_referencing_code_snippets`: Finds code snippets in which the symbol at the given location is referenced.
67+# * `find_referencing_symbols`: Finds symbols that reference the symbol at the given location (optionally filtered by type).
68+# * `find_symbol`: Performs a global (or local) search for symbols with/containing a given name/substring (optionally filtered by type).
69+# * `get_current_config`: Prints the current configuration of the agent, including the active and available projects, tools, contexts, and modes.
70+# * `get_symbols_overview`: Gets an overview of the top-level symbols defined in a given file.
71+# * `initial_instructions`: Gets the initial instructions for the current project.
72+# Should only be used in settings where the system prompt cannot be set,
73+# e.g. in clients you have no control over, like Claude Desktop.
74+# * `insert_after_symbol`: Inserts content after the end of the definition of a given symbol.
75+# * `insert_at_line`: Inserts content at a given line in a file.
76+# * `insert_before_symbol`: Inserts content before the beginning of the definition of a given symbol.
77+# * `list_dir`: Lists files and directories in the given directory (optionally with recursion).
78+# * `list_memories`: Lists memories in Serena's project-specific memory store.
79+# * `onboarding`: Performs onboarding (identifying the project structure and essential tasks, e.g. for testing or building).
80+# * `prepare_for_new_conversation`: Provides instructions for preparing for a new conversation (in order to continue with the necessary context).
81+# * `read_file`: Reads a file within the project directory.
82+# * `read_memory`: Reads the memory with the given name from Serena's project-specific memory store.
83+# * `remove_project`: Removes a project from the Serena configuration.
84+# * `replace_lines`: Replaces a range of lines within a file with new content.
85+# * `replace_symbol_body`: Replaces the full definition of a symbol.
86+# * `restart_language_server`: Restarts the language server, may be necessary when edits not through Serena happen.
87+# * `search_for_pattern`: Performs a search for a pattern in the project.
88+# * `summarize_changes`: Provides instructions for summarizing the changes made to the codebase.
89+# * `switch_modes`: Activates modes by providing a list of their names
90+# * `think_about_collected_information`: Thinking tool for pondering the completeness of collected information.
91+# * `think_about_task_adherence`: Thinking tool for determining whether the agent is still on track with the current task.
92+# * `think_about_whether_you_are_done`: Thinking tool for determining whether the task is truly completed.
93+# * `write_memory`: Writes a named memory (for future reference) to Serena's project-specific memory store.
94+excluded_tools: []
95+96+# list of tools to include that would otherwise be disabled (particularly optional tools that are disabled by default)
97+included_optional_tools: []
98+99+# fixed set of tools to use as the base tool set (if non-empty), replacing Serena's default set of tools.
100+# This cannot be combined with non-empty excluded_tools or included_optional_tools.
101+fixed_tools: []
102+103+# list of mode names to that are always to be included in the set of active modes
104+# The full set of modes to be activated is base_modes + default_modes.
105+# If the setting is undefined, the base_modes from the global configuration (serena_config.yml) apply.
106+# Otherwise, this setting overrides the global configuration.
107+# Set this to [] to disable base modes for this project.
108+# Set this to a list of mode names to always include the respective modes for this project.
109+base_modes:
110+111+# list of mode names that are to be activated by default.
112+# The full set of modes to be activated is base_modes + default_modes.
113+# If the setting is undefined, the default_modes from the global configuration (serena_config.yml) apply.
114+# Otherwise, this overrides the setting from the global configuration (serena_config.yml).
115+# This setting can, in turn, be overridden by CLI parameters (--mode).
116+default_modes:
117+118+# initial prompt for the project. It will always be given to the LLM upon activating the project
119+# (contrary to the memories, which are loaded on demand).
120+initial_prompt: ""
121+122+# time budget (seconds) per tool call for the retrieval of additional symbol information
123+# such as docstrings or parameter information.
124+# This overrides the corresponding setting in the global configuration; see the documentation there.
125+# If null or missing, use the setting from the global configuration.
126+symbol_info_budget:
···1+/*
2+|--------------------------------------------------------------------------
3+| JavaScript entrypoint for running ace commands
4+|--------------------------------------------------------------------------
5+|
6+| DO NOT MODIFY THIS FILE AS IT WILL BE OVERRIDDEN DURING THE BUILD
7+| PROCESS.
8+|
9+| See docs.adonisjs.com/guides/typescript-build-process#creating-production-build
10+|
11+| Since, we cannot run TypeScript source code using "node" binary, we need
12+| a JavaScript entrypoint to run ace commands.
13+|
14+| This file registers the "ts-node/esm" hook with the Node.js module system
15+| and then imports the "bin/console.ts" file.
16+|
17+*/
18+19+/**
20+ * Register hook to process TypeScript files using @poppinss/ts-exec
21+ */
22+import '@poppinss/ts-exec'
23+24+/**
25+ * Import ace console entrypoint
26+ */
27+await import('./bin/console.js')
···1+import app from '@adonisjs/core/services/app'
2+import { type HttpContext, ExceptionHandler } from '@adonisjs/core/http'
3+import type { StatusPageRange, StatusPageRenderer } from '@adonisjs/core/types/http'
4+5+export default class HttpExceptionHandler extends ExceptionHandler {
6+ /**
7+ * In debug mode, the exception handler will display verbose errors
8+ * with pretty printed stack traces.
9+ */
10+ protected debug = !app.inProduction
11+12+ /**
13+ * Status pages are used to display a custom HTML pages for certain error
14+ * codes. You might want to enable them in production only, but feel
15+ * free to enable them in development as well.
16+ */
17+ protected renderStatusPages = app.inProduction
18+19+ /**
20+ * Status pages is a collection of error code range and a callback
21+ * to return the HTML contents to send as a response.
22+ */
23+ protected statusPages: Record<StatusPageRange, StatusPageRenderer> = {
24+ '404': (_, { inertia }) => inertia.render('errors/not_found', {}),
25+ '500..599': (_, { inertia }) => inertia.render('errors/server_error', {}),
26+ }
27+28+ /**
29+ * The method is used for handling errors and returning
30+ * response to the client
31+ */
32+ async handle(error: unknown, ctx: HttpContext) {
33+ return super.handle(error, ctx)
34+ }
35+36+ /**
37+ * The method is used to report error to the logging service or
38+ * the a third party error monitoring service.
39+ *
40+ * @note You should not attempt to send a response from this method.
41+ */
42+ async report(error: unknown, ctx: HttpContext) {
43+ return super.report(error, ctx)
44+ }
45+}
+16
app/middleware/auth_middleware.ts
···0000000000000000
···1+import type { HttpContext } from '@adonisjs/core/http'
2+import type { NextFn } from '@adonisjs/core/types/http'
3+import type { Authenticators } from '@adonisjs/auth/types'
4+5+export default class AuthMiddleware {
6+ redirectTo = '/login'
7+8+ async handle(
9+ ctx: HttpContext,
10+ next: NextFn,
11+ options: { guards?: (keyof Authenticators)[] } = {}
12+ ) {
13+ await ctx.auth.authenticateUsing(options.guards, { loginRoute: this.redirectTo })
14+ return next()
15+ }
16+}
+19
app/middleware/container_bindings_middleware.ts
···0000000000000000000
···1+import { Logger } from '@adonisjs/core/logger'
2+import { HttpContext } from '@adonisjs/core/http'
3+import { type NextFn } from '@adonisjs/core/types/http'
4+5+/**
6+ * The container bindings middleware binds classes to their request
7+ * specific value using the container resolver.
8+ *
9+ * - We bind "HttpContext" class to the "ctx" object
10+ * - And bind "Logger" class to the "ctx.logger" object
11+ */
12+export default class ContainerBindingsMiddleware {
13+ handle(ctx: HttpContext, next: NextFn) {
14+ ctx.containerResolver.bindValue(HttpContext, ctx)
15+ ctx.containerResolver.bindValue(Logger, ctx.logger)
16+17+ return next()
18+ }
19+}
+32
app/middleware/guest_middleware.ts
···00000000000000000000000000000000
···1+import type { HttpContext } from '@adonisjs/core/http'
2+import type { NextFn } from '@adonisjs/core/types/http'
3+import type { Authenticators } from '@adonisjs/auth/types'
4+5+/**
6+ * Guest middleware is used to deny access to routes that should
7+ * be accessed by unauthenticated users.
8+ *
9+ * For example, the login page should not be accessible if the user
10+ * is already logged-in
11+ */
12+export default class GuestMiddleware {
13+ /**
14+ * The URL to redirect to when user is logged-in
15+ */
16+ redirectTo = '/'
17+18+ async handle(
19+ ctx: HttpContext,
20+ next: NextFn,
21+ options: { guards?: (keyof Authenticators)[] } = {}
22+ ) {
23+ for (let guard of options.guards || [ctx.auth.defaultGuard]) {
24+ if (await ctx.auth.use(guard).check()) {
25+ ctx.session.reflash()
26+ return ctx.response.redirect(this.redirectTo, true)
27+ }
28+ }
29+30+ return next()
31+ }
32+}
···1+import type { HttpContext } from '@adonisjs/core/http'
2+import type { NextFn } from '@adonisjs/core/types/http'
3+import UserTransformer from '#transformers/user_transformer'
4+import BaseInertiaMiddleware from '@adonisjs/inertia/inertia_middleware'
5+6+export default class InertiaMiddleware extends BaseInertiaMiddleware {
7+ share(ctx: HttpContext) {
8+ /**
9+ * The share method is called everytime an Inertia page is rendered. In
10+ * certain cases, a page may get rendered before the session middleware
11+ * or the auth middleware are executed. For example: During a 404 request.
12+ *
13+ * In that case, we must always assume that HttpContext is not fully hydrated
14+ * with all the properties
15+ */
16+ const { session, auth } = ctx as Partial<HttpContext>
17+18+ /**
19+ * Fetching the first error from the flash messages
20+ */
21+ const errorsBag = session?.flashMessages.get('errorsBag') ?? {}
22+ const error: string | undefined = Object.keys(errorsBag)
23+ .filter((code) => code !== 'E_VALIDATION_ERROR')
24+ .map((code) => errorsBag[code])[0]
25+26+ /**
27+ * Data shared with all Inertia pages. Make sure you are using
28+ * transformers for rich data-types like Models.
29+ */
30+ return {
31+ errors: ctx.inertia.always(this.getValidationErrors(ctx)),
32+ flash: ctx.inertia.always({
33+ error: error,
34+ }),
35+ user: ctx.inertia.always(auth?.user ? UserTransformer.transform(auth.user) : undefined),
36+ }
37+ }
38+39+ async handle(ctx: HttpContext, next: NextFn) {
40+ await this.init(ctx)
41+42+ const output = await next()
43+ this.dispose(ctx)
44+45+ return output
46+ }
47+}
48+49+declare module '@adonisjs/inertia/types' {
50+ type MiddlewareSharedProps = InferSharedProps<InertiaMiddleware>
51+ export interface SharedProps extends MiddlewareSharedProps {}
52+}
+16
app/middleware/silent_auth_middleware.ts
···0000000000000000
···1+import type { HttpContext } from '@adonisjs/core/http'
2+import type { NextFn } from '@adonisjs/core/types/http'
3+4+/**
5+ * Silent auth middleware can be used as a global middleware to silent check
6+ * if the user is logged-in or not.
7+ *
8+ * The request continues as usual, even when the user is not logged-in.
9+ */
10+export default class SilentAuthMiddleware {
11+ async handle(ctx: HttpContext, next: NextFn) {
12+ await ctx.auth.check()
13+14+ return next()
15+ }
16+}
···1+import env from '#start/env'
2+import app from '@adonisjs/core/services/app'
3+import { defineConfig } from '@adonisjs/core/http'
4+5+/**
6+ * The app key is used for encrypting cookies, generating signed URLs,
7+ * and by the "encryption" module.
8+ *
9+ * The encryption module will fail to decrypt data if the key is lost or
10+ * changed. Therefore it is recommended to keep the app key secure.
11+ */
12+export const appKey = env.get('APP_KEY')
13+14+/**
15+ * The configuration settings used by the HTTP server
16+ */
17+export const http = defineConfig({
18+ /**
19+ * Generate a unique request id for each incoming request.
20+ * Useful to correlate logs and debug a request flow.
21+ */
22+ generateRequestId: true,
23+24+ /**
25+ * Allow HTTP method spoofing via the "_method" form/query parameter.
26+ * This lets HTML forms target PUT/PATCH/DELETE routes while still
27+ * submitting with POST.
28+ */
29+ allowMethodSpoofing: false,
30+31+ /**
32+ * Enabling async local storage will let you access HTTP context
33+ * from anywhere inside your application.
34+ */
35+ useAsyncLocalStorage: false,
36+37+ /**
38+ * Manage cookies configuration. The settings for the session id cookie are
39+ * defined inside the "config/session.ts" file.
40+ */
41+ cookie: {
42+ /**
43+ * Restrict the cookie to a specific domain.
44+ * Keep empty to use the current host.
45+ */
46+ domain: '',
47+48+ /**
49+ * Restrict the cookie to a URL path. '/' means all routes.
50+ */
51+ path: '/',
52+53+ /**
54+ * Default lifetime for cookies managed by the HTTP layer.
55+ */
56+ maxAge: '2h',
57+58+ /**
59+ * Prevent JavaScript access to the cookie in the browser.
60+ */
61+ httpOnly: true,
62+63+ /**
64+ * Send cookies only over HTTPS in production.
65+ */
66+ secure: app.inProduction,
67+68+ /**
69+ * Cross-site policy for cookie sending.
70+ */
71+ sameSite: 'lax',
72+ },
73+})
+21
config/atproto_oauth.ts
···000000000000000000000
···1+import { defineConfig } from '@thisismissem/adonisjs-atproto-oauth'
2+import env from '#start/env'
3+import OAuthState from '#models/oauth_state'
4+import OAuthSession from '#models/oauth_session'
5+6+export default defineConfig({
7+ publicUrl: env.get('PUBLIC_URL'),
8+ metadata: {
9+ // If ATPROTO_OAUTH_CLIENT_ID is set, the client metadata will be fetched from that URL:
10+ client_id: env.get('ATPROTO_OAUTH_CLIENT_ID'),
11+ client_name: 'Some App',
12+ redirect_uris: ['/oauth/callback'],
13+ },
14+15+ // For a confidential client:
16+ // jwks: [env.get('ATPROTO_OAUTH_JWT_PRIVATE_KEY')],
17+18+ // Models to store OAuth State and Sessions:
19+ stateStore: OAuthState,
20+ sessionStore: OAuthSession,
21+})
+38
config/auth.ts
···00000000000000000000000000000000000000
···1+import { defineConfig } from '@adonisjs/auth'
2+import { sessionGuard } from '@adonisjs/auth/session'
3+import { atprotoAuthProvider } from '@thisismissem/adonisjs-atproto-oauth/auth/provider'
4+import type { InferAuthenticators, InferAuthEvents, Authenticators } from '@adonisjs/auth/types'
5+6+const authConfig = defineConfig({
7+ /**
8+ * Default guard used when no guard is explicitly specified.
9+ */
10+ default: 'web',
11+12+ guards: {
13+ /**
14+ * Session-based guard for browser authentication.
15+ */
16+ web: sessionGuard({
17+ /**
18+ * Enable persistent login using remember-me tokens.
19+ */
20+ useRememberMeTokens: false,
21+22+ provider: atprotoAuthProvider,
23+ }),
24+ },
25+})
26+27+export default authConfig
28+29+/**
30+ * Inferring types from the configured auth
31+ * guards.
32+ */
33+declare module '@adonisjs/auth/types' {
34+ export interface Authenticators extends InferAuthenticators<typeof authConfig> {}
35+}
36+declare module '@adonisjs/core/types' {
37+ interface EventsList extends InferAuthEvents<Authenticators> {}
38+}
···1+import env from '#start/env'
2+import app from '@adonisjs/core/services/app'
3+import { defineConfig, stores } from '@adonisjs/session'
4+5+const sessionConfig = defineConfig({
6+ /**
7+ * Enable or disable session support globally.
8+ */
9+ enabled: true,
10+11+ /**
12+ * Cookie name storing the session identifier.
13+ */
14+ cookieName: 'adonis-session',
15+16+ /**
17+ * When set to true, the session id cookie will be deleted
18+ * once the user closes the browser.
19+ */
20+ clearWithBrowser: false,
21+22+ /**
23+ * Define how long to keep the session data alive without
24+ * any activity.
25+ */
26+ age: '2h',
27+28+ /**
29+ * Configuration for session cookie and the
30+ * cookie store.
31+ */
32+ cookie: {
33+ /**
34+ * Restrict the cookie to a URL path. '/' means all routes.
35+ */
36+ path: '/',
37+38+ /**
39+ * Prevent JavaScript access to the cookie in the browser.
40+ */
41+ httpOnly: true,
42+43+ /**
44+ * Send cookies only over HTTPS in production.
45+ */
46+ secure: app.inProduction,
47+48+ /**
49+ * Cross-site policy for cookie sending.
50+ */
51+ sameSite: 'lax',
52+ },
53+54+ /**
55+ * The store to use. Make sure to validate the environment
56+ * variable in order to infer the store name without any
57+ * errors.
58+ */
59+ store: env.get('SESSION_DRIVER'),
60+61+ /**
62+ * List of configured stores. Refer documentation to see
63+ * list of available stores and their config.
64+ */
65+ stores: {
66+ /**
67+ * Store session data inside encrypted cookies.
68+ */
69+ cookie: stores.cookie(),
70+71+ /**
72+ * Store session data inside the configured database.
73+ */
74+ database: stores.database(),
75+ },
76+})
77+78+export default sessionConfig
···1+import { defineConfig } from '@adonisjs/shield'
2+3+const shieldConfig = defineConfig({
4+ /**
5+ * Configure CSP policies for your app. Refer documentation
6+ * to learn more.
7+ */
8+ csp: {
9+ /**
10+ * Enable the Content-Security-Policy header.
11+ */
12+ enabled: false,
13+14+ /**
15+ * Per-resource CSP directives.
16+ */
17+ directives: {},
18+19+ /**
20+ * Report violations without blocking resources.
21+ */
22+ reportOnly: false,
23+ },
24+25+ /**
26+ * Configure CSRF protection options. Refer documentation
27+ * to learn more.
28+ */
29+ csrf: {
30+ /**
31+ * Enable CSRF token verification for state-changing requests.
32+ */
33+ enabled: true,
34+35+ /**
36+ * Route patterns to exclude from CSRF checks.
37+ * Useful for external webhooks or API endpoints.
38+ */
39+ exceptRoutes: [],
40+41+ /**
42+ * Expose an encrypted XSRF-TOKEN cookie for frontend HTTP clients.
43+ */
44+ enableXsrfCookie: true,
45+46+ /**
47+ * HTTP methods protected by CSRF validation.
48+ */
49+ methods: ['POST', 'PUT', 'PATCH', 'DELETE'],
50+ },
51+52+ /**
53+ * Control how your website should be embedded inside
54+ * iframes.
55+ */
56+ xFrame: {
57+ /**
58+ * Enable the X-Frame-Options header.
59+ */
60+ enabled: true,
61+62+ /**
63+ * Block all framing attempts. Default value is DENY.
64+ */
65+ action: 'DENY',
66+ },
67+68+ /**
69+ * Force browser to always use HTTPS.
70+ */
71+ hsts: {
72+ /**
73+ * Enable the Strict-Transport-Security header.
74+ */
75+ enabled: true,
76+77+ /**
78+ * HSTS policy duration remembered by browsers.
79+ */
80+ maxAge: '180 days',
81+ },
82+83+ /**
84+ * Disable browsers from sniffing content types and rely only
85+ * on the response content-type header.
86+ */
87+ contentTypeSniffing: {
88+ /**
89+ * Enable X-Content-Type-Options: nosniff.
90+ */
91+ enabled: true,
92+ },
93+})
94+95+export default shieldConfig
+32
config/static.ts
···00000000000000000000000000000000
···1+import { defineConfig } from '@adonisjs/static'
2+3+/**
4+ * Configuration options to tweak the static files middleware.
5+ * The complete set of options are documented on the
6+ * official documentation website.
7+ *
8+ * https://docs.adonisjs.com/guides/basics/static-file-server
9+ */
10+const staticServerConfig = defineConfig({
11+ /**
12+ * Enable or disable static file serving middleware.
13+ */
14+ enabled: true,
15+16+ /**
17+ * Generate ETag headers for client/proxy caching.
18+ */
19+ etag: true,
20+21+ /**
22+ * Include Last-Modified headers for conditional requests.
23+ */
24+ lastModified: true,
25+26+ /**
27+ * Policy for files starting with a dot.
28+ */
29+ dotFiles: 'ignore',
30+})
31+32+export default staticServerConfig
+34
config/vite.ts
···0000000000000000000000000000000000
···1+import { defineConfig } from '@adonisjs/vite'
2+3+const viteBackendConfig = defineConfig({
4+ /**
5+ * The output of vite will be written inside this
6+ * directory. The path should be relative from
7+ * the application root.
8+ */
9+ buildDirectory: 'public/assets',
10+11+ /**
12+ * The path to the manifest file generated by the
13+ * "vite build" command.
14+ */
15+ manifestFile: 'public/assets/.vite/manifest.json',
16+17+ /**
18+ * Feel free to change the value of the "assetsUrl" to
19+ * point to a CDN in production.
20+ */
21+ assetsUrl: '/assets',
22+23+ /**
24+ * HTML attributes added to generated script tags.
25+ */
26+ scriptAttributes: {
27+ /**
28+ * Execute scripts after HTML parsing is complete.
29+ */
30+ defer: true,
31+ },
32+})
33+34+export default viteBackendConfig
···1+import { HttpContext } from '@adonisjs/core/http'
2+import { BaseSerializer } from '@adonisjs/core/transformers'
3+import { type SimplePaginatorMetaKeys } from '@adonisjs/lucid/types/querybuilder'
4+5+/**
6+ * Custom serializer for API responses that ensures consistent JSON structure
7+ * across all API endpoints. Wraps response data in a 'data' property and handles
8+ * pagination metadata for Lucid ORM query results.
9+ */
10+class ApiSerializer extends BaseSerializer<{
11+ Wrap: 'data'
12+ PaginationMetaData: SimplePaginatorMetaKeys
13+}> {
14+ /**
15+ * Wraps all serialized data under this key in the response object.
16+ * Example: { data: [...] } instead of returning raw arrays/objects
17+ */
18+ wrap: 'data' = 'data'
19+20+ /**
21+ * Validates and defines pagination metadata structure for paginated responses.
22+ * Ensures that pagination info from Lucid queries is properly formatted.
23+ *
24+ * @throws Error if metadata doesn't match Lucid's pagination structure
25+ */
26+ definePaginationMetaData(metaData: unknown): SimplePaginatorMetaKeys {
27+ if (!this.isLucidPaginatorMetaData(metaData)) {
28+ throw new Error(
29+ 'Invalid pagination metadata. Expected metadata to contain Lucid pagination keys'
30+ )
31+ }
32+ return metaData
33+ }
34+}
35+36+/**
37+ * Single instance of ApiSerializer used across the application
38+ */
39+const serializer = new ApiSerializer()
40+const serialize = serializer.serialize.bind(serializer) as ApiSerializer['serialize'] & {
41+ withoutWrapping: ApiSerializer['serializeWithoutWrapping']
42+}
43+serialize.withoutWrapping = serializer.serializeWithoutWrapping.bind(serializer)
44+45+/**
46+ * Adds the serialize method to all HttpContext instances.
47+ * Usage in controllers: return ctx.serialize(data)
48+ * This ensures all API responses follow the same structure with data wrapping.
49+ */
50+HttpContext.instanceProperty('serialize', serialize)
51+52+/**
53+ * Module augmentation to add the serialize method to HttpContext.
54+ * This allows controllers to use ctx.serialize() for consistent API responses.
55+ */
56+declare module '@adonisjs/core/http' {
57+ export interface HttpContext {
58+ serialize: typeof serialize
59+ }
60+}
···1+/*
2+|--------------------------------------------------------------------------
3+| Validator file
4+|--------------------------------------------------------------------------
5+|
6+| The validator file is used for configuring global transforms for VineJS.
7+| The transform below converts all VineJS date outputs from JavaScript
8+| Date objects to Luxon DateTime instances, so that validated dates are
9+| ready to use with Lucid models and other parts of the app that expect
10+| Luxon DateTime.
11+|
12+*/
13+14+import { DateTime } from 'luxon'
15+import { VineDate } from '@vinejs/vine'
16+17+declare module '@vinejs/vine/types' {
18+ interface VineGlobalTransforms {
19+ date: DateTime
20+ }
21+}
22+23+VineDate.transform((value) => DateTime.fromJSDate(value))
+37
tests/bootstrap.ts
···0000000000000000000000000000000000000
···1+import { assert } from '@japa/assert'
2+import app from '@adonisjs/core/services/app'
3+import type { Config } from '@japa/runner/types'
4+import { pluginAdonisJS } from '@japa/plugin-adonisjs'
5+import testUtils from '@adonisjs/core/services/test_utils'
6+7+/**
8+ * This file is imported by the "bin/test.ts" entrypoint file
9+ */
10+11+/**
12+ * Configure Japa plugins in the plugins array.
13+ * Learn more - https://japa.dev/docs/runner-config#plugins-optional
14+ */
15+export const plugins: Config['plugins'] = [assert(), pluginAdonisJS(app)]
16+17+/**
18+ * Configure lifecycle function to run before and after all the
19+ * tests.
20+ *
21+ * The setup functions are executed before all the tests
22+ * The teardown functions are executed after all the tests
23+ */
24+export const runnerHooks: Required<Pick<Config, 'setup' | 'teardown'>> = {
25+ setup: [],
26+ teardown: [],
27+}
28+29+/**
30+ * Configure suites by tapping into the test suite instance.
31+ * Learn more - https://japa.dev/docs/test-suites#lifecycle-hooks
32+ */
33+export const configureSuite: Config['configureSuite'] = (suite) => {
34+ if (['browser', 'functional', 'e2e'].includes(suite.name)) {
35+ return suite.setup(() => testUtils.httpServer().start())
36+ }
37+}