@venizia/ignis-docs 0.2.1-0 → 0.2.1-1
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/content/best-practices/architectural-patterns.md +3 -3
- package/content/best-practices/code-style-standards/naming-conventions.md +1 -1
- package/content/best-practices/contribution-workflow.md +2 -2
- package/content/best-practices/error-handling.md +94 -89
- package/content/best-practices/security-guidelines.md +5 -5
- package/content/extensions/components/api-reference.md +22 -21
- package/content/extensions/components/authentication/api.md +64 -28
- package/content/extensions/components/authentication/errors.md +19 -5
- package/content/extensions/components/authentication/index.md +19 -18
- package/content/extensions/components/authentication/usage.md +55 -30
- package/content/extensions/components/authorization/api.md +351 -84
- package/content/extensions/components/authorization/errors.md +51 -17
- package/content/extensions/components/authorization/getting-started.md +227 -0
- package/content/extensions/components/authorization/index.md +24 -16
- package/content/extensions/components/authorization/usage.md +45 -21
- package/content/extensions/components/health-check.md +15 -9
- package/content/extensions/components/index.md +24 -90
- package/content/extensions/components/mail/api.md +105 -54
- package/content/extensions/components/mail/errors.md +12 -10
- package/content/extensions/components/mail/index.md +32 -13
- package/content/extensions/components/mail/usage.md +26 -18
- package/content/extensions/components/request-tracker.md +18 -14
- package/content/extensions/components/socket-io/api.md +377 -882
- package/content/extensions/components/socket-io/errors.md +49 -51
- package/content/extensions/components/socket-io/index.md +72 -88
- package/content/extensions/components/socket-io/usage.md +107 -117
- package/content/extensions/components/static-asset/api.md +83 -31
- package/content/extensions/components/static-asset/errors.md +18 -7
- package/content/extensions/components/static-asset/index.md +18 -11
- package/content/extensions/components/static-asset/usage.md +11 -6
- package/content/extensions/components/template/index.md +3 -3
- package/content/extensions/components/websocket/api.md +58 -27
- package/content/extensions/components/websocket/errors.md +3 -3
- package/content/extensions/components/websocket/index.md +8 -7
- package/content/extensions/components/websocket/usage.md +21 -8
- package/content/extensions/helpers/cron/index.md +8 -7
- package/content/extensions/helpers/crypto/index.md +16 -8
- package/content/extensions/helpers/crypto/reference.md +96 -24
- package/content/extensions/helpers/env/index.md +14 -10
- package/content/extensions/helpers/error/index.md +99 -23
- package/content/extensions/helpers/index.md +61 -47
- package/content/extensions/helpers/inversion/index.md +23 -6
- package/content/extensions/helpers/inversion/reference.md +30 -22
- package/content/extensions/helpers/kafka/admin.md +3 -2
- package/content/extensions/helpers/kafka/compile-binary.md +69 -44
- package/content/extensions/helpers/kafka/consumer.md +24 -21
- package/content/extensions/helpers/kafka/examples.md +22 -234
- package/content/extensions/helpers/kafka/index.md +30 -62
- package/content/extensions/helpers/kafka/producer.md +31 -26
- package/content/extensions/helpers/kafka/schema-registry.md +19 -14
- package/content/extensions/helpers/logger/hf-logger.md +49 -22
- package/content/extensions/helpers/logger/index.md +37 -12
- package/content/extensions/helpers/logger/pino.md +31 -11
- package/content/extensions/helpers/logger/reference.md +243 -52
- package/content/extensions/helpers/network/api.md +65 -30
- package/content/extensions/helpers/network/index.md +32 -11
- package/content/extensions/helpers/queue/index.md +17 -6
- package/content/extensions/helpers/queue/reference.md +52 -25
- package/content/extensions/helpers/redis/index.md +29 -11
- package/content/extensions/helpers/redis/reference.md +85 -28
- package/content/extensions/helpers/secrets/index.md +82 -12
- package/content/extensions/helpers/socket-io/api.md +40 -21
- package/content/extensions/helpers/socket-io/index.md +26 -10
- package/content/extensions/helpers/storage/api.md +42 -24
- package/content/extensions/helpers/storage/index.md +10 -7
- package/content/extensions/helpers/types/index.md +20 -7
- package/content/extensions/helpers/types/reference.md +53 -14
- package/content/extensions/helpers/uid/index.md +166 -10
- package/content/extensions/helpers/websocket/api.md +52 -13
- package/content/extensions/helpers/websocket/index.md +7 -4
- package/content/extensions/helpers/worker-thread/index.md +9 -5
- package/content/extensions/helpers/worker-thread/reference.md +20 -20
- package/content/extensions/index.md +38 -39
- package/content/extensions/src-details/mcp-server.md +96 -548
- package/content/guides/core-concepts/persistent/datasources.md +2 -2
- package/content/guides/core-concepts/persistent/index.md +5 -1
- package/content/guides/core-concepts/persistent/pglite.md +218 -0
- package/content/guides/core-concepts/persistent/postgres-drivers.md +21 -15
- package/content/guides/core-concepts/persistent/search-meilisearch.md +22 -12
- package/content/guides/core-concepts/persistent/search-typesense.md +26 -14
- package/content/guides/core-concepts/persistent/sqlite.md +296 -0
- package/content/guides/core-concepts/persistent/transactions.md +12 -11
- package/content/guides/get-started/5-minute-quickstart.md +59 -206
- package/content/guides/get-started/philosophy.md +135 -670
- package/content/guides/get-started/setup.md +53 -74
- package/content/guides/migrations/redis-helpers-migration.md +4 -3
- package/content/guides/migrations/scoped-rbac-migration.md +5 -5
- package/content/guides/migrations/unified-connectors-migration.md +7 -6
- package/content/guides/tutorials/realtime-chat.md +1 -1
- package/content/references/base/application.md +63 -21
- package/content/references/base/components.md +3 -3
- package/content/references/base/connectors.md +14 -14
- package/content/references/base/controllers.md +12 -12
- package/content/references/base/datasources-reference.md +32 -31
- package/content/references/base/datasources.md +6 -6
- package/content/references/base/dependency-injection.md +12 -11
- package/content/references/base/filter-system/application-usage.md +54 -30
- package/content/references/base/filter-system/array-operators.md +24 -46
- package/content/references/base/filter-system/comparison-operators.md +47 -67
- package/content/references/base/filter-system/default-filter.md +59 -53
- package/content/references/base/filter-system/fields-order-pagination.md +92 -146
- package/content/references/base/filter-system/index.md +25 -13
- package/content/references/base/filter-system/json-filtering.md +45 -184
- package/content/references/base/filter-system/list-operators.md +23 -53
- package/content/references/base/filter-system/logical-operators.md +63 -121
- package/content/references/base/filter-system/null-operators.md +34 -104
- package/content/references/base/filter-system/pattern-matching.md +40 -55
- package/content/references/base/filter-system/quick-reference.md +86 -198
- package/content/references/base/filter-system/range-operators.md +18 -46
- package/content/references/base/filter-system/tips.md +6 -6
- package/content/references/base/filter-system/use-cases.md +33 -15
- package/content/references/base/grpc-controllers.md +53 -17
- package/content/references/base/index.md +5 -3
- package/content/references/base/middlewares.md +11 -10
- package/content/references/base/models-reference.md +17 -17
- package/content/references/base/models.md +4 -3
- package/content/references/base/providers.md +8 -8
- package/content/references/base/repositories/advanced.md +224 -326
- package/content/references/base/repositories/index.md +19 -6
- package/content/references/base/repositories/mixins.md +5 -5
- package/content/references/base/repositories/relations.md +160 -293
- package/content/references/base/repositories/soft-deletable.md +16 -6
- package/content/references/base/secrets.md +17 -13
- package/content/references/base/services.md +6 -4
- package/content/references/configuration/environment-variables.md +31 -23
- package/content/references/configuration/index.md +6 -4
- package/content/references/index.md +1 -1
- package/content/references/utilities/duration.md +85 -0
- package/content/references/utilities/index.md +5 -1
- package/content/references/utilities/jsx-reference.md +11 -11
- package/content/references/utilities/jsx.md +2 -2
- package/content/references/utilities/module.md +78 -25
- package/content/references/utilities/request.md +2 -1
- package/content/references/utilities/retry.md +139 -0
- package/content/references/utilities/schema.md +2 -2
- package/content/references/utilities/statuses-reference.md +4 -4
- package/content/references/utilities/statuses.md +5 -5
- package/dist/mcp-server/index.js +0 -0
- package/dist/mcp-server/tools/github/list-project-files.tool.d.ts +1 -1
- package/dist/mcp-server/tools/github/list-project-files.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/github/list-project-files.tool.js +3 -3
- package/dist/mcp-server/tools/github/search-code.tool.js +1 -1
- package/dist/mcp-server/tools/github/verify-dependencies.tool.js +1 -1
- package/dist/mcp-server/tools/github/view-source-file.tool.js +1 -1
- package/package.json +17 -16
|
@@ -1,52 +1,105 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Module Utility
|
|
3
|
-
description:
|
|
3
|
+
description: Loads an optional peer dependency with a clear install error, and without letting the bundler see the specifier
|
|
4
4
|
difficulty: beginner
|
|
5
|
-
lastUpdated: 2026-07-
|
|
5
|
+
lastUpdated: 2026-07-27
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# Module Utility
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
`ModuleUtility` loads an optional peer dependency. IGNIS components depend on packages the framework does not bundle - `nodemailer` for mail, `node-vault` for secrets. Loading one through `ModuleUtility` buys you two things: a missing package throws an install instruction instead of a cryptic crash, and the specifier stays invisible to `Bun.build`.
|
|
11
11
|
|
|
12
12
|
## In one example
|
|
13
13
|
|
|
14
|
+
This is how the secrets helper reaches `node-vault`:
|
|
15
|
+
|
|
14
16
|
```typescript
|
|
15
|
-
import {
|
|
17
|
+
import { ModuleUtility } from '@venizia/ignis-helpers';
|
|
18
|
+
|
|
19
|
+
// Fails fast with a clear install instruction if the peer is absent.
|
|
20
|
+
ModuleUtility.assertInstalled({
|
|
21
|
+
scope: 'HashiCorpVaultHelper',
|
|
22
|
+
modules: ['node-vault'],
|
|
23
|
+
allowRegistered: true,
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
// The specifier is a parameter, so Bun.build never sees it.
|
|
27
|
+
const vault = await ModuleUtility.load({ module: 'node-vault' });
|
|
28
|
+
const client = vault.default({ endpoint, apiVersion: 'v1' });
|
|
29
|
+
```
|
|
16
30
|
|
|
17
|
-
|
|
31
|
+
## Methods
|
|
18
32
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
33
|
+
| Method | Signature | What it does |
|
|
34
|
+
|--------|-----------|---------------|
|
|
35
|
+
| `load` | `load<T>(opts: { module: string }): Promise<T>` | Imports the module. Use this everywhere except a constructor |
|
|
36
|
+
| `loadSync` | `loadSync<T>(opts: { module: string }): T` | Same, without awaiting - for a constructor or any path that cannot be async |
|
|
37
|
+
| `assertInstalled` | `assertInstalled(opts: { modules: Array<string>; scope?: string; allowRegistered?: boolean }): void` | Presence check only. Resolves each module in order and throws on the first miss, without executing any of them |
|
|
38
|
+
| `register` | `register(opts: { modules: Record<string, AnyType> }): void` | Hands the framework peers the application already holds. `load` and `loadSync` serve a registered specifier from memory, with no filesystem lookup |
|
|
23
39
|
|
|
24
|
-
|
|
25
|
-
// ... register routes
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
```
|
|
40
|
+
### `allowRegistered`
|
|
29
41
|
|
|
30
|
-
|
|
42
|
+
`assertInstalled` reports what is on disk. Set `allowRegistered` to count a `register` entry as present too.
|
|
31
43
|
|
|
32
|
-
|
|
33
|
-
|----------|-----------|---------------|
|
|
34
|
-
| `validateModule` | `validateModule(opts: { scope?: string; modules: Array<string> }): Promise<void>` | Resolves each module in `modules`, in order, via `require.resolve`. Throws an `ApplicationError` on the first one that cannot be found. |
|
|
44
|
+
Set it only where `load` or `loadSync` is what finally loads the module. A caller that resolves the specifier itself cannot see the registry - `pino.transport()` resolves inside a worker thread, and the gRPC adapter uses its own `createRequire`. For those, counting a registration as installed would replace a precise error with an opaque one.
|
|
35
45
|
|
|
36
46
|
## Error message format
|
|
37
47
|
|
|
38
48
|
| `scope` | Message |
|
|
39
49
|
|---------|---------|
|
|
40
|
-
| provided | `[
|
|
41
|
-
| omitted | `[
|
|
50
|
+
| provided | `[ModuleUtility.<method>] <module> is required for <scope>. Please install '<module>'` |
|
|
51
|
+
| omitted | `[ModuleUtility.<method>] <module> is required. Please install '<module>'` |
|
|
52
|
+
|
|
53
|
+
## Why not a plain import
|
|
54
|
+
|
|
55
|
+
`Bun.build` resolves a literal specifier at bundle time. A literal `require('mailgun.js')` anywhere reachable from an entry point forces every consumer who compiles a binary to install that peer or list it in `external` - even a consumer who never touches mail.
|
|
56
|
+
|
|
57
|
+
A `const` does not help. `minify: { syntax: true }` folds `const s = 'mailgun.js'; import(s)` straight back into a resolvable literal.
|
|
58
|
+
|
|
59
|
+
Only a specifier that crosses a function boundary survives as a runtime import. That is the whole reason `ModuleUtility` takes the module name as a parameter.
|
|
60
|
+
|
|
61
|
+
## Compiled binaries
|
|
62
|
+
|
|
63
|
+
Runtime resolution needs a `node_modules` to resolve against. A `bun build --compile` binary usually runs without one - the deployment ships the executable and nothing else - so a peer the application genuinely installed is still unreachable at runtime, and the component that needs it dies at boot with the install hint.
|
|
64
|
+
|
|
65
|
+
**Check the component's options first.** Every component that reaches a peer this way takes it through its own options:
|
|
66
|
+
|
|
67
|
+
| Component | Option | You pass |
|
|
68
|
+
|---|---|---|
|
|
69
|
+
| Mail transports | `module` | the `nodemailer` or `mailgun.js` module |
|
|
70
|
+
| gRPC component | `module` | `{ connect, protocol }` from `@connectrpc/connect` |
|
|
71
|
+
| `HashiCorpVaultHelper` | `client` | an already-built vault client |
|
|
72
|
+
| `DotenvVaultHelper` | `decode` | your own decode function |
|
|
73
|
+
|
|
74
|
+
Prefer the option. It is typed, it lands where it is used, and no ordering can defeat it.
|
|
75
|
+
|
|
76
|
+
`register` is the fallback for a peer the framework reaches with no options seam in between. The static import is what pulls the library into the binary; `register` is what lets the framework find it there:
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
import { ModuleUtility } from '@venizia/ignis-helpers';
|
|
80
|
+
import * as vault from 'node-vault';
|
|
81
|
+
|
|
82
|
+
// At the entrypoint, before anything that reaches the peer runs.
|
|
83
|
+
ModuleUtility.register({ modules: { 'node-vault': vault } });
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
The registry is keyed by specifier and the value is returned as-is: what you register under `node-vault` is exactly what `load({ module: 'node-vault' })` hands the caller. `import * as` gives the right shape for a CommonJS peer.
|
|
87
|
+
|
|
88
|
+
Register before the consumer runs. Nothing enforces that ordering, which is the reason to prefer an options seam wherever one exists.
|
|
89
|
+
|
|
90
|
+
`register` cannot help a consumer that resolves the specifier itself. A `pino` transport target loads inside a worker thread the registry never reaches, so `pino-pretty` and `pino-roll` must be installed on disk.
|
|
91
|
+
|
|
92
|
+
Registration is only worth it for the compiled-binary case. An application running from source resolves its peers from `node_modules` already.
|
|
42
93
|
|
|
43
94
|
## Notes
|
|
44
95
|
|
|
45
|
-
- **Resolution is rooted at `process.cwd()/node_modules`** via Node's `createRequire`, so
|
|
46
|
-
-
|
|
47
|
-
- **`
|
|
48
|
-
- **Call it once, at startup
|
|
49
|
-
-
|
|
96
|
+
- **Resolution is rooted at `process.cwd()/node_modules`** via Node's `createRequire`, so peers installed in the consuming application resolve even though this utility ships inside `packages/helpers/dist/`.
|
|
97
|
+
- **`assertInstalled` stops at the first miss.** Later entries are never checked.
|
|
98
|
+
- **`assertInstalled` never executes the module** - it only locates the file. Reach for it when you want to fail at startup rather than on first use.
|
|
99
|
+
- **Call it once, at startup, not per request.** Place it in an initialisation hook (`configure`, `binding`, `boot`).
|
|
100
|
+
- **`register` wins over the filesystem.** `load` and `loadSync` check the registry first, so a registered peer is never resolved. `assertInstalled` ignores the registry unless you set `allowRegistered`.
|
|
101
|
+
- **`register` never logs.** It runs at the entrypoint of a compiled binary, which is exactly where no logger provider exists yet.
|
|
102
|
+
- **Recommended pattern:** declare the dependency in `peerDependenciesMeta` with `optional: true`, then load it through `ModuleUtility` and pass the feature or class name as `scope` so the thrown message pinpoints the caller.
|
|
50
103
|
|
|
51
104
|
## See also
|
|
52
105
|
|
|
@@ -71,7 +71,8 @@ export class FileController extends BaseRestController {
|
|
|
71
71
|
- **`storage` defaults to `'memory'`**; `uploadDir` defaults to `'./uploads'` and is created recursively if it does not exist.
|
|
72
72
|
- **`sanitizeFilename` is applied automatically** inside `createContentDispositionHeader` - callers do not need to sanitize twice. It also removes leading dots, collapses repeated dots, and strips `..` sequences to block directory traversal and hidden-file tricks.
|
|
73
73
|
- **`createContentDispositionHeader` always emits both forms** (`filename="..."; filename*=UTF-8''...`) for maximum browser compatibility - older browsers read the ASCII fallback, modern ones read the UTF-8 form.
|
|
74
|
-
- **`IRequestedRemark`** is a separately exported interface for describing a request: `{ id: string; url: string; method: string; [extra: string | symbol]: any }`.
|
|
74
|
+
- **`IRequestedRemark`** is a separately exported interface for describing a request: `{ id: string; url: string; method: string; [extra: string | symbol]: any }`.
|
|
75
|
+
- It is not consumed internally by `parseMultipartBody` or any other function on this page - it is a general-purpose shape for application code that needs to tag a request with an id, URL, method, and arbitrary extra fields.
|
|
75
76
|
|
|
76
77
|
## See also
|
|
77
78
|
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Retry Utility
|
|
3
|
+
description: Backoff-driven retry helpers - executeWithRetry retries on errors, executeWithRetryUntil retries until a result looks right
|
|
4
|
+
difficulty: intermediate
|
|
5
|
+
lastUpdated: 2026-07-18
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Retry Utility
|
|
9
|
+
|
|
10
|
+
Two retry helpers. One retries when a call **throws**. The other retries when a call **succeeds but the result is not what you want yet**.
|
|
11
|
+
|
|
12
|
+
## In one example
|
|
13
|
+
|
|
14
|
+
```typescript
|
|
15
|
+
import { executeWithRetry, executeWithRetryUntil } from '@venizia/ignis-helpers';
|
|
16
|
+
|
|
17
|
+
// Retries because the call THREW
|
|
18
|
+
const data = await executeWithRetry({
|
|
19
|
+
operation: 'fetch-remote-config',
|
|
20
|
+
execution: () => fetchConfig(),
|
|
21
|
+
maxAttempts: 5,
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
// Retries because the result is not YET what we want
|
|
25
|
+
const order = await executeWithRetryUntil({
|
|
26
|
+
operation: 'wait-for-paid-order',
|
|
27
|
+
execution: () => orderRepository.findById({ id: orderId }),
|
|
28
|
+
until: result => result?.status === 'PAID',
|
|
29
|
+
maxAttempts: 5,
|
|
30
|
+
});
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Which one do I need?
|
|
34
|
+
|
|
35
|
+
| Function | Retries when | Typical use |
|
|
36
|
+
|---|---|---|
|
|
37
|
+
| `executeWithRetry` | `execution` throws | Flaky network calls, connection setup |
|
|
38
|
+
| `executeWithRetryUntil` | `until(result)` returns `false` | Polling until data is fresh or a job is done. Powers the repository [`retry` option](/references/base/repositories/advanced#read-retry-replica-lag). |
|
|
39
|
+
|
|
40
|
+
Both share the same backoff engine and the same habit: on exhaustion, log one `logger.warn` and hand back the LAST outcome.
|
|
41
|
+
|
|
42
|
+
## `executeWithRetry`
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
const executeWithRetry: <T>(opts: {
|
|
46
|
+
operation: string;
|
|
47
|
+
execution: (context: { attempt: number; signal?: AbortSignal }) => ValueOrPromise<T>;
|
|
48
|
+
maxAttempts?: number; // default 3
|
|
49
|
+
maxTotalMs?: number; // total budget across attempts and sleeps
|
|
50
|
+
perAttemptTimeoutMs?: number; // race each attempt against a timeout
|
|
51
|
+
backoff?: IRetryBackoffOptions;
|
|
52
|
+
shouldRetry?: (context: IRetryContext) => boolean;
|
|
53
|
+
onRetry?: (context: IRetryContext & { nextDelayMs: number }) => ValueOrPromise<void>;
|
|
54
|
+
signal?: AbortSignal;
|
|
55
|
+
logger?: ILogger;
|
|
56
|
+
}) => Promise<T>;
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
The rules:
|
|
60
|
+
|
|
61
|
+
- Every thrown error retries, unless `shouldRetry` returns `false` - then it rethrows immediately. Use this for permanent errors like a `400`.
|
|
62
|
+
- Out of attempts or budget? The LAST error is thrown.
|
|
63
|
+
- `signal` aborts between attempts and during sleeps. It is also passed to `execution` - a running promise cannot be cancelled from outside, so honor it inside if you can.
|
|
64
|
+
|
|
65
|
+
## `executeWithRetryUntil`
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
const executeWithRetryUntil: <T>(opts: {
|
|
69
|
+
operation: string;
|
|
70
|
+
execution: (context: { attempt: number; signal?: AbortSignal }) => ValueOrPromise<T>;
|
|
71
|
+
until: (result: T) => boolean; // return true to stop: "the result is good"
|
|
72
|
+
maxAttempts?: number; // default 3
|
|
73
|
+
maxTotalMs?: number; // stop starting NEW attempts after this much time
|
|
74
|
+
backoff?: IRetryBackoffOptions;
|
|
75
|
+
signal?: AbortSignal;
|
|
76
|
+
logger?: ILogger;
|
|
77
|
+
}) => Promise<T>;
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
The rules:
|
|
81
|
+
|
|
82
|
+
- A thrown error is never retried. It rethrows immediately. Only a successful call with a "not yet" result retries.
|
|
83
|
+
- Out of attempts or budget? The LAST result is returned as-is. No error.
|
|
84
|
+
- `maxTotalMs` never cuts a running read short. It only stops NEW attempts from starting. Zero or negative just means "no retries" - one call still runs.
|
|
85
|
+
- `maxAttempts` below `1` throws before anything runs.
|
|
86
|
+
- An aborted `signal` rejects the call - a cancelled caller does not want a stale result.
|
|
87
|
+
|
|
88
|
+
Use it for any polling: waiting for a job status to flip, for a downstream service to come up, for a replica to catch up.
|
|
89
|
+
|
|
90
|
+
## Backoff and jitter
|
|
91
|
+
|
|
92
|
+
Both helpers wait between attempts using `IRetryBackoffOptions`:
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
interface IRetryBackoffOptions {
|
|
96
|
+
strategy?: 'fixed' | 'linear' | 'exponential' | 'schedule'; // default exponential
|
|
97
|
+
initialDelayMs?: number; // default 250
|
|
98
|
+
multiplier?: number; // exponential growth factor, default 2
|
|
99
|
+
maxDelayMs?: number; // cap before jitter, default 30000
|
|
100
|
+
scheduleMs?: readonly number[]; // required for 'schedule'
|
|
101
|
+
jitter?: 'none' | 'full' | 'equal'; // default full
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
| Strategy | Delay for attempt N |
|
|
106
|
+
|---|---|
|
|
107
|
+
| `fixed` | `initialDelayMs` |
|
|
108
|
+
| `linear` | `initialDelayMs * N` |
|
|
109
|
+
| `exponential` | `initialDelayMs * multiplier ** (N - 1)` |
|
|
110
|
+
| `schedule` | `scheduleMs[N - 1]`, last entry repeats |
|
|
111
|
+
|
|
112
|
+
| Jitter | Effect |
|
|
113
|
+
|---|---|
|
|
114
|
+
| `none` | delay used as-is |
|
|
115
|
+
| `full` | random in `[0, delay)` |
|
|
116
|
+
| `equal` | random in `[delay/2, delay)` |
|
|
117
|
+
|
|
118
|
+
Prefer named constants? `RetryBackoffStrategies.EXPONENTIAL`, `RetryJitterModes.EQUAL`, etc.
|
|
119
|
+
|
|
120
|
+
> [!NOTE]
|
|
121
|
+
> These defaults (250ms, 30s cap) suit network retries. The repository `retry` option uses its own tighter defaults (50ms up to 500ms) - see [Read Retry](/references/base/repositories/advanced#read-retry-replica-lag).
|
|
122
|
+
|
|
123
|
+
## Other exports
|
|
124
|
+
|
|
125
|
+
| Export | What it does |
|
|
126
|
+
|---|---|
|
|
127
|
+
| `runWithTimeout({ operation, timeoutMs, execution })` | Races `execution` against a timeout. Omitted or `<= 0` means no timeout. |
|
|
128
|
+
| `isRetryTimeoutError(error)` | `true` when the error is a timeout from `runWithTimeout`/`executeWithRetry`. |
|
|
129
|
+
| `computeBackoffDelayMs({ attempt, backoff })` | The delay both helpers use, exposed for your own loops. |
|
|
130
|
+
|
|
131
|
+
## See also
|
|
132
|
+
|
|
133
|
+
- [Read Retry](/references/base/repositories/advanced#read-retry-replica-lag) - the repository `retry` option built on `executeWithRetryUntil`
|
|
134
|
+
- [Repository Read Retry changelog](/changelogs/2026-07-18-repository-read-retry) - what shipped and why
|
|
135
|
+
- [Utilities Overview](/references/utilities/)
|
|
136
|
+
|
|
137
|
+
**Files:**
|
|
138
|
+
|
|
139
|
+
- [`packages/helpers/src/utilities/retry.utility.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/helpers/src/utilities/retry.utility.ts)
|
|
@@ -64,5 +64,5 @@ this.defineRoute({
|
|
|
64
64
|
|
|
65
65
|
**Files:**
|
|
66
66
|
|
|
67
|
-
- [`packages/core/src/utilities/schema.utility.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/utilities/schema.utility.ts)
|
|
68
|
-
- [`packages/core/src/base/models/common/types.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/base/models/common/types.ts)
|
|
67
|
+
- [`packages/core-server/src/utilities/schema.utility.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/utilities/schema.utility.ts)
|
|
68
|
+
- [`packages/core-server/src/base/models/common/types.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/base/models/common/types.ts)
|
|
@@ -11,14 +11,14 @@ Exhaustive reference for `Statuses`, its specialized subclasses, and the `Bindin
|
|
|
11
11
|
|
|
12
12
|
**Files:**
|
|
13
13
|
|
|
14
|
-
- [`packages/core/src/common/statuses.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/common/statuses.ts)
|
|
15
|
-
- [`packages/core/src/common/bindings.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/common/bindings.ts)
|
|
14
|
+
- [`packages/core-server/src/common/statuses.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/common/statuses.ts)
|
|
15
|
+
- [`packages/core-server/src/common/bindings.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/common/bindings.ts)
|
|
16
16
|
|
|
17
17
|
## `Statuses`
|
|
18
18
|
|
|
19
19
|
A static class of `'NNN_NAME'` status code constants, grouped by an HTTP-inspired numeric prefix, plus `Set` groupings and validator methods.
|
|
20
20
|
|
|
21
|
-
`Source ->` [`packages/core/src/common/statuses.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/common/statuses.ts)
|
|
21
|
+
`Source ->` [`packages/core-server/src/common/statuses.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/common/statuses.ts)
|
|
22
22
|
|
|
23
23
|
### Status code scheme
|
|
24
24
|
|
|
@@ -227,7 +227,7 @@ export class UserTypes {
|
|
|
227
227
|
|
|
228
228
|
Organizes dependency-injection binding keys by artifact type. Distinct from `Statuses` - not a lifecycle catalog.
|
|
229
229
|
|
|
230
|
-
`Source ->` [`packages/core/src/common/bindings.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/common/bindings.ts)
|
|
230
|
+
`Source ->` [`packages/core-server/src/common/bindings.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/common/bindings.ts)
|
|
231
231
|
|
|
232
232
|
### `BindingNamespaces`
|
|
233
233
|
|
|
@@ -7,7 +7,7 @@ lastUpdated: 2026-07-16
|
|
|
7
7
|
|
|
8
8
|
# Statuses
|
|
9
9
|
|
|
10
|
-
`Statuses` is a static catalog of lifecycle status codes - a shared vocabulary
|
|
10
|
+
`Statuses` is a static catalog of lifecycle status codes - a shared vocabulary. Every entity in an app uses the same strings for "draft", "active", "failed", and so on.
|
|
11
11
|
|
|
12
12
|
## In one example
|
|
13
13
|
|
|
@@ -30,8 +30,8 @@ if (Statuses.isActive(job.status)) {
|
|
|
30
30
|
|
|
31
31
|
- **HTTP-inspired numeric prefix.** Each status is a `'NNN_NAME'` string (e.g. `'302_SUCCESS'`). The leading digit groups statuses into six phases.
|
|
32
32
|
- **Group sets for classification.** Every phase has a matching `*_SCHEME_SET` (a `Set<string>`) plus a validator method (`isActive`, `isFailed`, etc.) that just checks set membership.
|
|
33
|
-
- **Specialized classes narrow the catalog.** `MigrationStatuses`, `CommonStatuses`, `UserStatuses`, and `RoleStatuses` each expose a small, named subset of `Statuses` values for a specific use case
|
|
34
|
-
- **A separate constant catalog for DI.** `BindingNamespaces` and `CoreBindings` (in the same file area) are unrelated to entity lifecycle
|
|
33
|
+
- **Specialized classes narrow the catalog.** `MigrationStatuses`, `CommonStatuses`, `UserStatuses`, and `RoleStatuses` each expose a small, named subset of `Statuses` values for a specific use case. None of them invent new status strings.
|
|
34
|
+
- **A separate constant catalog for DI.** `BindingNamespaces` and `CoreBindings` (in the same file area) are unrelated to entity lifecycle. They're the namespace/key strings the container uses for dependency injection.
|
|
35
35
|
|
|
36
36
|
**The six phases**
|
|
37
37
|
|
|
@@ -118,5 +118,5 @@ await userRepository.create({
|
|
|
118
118
|
|
|
119
119
|
**Files:**
|
|
120
120
|
|
|
121
|
-
- [`packages/core/src/common/statuses.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/common/statuses.ts)
|
|
122
|
-
- [`packages/core/src/common/bindings.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/common/bindings.ts)
|
|
121
|
+
- [`packages/core-server/src/common/statuses.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/common/statuses.ts)
|
|
122
|
+
- [`packages/core-server/src/common/bindings.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/common/bindings.ts)
|
package/dist/mcp-server/index.js
CHANGED
|
File without changes
|
|
@@ -11,7 +11,7 @@ declare const OutputSchema: z.ZodObject<{
|
|
|
11
11
|
}, z.core.$strip>;
|
|
12
12
|
export declare class ListProjectFilesTool extends BaseTool<typeof InputSchema, typeof OutputSchema> {
|
|
13
13
|
readonly id = "listProjectFiles";
|
|
14
|
-
readonly description = "\nLists files and directories within the Ignis GitHub repository.\n\nPURPOSE:\nExplore the project structure, discover source code files, and navigate the monorepo.\nPrimary tool for understanding codebase layout before reading specific files.\n\nWHEN TO USE:\n- To understand overall project structure\n- To find location of specific modules (e.g., \"where are the controllers?\")\n- To get list of files in a directory before using viewSourceFile\n- To find configuration files, examples, or documentation\n\nWHEN NOT TO USE:\n- When searching for specific code patterns or keywords (use searchCode instead)\n- When you need to read a file's content (use viewSourceFile instead)\n- For documentation content (use searchDocs, listDocs, getDocContent instead)\n\nWORKFLOW:\n1. Start at root: listProjectFiles()\n2. Explore a package: listProjectFiles({ directoryPath: \"packages/core/src\" })\n3. Identify a file of interest\n4. Read the file: viewSourceFile({ filePath: \"packages/core/src/application.ts\" })\n";
|
|
14
|
+
readonly description = "\nLists files and directories within the Ignis GitHub repository.\n\nPURPOSE:\nExplore the project structure, discover source code files, and navigate the monorepo.\nPrimary tool for understanding codebase layout before reading specific files.\n\nWHEN TO USE:\n- To understand overall project structure\n- To find location of specific modules (e.g., \"where are the controllers?\")\n- To get list of files in a directory before using viewSourceFile\n- To find configuration files, examples, or documentation\n\nWHEN NOT TO USE:\n- When searching for specific code patterns or keywords (use searchCode instead)\n- When you need to read a file's content (use viewSourceFile instead)\n- For documentation content (use searchDocs, listDocs, getDocContent instead)\n\nWORKFLOW:\n1. Start at root: listProjectFiles()\n2. Explore a package: listProjectFiles({ directoryPath: \"packages/core-server/src\" })\n3. Identify a file of interest\n4. Read the file: viewSourceFile({ filePath: \"packages/core-server/src/application.ts\" })\n";
|
|
15
15
|
readonly inputSchema: z.ZodObject<{
|
|
16
16
|
directoryPath: z.ZodDefault<z.ZodString>;
|
|
17
17
|
}, z.core.$strip>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"list-project-files.tool.d.ts","sourceRoot":"","sources":["../../../../mcp-server/tools/github/list-project-files.tool.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAsCxC,QAAA,MAAM,WAAW;;iBAEf,CAAC;AAEH,QAAA,MAAM,YAAY;;;;;iBAOhB,CAAC;AAEH,qBAAa,oBAAqB,SAAQ,QAAQ,CAAC,OAAO,WAAW,EAAE,OAAO,YAAY,CAAC;IACzF,QAAQ,CAAC,EAAE,sBAAsB;IACjC,QAAQ,CAAC,WAAW,
|
|
1
|
+
{"version":3,"file":"list-project-files.tool.d.ts","sourceRoot":"","sources":["../../../../mcp-server/tools/github/list-project-files.tool.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAsCxC,QAAA,MAAM,WAAW;;iBAEf,CAAC;AAEH,QAAA,MAAM,YAAY;;;;;iBAOhB,CAAC;AAEH,qBAAa,oBAAqB,SAAQ,QAAQ,CAAC,OAAO,WAAW,EAAE,OAAO,YAAY,CAAC;IACzF,QAAQ,CAAC,EAAE,sBAAsB;IACjC,QAAQ,CAAC,WAAW,wgCAAoB;IACxC,QAAQ,CAAC,WAAW;;sBAAe;IACnC,QAAQ,CAAC,YAAY;;;;;sBAAgB;IAE/B,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAC;IAuBvF,OAAO;;;;;;;;CASR"}
|
|
@@ -25,9 +25,9 @@ WHEN NOT TO USE:
|
|
|
25
25
|
|
|
26
26
|
WORKFLOW:
|
|
27
27
|
1. Start at root: listProjectFiles()
|
|
28
|
-
2. Explore a package: listProjectFiles({ directoryPath: "packages/core/src" })
|
|
28
|
+
2. Explore a package: listProjectFiles({ directoryPath: "packages/core-server/src" })
|
|
29
29
|
3. Identify a file of interest
|
|
30
|
-
4. Read the file: viewSourceFile({ filePath: "packages/core/src/application.ts" })
|
|
30
|
+
4. Read the file: viewSourceFile({ filePath: "packages/core-server/src/application.ts" })
|
|
31
31
|
`;
|
|
32
32
|
const DIRECTORY_PATH_DESCRIPTION = `
|
|
33
33
|
The path to the directory you want to list, relative to the project root.
|
|
@@ -36,7 +36,7 @@ If omitted, it defaults to the root of the repository.
|
|
|
36
36
|
EXAMPLES:
|
|
37
37
|
- "." (or omitted) -> lists the root directory
|
|
38
38
|
- "packages" -> lists the contents of the 'packages' directory
|
|
39
|
-
- "packages/core/src" -> lists the source files of the core package
|
|
39
|
+
- "packages/core-server/src" -> lists the source files of the core package
|
|
40
40
|
`;
|
|
41
41
|
const InputSchema = zod_1.z.object({
|
|
42
42
|
directoryPath: zod_1.z.string().default('.').describe(DIRECTORY_PATH_DESCRIPTION),
|
|
@@ -43,7 +43,7 @@ QUERY SYNTAX:
|
|
|
43
43
|
- Multiple terms: "inject service" - files containing both terms
|
|
44
44
|
- Exact phrase: "\\"dependency injection\\"" - exact phrase match
|
|
45
45
|
- File extension: "extension:ts middleware" - only TypeScript files
|
|
46
|
-
- Path filter: "path:packages/core createTool" - search in specific path
|
|
46
|
+
- Path filter: "path:packages/core-server createTool" - search in specific path
|
|
47
47
|
|
|
48
48
|
EXAMPLES:
|
|
49
49
|
- "class Application" - find Application class definition
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@venizia/ignis-docs",
|
|
3
|
-
"version": "0.2.1-
|
|
3
|
+
"version": "0.2.1-1",
|
|
4
4
|
"description": "Interactive documentation site and MCP (Model Context Protocol) server for the Ignis Framework. Includes a VitePress-powered documentation site with guides, API references, and best practices. Ships an MCP server (CLI: ignis-docs-mcp) with 11 tools for AI assistants to search docs, browse source code, verify dependencies, and access real-time framework knowledge. Built with Mastra MCP SDK and Fuse.js fuzzy search.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -96,40 +96,41 @@
|
|
|
96
96
|
"access": "public"
|
|
97
97
|
},
|
|
98
98
|
"scripts": {
|
|
99
|
-
"
|
|
99
|
+
"docs:build": "sh ./scripts/docs-build.sh",
|
|
100
|
+
"docs:check-sidebar": "bun scripts/check-sidebar.ts",
|
|
101
|
+
"docs:clean": "sh ./scripts/docs-clean.sh",
|
|
102
|
+
"docs:dev": "vitepress dev site",
|
|
103
|
+
"docs:preview": "vitepress preview site",
|
|
100
104
|
"eslint": "eslint --report-unused-disable-directives .",
|
|
105
|
+
"force-update": "sh ./scripts/force-update.sh",
|
|
101
106
|
"lint": "bun run eslint && bun run prettier:cli",
|
|
102
107
|
"lint:fix": "bun run eslint --fix && bun run prettier:fix",
|
|
103
|
-
"prettier:cli": "prettier \"**/*.{js,ts}\" -l",
|
|
104
|
-
"prettier:fix": "bun run prettier:cli --write",
|
|
105
|
-
"docs:dev": "vitepress dev site",
|
|
106
|
-
"docs:clean": "sh ./scripts/docs-clean.sh",
|
|
107
|
-
"docs:build": "sh ./scripts/docs-build.sh",
|
|
108
|
-
"docs:preview": "vitepress preview site",
|
|
109
|
-
"rebuild": "sh ./scripts/mcp-rebuild.sh no-version",
|
|
110
|
-
"mcp:rebuild": "bun run rebuild",
|
|
111
108
|
"mcp:build": "sh ./scripts/mcp-build.sh",
|
|
112
109
|
"mcp:clean": "sh ./scripts/mcp-clean.sh",
|
|
113
|
-
"mcp:start": "bun run mcp-server/index.ts",
|
|
114
110
|
"mcp:dev": "bun --watch mcp-server/index.ts",
|
|
115
|
-
"
|
|
111
|
+
"mcp:rebuild": "bun run rebuild",
|
|
112
|
+
"mcp:start": "bun run mcp-server/index.ts",
|
|
113
|
+
"prepublishOnly": "bun run mcp:rebuild",
|
|
114
|
+
"prettier:cli": "prettier \"**/*.{js,ts}\" -l",
|
|
115
|
+
"prettier:fix": "bun run prettier:cli --write",
|
|
116
|
+
"rebuild": "sh ./scripts/mcp-rebuild.sh no-version"
|
|
116
117
|
},
|
|
117
118
|
"dependencies": {
|
|
118
119
|
"@mastra/core": "^1.51.0",
|
|
119
120
|
"@mastra/mcp": "^1.14.0",
|
|
120
|
-
"cytoscape": "^3.
|
|
121
|
+
"cytoscape": "^3.34.0",
|
|
121
122
|
"cytoscape-cose-bilkent": "^4.1.0",
|
|
122
|
-
"dayjs": "^1.11.
|
|
123
|
+
"dayjs": "^1.11.21",
|
|
123
124
|
"debug": "^4.4.3",
|
|
124
125
|
"fast-glob": "^3.3.3",
|
|
125
126
|
"fuse.js": "^7.5.0",
|
|
126
127
|
"gray-matter": "^4.0.3",
|
|
127
|
-
"zod": "^4.3
|
|
128
|
+
"zod": "^4.4.3"
|
|
128
129
|
},
|
|
129
130
|
"devDependencies": {
|
|
130
131
|
"@braintree/sanitize-url": "^7.1.2",
|
|
131
132
|
"@types/bun": "^1.3.14",
|
|
132
|
-
"@venizia/dev-configs": "^0.
|
|
133
|
+
"@venizia/dev-configs": "^0.2.0-1",
|
|
133
134
|
"eslint": "^10.7.0",
|
|
134
135
|
"prettier": "^3.9.5",
|
|
135
136
|
"tsc-alias": "^1.9.1",
|