@directive-run/knowledge 0.2.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.
Files changed (68) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +63 -0
  3. package/ai/ai-adapters.md +250 -0
  4. package/ai/ai-agents-streaming.md +269 -0
  5. package/ai/ai-budget-resilience.md +235 -0
  6. package/ai/ai-communication.md +281 -0
  7. package/ai/ai-debug-observability.md +243 -0
  8. package/ai/ai-guardrails-memory.md +332 -0
  9. package/ai/ai-mcp-rag.md +288 -0
  10. package/ai/ai-multi-agent.md +274 -0
  11. package/ai/ai-orchestrator.md +227 -0
  12. package/ai/ai-security.md +293 -0
  13. package/ai/ai-tasks.md +261 -0
  14. package/ai/ai-testing-evals.md +378 -0
  15. package/api-skeleton.md +5 -0
  16. package/core/anti-patterns.md +382 -0
  17. package/core/constraints.md +263 -0
  18. package/core/core-patterns.md +228 -0
  19. package/core/error-boundaries.md +322 -0
  20. package/core/multi-module.md +315 -0
  21. package/core/naming.md +283 -0
  22. package/core/plugins.md +344 -0
  23. package/core/react-adapter.md +262 -0
  24. package/core/resolvers.md +357 -0
  25. package/core/schema-types.md +262 -0
  26. package/core/system-api.md +271 -0
  27. package/core/testing.md +257 -0
  28. package/core/time-travel.md +238 -0
  29. package/dist/index.cjs +111 -0
  30. package/dist/index.cjs.map +1 -0
  31. package/dist/index.d.cts +10 -0
  32. package/dist/index.d.ts +10 -0
  33. package/dist/index.js +102 -0
  34. package/dist/index.js.map +1 -0
  35. package/examples/ab-testing.ts +385 -0
  36. package/examples/ai-checkpoint.ts +509 -0
  37. package/examples/ai-guardrails.ts +319 -0
  38. package/examples/ai-orchestrator.ts +589 -0
  39. package/examples/async-chains.ts +287 -0
  40. package/examples/auth-flow.ts +371 -0
  41. package/examples/batch-resolver.ts +341 -0
  42. package/examples/checkers.ts +589 -0
  43. package/examples/contact-form.ts +176 -0
  44. package/examples/counter.ts +393 -0
  45. package/examples/dashboard-loader.ts +512 -0
  46. package/examples/debounce-constraints.ts +105 -0
  47. package/examples/dynamic-modules.ts +293 -0
  48. package/examples/error-boundaries.ts +430 -0
  49. package/examples/feature-flags.ts +220 -0
  50. package/examples/form-wizard.ts +347 -0
  51. package/examples/fraud-analysis.ts +663 -0
  52. package/examples/goal-heist.ts +341 -0
  53. package/examples/multi-module.ts +57 -0
  54. package/examples/newsletter.ts +241 -0
  55. package/examples/notifications.ts +210 -0
  56. package/examples/optimistic-updates.ts +317 -0
  57. package/examples/pagination.ts +260 -0
  58. package/examples/permissions.ts +337 -0
  59. package/examples/provider-routing.ts +403 -0
  60. package/examples/server.ts +316 -0
  61. package/examples/shopping-cart.ts +422 -0
  62. package/examples/sudoku.ts +630 -0
  63. package/examples/theme-locale.ts +204 -0
  64. package/examples/time-machine.ts +225 -0
  65. package/examples/topic-guard.ts +306 -0
  66. package/examples/url-sync.ts +333 -0
  67. package/examples/websocket.ts +404 -0
  68. package/package.json +65 -0
@@ -0,0 +1,341 @@
1
+ // Example: batch-resolver
2
+ // Source: examples/batch-resolver/src/main.ts
3
+ // Extracted for AI rules — DOM wiring stripped
4
+
5
+ /**
6
+ * Batch Data Loader — Batched Resolution & Schema Validation
7
+ *
8
+ * User directory that loads profiles. Multiple constraints fire simultaneously;
9
+ * the batch resolver groups them into one call. Dev-mode schema validation
10
+ * catches type mismatches.
11
+ */
12
+
13
+ import {
14
+ type ModuleSchema,
15
+ createModule,
16
+ createSystem,
17
+ t,
18
+ } from "@directive-run/core";
19
+ import { devtoolsPlugin } from "@directive-run/core/plugins";
20
+
21
+ // ============================================================================
22
+ // Types
23
+ // ============================================================================
24
+
25
+ interface UserProfile {
26
+ id: number;
27
+ name: string;
28
+ email: string;
29
+ role: string;
30
+ }
31
+
32
+ interface TimelineEntry {
33
+ time: number;
34
+ event: string;
35
+ detail: string;
36
+ type: "info" | "batch" | "error" | "success" | "validation";
37
+ }
38
+
39
+ // ============================================================================
40
+ // Mock Data
41
+ // ============================================================================
42
+
43
+ const MOCK_USERS: Record<number, UserProfile> = {
44
+ 1: { id: 1, name: "Alice Chen", email: "alice@acme.com", role: "Admin" },
45
+ 2: { id: 2, name: "Bob Smith", email: "bob@acme.com", role: "Editor" },
46
+ 3: { id: 3, name: "Carol Davis", email: "carol@acme.com", role: "Viewer" },
47
+ 4: { id: 4, name: "Dave Wilson", email: "dave@acme.com", role: "Editor" },
48
+ 5: { id: 5, name: "Eve Brown", email: "eve@acme.com", role: "Admin" },
49
+ 6: { id: 6, name: "Frank Lee", email: "frank@acme.com", role: "Viewer" },
50
+ 7: { id: 7, name: "Grace Kim", email: "grace@acme.com", role: "Editor" },
51
+ 8: { id: 8, name: "Hank Moore", email: "hank@acme.com", role: "Viewer" },
52
+ 9: { id: 9, name: "Iris Park", email: "iris@acme.com", role: "Admin" },
53
+ 10: { id: 10, name: "Jack Turner", email: "jack@acme.com", role: "Editor" },
54
+ 11: { id: 11, name: "Kate Adams", email: "kate@acme.com", role: "Viewer" },
55
+ 12: { id: 12, name: "Leo Garcia", email: "leo@acme.com", role: "Editor" },
56
+ 13: { id: 13, name: "Mia Jones", email: "mia@acme.com", role: "Admin" },
57
+ 14: { id: 14, name: "Nick White", email: "nick@acme.com", role: "Viewer" },
58
+ 15: { id: 15, name: "Olivia Hall", email: "olivia@acme.com", role: "Editor" },
59
+ 16: { id: 16, name: "Pete Clark", email: "pete@acme.com", role: "Viewer" },
60
+ 17: { id: 17, name: "Quinn Ross", email: "quinn@acme.com", role: "Admin" },
61
+ 18: { id: 18, name: "Rosa Martin", email: "rosa@acme.com", role: "Editor" },
62
+ 19: { id: 19, name: "Steve Young", email: "steve@acme.com", role: "Viewer" },
63
+ 20: { id: 20, name: "Tina Allen", email: "tina@acme.com", role: "Admin" },
64
+ };
65
+
66
+ // ============================================================================
67
+ // Timeline
68
+ // ============================================================================
69
+
70
+ const timeline: TimelineEntry[] = [];
71
+
72
+ function addTimeline(
73
+ event: string,
74
+ detail: string,
75
+ type: TimelineEntry["type"],
76
+ ) {
77
+ timeline.unshift({ time: Date.now(), event, detail, type });
78
+ if (timeline.length > 50) {
79
+ timeline.length = 50;
80
+ }
81
+ }
82
+
83
+ // ============================================================================
84
+ // Schema
85
+ // ============================================================================
86
+
87
+ const schema = {
88
+ facts: {
89
+ users: t.object<UserProfile[]>(),
90
+ loadingIds: t.object<number[]>(),
91
+ batchCount: t.number(),
92
+ totalRequests: t.number(),
93
+ batchWindowMs: t.number(),
94
+ failItemId: t.number(),
95
+ validationErrors: t.object<string[]>(),
96
+ },
97
+ derivations: {
98
+ userCount: t.number(),
99
+ loadingCount: t.number(),
100
+ batchEfficiency: t.string(),
101
+ hasValidationErrors: t.boolean(),
102
+ },
103
+ events: {
104
+ loadUser: { id: t.number() },
105
+ loadRange: { start: t.number(), count: t.number() },
106
+ setBatchWindow: { value: t.number() },
107
+ setFailItemId: { value: t.number() },
108
+ injectSchemaError: {},
109
+ clearUsers: {},
110
+ resetAll: {},
111
+ },
112
+ requirements: {
113
+ LOAD_USER: { userId: t.number() },
114
+ },
115
+ } satisfies ModuleSchema;
116
+
117
+ // ============================================================================
118
+ // Module
119
+ // ============================================================================
120
+
121
+ const batchModule = createModule("batch-loader", {
122
+ schema,
123
+
124
+ init: (facts) => {
125
+ facts.users = [];
126
+ facts.loadingIds = [];
127
+ facts.batchCount = 0;
128
+ facts.totalRequests = 0;
129
+ facts.batchWindowMs = 50;
130
+ facts.failItemId = 0;
131
+ facts.validationErrors = [];
132
+ },
133
+
134
+ derive: {
135
+ userCount: (facts) => facts.users.length,
136
+ loadingCount: (facts) => facts.loadingIds.length,
137
+ batchEfficiency: (facts) => {
138
+ if (facts.totalRequests === 0) {
139
+ return "N/A";
140
+ }
141
+
142
+ return `${facts.batchCount} batches / ${facts.totalRequests} requests`;
143
+ },
144
+ hasValidationErrors: (facts) => facts.validationErrors.length > 0,
145
+ },
146
+
147
+ events: {
148
+ loadUser: (facts, { id }) => {
149
+ if (
150
+ !facts.loadingIds.includes(id) &&
151
+ !facts.users.find((u: UserProfile) => u.id === id)
152
+ ) {
153
+ facts.loadingIds = [...facts.loadingIds, id];
154
+ facts.totalRequests = facts.totalRequests + 1;
155
+ }
156
+ },
157
+ loadRange: (facts, { start, count }) => {
158
+ const newIds: number[] = [];
159
+ for (let i = start; i < start + count; i++) {
160
+ if (
161
+ !facts.loadingIds.includes(i) &&
162
+ !facts.users.find((u: UserProfile) => u.id === i)
163
+ ) {
164
+ newIds.push(i);
165
+ }
166
+ }
167
+ if (newIds.length > 0) {
168
+ facts.loadingIds = [...facts.loadingIds, ...newIds];
169
+ facts.totalRequests = facts.totalRequests + newIds.length;
170
+ }
171
+ },
172
+ setBatchWindow: (facts, { value }) => {
173
+ facts.batchWindowMs = value;
174
+ },
175
+ setFailItemId: (facts, { value }) => {
176
+ facts.failItemId = value;
177
+ },
178
+ injectSchemaError: (facts) => {
179
+ // Intentionally write a bad type to trigger validation
180
+ (facts as Record<string, unknown>).users = "not-an-array";
181
+ facts.validationErrors = [
182
+ ...facts.validationErrors,
183
+ "schema: expected array for 'users', got string",
184
+ ];
185
+ "validation",
186
+ "schema error: expected array for 'users'",
187
+ "validation",
188
+ );
189
+ // Fix it immediately so the system keeps working
190
+ facts.users = [];
191
+ },
192
+ clearUsers: (facts) => {
193
+ facts.users = [];
194
+ },
195
+ resetAll: (facts) => {
196
+ facts.users = [];
197
+ facts.loadingIds = [];
198
+ facts.batchCount = 0;
199
+ facts.totalRequests = 0;
200
+ facts.failItemId = 0;
201
+ facts.validationErrors = [];
202
+ timeline.length = 0;
203
+ },
204
+ },
205
+
206
+ constraints: {
207
+ needsLoad: {
208
+ priority: 50,
209
+ when: (facts) => facts.loadingIds.length > 0,
210
+ require: (facts) => {
211
+ // Emit one requirement per loading ID — the batch resolver groups them
212
+ const id = facts.loadingIds[0];
213
+
214
+ return { type: "LOAD_USER", userId: id };
215
+ },
216
+ },
217
+ },
218
+
219
+ resolvers: {
220
+ loadUser: {
221
+ requirement: "LOAD_USER",
222
+ batch: {
223
+ enabled: true,
224
+ windowMs: 50,
225
+ },
226
+ resolveBatchWithResults: async (requirements, context) => {
227
+ const ids = requirements.map((r) => r.userId);
228
+ "batch",
229
+ `batch formed: ${ids.length} items [${ids.join(", ")}]`,
230
+ "batch",
231
+ );
232
+ context.facts.batchCount = context.facts.batchCount + 1;
233
+
234
+ // Simulate API delay
235
+ await new Promise((resolve) =>
236
+ setTimeout(resolve, 150 + Math.random() * 100),
237
+ );
238
+
239
+ const failId = context.facts.failItemId;
240
+ const results = ids.map((id) => {
241
+ if (id === failId) {
242
+
243
+ return {
244
+ success: false as const,
245
+ error: new Error(`Failed to load user ${id}`),
246
+ };
247
+ }
248
+
249
+ const user = MOCK_USERS[id];
250
+ if (!user) {
251
+
252
+ return {
253
+ success: false as const,
254
+ error: new Error(`User ${id} not found`),
255
+ };
256
+ }
257
+
258
+ return { success: true as const };
259
+ });
260
+
261
+ // Add successful users to facts
262
+ const successUsers = ids
263
+ .filter((id) => id !== failId && MOCK_USERS[id])
264
+ .map((id) => MOCK_USERS[id]!);
265
+
266
+ if (successUsers.length > 0) {
267
+ const existing = context.facts.users as UserProfile[];
268
+ context.facts.users = [...existing, ...successUsers];
269
+ }
270
+
271
+ // Remove all processed IDs from loading
272
+ const loadingIds = context.facts.loadingIds as number[];
273
+ context.facts.loadingIds = loadingIds.filter(
274
+ (lid: number) => !ids.includes(lid),
275
+ );
276
+
277
+ const successCount = results.filter((r) => r.success).length;
278
+ "success",
279
+ `batch resolved: ${successCount}/${ids.length} success`,
280
+ "success",
281
+ );
282
+
283
+ return results;
284
+ },
285
+ },
286
+ },
287
+ });
288
+
289
+ // ============================================================================
290
+ // System
291
+ // ============================================================================
292
+
293
+ const system = createSystem({
294
+ module: batchModule,
295
+ debug: { runHistory: true },
296
+ plugins: [devtoolsPlugin({ name: "batch-resolver" })],
297
+ });
298
+ system.start();
299
+
300
+ // ============================================================================
301
+ // DOM References
302
+ // ============================================================================
303
+
304
+ "bl-fail-item",
305
+
306
+ // ============================================================================
307
+ // Render
308
+ // ============================================================================
309
+
310
+ function escapeHtml(text: string): string {
311
+
312
+ return div.innerHTML;
313
+ }
314
+
315
+
316
+ // ============================================================================
317
+ // Subscribe
318
+ // ============================================================================
319
+
320
+ const allKeys = [
321
+ ...Object.keys(schema.facts),
322
+ ...Object.keys(schema.derivations),
323
+ ];
324
+ system.subscribe(allKeys, render);
325
+
326
+ // ============================================================================
327
+ // Controls
328
+ // ============================================================================
329
+
330
+ // Individual load buttons (1-5)
331
+ for (let i = 1; i <= 5; i++) {
332
+ system.events.loadUser({ id: i });
333
+ });
334
+ }
335
+
336
+
337
+ // ============================================================================
338
+ // Initial Render
339
+ // ============================================================================
340
+
341
+ render();