@arkstack/common 0.19.2 → 0.19.3

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/README.md CHANGED
@@ -46,11 +46,11 @@ Provides core application-level utilities for environment variable access, confi
46
46
  Reads a value from `process.env` with automatic type coercion. Booleans (`true`, `false`, `on`, `off`), numbers, `null`, and empty strings are all handled gracefully.
47
47
 
48
48
  ```ts
49
- import { env } from '@arkstack/common';
49
+ import { env } from '@arkstack/common'
50
50
 
51
- const port = env('PORT', 3000); // number
52
- const debug = env('DEBUG', false); // boolean
53
- const name = env('APP_NAME', 'App'); // string
51
+ const port = env('PORT', 3000) // number
52
+ const debug = env('DEBUG', false) // boolean
53
+ const name = env('APP_NAME', 'App') // string
54
54
  ```
55
55
 
56
56
  **Type coercion rules:**
@@ -70,13 +70,13 @@ const name = env('APP_NAME', 'App'); // string
70
70
  Loads and merges all configuration files from the build output's `config/` directory. Supports dot-path key access with full TypeScript inference.
71
71
 
72
72
  ```ts
73
- import { config } from '@arkstack/common';
73
+ import { config } from '@arkstack/common'
74
74
 
75
75
  // Get the full config object
76
- const allConfig = config();
76
+ const allConfig = config()
77
77
 
78
78
  // Access a nested key
79
- const dbHost = config('database.host', 'localhost');
79
+ const dbHost = config('database.host', 'localhost')
80
80
  ```
81
81
 
82
82
  Config files are loaded from the resolved `outputDir()` using `createRequire`. Middleware config files are skipped when running in CLI context.
@@ -88,10 +88,10 @@ Config files are loaded from the resolved `outputDir()` using `createRequire`. M
88
88
  Builds a fully-qualified application URL from `APP_URL` and `PORT` environment variables.
89
89
 
90
90
  ```ts
91
- import { appUrl } from '@arkstack/common';
91
+ import { appUrl } from '@arkstack/common'
92
92
 
93
- appUrl(); // "http://localhost:3000"
94
- appUrl('/api/health'); // "http://localhost:3000/api/health"
93
+ appUrl() // "http://localhost:3000"
94
+ appUrl('/api/health') // "http://localhost:3000/api/health"
95
95
  ```
96
96
 
97
97
  ---
@@ -101,9 +101,9 @@ appUrl('/api/health'); // "http://localhost:3000/api/health"
101
101
  Returns `'dev'` or `'prod'` based on the `NODE_ENV` environment variable. Defaults to `'dev'` for any unrecognised value.
102
102
 
103
103
  ```ts
104
- import { nodeEnv } from '@arkstack/common';
104
+ import { nodeEnv } from '@arkstack/common'
105
105
 
106
- nodeEnv(); // "dev" | "prod"
106
+ nodeEnv() // "dev" | "prod"
107
107
  ```
108
108
 
109
109
  ---
@@ -124,9 +124,9 @@ Resolves the build output directory. In development, defaults to `.arkstack/buil
124
124
  Dynamically imports a file using [Jiti](https://github.com/unjs/jiti), with TypeScript and `tsconfig` path support. Useful for loading user-defined config or plugin files at runtime.
125
125
 
126
126
  ```ts
127
- import { importFile } from '@arkstack/common';
127
+ import { importFile } from '@arkstack/common'
128
128
 
129
- const module = await importFile<{ default: MyConfig }>('./config/app.ts');
129
+ const module = await importFile<{ default: MyConfig }>('./config/app.ts')
130
130
  ```
131
131
 
132
132
  ---
@@ -140,13 +140,13 @@ A structured, chalk-powered console logger with verbosity control, two-column fo
140
140
  #### Basic log levels
141
141
 
142
142
  ```ts
143
- import { Logger } from '@arkstack/common';
143
+ import { Logger } from '@arkstack/common'
144
144
 
145
- Logger.success('Server started');
146
- Logger.info('Listening on port 3000');
147
- Logger.warn('Deprecated option used');
148
- Logger.error('Something went wrong', false); // false = don't exit
149
- Logger.debug('Internal state dump'); // only shown at verbosity >= 3
145
+ Logger.success('Server started')
146
+ Logger.info('Listening on port 3000')
147
+ Logger.warn('Deprecated option used')
148
+ Logger.error('Something went wrong', false) // false = don't exit
149
+ Logger.debug('Internal state dump') // only shown at verbosity >= 3
150
150
  ```
151
151
 
152
152
  Each level uses a distinct icon and colour:
@@ -172,7 +172,7 @@ Logger.configure({
172
172
  verbosity: 3, // enables debug output
173
173
  quiet: true, // suppresses info and success
174
174
  silent: true, // suppresses all output
175
- });
175
+ })
176
176
  ```
177
177
 
178
178
  ---
@@ -182,10 +182,10 @@ Logger.configure({
182
182
  Renders a right-aligned two-column layout padded to the terminal width.
183
183
 
184
184
  ```ts
185
- Logger.twoColumnDetail('Route', 'GET /api/users');
185
+ Logger.twoColumnDetail('Route', 'GET /api/users')
186
186
  // "Route ......................................... GET /api/users"
187
187
 
188
- const row = Logger.twoColumnDetail('Route', 'GET /api/users', false);
188
+ const row = Logger.twoColumnDetail('Route', 'GET /api/users', false)
189
189
  // returns [name, dots, value] without printing
190
190
  ```
191
191
 
@@ -196,7 +196,7 @@ const row = Logger.twoColumnDetail('Route', 'GET /api/users', false);
196
196
  Similar to `twoColumnDetail`, but uses a fixed width with space padding rather than dots. Useful for command help listings.
197
197
 
198
198
  ```ts
199
- Logger.describe('--port', 'Port to listen on', 40);
199
+ Logger.describe('--port', 'Port to listen on', 40)
200
200
  // "--port Port to listen on"
201
201
  ```
202
202
 
@@ -207,8 +207,8 @@ Logger.describe('--port', 'Port to listen on', 40);
207
207
  Like `twoColumnDetail`, but wraps the left column with a coloured background badge based on `status`.
208
208
 
209
209
  ```ts
210
- Logger.split('Database', 'Connected', 'success');
211
- Logger.split('Migration', 'Failed', 'error', true); // exits after logging
210
+ Logger.split('Database', 'Connected', 'success')
211
+ Logger.split('Migration', 'Failed', 'error', true) // exits after logging
212
212
  ```
213
213
 
214
214
  ---
@@ -224,10 +224,10 @@ Logger.parse(
224
224
  ['v1.0.0', 'gray'],
225
225
  ],
226
226
  ' ',
227
- ); // "Arkstack v1.0.0"
227
+ ) // "Arkstack v1.0.0"
228
228
 
229
229
  // Return instead of print
230
- const str = Logger.parse([['Ready', 'green']], ' ', false);
230
+ const str = Logger.parse([['Ready', 'green']], ' ', false)
231
231
  ```
232
232
 
233
233
  ---
@@ -237,14 +237,14 @@ const str = Logger.parse([['Ready', 'green']], ' ', false);
237
237
  A flexible polymorphic logger that accepts either a string + style, or a `LoggerParseSignature` array. Returns the `Logger` class when called with no arguments.
238
238
 
239
239
  ```ts
240
- Logger.log('PORT:3000', 'cyan');
240
+ Logger.log('PORT:3000', 'cyan')
241
241
  Logger.log(
242
242
  [
243
243
  ['PORT', 'bold'],
244
244
  ['3000', 'cyan'],
245
245
  ],
246
246
  ' ',
247
- );
247
+ )
248
248
  ```
249
249
 
250
250
  ---
@@ -254,8 +254,8 @@ Logger.log(
254
254
  Returns a function that applies a chain of chalk styles to any input.
255
255
 
256
256
  ```ts
257
- const highlight = Logger.chalker(['bold', 'green']);
258
- console.log(highlight('Ready'));
257
+ const highlight = Logger.chalker(['bold', 'green'])
258
+ console.log(highlight('Ready'))
259
259
  ```
260
260
 
261
261
  ---
@@ -265,9 +265,9 @@ console.log(highlight('Ready'));
265
265
  Returns a `Console`-compatible object with `log`, `debug`, `warn`, `info`, and `error` methods. Can be used as a drop-in replacement for `globalThis.console`.
266
266
 
267
267
  ```ts
268
- const console = Logger.console();
269
- console.log('hello');
270
- console.warn('watch out');
268
+ const console = Logger.console()
269
+ console.log('hello')
270
+ console.warn('watch out')
271
271
  ```
272
272
 
273
273
  ---
@@ -283,12 +283,12 @@ A static utility class for normalising, serialising, classifying, and logging er
283
283
  The primary method. Converts any thrown value into a consistent `ArkstackErrorPayload` object, handling validation errors, model-not-found errors, and generic errors uniformly.
284
284
 
285
285
  ```ts
286
- import { ErrorHandler } from '@arkstack/common';
286
+ import { ErrorHandler } from '@arkstack/common'
287
287
 
288
288
  try {
289
289
  // ...
290
290
  } catch (err) {
291
- const payload = ErrorHandler.createErrorPayload(err, 'Request failed');
291
+ const payload = ErrorHandler.createErrorPayload(err, 'Request failed')
292
292
  // { status: 'error', code: 422, message: '...', errors: {...} }
293
293
  }
294
294
  ```
@@ -320,7 +320,7 @@ try {
320
320
  Recursively serialises any value — including `Error` instances and circular references — into a plain JSON-safe object. Circular references are replaced with `'[Circular]'`.
321
321
 
322
322
  ```ts
323
- const serialized = ErrorHandler.serializeError(new Error('oops'));
323
+ const serialized = ErrorHandler.serializeError(new Error('oops'))
324
324
  // { name: 'Error', message: 'oops', stack: '...' }
325
325
  ```
326
326
 
@@ -331,8 +331,8 @@ const serialized = ErrorHandler.serializeError(new Error('oops'));
331
331
  Ensures a status code is a valid integer in the range `100–599`. Returns the fallback (default `500`) for anything invalid.
332
332
 
333
333
  ```ts
334
- ErrorHandler.normalizeStatusCode('422'); // 422
335
- ErrorHandler.normalizeStatusCode('xyz'); // 500
334
+ ErrorHandler.normalizeStatusCode('422') // 422
335
+ ErrorHandler.normalizeStatusCode('xyz') // 500
336
336
  ```
337
337
 
338
338
  ---
@@ -348,11 +348,7 @@ Returns a Pino logger instance that writes to `storage/logs/error.log` (created
348
348
  Persists an unhandled error to the error log file, including the serialised error and the associated request context.
349
349
 
350
350
  ```ts
351
- ErrorHandler.logUnhandledError(
352
- err,
353
- { method: 'GET', url: '/api' },
354
- 'Unhandled exception',
355
- );
351
+ ErrorHandler.logUnhandledError(err, { method: 'GET', url: '/api' }, 'Unhandled exception')
356
352
  ```
357
353
 
358
354
  ---
@@ -360,12 +356,12 @@ ErrorHandler.logUnhandledError(
360
356
  #### Classification helpers
361
357
 
362
358
  ```ts
363
- ErrorHandler.isValidationError(err); // true if err.errors is defined
364
- ErrorHandler.isModelNotFoundError(err); // true if err.getModelName is a function
365
- ErrorHandler.shouldLogError(err); // false for validation/model-not-found errors
366
- ErrorHandler.shouldHideStack(); // true if HIDE_ERROR_STACK env is set
367
- ErrorHandler.getPrimaryError(err); // unwraps err.cause if present
368
- ErrorHandler.toErrorShape(value); // casts unknown to ArkstackErrorShape if object
359
+ ErrorHandler.isValidationError(err) // true if err.errors is defined
360
+ ErrorHandler.isModelNotFoundError(err) // true if err.getModelName is a function
361
+ ErrorHandler.shouldLogError(err) // false for validation/model-not-found errors
362
+ ErrorHandler.shouldHideStack() // true if HIDE_ERROR_STACK env is set
363
+ ErrorHandler.getPrimaryError(err) // unwraps err.cause if present
364
+ ErrorHandler.toErrorShape(value) // casts unknown to ArkstackErrorShape if object
369
365
  ```
370
366
 
371
367
  All static methods are also exported as named standalone functions for convenience:
@@ -377,7 +373,7 @@ import {
377
373
  serializeError,
378
374
  logUnhandledError,
379
375
  // ...
380
- } from '@arkstack/common';
376
+ } from '@arkstack/common'
381
377
  ```
382
378
 
383
379
  ---
@@ -393,9 +389,9 @@ A three-level exception hierarchy for structured error throwing.
393
389
  Base class extending `Error`. Sets `.name` to `'Exception'`.
394
390
 
395
391
  ```ts
396
- import { Exception } from '@arkstack/common';
392
+ import { Exception } from '@arkstack/common'
397
393
 
398
- throw new Exception('Something went wrong');
394
+ throw new Exception('Something went wrong')
399
395
  ```
400
396
 
401
397
  ---
@@ -405,10 +401,10 @@ throw new Exception('Something went wrong');
405
401
  Extends `Exception`. Adds `statusCode` (default `400`) and an optional `errors` map for field-level validation errors.
406
402
 
407
403
  ```ts
408
- import { AppException } from '@arkstack/common';
404
+ import { AppException } from '@arkstack/common'
409
405
 
410
- const err = new AppException('Validation failed', 422);
411
- err.errors = { email: ['Email is required'] };
406
+ const err = new AppException('Validation failed', 422)
407
+ err.errors = { email: ['Email is required'] }
412
408
  ```
413
409
 
414
410
  ---
@@ -422,10 +418,10 @@ Extends `AppException`. Intended for HTTP request-level errors. Provides two sta
422
418
  Throws a `RequestException` if the value is `null` or `undefined`. Narrows the type on success.
423
419
 
424
420
  ```ts
425
- import { RequestException } from '@arkstack/common';
421
+ import { RequestException } from '@arkstack/common'
426
422
 
427
- const user = await User.find(id);
428
- RequestException.assertNotEmpty(user, 'User not found', 404);
423
+ const user = await User.find(id)
424
+ RequestException.assertNotEmpty(user, 'User not found', 404)
429
425
  // user is now User (not null | undefined)
430
426
  ```
431
427
 
@@ -434,7 +430,7 @@ RequestException.assertNotEmpty(user, 'User not found', 404);
434
430
  Throws if the condition is truthy.
435
431
 
436
432
  ```ts
437
- RequestException.abortIf(!user.isActive, 'Account is suspended', 403);
433
+ RequestException.abortIf(!user.isActive, 'Account is suspended', 403)
438
434
  ```
439
435
 
440
436
  ---
@@ -450,12 +446,12 @@ A global, named hook registry for extending Arkstack internals without modifying
450
446
  Registers a hook. Multiple calls for the same name are merged.
451
447
 
452
448
  ```ts
453
- import { Hook } from '@arkstack/common';
449
+ import { Hook } from '@arkstack/common'
454
450
 
455
451
  Hook.set('request:handle', {
456
452
  before: (ctx) => console.log('before handler'),
457
453
  after: (ctx) => console.log('after handler'),
458
- });
454
+ })
459
455
  ```
460
456
 
461
457
  ---
@@ -465,8 +461,8 @@ Hook.set('request:handle', {
465
461
  Retrieves the full hook object or a specific positional handler.
466
462
 
467
463
  ```ts
468
- const hook = Hook.get('request:handle'); // IHook | undefined
469
- const before = Hook.get('request:handle', 'before'); // function | undefined
464
+ const hook = Hook.get('request:handle') // IHook | undefined
465
+ const before = Hook.get('request:handle', 'before') // function | undefined
470
466
  ```
471
467
 
472
468
  ---
@@ -476,8 +472,8 @@ const before = Hook.get('request:handle', 'before'); // function | undefined
476
472
  Checks whether a hook (or a specific position within it) exists.
477
473
 
478
474
  ```ts
479
- Hook.has('request:handle'); // true | false
480
- Hook.has('request:handle', 'after'); // true | false
475
+ Hook.has('request:handle') // true | false
476
+ Hook.has('request:handle', 'after') // true | false
481
477
  ```
482
478
 
483
479
  ---
@@ -487,9 +483,9 @@ Hook.has('request:handle', 'after'); // true | false
487
483
  Removes a hook or a single positional handler. If the hook becomes empty after removal, it is deleted entirely. Called with no arguments, it delegates to `Hook.clear()`.
488
484
 
489
485
  ```ts
490
- Hook.unset('request:handle', 'before'); // removes only the 'before' handler
491
- Hook.unset('request:handle'); // removes the entire hook
492
- Hook.unset(); // clears all hooks
486
+ Hook.unset('request:handle', 'before') // removes only the 'before' handler
487
+ Hook.unset('request:handle') // removes the entire hook
488
+ Hook.unset() // clears all hooks
493
489
  ```
494
490
 
495
491
  ---
@@ -499,7 +495,7 @@ Hook.unset(); // clears all hooks
499
495
  Returns all registered hooks as a plain record.
500
496
 
501
497
  ```ts
502
- const hooks = Hook.getAll();
498
+ const hooks = Hook.getAll()
503
499
  // { 'request:handle': { before: fn, after: fn } }
504
500
  ```
505
501
 
@@ -522,9 +518,9 @@ A thin wrapper around [`@arkstack/encryption`](https://www.npmjs.com/package/@ar
522
518
  Encrypts a string. Returns a colon-delimited base64url string: `<iv>:<authTag>:<ciphertext>`.
523
519
 
524
520
  ```ts
525
- import { Encryption } from '@arkstack/common';
521
+ import { Encryption } from '@arkstack/common'
526
522
 
527
- const token = Encryption.encrypt('my-secret-value');
523
+ const token = Encryption.encrypt('my-secret-value')
528
524
  // "abc123:def456:ghi789"
529
525
  ```
530
526
 
@@ -535,7 +531,7 @@ const token = Encryption.encrypt('my-secret-value');
535
531
  Decrypts a payload produced by `encrypt`. Throws if the format is invalid or the key is wrong.
536
532
 
537
533
  ```ts
538
- const original = Encryption.decrypt(token);
534
+ const original = Encryption.decrypt(token)
539
535
  // "my-secret-value"
540
536
  ```
541
537
 
@@ -556,11 +552,11 @@ A `Cipher` bound to the application key, for encrypting many values without re-d
556
552
  #### Key utilities
557
553
 
558
554
  ```ts
559
- Encryption.generateKey(); // random base64url key
560
- await Encryption.generateKeyPair(); // { publicKey, privateKey } ECDH identity
561
- await Encryption.deriveKey(password); // PBKDF2 → { key, salt, iterations }
562
- await Encryption.compareKeys(left, right); // constant time
563
- await Encryption.fingerprint(); // displayable digest of the app key
555
+ Encryption.generateKey() // random base64url key
556
+ await Encryption.generateKeyPair() // { publicKey, privateKey } ECDH identity
557
+ await Encryption.deriveKey(password) // PBKDF2 → { key, salt, iterations }
558
+ await Encryption.compareKeys(left, right) // constant time
559
+ await Encryption.fingerprint() // displayable digest of the app key
564
560
  ```
565
561
 
566
562
  ---
@@ -568,14 +564,14 @@ await Encryption.fingerprint(); // displayable digest of the app key
568
564
  #### End-to-end encryption
569
565
 
570
566
  ```ts
571
- const channel = await Encryption.channel(myPrivateKey, peerPublicKey);
567
+ const channel = await Encryption.channel(myPrivateKey, peerPublicKey)
572
568
 
573
- await channel.decrypt(await channel.encrypt('hey'));
569
+ await channel.decrypt(await channel.encrypt('hey'))
574
570
 
575
- await Encryption.seal('anonymous tip', peerPublicKey);
576
- await Encryption.open(payload, myPrivateKey);
571
+ await Encryption.seal('anonymous tip', peerPublicKey)
572
+ await Encryption.open(payload, myPrivateKey)
577
573
 
578
- await Encryption.safetyNumber(myPublicKey, peerPublicKey);
574
+ await Encryption.safetyNumber(myPublicKey, peerPublicKey)
579
575
  ```
580
576
 
581
577
  The full `@arkstack/encryption` surface — `Cipher`, `Codec`, `EncryptionKey`, `KeyPair`, `Keys`, `SealedBox`, `SecureChannel`, `NodeCipher` — is re-exported from this package.
@@ -601,9 +597,9 @@ Password hashing and OTP generation utilities.
601
597
  Hashes a string using bcrypt with a salt factor of 10.
602
598
 
603
599
  ```ts
604
- import { Hash } from '@arkstack/common';
600
+ import { Hash } from '@arkstack/common'
605
601
 
606
- const hashed = await Hash.make('user-password');
602
+ const hashed = await Hash.make('user-password')
607
603
  ```
608
604
 
609
605
  #### `Hash.verify(value, hashedValue)`
@@ -611,7 +607,7 @@ const hashed = await Hash.make('user-password');
611
607
  Compares a plain-text value against a bcrypt hash.
612
608
 
613
609
  ```ts
614
- const isValid = await Hash.verify('user-password', hashed);
610
+ const isValid = await Hash.verify('user-password', hashed)
615
611
  ```
616
612
 
617
613
  #### `Hash.otp(digits?, label?, period?)`
@@ -619,8 +615,8 @@ const isValid = await Hash.verify('user-password', hashed);
619
615
  Creates a TOTP instance using the `otpauth` library with `SHA1` and a static secret. Suitable for simple time-based OTP flows.
620
616
 
621
617
  ```ts
622
- const totp = Hash.otp(6, 'user@example.com', 60);
623
- const token = totp.generate();
618
+ const totp = Hash.otp(6, 'user@example.com', 60)
619
+ const token = totp.generate()
624
620
  ```
625
621
 
626
622
  #### `Hash.totp(secret, label, issuer?, period?)`
@@ -628,8 +624,8 @@ const token = totp.generate();
628
624
  Creates a TOTP instance from a base32-encoded secret. Intended for user-specific TOTP (e.g. authenticator app integration).
629
625
 
630
626
  ```ts
631
- const totp = Hash.totp(user.totpSecret, user.email);
632
- const isValid = totp.validate({ token: userInput }) !== null;
627
+ const totp = Hash.totp(user.totpSecret, user.email)
628
+ const isValid = totp.validate({ token: userInput }) !== null
633
629
  ```
634
630
 
635
631
  ---
@@ -645,16 +641,16 @@ Utilities for starting an HTTP server with automatic port detection and renderin
645
641
  Detects whether the preferred port is available (using `detect-port`) and boots the server on the first free port. Also initialises key globals: `env`, `config`, `str`, `app`, and `arkctx`.
646
642
 
647
643
  ```ts
648
- import { bootWithDetectedPort } from '@arkstack/common';
644
+ import { bootWithDetectedPort } from '@arkstack/common'
649
645
 
650
646
  await bootWithDetectedPort(
651
647
  async (port) => {
652
- server.listen(port);
653
- Logger.success(`Server:http://localhost:${port}`);
648
+ server.listen(port)
649
+ Logger.success(`Server:http://localhost:${port}`)
654
650
  },
655
651
  3000,
656
652
  appInstance,
657
- );
653
+ )
658
654
  ```
659
655
 
660
656
  **Globals set:**
@@ -674,9 +670,9 @@ await bootWithDetectedPort(
674
670
  Renders an error page using the `~arkstack/common.error` view template. Falls back to a human-readable title from a built-in status code map.
675
671
 
676
672
  ```ts
677
- import { renderError } from '@arkstack/common';
673
+ import { renderError } from '@arkstack/common'
678
674
 
679
- const html = renderError({ code: 404, message: 'Page not found' });
675
+ const html = renderError({ code: 404, message: 'Page not found' })
680
676
  ```
681
677
 
682
678
  **Built-in status titles:** `400`, `401`, `403`, `404`, `500`, `502`, `503`, `504`.
@@ -692,12 +688,12 @@ const html = renderError({ code: 404, message: 'Page not found' });
692
688
  Registers a cleanup callback for `SIGINT`, `SIGTERM`, and `SIGQUIT` signals, ensuring the application shuts down cleanly.
693
689
 
694
690
  ```ts
695
- import { bindGracefulShutdown } from '@arkstack/common';
691
+ import { bindGracefulShutdown } from '@arkstack/common'
696
692
 
697
693
  bindGracefulShutdown(async () => {
698
- await db.disconnect();
699
- Logger.info('Server shut down gracefully');
700
- });
694
+ await db.disconnect()
695
+ Logger.info('Server shut down gracefully')
696
+ })
701
697
  ```
702
698
 
703
699
  ---
@@ -711,9 +707,9 @@ bindGracefulShutdown(async () => {
711
707
  Extends `String.prototype` with four utility methods. Call this once during application bootstrap.
712
708
 
713
709
  ```ts
714
- import { loadPrototypes } from '@arkstack/common';
710
+ import { loadPrototypes } from '@arkstack/common'
715
711
 
716
- loadPrototypes();
712
+ loadPrototypes()
717
713
  ```
718
714
 
719
715
  **Methods added:**
@@ -735,14 +731,14 @@ When `loadPrototypes()` is called and `bootWithDetectedPort()` initialises the r
735
731
 
736
732
  ```ts
737
733
  // Globals (set by bootWithDetectedPort)
738
- globalThis.env; // GlobalEnv — typed env() accessor
739
- globalThis.config; // GlobalConfig — typed config() accessor
734
+ globalThis.env // GlobalEnv — typed env() accessor
735
+ globalThis.config // GlobalConfig — typed config() accessor
740
736
 
741
737
  // String prototype extensions (set by loadPrototypes)
742
- 'my_string'.titleCase();
743
- 'my_string'.camelCase();
744
- 'my_string'.pascalCase();
745
- 'my long string'.truncate(10, '…');
738
+ 'my_string'.titleCase()
739
+ 'my_string'.camelCase()
740
+ 'my_string'.pascalCase()
741
+ 'my long string'.truncate(10, '…')
746
742
  ```
747
743
 
748
744
  ---
@@ -789,12 +785,12 @@ Key exported types from the package:
789
785
  Extracts a safe pagination limit from a query object. Clamps the result between `1` and `50` or the configured default `maxPerPage`, defaulting to `25` or the configured default `perPage`.
790
786
 
791
787
  ```ts
792
- import { perPage } from '@arkstack/common';
788
+ import { perPage } from '@arkstack/common'
793
789
 
794
- const limit = perPage({ limit: 100 }); // 50 (clamped)
795
- const limit2 = perPage({ limit: 100 }, { maxPerPage: 100 }); // 100
796
- const limit3 = perPage({}); // 25 (default)
797
- const limit3 = perPage({}, { perPage: 100 }); // 100
790
+ const limit = perPage({ limit: 100 }) // 50 (clamped)
791
+ const limit2 = perPage({ limit: 100 }, { maxPerPage: 100 }) // 100
792
+ const limit3 = perPage({}) // 25 (default)
793
+ const limit3 = perPage({}, { perPage: 100 }) // 100
798
794
  ```
799
795
 
800
796
  #### `resolvePagination(query, defaults?)`
@@ -802,12 +798,12 @@ const limit3 = perPage({}, { perPage: 100 }); // 100
802
798
  Extracts the current page and a safe pagination limit from a query object. Clamps the resulting `perPage` between `1` and `50` or the configured default `maxPerPage`, defaulting to `25` or the configured default `perPage`.
803
799
 
804
800
  ```ts
805
- import { resolvePagination } from '@arkstack/common';
801
+ import { resolvePagination } from '@arkstack/common'
806
802
 
807
- const limit = resolvePagination({ limit: 100 }); // {perPage: 50, page: 1} (clamped)
808
- const limi2 = resolvePagination({ limit: 100 }, { maxPerPage: 100 }); // {perPage: 100, page: 1}
809
- const limit3 = resolvePagination({}); // {perPage: 50, page: 1} (default)
810
- const limit4 = resolvePagination({}, { perPage: 100, page: 2 }); // {perPage: 100, page: 2}
803
+ const limit = resolvePagination({ limit: 100 }) // {perPage: 50, page: 1} (clamped)
804
+ const limi2 = resolvePagination({ limit: 100 }, { maxPerPage: 100 }) // {perPage: 100, page: 1}
805
+ const limit3 = resolvePagination({}) // {perPage: 50, page: 1} (default)
806
+ const limit4 = resolvePagination({}, { perPage: 100, page: 2 }) // {perPage: 100, page: 2}
811
807
  ```
812
808
 
813
809
  #### `getModel(modelName)`
@@ -815,17 +811,17 @@ const limit4 = resolvePagination({}, { perPage: 100, page: 2 }); // {perPage: 10
815
811
  Dynamically imports an application model by name from the configured models directory (default: `./src/app/models`). Supports augmenting `ModelRegistry` for type-safe lookups.
816
812
 
817
813
  ```ts
818
- import { getModel } from '@arkstack/common';
814
+ import { getModel } from '@arkstack/common'
819
815
 
820
- const User = await getModel('User');
821
- const users = await User.findAll();
816
+ const User = await getModel('User')
817
+ const users = await User.findAll()
822
818
 
823
819
  // With type augmentation:
824
820
  declare module '@arkstack/common' {
825
821
  interface ModelRegistry {
826
- User: typeof User;
822
+ User: typeof User
827
823
  }
828
824
  }
829
825
 
830
- const TypedUser = await getModel('User'); // typeof User
826
+ const TypedUser = await getModel('User') // typeof User
831
827
  ```