@theokit/sdk 1.7.0 → 1.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/bin/init-claude.mjs +34 -0
- package/claude-template/AGENTS.md +139 -0
- package/claude-template/CLAUDE.md +51 -0
- package/claude-template/dot-claude/rules/theokit-conventions.md +33 -0
- package/claude-template/dot-claude/settings.json +16 -0
- package/claude-template/dot-claude/skills/theokit-agent-core/SKILL.md +209 -0
- package/claude-template/dot-claude/skills/theokit-budget/SKILL.md +176 -0
- package/claude-template/dot-claude/skills/theokit-config/SKILL.md +139 -0
- package/claude-template/dot-claude/skills/theokit-cron/SKILL.md +148 -0
- package/claude-template/dot-claude/skills/theokit-di/SKILL.md +233 -0
- package/claude-template/dot-claude/skills/theokit-di-agent/SKILL.md +294 -0
- package/claude-template/dot-claude/skills/theokit-errors/SKILL.md +172 -0
- package/claude-template/dot-claude/skills/theokit-eval/SKILL.md +144 -0
- package/claude-template/dot-claude/skills/theokit-gateways/SKILL.md +209 -0
- package/claude-template/dot-claude/skills/theokit-memory/SKILL.md +176 -0
- package/claude-template/dot-claude/skills/theokit-rag/SKILL.md +226 -0
- package/claude-template/dot-claude/skills/theokit-streaming/SKILL.md +156 -0
- package/claude-template/dot-claude/skills/theokit-subscriptions/SKILL.md +148 -0
- package/claude-template/dot-claude/skills/theokit-tools/SKILL.md +170 -0
- package/claude-template/dot-claude/skills/theokit-workflows/SKILL.md +218 -0
- package/package.json +3 -1
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
---
|
|
2
|
+
user-invocable: false
|
|
3
|
+
paths:
|
|
4
|
+
- "**/.theokit/**"
|
|
5
|
+
- "**/config.*"
|
|
6
|
+
- "**/theo.config.*"
|
|
7
|
+
description: TheoKit SDK configuration reference — .theokit/ structure, mcp.json, hooks, env vars, config discovery
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# TheoKit Configuration
|
|
11
|
+
|
|
12
|
+
## Directory structure
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
.theokit/
|
|
16
|
+
+-- hooks/ # one .md per hook
|
|
17
|
+
| +-- shell-policy.md
|
|
18
|
+
+-- context/ # one .md per context source
|
|
19
|
+
| +-- bot-readme.md
|
|
20
|
+
+-- skills/<name>/SKILL.md # named capability packs
|
|
21
|
+
+-- plugins/<name>/PLUGIN.md # plugin definitions
|
|
22
|
+
+-- cron/
|
|
23
|
+
| +-- jobs.json # local cron state (auto-created)
|
|
24
|
+
+-- agents/*.md # subagent definitions (name + description frontmatter)
|
|
25
|
+
+-- memory/ # local memory storage
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
User-level config lives at `~/.theokit/` with the same structure.
|
|
29
|
+
|
|
30
|
+
## Config file format (v1.5+)
|
|
31
|
+
|
|
32
|
+
Markdown + YAML frontmatter. One file per entity.
|
|
33
|
+
|
|
34
|
+
### Hook example
|
|
35
|
+
|
|
36
|
+
```markdown
|
|
37
|
+
---
|
|
38
|
+
event: preToolUse
|
|
39
|
+
matcher: ^shell$
|
|
40
|
+
command: node .theokit/policy.js
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
# Shell tool policy gate
|
|
44
|
+
|
|
45
|
+
Vets shell tool invocations before spawn.
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Disabling an entry
|
|
49
|
+
|
|
50
|
+
Rename `<name>.md` to `<name>.md.disabled` — the loader silently skips it.
|
|
51
|
+
|
|
52
|
+
## Setting sources
|
|
53
|
+
|
|
54
|
+
`local.settingSources` controls which config layers a local agent loads:
|
|
55
|
+
|
|
56
|
+
| Value | Source |
|
|
57
|
+
|---|---|
|
|
58
|
+
| `"project"` | `.theokit/` in the workspace |
|
|
59
|
+
| `"user"` | `~/.theokit/` |
|
|
60
|
+
| `"team"` | Team settings synced from the dashboard |
|
|
61
|
+
| `"mdm"` | MDM-managed enterprise settings |
|
|
62
|
+
| `"plugins"` | Plugin-provided settings |
|
|
63
|
+
| `"all"` | All of the above |
|
|
64
|
+
|
|
65
|
+
Cloud agents always load project / team / plugins and ignore this field.
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
const agent = await Agent.create({
|
|
69
|
+
apiKey: process.env.THEOKIT_API_KEY!,
|
|
70
|
+
model: { id: "google/gemini-2.0-flash-001" },
|
|
71
|
+
local: { cwd: process.cwd(), settingSources: ["project", "user"] },
|
|
72
|
+
});
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Environment variables
|
|
76
|
+
|
|
77
|
+
| Env var | Purpose |
|
|
78
|
+
|---|---|
|
|
79
|
+
| `THEOKIT_API_KEY` | Default API key (user or service account) |
|
|
80
|
+
| `THEOKIT_REDACT_SECRETS` | Set `false` to disable secret redaction (default: `true`) |
|
|
81
|
+
| `OLLAMA_HOST` | Ollama server URL (default: `http://localhost:11434`) |
|
|
82
|
+
| `OLLAMA_API_KEY` | Bearer token for Ollama Cloud or proxy |
|
|
83
|
+
| `OPENROUTER_API_KEY` | OpenRouter provider key |
|
|
84
|
+
| `ANTHROPIC_API_KEY` | Anthropic provider key |
|
|
85
|
+
| `OPENAI_API_KEY` | OpenAI provider key |
|
|
86
|
+
|
|
87
|
+
## MCP server discovery
|
|
88
|
+
|
|
89
|
+
Servers are loaded with first-match-wins precedence:
|
|
90
|
+
|
|
91
|
+
1. `mcpServers` on `agent.send()` — fully replaces creation-time servers
|
|
92
|
+
2. `mcpServers` on `Agent.create()` — used when no per-send override
|
|
93
|
+
3. Plugin servers (if settingSources includes `"plugins"`)
|
|
94
|
+
4. Project servers from `.theokit/mcp.json` (if settingSources includes `"project"`)
|
|
95
|
+
5. User servers from `~/.theokit/mcp.json` (if settingSources includes `"user"`)
|
|
96
|
+
|
|
97
|
+
## Context manager config
|
|
98
|
+
|
|
99
|
+
```typescript
|
|
100
|
+
const agent = await Agent.create({
|
|
101
|
+
context: {
|
|
102
|
+
manager: "file", // reads .theokit/context/<name>.md
|
|
103
|
+
maxTokens: 1200,
|
|
104
|
+
},
|
|
105
|
+
local: { cwd: process.cwd(), settingSources: ["project"] },
|
|
106
|
+
});
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
`manager: "inline"` uses `sources` passed directly in `Agent.create()`.
|
|
110
|
+
|
|
111
|
+
## Skills config
|
|
112
|
+
|
|
113
|
+
```typescript
|
|
114
|
+
const agent = await Agent.create({
|
|
115
|
+
skills: {
|
|
116
|
+
enabled: ["code-review", "test-architect"],
|
|
117
|
+
},
|
|
118
|
+
local: { cwd: process.cwd(), settingSources: ["project"] },
|
|
119
|
+
});
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Skills live at `.theokit/skills/<name>/SKILL.md` with strict YAML frontmatter
|
|
123
|
+
(`name`, `description` required).
|
|
124
|
+
|
|
125
|
+
## Migration from legacy JSON
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
npx theokit-migrate-config --apply
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Dry-run by default; `--apply` writes. Backs up originals to
|
|
132
|
+
`<file>.json.<unix-ts>.bak`. Legacy JSON still works in v1.x with a
|
|
133
|
+
deprecation warning. JSON support removed in v2.0.
|
|
134
|
+
|
|
135
|
+
## `agent.reload()`
|
|
136
|
+
|
|
137
|
+
Re-reads filesystem config (context, skills, hooks, project MCP, subagents)
|
|
138
|
+
without disposing the agent or losing conversation state. Invalid files
|
|
139
|
+
raise `ConfigurationError`.
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
---
|
|
2
|
+
user-invocable: false
|
|
3
|
+
paths:
|
|
4
|
+
- "**/*cron*"
|
|
5
|
+
- "**/*Cron*"
|
|
6
|
+
- "**/*job*"
|
|
7
|
+
- "**/*schedule*"
|
|
8
|
+
description: TheoKit SDK Cron jobs API reference — Cron.create, schedule syntax, job lifecycle
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# TheoKit Cron Jobs
|
|
12
|
+
|
|
13
|
+
Schedule Theo agent runs on a cron expression. Two runtimes mirror the agent
|
|
14
|
+
split: local (in-process scheduler) and cloud (Theo PaaS, pre-release).
|
|
15
|
+
|
|
16
|
+
## Creating a job
|
|
17
|
+
|
|
18
|
+
```typescript
|
|
19
|
+
import { Cron } from "@theokit/sdk";
|
|
20
|
+
|
|
21
|
+
const job = await Cron.create({
|
|
22
|
+
cron: "0 9 * * *", // every day at 09:00
|
|
23
|
+
timezone: "America/Sao_Paulo",
|
|
24
|
+
message: "Summarize yesterday's commits and post to #engineering",
|
|
25
|
+
agent: {
|
|
26
|
+
apiKey: process.env.THEOKIT_API_KEY!,
|
|
27
|
+
model: { id: "google/gemini-2.0-flash-001" },
|
|
28
|
+
local: { cwd: process.cwd() },
|
|
29
|
+
},
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
await Cron.start(); // required for local jobs to fire
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Agent binding
|
|
36
|
+
|
|
37
|
+
Pass exactly one of:
|
|
38
|
+
|
|
39
|
+
- **`agent`** (full `AgentOptions`) — a fresh agent is created on every fire.
|
|
40
|
+
Use for independent runs.
|
|
41
|
+
- **`agentId`** (string) — reuses an existing agent's conversation context
|
|
42
|
+
across fires. Use for continuity (e.g., weekly review building on past notes).
|
|
43
|
+
|
|
44
|
+
Setting both raises `ConfigurationError`.
|
|
45
|
+
|
|
46
|
+
## Cron expressions
|
|
47
|
+
|
|
48
|
+
| Format | Example | Meaning |
|
|
49
|
+
|---|---|---|
|
|
50
|
+
| 5-field POSIX | `0 9 * * *` | Minute, hour, day-of-month, month, day-of-week |
|
|
51
|
+
| `@hourly` | `@hourly` | Every hour at minute 0 |
|
|
52
|
+
| `@daily` | `@daily` | Every day at midnight |
|
|
53
|
+
| `@weekly` | `@weekly` | Every Sunday at midnight |
|
|
54
|
+
| `@monthly` | `@monthly` | First day of month at midnight |
|
|
55
|
+
| `@yearly` | `@yearly` | January 1 at midnight |
|
|
56
|
+
|
|
57
|
+
`timezone` accepts any IANA identifier (default: `"UTC"`). Invalid expressions
|
|
58
|
+
throw `ConfigurationError` synchronously at create time.
|
|
59
|
+
|
|
60
|
+
## Managing jobs
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
const { items } = await Cron.list({ runtime: "local", cwd: process.cwd() });
|
|
64
|
+
const job = await Cron.get(jobId);
|
|
65
|
+
|
|
66
|
+
await Cron.disable(jobId); // pause without deleting
|
|
67
|
+
await Cron.enable(jobId); // resume
|
|
68
|
+
await Cron.delete(jobId); // permanent removal
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Manual fire (off-schedule)
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
const run = await Cron.run(jobId);
|
|
75
|
+
|
|
76
|
+
for await (const event of run.stream()) {
|
|
77
|
+
// same SDKMessage events as any other run
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Manual fires do not update `lastRunAt` — only scheduled fires do.
|
|
82
|
+
|
|
83
|
+
## Local scheduler lifecycle
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
await Cron.start({ cwd: process.cwd() }); // reads .theokit/cron/jobs.json
|
|
87
|
+
const status = await Cron.status();
|
|
88
|
+
// { running: true, jobCount: 3, nextFireAt: 1747... }
|
|
89
|
+
await Cron.stop(); // halts scheduling; does NOT delete jobs
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Local jobs only fire while the host process is alive. Run as `pm2` / `systemd`
|
|
93
|
+
service for 24/7 local scheduling.
|
|
94
|
+
|
|
95
|
+
## Persistence
|
|
96
|
+
|
|
97
|
+
Local cron state lives in `.theokit/cron/jobs.json`. Created automatically by
|
|
98
|
+
`Cron.create()`. Commit it if jobs should travel with the repo; add to
|
|
99
|
+
`.gitignore` if environment-specific.
|
|
100
|
+
|
|
101
|
+
## Type reference
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
interface CronJob {
|
|
105
|
+
id: string;
|
|
106
|
+
name?: string;
|
|
107
|
+
cron: string;
|
|
108
|
+
timezone?: string;
|
|
109
|
+
message: string | SDKUserMessage;
|
|
110
|
+
agent?: AgentOptions; // mutually exclusive with agentId
|
|
111
|
+
agentId?: string;
|
|
112
|
+
enabled: boolean;
|
|
113
|
+
status: "scheduled" | "running" | "paused" | "errored";
|
|
114
|
+
runtime: "local" | "cloud";
|
|
115
|
+
lastRunAt?: number;
|
|
116
|
+
nextRunAt?: number;
|
|
117
|
+
createdAt: number;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
interface CronCreateOptions {
|
|
121
|
+
cron: string;
|
|
122
|
+
message: string | SDKUserMessage;
|
|
123
|
+
agent?: AgentOptions;
|
|
124
|
+
agentId?: string;
|
|
125
|
+
name?: string;
|
|
126
|
+
timezone?: string;
|
|
127
|
+
enabled?: boolean; // defaults to true
|
|
128
|
+
apiKey?: string;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
interface CronSchedulerStatus {
|
|
132
|
+
running: boolean;
|
|
133
|
+
jobCount: number;
|
|
134
|
+
nextFireAt?: number;
|
|
135
|
+
lastError?: { jobId: string; message: string; at: number };
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Cloud jobs (pre-release)
|
|
140
|
+
|
|
141
|
+
Cloud jobs use Theo PaaS and do not need `Cron.start()`. Pass `agent.cloud`
|
|
142
|
+
to create a cloud-scheduled job. Pre-release — not yet GA.
|
|
143
|
+
|
|
144
|
+
## Known limitations
|
|
145
|
+
|
|
146
|
+
- Local jobs only fire while the host process is alive.
|
|
147
|
+
- In-flight fires are not resumed if the host process crashes mid-run.
|
|
148
|
+
- `Cron.run()` (manual fire) does not update `lastRunAt`.
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
---
|
|
2
|
+
user-invocable: false
|
|
3
|
+
description: Dependency injection container, decorators, scopes, and modules for @theokit/di.
|
|
4
|
+
paths:
|
|
5
|
+
- "**/*container*"
|
|
6
|
+
- "**/*inject*"
|
|
7
|
+
- "**/*provider*"
|
|
8
|
+
- "**/*module*"
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# TheoKit DI -- Dependency Injection
|
|
12
|
+
|
|
13
|
+
Quick reference for `@theokit/di` -- a TypeScript DI container with decorator metadata.
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
pnpm add @theokit/di reflect-metadata
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Requires `reflect-metadata` polyfill imported once at app entry and `experimentalDecorators` + `emitDecoratorMetadata` in `tsconfig.json`.
|
|
22
|
+
|
|
23
|
+
## Core decorators
|
|
24
|
+
|
|
25
|
+
### @Injectable
|
|
26
|
+
|
|
27
|
+
```typescript
|
|
28
|
+
import { Injectable, Scope } from "@theokit/di";
|
|
29
|
+
|
|
30
|
+
@Injectable()
|
|
31
|
+
class UserRepository {
|
|
32
|
+
findById(id: string) { /* ... */ }
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// With options:
|
|
36
|
+
@Injectable({ scope: Scope.REQUEST })
|
|
37
|
+
class RequestScopedService { /* ... */ }
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
`InjectableOptions`:
|
|
41
|
+
|
|
42
|
+
| Option | Type | Default | Description |
|
|
43
|
+
|---|---|---|---|
|
|
44
|
+
| `scope` | `Scope` | `Scope.SINGLETON` | Lifecycle scope. |
|
|
45
|
+
|
|
46
|
+
### @Inject
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
import { Inject } from "@theokit/di";
|
|
50
|
+
|
|
51
|
+
@Injectable()
|
|
52
|
+
class OrderService {
|
|
53
|
+
constructor(
|
|
54
|
+
@Inject("DATABASE_URL") private readonly dbUrl: string,
|
|
55
|
+
private readonly repo: UserRepository, // auto-resolved by type
|
|
56
|
+
) {}
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Use `@Inject(token)` for string/symbol tokens. Constructor parameter types are auto-resolved via `reflect-metadata` when the parameter is a class.
|
|
61
|
+
|
|
62
|
+
### @Optional
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
import { Optional } from "@theokit/di";
|
|
66
|
+
|
|
67
|
+
@Injectable()
|
|
68
|
+
class NotificationService {
|
|
69
|
+
constructor(
|
|
70
|
+
@Optional() private readonly sms?: SmsGateway,
|
|
71
|
+
) {}
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Resolves to `undefined` instead of throwing `TokenNotFoundError` when the dependency is not registered.
|
|
76
|
+
|
|
77
|
+
### @Qualifier
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
import { Qualifier } from "@theokit/di";
|
|
81
|
+
|
|
82
|
+
@Injectable()
|
|
83
|
+
class PaymentService {
|
|
84
|
+
constructor(
|
|
85
|
+
@Qualifier("stripe") private readonly gateway: PaymentGateway,
|
|
86
|
+
) {}
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Disambiguates between multiple providers registered under the same interface token.
|
|
91
|
+
|
|
92
|
+
### @Primary
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
import { Primary, Injectable } from "@theokit/di";
|
|
96
|
+
|
|
97
|
+
@Injectable()
|
|
98
|
+
@Primary()
|
|
99
|
+
class StripeGateway implements PaymentGateway { /* ... */ }
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Marks a provider as the default when multiple are registered for the same token. Wins over non-primary providers unless `@Qualifier` is used.
|
|
103
|
+
|
|
104
|
+
### @PostConstruct / @PreDestroy
|
|
105
|
+
|
|
106
|
+
```typescript
|
|
107
|
+
import { PostConstruct, PreDestroy, Injectable } from "@theokit/di";
|
|
108
|
+
|
|
109
|
+
@Injectable()
|
|
110
|
+
class DatabasePool {
|
|
111
|
+
@PostConstruct()
|
|
112
|
+
async init() { /* called after construction */ }
|
|
113
|
+
|
|
114
|
+
@PreDestroy()
|
|
115
|
+
async shutdown() { /* called on container.dispose() */ }
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Container
|
|
120
|
+
|
|
121
|
+
```typescript
|
|
122
|
+
import { Container } from "@theokit/di";
|
|
123
|
+
|
|
124
|
+
const container = new Container();
|
|
125
|
+
|
|
126
|
+
// Register classes
|
|
127
|
+
container.register(UserRepository);
|
|
128
|
+
container.register(OrderService);
|
|
129
|
+
|
|
130
|
+
// Register value providers
|
|
131
|
+
container.register("DATABASE_URL", { useValue: "postgres://..." });
|
|
132
|
+
|
|
133
|
+
// Register factory providers
|
|
134
|
+
container.register("Logger", {
|
|
135
|
+
useFactory: (ctx) => new Logger(ctx.resolve("DATABASE_URL")),
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
// Register existing (alias)
|
|
139
|
+
container.register("PrimaryRepo", { useExisting: UserRepository });
|
|
140
|
+
|
|
141
|
+
// Resolve
|
|
142
|
+
const service = container.resolve(OrderService);
|
|
143
|
+
const asyncService = await container.resolveAsync(OrderService);
|
|
144
|
+
|
|
145
|
+
// Dispose (calls @PreDestroy hooks)
|
|
146
|
+
await container.dispose();
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### ContainerOptions
|
|
150
|
+
|
|
151
|
+
```typescript
|
|
152
|
+
interface ContainerOptions {
|
|
153
|
+
parent?: Container; // hierarchical containers
|
|
154
|
+
autoRegister?: boolean; // default false
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### Provider types
|
|
159
|
+
|
|
160
|
+
```typescript
|
|
161
|
+
type Provider =
|
|
162
|
+
| ClassProvider // { useClass: Constructor, scope? }
|
|
163
|
+
| ValueProvider // { useValue: any }
|
|
164
|
+
| FactoryProvider // { useFactory: (ctx) => any, scope? }
|
|
165
|
+
| ExistingProvider; // { useExisting: Token }
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
## Scopes
|
|
169
|
+
|
|
170
|
+
```typescript
|
|
171
|
+
import { Scope } from "@theokit/di";
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
| Scope | Behavior |
|
|
175
|
+
|---|---|
|
|
176
|
+
| `Scope.SINGLETON` | One instance per container (default). |
|
|
177
|
+
| `Scope.TRANSIENT` | New instance on every resolve. |
|
|
178
|
+
| `Scope.REQUEST` | One instance per request scope (via `container.createScope()`). |
|
|
179
|
+
|
|
180
|
+
Request scope example:
|
|
181
|
+
|
|
182
|
+
```typescript
|
|
183
|
+
const requestContainer = container.createScope();
|
|
184
|
+
const handler = requestContainer.resolve(RequestHandler);
|
|
185
|
+
// All REQUEST-scoped deps share the same instance within this scope
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
## @Module
|
|
189
|
+
|
|
190
|
+
```typescript
|
|
191
|
+
import { Module } from "@theokit/di";
|
|
192
|
+
|
|
193
|
+
@Module({
|
|
194
|
+
providers: [UserRepository, OrderService],
|
|
195
|
+
imports: [DatabaseModule],
|
|
196
|
+
exports: [UserRepository],
|
|
197
|
+
})
|
|
198
|
+
class UserModule {}
|
|
199
|
+
|
|
200
|
+
// Load module into container
|
|
201
|
+
container.loadModule(UserModule);
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
`ModuleMetadata`:
|
|
205
|
+
|
|
206
|
+
| Field | Type | Description |
|
|
207
|
+
|---|---|---|
|
|
208
|
+
| `providers` | `Provider[]` | Classes/providers registered in this module. |
|
|
209
|
+
| `imports` | `Module[]` | Other modules whose exports become available. |
|
|
210
|
+
| `exports` | `Token[]` | Tokens visible to importing modules. |
|
|
211
|
+
|
|
212
|
+
## Errors
|
|
213
|
+
|
|
214
|
+
| Error | Cause |
|
|
215
|
+
|---|---|
|
|
216
|
+
| `TokenNotFoundError` | Token not registered and not `@Optional`. |
|
|
217
|
+
| `CyclicDependencyError` | Circular dependency detected in resolution graph. |
|
|
218
|
+
| `MissingInjectableError` | Class used as dependency without `@Injectable`. |
|
|
219
|
+
| `ScopeViolationError` | Singleton depends on transient/request-scoped dep. |
|
|
220
|
+
| `ContainerDisposedError` | Resolve called after `container.dispose()`. |
|
|
221
|
+
| `ContainerFrozenError` | Register called after container is frozen. |
|
|
222
|
+
| `AsyncProviderInSyncResolveError` | Async factory used with `resolve()` instead of `resolveAsync()`. |
|
|
223
|
+
| `ReflectMetadataMissingError` | `reflect-metadata` polyfill not imported. |
|
|
224
|
+
| `CyclicModuleImportError` | Circular module imports detected. |
|
|
225
|
+
| `InvalidModuleError` | Module class missing `@Module` decorator. |
|
|
226
|
+
| `InvalidExportError` | Module exports a token not in its providers. |
|
|
227
|
+
|
|
228
|
+
## Graph analysis
|
|
229
|
+
|
|
230
|
+
```typescript
|
|
231
|
+
const graph: DependencyGraph = container.analyzeGraph();
|
|
232
|
+
// Useful for debugging dependency chains and detecting issues
|
|
233
|
+
```
|