@ranimontagna/agent-toolkit 0.1.10 → 0.1.12

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.
@@ -0,0 +1,559 @@
1
+ # Constraints & Gotchas
2
+
3
+ Critical constraints and common pitfalls when developing in the Astro monorepo.
4
+
5
+ ## Node.js API Restrictions
6
+
7
+ **MOST IMPORTANT CONSTRAINT**
8
+
9
+ ### The Rule (Conservative Approach)
10
+
11
+ **Location**: `/CONTRIBUTING.md:84-98`
12
+
13
+ Code in `packages/astro` has restricted Node.js API usage because Astro runs in multiple runtimes (Node.js, Cloudflare Workers, Deno, edge runtimes).
14
+
15
+ **Safe decision rule:**
16
+
17
+ ```
18
+ 1. In Vite plugin implementations → Node.js APIs allowed
19
+ 2. In /runtime/ folders → Node.js APIs FORBIDDEN
20
+ 3. Everywhere else → Avoid Node.js APIs, use @astrojs/internal-helpers
21
+ ```
22
+
23
+ **Reality**: The codebase is messy. Not all code follows clear boundaries. The safest approach is to avoid Node.js APIs unless you're in a Vite plugin.
24
+
25
+ ### Where Node.js APIs Are ABSOLUTELY FORBIDDEN
26
+
27
+ **Pattern** (enforced by Biome linter):
28
+
29
+ 1. Any file in a `runtime/` folder: `**/packages/astro/src/**/runtime/**/*.ts`
30
+ 2. Any file with `runtime` in its name: `**/packages/astro/src/**/*runtime*.ts`
31
+
32
+ **Examples of forbidden locations**:
33
+
34
+ - `packages/astro/src/runtime/server/` → FORBIDDEN (runtime folder)
35
+ - `packages/astro/src/runtime/client/` → FORBIDDEN (runtime folder)
36
+ - `packages/astro/src/vite-plugin-astro/runtime.ts` → FORBIDDEN (runtime in name)
37
+ - `packages/astro/src/core/render/runtime-utils.ts` → FORBIDDEN (runtime in name)
38
+
39
+ **Forbidden APIs**:
40
+
41
+ ```typescript
42
+ // FORBIDDEN in runtime/ folders or *runtime*.ts files
43
+ import fs from 'node:fs';
44
+ import path from 'node:path';
45
+ import { Buffer } from 'node:buffer';
46
+ import process from 'node:process';
47
+ import crypto from 'node:crypto';
48
+ // etc.
49
+ ```
50
+
51
+ **Enforcement**: Biome linter rule `noNodejsModules` prevents this at lint time.
52
+
53
+ ### Where Node.js APIs Are SAFE
54
+
55
+ **Vite Plugin Implementations**: Node.js APIs are safe in Vite plugins
56
+
57
+ **Locations**:
58
+
59
+ - `packages/astro/src/vite-plugin-*/` → Safe for Node.js APIs
60
+ - `packages/astro/src/cli/` → Safe for Node.js APIs
61
+ - Test files → Safe for Node.js APIs
62
+
63
+ **Mixed/Unclear locations**:
64
+
65
+ - `packages/astro/src/core/` → Mixed (contains both build-time and runtime code)
66
+
67
+ **Safe approach for core/**:
68
+
69
+ ```typescript
70
+ // AVOID in core/ unless in Vite plugin
71
+ import fs from 'node:fs';
72
+
73
+ // PREFER cross-platform utilities
74
+ import { fileURLToPath } from '@astrojs/internal-helpers/path';
75
+ ```
76
+
77
+ ### Special Case: Vite Plugins
78
+
79
+ **CAN use Node.js APIs**: In the plugin implementation itself
80
+
81
+ ```typescript
82
+ // ALLOWED
83
+ export function myVitePlugin() {
84
+ return {
85
+ name: 'my-plugin',
86
+ load: {
87
+ filter: {
88
+ id: /\.astro$/,
89
+ },
90
+ async handler(id) {
91
+ // Can use Node.js APIs here
92
+ const fs = await import('node:fs/promises');
93
+ const content = await fs.readFile(id, 'utf-8');
94
+ return { code: content };
95
+ },
96
+ },
97
+ };
98
+ }
99
+ ```
100
+
101
+ **CANNOT use Node.js APIs**: In virtual modules returned by plugins
102
+
103
+ ```typescript
104
+ // FORBIDDEN
105
+ export function myVitePlugin() {
106
+ return {
107
+ name: 'my-plugin',
108
+ load: {
109
+ filter: {
110
+ id: new RegExp(`^\\0virtual:my-module$`),
111
+ },
112
+ handler() {
113
+ // This code runs in runtime/server context
114
+ return {
115
+ code: `
116
+ import fs from 'node:fs'; // FORBIDDEN
117
+ export const data = fs.readFileSync('/data.json');
118
+ `,
119
+ };
120
+ },
121
+ },
122
+ };
123
+ }
124
+ ```
125
+
126
+ ### Critical: NonRunnableDevEnvironment
127
+
128
+ **Important**: Some adapters (like Cloudflare) set Vite's `NonRunnableDevEnvironment`, which imposes limitations on what Vite plugins can do.
129
+
130
+ **Limitation**: Vite plugins execute, but certain operations are restricted. For example, you cannot use `runner.import()` in this environment.
131
+
132
+ **Implication**: While Vite plugins still run their hooks (transform, load, etc.), they may not have access to all runtime capabilities. Code must work with these limitations.
133
+
134
+ **Rule**: Write code that doesn't depend on full Vite runtime capabilities. This is why runtime-agnostic code is essential.
135
+
136
+ ### Why This Matters
137
+
138
+ **Multi-runtime support**: Astro code must run in:
139
+
140
+ - Node.js (traditional hosting)
141
+ - Cloudflare Workers (V8 isolates)
142
+ - Deno (alternative runtime)
143
+ - Edge runtimes (limited APIs)
144
+
145
+ **Implication**: Most code must be platform-agnostic.
146
+
147
+ **Reality**: The codebase doesn't have perfect separation yet. When in doubt, avoid Node.js APIs and use cross-platform utilities from `@astrojs/internal-helpers`.
148
+
149
+ ### How to Handle This
150
+
151
+ #### Pattern 1: Use Cross-Platform Utilities
152
+
153
+ Use `@astrojs/internal-helpers` instead of Node.js APIs:
154
+
155
+ ```typescript
156
+ // BAD: Direct Node.js API
157
+ import { resolve } from 'node:path';
158
+ const fullPath = resolve('./config.json');
159
+
160
+ // GOOD: Cross-platform utility
161
+ import { fileURLToPath } from '@astrojs/internal-helpers/path';
162
+ const fullPath = fileURLToPath(new URL('./config.json', import.meta.url));
163
+ ```
164
+
165
+ #### Pattern 2: Vite Plugin for File Operations
166
+
167
+ If you need file operations, do them in a Vite plugin:
168
+
169
+ ```typescript
170
+ // GOOD: In Vite plugin implementation
171
+ export function myVitePlugin() {
172
+ return {
173
+ name: 'my-plugin',
174
+ load: {
175
+ filter: {
176
+ id: /\.config\.js$/,
177
+ },
178
+ async handler(id) {
179
+ // Safe to use Node.js APIs here
180
+ const fs = await import('node:fs/promises');
181
+ const content = await fs.readFile(id, 'utf-8');
182
+ return { code: content };
183
+ },
184
+ },
185
+ };
186
+ }
187
+ ```
188
+
189
+ #### Pattern 3: Build-Time Data Generation
190
+
191
+ Generate data at build time via Vite plugin, embed in virtual module:
192
+
193
+ ```typescript
194
+ // Vite plugin - safe to use Node.js APIs
195
+ const VIRTUAL_MODULE_ID = 'virtual:my-config';
196
+ const RESOLVED_VIRTUAL_MODULE_ID = '\0' + VIRTUAL_MODULE_ID;
197
+
198
+ export function myVitePlugin() {
199
+ return {
200
+ name: 'my-plugin',
201
+ resolveId: {
202
+ filter: {
203
+ id: new RegExp(`^${VIRTUAL_MODULE_ID}$`),
204
+ },
205
+ handler() {
206
+ return RESOLVED_VIRTUAL_MODULE_ID;
207
+ },
208
+ },
209
+ load: {
210
+ filter: {
211
+ id: new RegExp(`^${RESOLVED_VIRTUAL_MODULE_ID}$`),
212
+ },
213
+ async handler() {
214
+ // Read at build time (safe here)
215
+ const fs = await import('node:fs/promises');
216
+ const config = JSON.parse(await fs.readFile('./config.json', 'utf-8'));
217
+ // Embed in generated code (no Node.js APIs in output)
218
+ return {
219
+ code: `export default ${JSON.stringify(config)}`,
220
+ };
221
+ },
222
+ },
223
+ };
224
+ }
225
+ ```
226
+
227
+ ### Detection
228
+
229
+ **Error message**: If you violate this, you'll typically see:
230
+
231
+ - `ReferenceError: fs is not defined`
232
+ - `ReferenceError: process is not defined`
233
+ - Build succeeds but runtime fails in edge environments
234
+
235
+ **Prevention**: Code review, test in multiple environments
236
+
237
+ ## Test Isolation Requirements
238
+
239
+ **Every test fixture MUST have a unique `outDir`** to avoid cache pollution between tests.
240
+
241
+ **Why**: Build artifacts are cached and shared via ESM between test runs.
242
+
243
+ **Reference**: See [testing.md](testing.md) for detailed explanation, examples, and detection strategies.
244
+
245
+ ## Circular Dependencies
246
+
247
+ ### The Problem
248
+
249
+ TypeScript circular dependencies can cause:
250
+
251
+ - Undefined exports at runtime
252
+ - Type resolution issues
253
+ - Build failures
254
+
255
+ ### Where It Happens
256
+
257
+ Most commonly in type imports.
258
+
259
+ ### The Solution
260
+
261
+ **Types are centralized**: `packages/astro/src/types/`
262
+
263
+ ```typescript
264
+ // BAD: Import type from implementation
265
+ import type { AstroConfig } from '../config/index.js';
266
+
267
+ // GOOD: Import type from types/
268
+ import type { AstroConfig } from '../types/public.js';
269
+ ```
270
+
271
+ ### Prevention
272
+
273
+ - Import types from `types/` directory
274
+ - Avoid importing implementation files for types
275
+ - Use `import type` (not `import`) for type-only imports
276
+
277
+ ## Virtual Module Conventions
278
+
279
+ **Constraint**: New virtual modules must use `virtual:astro:*` prefix (not `@astro-page:*` which is legacy).
280
+
281
+ **Why**: Standard convention, avoids conflicts, follows Rollup/Vite patterns.
282
+
283
+ **Reference**: See [architecture.md](architecture.md) for virtual module registry, implementation patterns, and detailed conventions.
284
+
285
+ ## Build vs Runtime Boundaries
286
+
287
+ ### The Separation
288
+
289
+ Code must respect execution boundaries:
290
+
291
+ | Context | Location | When Runs | Node APIs |
292
+ | -------------- | ----------------- | ----------------- | --------- |
293
+ | Build | `core/` | `astro build` | Yes |
294
+ | Dev | `core/` | `astro dev` setup | Yes |
295
+ | Runtime Server | `runtime/server/` | SSR rendering | No |
296
+ | Runtime Client | `runtime/client/` | Browser | No |
297
+
298
+ ### Common Violation
299
+
300
+ ```typescript
301
+ // BAD: Runtime code importing build code
302
+ // In runtime/server/render.ts
303
+ import { buildSomething } from '../../core/build/utils.js';
304
+ ```
305
+
306
+ **Why bad**: Runtime shouldn't depend on build-time code. Creates coupling and increases bundle size.
307
+
308
+ ### Correct Pattern
309
+
310
+ ```typescript
311
+ // GOOD: Data flows from build to runtime via manifest
312
+ // Build time (core/build/)
313
+ const manifest = {
314
+ routes: processedRoutes,
315
+ config: runtimeConfig,
316
+ };
317
+
318
+ // Runtime (runtime/server/)
319
+ import { manifest } from 'virtual:astro:manifest';
320
+ ```
321
+
322
+ ## Package Boundaries
323
+
324
+ ### Workspace Dependencies
325
+
326
+ Test fixtures and examples MUST use workspace dependencies:
327
+
328
+ ```json
329
+ // GOOD: fixture package.json
330
+ {
331
+ "dependencies": {
332
+ "astro": "workspace:*",
333
+ "@astrojs/react": "workspace:*"
334
+ }
335
+ }
336
+ ```
337
+
338
+ ```json
339
+ // BAD: specific versions
340
+ {
341
+ "dependencies": {
342
+ "astro": "^4.0.0",
343
+ "@astrojs/react": "^3.0.0"
344
+ }
345
+ }
346
+ ```
347
+
348
+ ### Why
349
+
350
+ - Links to local packages during development
351
+ - Automatically uses latest local code
352
+ - Prevents version mismatches
353
+
354
+ ### Catalog Dependencies
355
+
356
+ For external packages, use catalog when available:
357
+
358
+ ```json
359
+ {
360
+ "dependencies": {
361
+ "astro": "workspace:*",
362
+ "react": "catalog:",
363
+ "react-dom": "catalog:"
364
+ }
365
+ }
366
+ ```
367
+
368
+ **Catalog location**: Root `package.json`
369
+
370
+ ## Changeset Requirements
371
+
372
+ ### When Required
373
+
374
+ **Required for**:
375
+
376
+ - All packages in `packages/`
377
+ - Any user-facing changes
378
+
379
+ **NOT required for**:
380
+
381
+ - Examples in `examples/`
382
+ - Test fixtures
383
+ - Documentation only changes
384
+ - Internal refactors with no API changes
385
+
386
+ ### Prerelease Mode
387
+
388
+ **Current state**: Repository in prerelease mode (check `.changeset/config.json`)
389
+
390
+ ```json
391
+ {
392
+ "baseBranch": "origin/next"
393
+ }
394
+ ```
395
+
396
+ **Implication**: Changes go to `next` release, not `latest`
397
+
398
+ ### Creating Changeset
399
+
400
+ ```bash
401
+ pnpm exec changeset
402
+ ```
403
+
404
+ Select packages and describe changes.
405
+
406
+ ## Performance Constraints
407
+
408
+ ### Build Cache
409
+
410
+ **Shared cache**: Build artifacts cached in `.astro/` and `dist/`
411
+
412
+ **Implication**:
413
+
414
+ - Tests must use unique `outDir`
415
+ - Manual cache clear may be needed
416
+ - Cache can speed up but also cause issues
417
+
418
+ ### Content Layer Concurrency
419
+
420
+ **Location**: `packages/astro/src/content/content-layer.ts`
421
+
422
+ **Pattern**: Uses PQueue with concurrency: 1
423
+
424
+ ```typescript
425
+ const queue = new PQueue({ concurrency: 1 });
426
+ ```
427
+
428
+ **Implication**: Loaders run sequentially, not in parallel
429
+
430
+ **Reason**: Prevents race conditions in data store
431
+
432
+ ### Memory Constraints
433
+
434
+ **Large sites**: May hit memory limits during build
435
+
436
+ **Mitigation**:
437
+
438
+ ```bash
439
+ node --max-old-space-size=4096 node_modules/.bin/astro build
440
+ ```
441
+
442
+ ## Debugging Constraints
443
+
444
+ ### Cannot Use Interactive Commands
445
+
446
+ **Forbidden in CI**:
447
+
448
+ ```bash
449
+ # BAD: Interactive
450
+ git rebase -i
451
+ git add -i
452
+ ```
453
+
454
+ **Reason**: No TTY in CI environment
455
+
456
+ ### Log Levels
457
+
458
+ **Production**: Don't log verbosely by default
459
+
460
+ ```typescript
461
+ // BAD: Always logs
462
+ console.log('Processing file:', file);
463
+
464
+ // GOOD: Use logger with levels
465
+ logger.debug('Processing file:', file);
466
+ ```
467
+
468
+ ## Common Gotchas
469
+
470
+ ### 1. File Paths in Tests
471
+
472
+ ```typescript
473
+ // BAD: Relative to cwd
474
+ const fixture = await loadFixture({
475
+ root: 'fixtures/my-test/',
476
+ });
477
+
478
+ // GOOD: Relative to test file
479
+ const fixture = await loadFixture({
480
+ root: './fixtures/my-test/',
481
+ });
482
+ ```
483
+
484
+ ### 2. Async/Await in Hooks
485
+
486
+ ```typescript
487
+ // BAD: Forgetting await
488
+ before(async () => {
489
+ fixture.build(); // Missing await
490
+ });
491
+
492
+ // GOOD: Proper await
493
+ before(async () => {
494
+ await fixture.build();
495
+ });
496
+ ```
497
+
498
+ ### 3. Server Cleanup
499
+
500
+ ```typescript
501
+ // BAD: Server not stopped
502
+ describe('dev', () => {
503
+ before(async () => {
504
+ devServer = await fixture.startDevServer();
505
+ });
506
+ // Missing after() hook
507
+ });
508
+
509
+ // GOOD: Always cleanup
510
+ describe('dev', () => {
511
+ before(async () => {
512
+ devServer = await fixture.startDevServer();
513
+ });
514
+ after(async () => {
515
+ await devServer.stop();
516
+ });
517
+ });
518
+ ```
519
+
520
+ ### 4. Type Imports
521
+
522
+ ```typescript
523
+ // BAD: Runtime import for types
524
+ import { AstroConfig } from 'astro';
525
+
526
+ // GOOD: Type-only import
527
+ import type { AstroConfig } from 'astro';
528
+ ```
529
+
530
+ ### 5. Module Resolution
531
+
532
+ ```typescript
533
+ // BAD: May fail in different contexts
534
+ import helper from '../utils';
535
+
536
+ // GOOD: Explicit extension
537
+ import helper from '../utils.js';
538
+ ```
539
+
540
+ ## Constraint Checklist
541
+
542
+ Before submitting code, verify:
543
+
544
+ - [ ] No Node.js APIs in `runtime/` code
545
+ - [ ] Tests have unique `outDir`
546
+ - [ ] No circular dependencies
547
+ - [ ] Virtual modules follow naming conventions
548
+ - [ ] Workspace dependencies in fixtures
549
+ - [ ] Changeset created (if needed)
550
+ - [ ] Servers cleaned up in tests
551
+ - [ ] Type imports use `import type`
552
+ - [ ] File extensions explicit (`.js`)
553
+
554
+ ## Further Reading
555
+
556
+ - CONTRIBUTING.md: Node.js API restrictions (lines 84-98)
557
+ - CONTRIBUTING.md: Test isolation (lines 203-214)
558
+ - architecture.md: Execution contexts
559
+ - testing.md: Test patterns