create-mantiq 0.5.7 → 0.5.8

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,6 +1,6 @@
1
1
  {
2
2
  "name": "create-mantiq",
3
- "version": "0.5.7",
3
+ "version": "0.5.8",
4
4
  "description": "Scaffold a new MantiqJS application",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -1,28 +1,7 @@
1
1
  import { Model } from '@mantiq/database'
2
- import type { Authenticatable } from '@mantiq/auth'
3
- import { applyHasApiTokens } from '@mantiq/auth'
2
+ import { AuthenticatableModel } from '@mantiq/auth'
4
3
 
5
- export class User extends Model implements Authenticatable {
6
- static override table = 'users'
4
+ export class User extends AuthenticatableModel(Model) {
7
5
  static override fillable = ['name', 'email', 'password']
8
- static override guarded = ['id']
9
6
  static override hidden = ['password', 'remember_token']
10
- static override timestamps = true
11
-
12
- getAuthIdentifierName(): string { return 'id' }
13
- getAuthIdentifier(): number { return this.getAttribute('id') as number }
14
- getAuthPasswordName(): string { return 'password' }
15
- getAuthPassword(): string { return this.getAttribute('password') as string }
16
- getRememberToken(): string | null { return (this.getAttribute('remember_token') as string) ?? null }
17
- setRememberToken(token: string | null): void { this.setAttribute('remember_token', token) }
18
- getRememberTokenName(): string { return 'remember_token' }
19
-
20
- // Token methods: createToken(), tokens(), currentAccessToken(), tokenCan(), tokenCant()
21
- declare createToken: (name: string, abilities?: string[], expiresAt?: Date) => Promise<{ accessToken: any; plainTextToken: string }>
22
- declare tokens: () => any
23
- declare currentAccessToken: () => any
24
- declare tokenCan: (ability: string) => boolean
25
- declare tokenCant: (ability: string) => boolean
26
7
  }
27
-
28
- applyHasApiTokens(User)
@@ -1,27 +1,17 @@
1
1
  import { ServiceProvider, config } from '@mantiq/core'
2
- import { DatabaseManager, setupModels, setManager, Migrator } from '@mantiq/database'
3
- import { applyHasApiTokens, PersonalAccessToken } from '@mantiq/auth'
4
- import { User } from '../Models/User.ts'
2
+ import { DatabaseManager, setupModels, setManager } from '@mantiq/database'
5
3
 
6
4
  export class DatabaseServiceProvider extends ServiceProvider {
7
5
  override register(): void {
8
6
  this.app.singleton(DatabaseManager, () => {
9
- const dbConfig = config('database')
10
- const manager = new DatabaseManager(dbConfig)
11
-
7
+ const manager = new DatabaseManager(config('database'))
12
8
  setManager(manager)
13
9
  setupModels(manager)
14
-
15
10
  return manager
16
11
  })
17
12
  }
18
13
 
19
14
  override async boot(): Promise<void> {
20
- // Resolve the manager (triggers creation via the singleton factory)
21
- const manager = this.app.make(DatabaseManager)
22
-
23
- // Set up PersonalAccessToken connection and apply HasApiTokens mixin
24
- PersonalAccessToken.setConnection(manager.connection())
25
- applyHasApiTokens(User)
15
+ this.app.make(DatabaseManager)
26
16
  }
27
17
  }
@@ -1,14 +1,108 @@
1
1
  import { env } from '@mantiq/core'
2
2
 
3
3
  export default {
4
+
5
+ /*
6
+ |--------------------------------------------------------------------------
7
+ | Application Name
8
+ |--------------------------------------------------------------------------
9
+ |
10
+ | This value is the name of your application. It is used when the
11
+ | framework needs to place the application's name in a notification,
12
+ | log entry, or any other location as required by the application.
13
+ |
14
+ */
4
15
  name: env('APP_NAME', 'MantiqJS'),
16
+
17
+ /*
18
+ |--------------------------------------------------------------------------
19
+ | Application Environment
20
+ |--------------------------------------------------------------------------
21
+ |
22
+ | This value determines the "environment" your application is running in.
23
+ | This may influence how you configure various services the application
24
+ | uses. Set this in your ".env" file.
25
+ |
26
+ | Supported: 'production', 'local', 'staging', 'testing'
27
+ |
28
+ */
5
29
  env: env('APP_ENV', 'production'),
30
+
31
+ /*
32
+ |--------------------------------------------------------------------------
33
+ | Application Debug Mode
34
+ |--------------------------------------------------------------------------
35
+ |
36
+ | When your application is in debug mode, detailed error messages with
37
+ | stack traces will be shown on every error. If disabled, a simple
38
+ | generic error page is shown. Also controls the heartbeat debug widget.
39
+ |
40
+ | WARNING: Never enable debug mode in production.
41
+ |
42
+ */
6
43
  debug: env('APP_DEBUG', false),
44
+
45
+ /*
46
+ |--------------------------------------------------------------------------
47
+ | Encryption Key
48
+ |--------------------------------------------------------------------------
49
+ |
50
+ | This key is used by the encryption service and should be set to a
51
+ | random, 32-character string. You should do this before deploying.
52
+ |
53
+ | Generate with: bun mantiq key:generate
54
+ |
55
+ */
7
56
  key: env('APP_KEY', ''),
57
+
58
+ /*
59
+ |--------------------------------------------------------------------------
60
+ | Application URL
61
+ |--------------------------------------------------------------------------
62
+ |
63
+ | This URL is used by the framework to generate URLs, configure CORS
64
+ | origin, and properly redirect. You should set this to the root of
65
+ | your application so that it is used when running CLI commands.
66
+ |
67
+ */
8
68
  url: env('APP_URL', 'http://localhost:3000'),
69
+
70
+ /*
71
+ |--------------------------------------------------------------------------
72
+ | Application Port
73
+ |--------------------------------------------------------------------------
74
+ |
75
+ | The port the HTTP server will listen on.
76
+ |
77
+ */
9
78
  port: Number(env('APP_PORT', '3000')),
79
+
80
+ /*
81
+ |--------------------------------------------------------------------------
82
+ | Base Path
83
+ |--------------------------------------------------------------------------
84
+ |
85
+ | The absolute path to the project root directory. Used for resolving
86
+ | config files, routes, migrations, and other project resources.
87
+ |
88
+ */
10
89
  basePath: import.meta.dir + '/..',
11
90
 
12
- // Global middleware applied to every request
13
- middleware: ['cors', 'encrypt.cookies', 'session', 'csrf'],
91
+ /*
92
+ |--------------------------------------------------------------------------
93
+ | Middleware Groups
94
+ |--------------------------------------------------------------------------
95
+ |
96
+ | Middleware groups are applied automatically based on the route file:
97
+ | routes/web.ts → 'web' group (stateful: sessions, CSRF, cookies)
98
+ | routes/api.ts → 'api' group (stateless: rate-limited, no sessions)
99
+ |
100
+ | Available aliases: cors, encrypt.cookies, session, csrf, throttle,
101
+ | auth, guest, trim, static, heartbeat
102
+ |
103
+ */
104
+ middlewareGroups: {
105
+ web: ['cors', 'encrypt.cookies', 'session', 'csrf'],
106
+ api: ['cors', 'throttle'],
107
+ },
14
108
  }
@@ -1,15 +1,50 @@
1
1
  import { User } from '../app/Models/User.ts'
2
2
 
3
3
  export default {
4
+
5
+ /*
6
+ |--------------------------------------------------------------------------
7
+ | Authentication Defaults
8
+ |--------------------------------------------------------------------------
9
+ |
10
+ | This option controls the default authentication "guard" for your
11
+ | application. You may change this to any of the guards defined below.
12
+ |
13
+ */
4
14
  defaults: {
5
15
  guard: 'web',
6
16
  },
7
17
 
18
+ /*
19
+ |--------------------------------------------------------------------------
20
+ | Authentication Guards
21
+ |--------------------------------------------------------------------------
22
+ |
23
+ | Guards define how users are authenticated for each request. The "web"
24
+ | guard uses session cookies (for browsers and SPAs). The "api" guard
25
+ | uses Sanctum-style bearer tokens (for mobile apps and third-party).
26
+ |
27
+ | Supported drivers: 'session', 'token'
28
+ |
29
+ | Token format: Authorization: Bearer {id}|{plaintext}
30
+ |
31
+ */
8
32
  guards: {
9
33
  web: { driver: 'session', provider: 'users' },
10
34
  api: { driver: 'token', provider: 'users' },
11
35
  },
12
36
 
37
+ /*
38
+ |--------------------------------------------------------------------------
39
+ | User Providers
40
+ |--------------------------------------------------------------------------
41
+ |
42
+ | Providers define how users are retrieved from your database. The
43
+ | "database" driver queries the model specified below.
44
+ |
45
+ | Supported drivers: 'database'
46
+ |
47
+ */
13
48
  providers: {
14
49
  users: { driver: 'database', model: User },
15
50
  },
@@ -0,0 +1,61 @@
1
+ import { env } from '@mantiq/core'
2
+
3
+ export default {
4
+
5
+ /*
6
+ |--------------------------------------------------------------------------
7
+ | Default Cache Store
8
+ |--------------------------------------------------------------------------
9
+ |
10
+ | This option controls the default cache connection that gets used
11
+ | while using this caching library. You may use any of the stores
12
+ | defined in the "stores" object below.
13
+ |
14
+ | Supported: 'memory', 'file', 'redis', 'memcached', 'null'
15
+ |
16
+ */
17
+ default: env('CACHE_STORE', 'memory'),
18
+
19
+ /*
20
+ |--------------------------------------------------------------------------
21
+ | Cache Key Prefix
22
+ |--------------------------------------------------------------------------
23
+ |
24
+ | When utilizing a RAM-based store such as Redis or Memcached, there
25
+ | might be other applications using the same cache. To avoid collisions,
26
+ | you may prefix every cache key.
27
+ |
28
+ */
29
+ prefix: env('CACHE_PREFIX', 'mantiq_cache_'),
30
+
31
+ /*
32
+ |--------------------------------------------------------------------------
33
+ | Cache Stores
34
+ |--------------------------------------------------------------------------
35
+ |
36
+ | Here you may define all of the cache "stores" for your application
37
+ | as well as their drivers. You may even define multiple stores for
38
+ | the same driver to group types of items stored in your caches.
39
+ |
40
+ */
41
+ stores: {
42
+ memory: {},
43
+
44
+ file: {
45
+ path: 'storage/cache',
46
+ },
47
+
48
+ redis: {
49
+ url: env('REDIS_URL', ''),
50
+ host: env('REDIS_HOST', '127.0.0.1'),
51
+ port: Number(env('REDIS_PORT', '6379')),
52
+ password: env('REDIS_PASSWORD', ''),
53
+ db: Number(env('REDIS_CACHE_DB', '1')),
54
+ },
55
+
56
+ memcached: {
57
+ host: env('MEMCACHED_HOST', '127.0.0.1'),
58
+ port: Number(env('MEMCACHED_PORT', '11211')),
59
+ },
60
+ },
61
+ }
@@ -0,0 +1,77 @@
1
+ import { env } from '@mantiq/core'
2
+
3
+ export default {
4
+
5
+ /*
6
+ |--------------------------------------------------------------------------
7
+ | Allowed Origins
8
+ |--------------------------------------------------------------------------
9
+ |
10
+ | The origin(s) that are allowed to make cross-origin requests. Defaults
11
+ | to the APP_URL for same-origin SPA requests. Use '*' for public APIs,
12
+ | or an array for multiple specific origins.
13
+ |
14
+ */
15
+ origin: env('CORS_ORIGIN', env('APP_URL', 'http://localhost:3000')),
16
+
17
+ /*
18
+ |--------------------------------------------------------------------------
19
+ | Allowed HTTP Methods
20
+ |--------------------------------------------------------------------------
21
+ |
22
+ | The HTTP methods that are allowed in CORS requests.
23
+ |
24
+ */
25
+ methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],
26
+
27
+ /*
28
+ |--------------------------------------------------------------------------
29
+ | Allowed Headers
30
+ |--------------------------------------------------------------------------
31
+ |
32
+ | The HTTP headers that the client is allowed to send in CORS requests.
33
+ | X-XSRF-TOKEN is required for CSRF protection in SPA applications.
34
+ |
35
+ */
36
+ allowedHeaders: [
37
+ 'Content-Type',
38
+ 'Authorization',
39
+ 'X-Requested-With',
40
+ 'X-CSRF-TOKEN',
41
+ 'X-XSRF-TOKEN',
42
+ 'X-Mantiq',
43
+ ],
44
+
45
+ /*
46
+ |--------------------------------------------------------------------------
47
+ | Exposed Headers
48
+ |--------------------------------------------------------------------------
49
+ |
50
+ | Headers that the browser is allowed to read from the response.
51
+ |
52
+ */
53
+ exposedHeaders: ['X-Heartbeat'],
54
+
55
+ /*
56
+ |--------------------------------------------------------------------------
57
+ | Credentials
58
+ |--------------------------------------------------------------------------
59
+ |
60
+ | Whether to include credentials (cookies, Authorization header) in
61
+ | cross-origin requests. Must be true for session-based SPA auth.
62
+ | When true, origin cannot be '*'.
63
+ |
64
+ */
65
+ credentials: true,
66
+
67
+ /*
68
+ |--------------------------------------------------------------------------
69
+ | Preflight Max Age
70
+ |--------------------------------------------------------------------------
71
+ |
72
+ | How long (in seconds) the browser should cache the preflight response.
73
+ | Reduces the number of OPTIONS requests for repeated CORS calls.
74
+ |
75
+ */
76
+ maxAge: 7200,
77
+ }
@@ -1,12 +1,68 @@
1
1
  import { env } from '@mantiq/core'
2
2
 
3
3
  export default {
4
+
5
+ /*
6
+ |--------------------------------------------------------------------------
7
+ | Default Database Connection
8
+ |--------------------------------------------------------------------------
9
+ |
10
+ | The database connection used by default for all database operations.
11
+ | This corresponds to one of the connections defined below. You can
12
+ | switch connections at runtime with db().connection('name').
13
+ |
14
+ */
4
15
  default: env('DB_CONNECTION', 'sqlite'),
5
16
 
17
+ /*
18
+ |--------------------------------------------------------------------------
19
+ | Database Connections
20
+ |--------------------------------------------------------------------------
21
+ |
22
+ | Here are each of the database connections set up for your application.
23
+ | SQLite is pre-configured and requires no external services. Add
24
+ | additional connections for PostgreSQL, MySQL, or MongoDB as needed.
25
+ |
26
+ | Supported drivers: 'sqlite', 'postgres', 'mysql', 'mssql', 'mongodb'
27
+ |
28
+ */
6
29
  connections: {
7
30
  sqlite: {
8
31
  driver: 'sqlite' as const,
9
32
  database: env('DB_DATABASE', import.meta.dir + '/../database/database.sqlite'),
10
33
  },
34
+
35
+ // postgres: {
36
+ // driver: 'postgres' as const,
37
+ // host: env('DB_HOST', '127.0.0.1'),
38
+ // port: Number(env('DB_PORT', '5432')),
39
+ // database: env('DB_DATABASE', 'mantiq'),
40
+ // username: env('DB_USERNAME', 'postgres'),
41
+ // password: env('DB_PASSWORD', ''),
42
+ // },
43
+
44
+ // mysql: {
45
+ // driver: 'mysql' as const,
46
+ // host: env('DB_HOST', '127.0.0.1'),
47
+ // port: Number(env('DB_PORT', '3306')),
48
+ // database: env('DB_DATABASE', 'mantiq'),
49
+ // username: env('DB_USERNAME', 'root'),
50
+ // password: env('DB_PASSWORD', ''),
51
+ // },
52
+
53
+ // mssql: {
54
+ // driver: 'mssql' as const,
55
+ // host: env('DB_HOST', '127.0.0.1'),
56
+ // port: Number(env('DB_PORT', '1433')),
57
+ // database: env('DB_DATABASE', 'mantiq'),
58
+ // username: env('DB_USERNAME', 'sa'),
59
+ // password: env('DB_PASSWORD', ''),
60
+ // },
61
+
62
+ // mongodb: {
63
+ // driver: 'mongodb' as const,
64
+ // url: env('MONGODB_URL', 'mongodb://127.0.0.1:27017'),
65
+ // database: env('DB_DATABASE', 'mantiq'),
66
+ // },
11
67
  },
12
68
  }
@@ -1,17 +1,58 @@
1
1
  import { env } from '@mantiq/core'
2
2
 
3
3
  export default {
4
+
5
+ /*
6
+ |--------------------------------------------------------------------------
7
+ | Default Filesystem Disk
8
+ |--------------------------------------------------------------------------
9
+ |
10
+ | The default filesystem disk used by the storage() helper and all
11
+ | file operations. You may use any of the disks defined below.
12
+ |
13
+ */
4
14
  default: env('FILESYSTEM_DISK', 'local'),
5
15
 
16
+ /*
17
+ |--------------------------------------------------------------------------
18
+ | Filesystem Disks
19
+ |--------------------------------------------------------------------------
20
+ |
21
+ | Here you may configure as many filesystem "disks" as you wish. Each
22
+ | disk represents a particular storage driver and location.
23
+ |
24
+ | Supported drivers: 'local', 's3', 'gcs', 'r2', 'azure', 'ftp', 'sftp'
25
+ |
26
+ */
6
27
  disks: {
28
+ // Private storage — not web-accessible (uploads, temp files, exports)
7
29
  local: {
8
30
  driver: 'local' as const,
9
31
  root: import.meta.dir + '/../storage/app',
10
32
  },
33
+
34
+ // Public storage — web-accessible via /storage URL
35
+ // Run: bun mantiq storage:link
11
36
  public: {
12
37
  driver: 'local' as const,
13
38
  root: import.meta.dir + '/../storage/app/public',
14
39
  visibility: 'public' as const,
15
40
  },
41
+
42
+ // s3: {
43
+ // driver: 's3' as const,
44
+ // bucket: env('AWS_BUCKET', ''),
45
+ // region: env('AWS_REGION', 'us-east-1'),
46
+ // accessKeyId: env('AWS_ACCESS_KEY_ID', ''),
47
+ // secretAccessKey: env('AWS_SECRET_ACCESS_KEY', ''),
48
+ // },
49
+
50
+ // r2: {
51
+ // driver: 'r2' as const,
52
+ // accountId: env('CLOUDFLARE_ACCOUNT_ID', ''),
53
+ // bucket: env('R2_BUCKET', ''),
54
+ // accessKeyId: env('R2_ACCESS_KEY_ID', ''),
55
+ // secretAccessKey: env('R2_SECRET_ACCESS_KEY', ''),
56
+ // },
16
57
  },
17
58
  }
@@ -0,0 +1,47 @@
1
+ import { env } from '@mantiq/core'
2
+
3
+ export default {
4
+
5
+ /*
6
+ |--------------------------------------------------------------------------
7
+ | Default Hash Driver
8
+ |--------------------------------------------------------------------------
9
+ |
10
+ | This option controls the default hash driver used for hashing
11
+ | passwords and other values. Bcrypt is the recommended default.
12
+ |
13
+ | Supported: 'bcrypt', 'argon2'
14
+ |
15
+ */
16
+ driver: env('HASH_DRIVER', 'bcrypt'),
17
+
18
+ /*
19
+ |--------------------------------------------------------------------------
20
+ | Bcrypt Options
21
+ |--------------------------------------------------------------------------
22
+ |
23
+ | Here you may configure the round count used by the Bcrypt hashing
24
+ | algorithm. Higher rounds increase security but also increase the
25
+ | time required to hash a value (10-12 recommended).
26
+ |
27
+ */
28
+ bcrypt: {
29
+ rounds: Number(env('BCRYPT_ROUNDS', '10')),
30
+ },
31
+
32
+ /*
33
+ |--------------------------------------------------------------------------
34
+ | Argon2 Options
35
+ |--------------------------------------------------------------------------
36
+ |
37
+ | Here you may configure the memory cost, time cost, and parallelism
38
+ | used by the Argon2 hashing algorithm. These values control the
39
+ | difficulty of producing a valid hash.
40
+ |
41
+ */
42
+ argon2: {
43
+ memory: 65536, // Memory cost in KiB (64 MB)
44
+ time: 4, // Number of iterations
45
+ parallelism: 1, // Degree of parallelism
46
+ },
47
+ }
@@ -1,23 +1,62 @@
1
1
  export default {
2
+
3
+ /*
4
+ |--------------------------------------------------------------------------
5
+ | Heartbeat Enabled
6
+ |--------------------------------------------------------------------------
7
+ |
8
+ | Master switch for the APM & observability system. When disabled, no
9
+ | telemetry is recorded and the dashboard is inaccessible.
10
+ |
11
+ */
2
12
  enabled: true,
3
13
 
14
+ /*
15
+ |--------------------------------------------------------------------------
16
+ | Telemetry Storage
17
+ |--------------------------------------------------------------------------
18
+ |
19
+ | Where Heartbeat stores request traces, queries, exceptions, and other
20
+ | telemetry data. SQLite is zero-config. Retention controls how long
21
+ | entries are kept before automatic pruning.
22
+ |
23
+ */
4
24
  storage: {
5
25
  driver: 'sqlite' as const,
6
26
  path: 'storage/heartbeat/heartbeat.sqlite',
7
- retention: 86400, // 24 hours
8
- pruneInterval: 300, // 5 minutes
27
+ retention: 86400, // Seconds to keep entries (86400 = 24 hours)
28
+ pruneInterval: 300, // Seconds between prune runs (300 = 5 minutes)
9
29
  },
10
30
 
31
+ /*
32
+ |--------------------------------------------------------------------------
33
+ | Queue Configuration
34
+ |--------------------------------------------------------------------------
35
+ |
36
+ | Controls how telemetry data is flushed to storage. Use 'sync' for
37
+ | immediate writes (simpler) or a queue connection for async (faster).
38
+ |
39
+ */
11
40
  queue: {
12
41
  connection: 'sync',
13
42
  queue: 'heartbeat',
14
- batchSize: 50,
15
- flushInterval: 1000,
43
+ batchSize: 50, // Entries to flush per batch
44
+ flushInterval: 1000, // Milliseconds between flushes
16
45
  },
17
46
 
47
+ /*
48
+ |--------------------------------------------------------------------------
49
+ | Watchers
50
+ |--------------------------------------------------------------------------
51
+ |
52
+ | Each watcher monitors a specific aspect of your application. Disable
53
+ | individual watchers to reduce telemetry volume or ignore specific
54
+ | classes/routes via the ignore arrays.
55
+ |
56
+ */
18
57
  watchers: {
19
- request: { enabled: true, slow_threshold: 1000, ignore: [] },
20
- query: { enabled: true, slow_threshold: 100, detect_n_plus_one: true },
58
+ request: { enabled: true, slow_threshold: 1000, ignore: [] }, // ms
59
+ query: { enabled: true, slow_threshold: 100, detect_n_plus_one: true }, // ms
21
60
  exception: { enabled: true, ignore: [] },
22
61
  cache: { enabled: true },
23
62
  job: { enabled: true },
@@ -27,16 +66,44 @@ export default {
27
66
  schedule: { enabled: true },
28
67
  },
29
68
 
69
+ /*
70
+ |--------------------------------------------------------------------------
71
+ | Distributed Tracing
72
+ |--------------------------------------------------------------------------
73
+ |
74
+ | When enabled, Heartbeat generates trace IDs and propagates them across
75
+ | service boundaries via HTTP headers for end-to-end request tracking.
76
+ |
77
+ */
30
78
  tracing: {
31
79
  enabled: true,
32
80
  propagate: true,
33
81
  },
34
82
 
83
+ /*
84
+ |--------------------------------------------------------------------------
85
+ | Sampling
86
+ |--------------------------------------------------------------------------
87
+ |
88
+ | In high-traffic environments, record only a fraction of requests to
89
+ | reduce storage and performance overhead. Errors are always recorded
90
+ | regardless of the sampling rate.
91
+ |
92
+ */
35
93
  sampling: {
36
- rate: 1.0,
94
+ rate: 1.0, // 1.0 = 100%, 0.1 = 10%
37
95
  always_sample_errors: true,
38
96
  },
39
97
 
98
+ /*
99
+ |--------------------------------------------------------------------------
100
+ | Dashboard
101
+ |--------------------------------------------------------------------------
102
+ |
103
+ | The built-in web dashboard for viewing recorded telemetry. Protect it
104
+ | with middleware in production (e.g., ['auth'] to require login).
105
+ |
106
+ */
40
107
  dashboard: {
41
108
  enabled: true,
42
109
  path: '/_heartbeat',