tidewave 0.5.0 → 0.5.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/CHANGELOG.md +4 -50
- package/README.md +12 -8
- package/dist/cli/index.js +345 -17
- package/dist/cli/install.d.ts +7 -0
- package/dist/next-js/handler.js +438 -29
- package/dist/vite-plugin.js +438 -29
- package/package.json +4 -11
package/CHANGELOG.md
CHANGED
|
@@ -1,55 +1,9 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
## [0.5.1] - 2025-11-11
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
5
|
+
* Add `npx tidewave install` and trim down dependency list.
|
|
7
6
|
|
|
8
|
-
## [0.
|
|
7
|
+
## [0.5.0] - 2025-11-10
|
|
9
8
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
#### Core Features
|
|
13
|
-
- **MCP Server Support**: STDIO-based Model Context Protocol server for integration with AI coding assistants
|
|
14
|
-
- **Documentation Extraction**: Extract TypeScript/JavaScript documentation and type information for symbols, classes, functions, and methods
|
|
15
|
-
- **Source Location Resolution**: Get source file paths for modules, symbols, and members
|
|
16
|
-
- **Multi-format Support**: Support for local files, npm dependencies, and Node.js builtin modules
|
|
17
|
-
|
|
18
|
-
#### Module Reference Formats
|
|
19
|
-
- `module:symbol` - Extract documentation for top-level symbols
|
|
20
|
-
- `module:Class#method` - Extract documentation for instance methods
|
|
21
|
-
- `module:Class.method` - Extract documentation for static methods
|
|
22
|
-
- `node:Class#method` - Extract documentation for Node.js builtin instance methods
|
|
23
|
-
- `node:Class.method` - Extract documentation for Node.js builtin static methods
|
|
24
|
-
|
|
25
|
-
#### CLI Commands
|
|
26
|
-
- `tidewave mcp` - Start the MCP server via STDIO
|
|
27
|
-
- `tidewave docs <module-path>` - Extract documentation for a symbol
|
|
28
|
-
- `tidewave source <module>` - Get the source file path for a module
|
|
29
|
-
|
|
30
|
-
#### Runtime Support
|
|
31
|
-
- Full support for Node.js with npm/npx
|
|
32
|
-
- Native support for Bun with bunx
|
|
33
|
-
- Support for Deno via npm: protocol
|
|
34
|
-
|
|
35
|
-
### Fixed
|
|
36
|
-
- Handle source location of symbols and members correctly (#7)
|
|
37
|
-
- Handle prefix option only on CLI layer, not in core extraction (#6)
|
|
38
|
-
- Correctly extract JavaScript/TypeScript symbols, instances, and methods
|
|
39
|
-
- Show interface types correctly
|
|
40
|
-
- Handle falsy values and improve error handling (#1)
|
|
41
|
-
|
|
42
|
-
### Changed
|
|
43
|
-
- Refactored codebase into modular structure for better maintainability
|
|
44
|
-
- Simplified module resolution and extraction logic
|
|
45
|
-
- Improved TypeScript and Node.js module resolution
|
|
46
|
-
- Changed config flag for project path handling (#3)
|
|
47
|
-
|
|
48
|
-
### Technical Details
|
|
49
|
-
- Built with TypeScript for type safety
|
|
50
|
-
- Uses TypeScript Compiler API for accurate code analysis
|
|
51
|
-
- Supports ESM modules
|
|
52
|
-
- Includes comprehensive error handling and user-friendly error messages
|
|
53
|
-
- Optimized for use with AI coding assistants through MCP protocol
|
|
54
|
-
|
|
55
|
-
[0.1.0]: https://github.com/dashbit/tidewave_javascript/releases/tag/v0.1.0
|
|
9
|
+
* Initial release.
|
package/README.md
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
# Tidewave
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Tidewave is the coding agent for full-stack web app development. Integrate
|
|
4
|
+
Claude Code, OpenAI Codex, and other agents with your web app and web framework
|
|
5
|
+
at every layer, from UI to database. [See our website](https://tidewave.ai) for
|
|
6
|
+
more information.
|
|
4
7
|
|
|
5
|
-
|
|
6
|
-
[See our website](https://tidewave.ai) for more information.
|
|
8
|
+
This project supports:
|
|
7
9
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
10
|
+
- Next.js 15/16
|
|
11
|
+
|
|
12
|
+
- React + Vite frontends, with either a backend as a service (such as Supabase)
|
|
13
|
+
or a third-party framework
|
|
11
14
|
|
|
12
15
|
If you are using React with Django, FastAPI, Flask, Phoenix, or Rails,
|
|
13
16
|
[follow the steps here instead](http://hexdocs.pm/tidewave/react.html).
|
|
@@ -187,8 +190,9 @@ database calls, etc) won't be available.
|
|
|
187
190
|
Next.js' `tidewaveHandler` and Vite's `tidewave` accept the configuration
|
|
188
191
|
options below:
|
|
189
192
|
|
|
190
|
-
- `allow_remote_access:` allow remote connections when true (default false)
|
|
191
|
-
|
|
193
|
+
- `allow_remote_access:` allow remote connections when true (default false).
|
|
194
|
+
Enable this only if you trust your network and you want Tidewave MCP to be
|
|
195
|
+
accessed from another trusted machine
|
|
192
196
|
- `team`: enable Tidewave Web for teams
|
|
193
197
|
|
|
194
198
|
## CLI
|
package/dist/cli/index.js
CHANGED
|
@@ -4924,7 +4924,7 @@ var init_src = __esm(() => {
|
|
|
4924
4924
|
});
|
|
4925
4925
|
|
|
4926
4926
|
// package.json
|
|
4927
|
-
var name = "tidewave", version = "0.5.
|
|
4927
|
+
var name = "tidewave", version = "0.5.1", package_default;
|
|
4928
4928
|
var init_package = __esm(() => {
|
|
4929
4929
|
package_default = {
|
|
4930
4930
|
name,
|
|
@@ -4995,23 +4995,14 @@ var init_package = __esm(() => {
|
|
|
4995
4995
|
},
|
|
4996
4996
|
dependencies: {
|
|
4997
4997
|
"@modelcontextprotocol/sdk": "^1.17.4",
|
|
4998
|
-
"@opentelemetry/api": "^1.9.0",
|
|
4999
|
-
"@opentelemetry/api-logs": "^0.206.0",
|
|
5000
|
-
"@opentelemetry/core": "^2.1.0",
|
|
5001
|
-
"@opentelemetry/resources": "^2.1.0",
|
|
5002
|
-
"@opentelemetry/sdk-logs": "^0.206.0",
|
|
5003
|
-
"@opentelemetry/sdk-trace-base": "^2.1.0",
|
|
5004
|
-
"@opentelemetry/sdk-trace-node": "^2.1.0",
|
|
5005
|
-
"@opentelemetry/semantic-conventions": "^1.37.0",
|
|
5006
4998
|
"body-parser": "^2.2.0",
|
|
5007
|
-
chalk: "^5.3.0",
|
|
5008
|
-
commander: "^12.1.0",
|
|
5009
4999
|
connect: "^3.7.0",
|
|
5010
5000
|
typescript: "^5",
|
|
5011
5001
|
zod: "3.25.76"
|
|
5012
5002
|
},
|
|
5013
5003
|
devDependencies: {
|
|
5014
5004
|
"@eslint/js": "^9.16.0",
|
|
5005
|
+
"@opentelemetry/sdk-trace-node": "^2.1.0",
|
|
5015
5006
|
"@types/body-parser": "^1.19.6",
|
|
5016
5007
|
"@types/bun": "latest",
|
|
5017
5008
|
"@types/connect": "^3.4.38",
|
|
@@ -5021,6 +5012,8 @@ var init_package = __esm(() => {
|
|
|
5021
5012
|
"@vercel/otel": "^2.0.1",
|
|
5022
5013
|
"@vitest/ui": "^3.2.4",
|
|
5023
5014
|
"bun-types": "latest",
|
|
5015
|
+
commander: "^12.1.0",
|
|
5016
|
+
chalk: "^5.3.0",
|
|
5024
5017
|
eslint: "^9.16.0",
|
|
5025
5018
|
globals: "^15.14.0",
|
|
5026
5019
|
next: "^15.5.3",
|
|
@@ -14525,7 +14518,7 @@ init_tools();
|
|
|
14525
14518
|
init_src();
|
|
14526
14519
|
init_package();
|
|
14527
14520
|
import { program } from "commander";
|
|
14528
|
-
import
|
|
14521
|
+
import chalk2 from "chalk";
|
|
14529
14522
|
|
|
14530
14523
|
// node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js
|
|
14531
14524
|
import process2 from "node:process";
|
|
@@ -14625,11 +14618,345 @@ class StdioServerTransport {
|
|
|
14625
14618
|
|
|
14626
14619
|
// src/cli/index.ts
|
|
14627
14620
|
init_mcp2();
|
|
14628
|
-
|
|
14621
|
+
|
|
14622
|
+
// src/cli/install.ts
|
|
14623
|
+
import * as fs from "fs";
|
|
14624
|
+
import * as path4 from "path";
|
|
14625
|
+
import * as child_process from "child_process";
|
|
14626
|
+
import * as readline from "readline";
|
|
14627
|
+
import chalk from "chalk";
|
|
14628
|
+
async function handleInstall(options) {
|
|
14629
|
+
const targetDir = options.prefix || process.cwd();
|
|
14630
|
+
const dryRun = options.dryRun || false;
|
|
14631
|
+
const skipDeps = options.skipDeps || false;
|
|
14632
|
+
console.log(chalk.blue(`
|
|
14633
|
+
\uD83C\uDF0A Tidewave Installer
|
|
14634
|
+
`));
|
|
14635
|
+
console.log(chalk.gray(`Target directory: ${targetDir}`));
|
|
14636
|
+
if (dryRun) {
|
|
14637
|
+
console.log(chalk.yellow(`
|
|
14638
|
+
⚠️ DRY RUN MODE - No files will be created
|
|
14639
|
+
`));
|
|
14640
|
+
}
|
|
14641
|
+
const nextVersion = await detectNextJsVersion(targetDir);
|
|
14642
|
+
if (!nextVersion) {
|
|
14643
|
+
console.error(chalk.red(`
|
|
14644
|
+
❌ Could not find Next.js in node_modules.`));
|
|
14645
|
+
console.log(chalk.gray(`
|
|
14646
|
+
The installer only works for Next.js projects
|
|
14647
|
+
`));
|
|
14648
|
+
process.exit(1);
|
|
14649
|
+
}
|
|
14650
|
+
console.log(chalk.green(`✅ Detected Next.js ${nextVersion.raw} (v${nextVersion.major})`));
|
|
14651
|
+
if (!skipDeps) {
|
|
14652
|
+
await installDependencies(targetDir, dryRun);
|
|
14653
|
+
} else {
|
|
14654
|
+
console.log(chalk.gray("⏭️ Skipping dependency installation"));
|
|
14655
|
+
}
|
|
14656
|
+
const steps = [
|
|
14657
|
+
() => createApiHandler(targetDir, dryRun),
|
|
14658
|
+
() => createMiddleware(targetDir, nextVersion, dryRun),
|
|
14659
|
+
() => createInstrumentation(targetDir, dryRun)
|
|
14660
|
+
];
|
|
14661
|
+
for (const step of steps) {
|
|
14662
|
+
await step();
|
|
14663
|
+
}
|
|
14664
|
+
console.log(chalk.green(`
|
|
14665
|
+
✅ Tidewave setup complete!
|
|
14666
|
+
`));
|
|
14667
|
+
console.log(chalk.blue("Next steps:"));
|
|
14668
|
+
console.log(" 1. Start your Next.js dev server: npm run dev");
|
|
14669
|
+
console.log(" 2. Install the Tidewave app: https://hexdocs.pm/tidewave/");
|
|
14670
|
+
console.log(` 3. Connect to your app through Tidewave
|
|
14671
|
+
`);
|
|
14672
|
+
}
|
|
14673
|
+
async function detectNextJsVersion(dir) {
|
|
14674
|
+
try {
|
|
14675
|
+
const nextPackageJsonPath = path4.join(dir, "node_modules", "next", "package.json");
|
|
14676
|
+
if (!fs.existsSync(nextPackageJsonPath)) {
|
|
14677
|
+
return null;
|
|
14678
|
+
}
|
|
14679
|
+
const nextPackageJson = JSON.parse(fs.readFileSync(nextPackageJsonPath, "utf-8"));
|
|
14680
|
+
const { version: version2 } = nextPackageJson;
|
|
14681
|
+
const match = version2.match(/^(\d+)\.(\d+)\.(\d+)/);
|
|
14682
|
+
if (match) {
|
|
14683
|
+
return {
|
|
14684
|
+
major: parseInt(match[1]),
|
|
14685
|
+
minor: parseInt(match[2]),
|
|
14686
|
+
raw: version2
|
|
14687
|
+
};
|
|
14688
|
+
}
|
|
14689
|
+
return null;
|
|
14690
|
+
} catch {
|
|
14691
|
+
return null;
|
|
14692
|
+
}
|
|
14693
|
+
}
|
|
14694
|
+
function detectPackageManager(dir) {
|
|
14695
|
+
if (fs.existsSync(path4.join(dir, "bun.lockb")))
|
|
14696
|
+
return "bun";
|
|
14697
|
+
if (fs.existsSync(path4.join(dir, "pnpm-lock.yaml")))
|
|
14698
|
+
return "pnpm";
|
|
14699
|
+
if (fs.existsSync(path4.join(dir, "yarn.lock")))
|
|
14700
|
+
return "yarn";
|
|
14701
|
+
if (fs.existsSync(path4.join(dir, "package-lock.json")))
|
|
14702
|
+
return "npm";
|
|
14703
|
+
return "npm";
|
|
14704
|
+
}
|
|
14705
|
+
async function promptUser(question) {
|
|
14706
|
+
const rl = readline.createInterface({
|
|
14707
|
+
input: process.stdin,
|
|
14708
|
+
output: process.stdout
|
|
14709
|
+
});
|
|
14710
|
+
return new Promise((resolve) => {
|
|
14711
|
+
rl.question(question, (answer) => {
|
|
14712
|
+
rl.close();
|
|
14713
|
+
const normalized = answer.trim().toLowerCase();
|
|
14714
|
+
resolve(normalized === "" || normalized === "y" || normalized === "yes");
|
|
14715
|
+
});
|
|
14716
|
+
});
|
|
14717
|
+
}
|
|
14718
|
+
async function installDependencies(dir, dryRun) {
|
|
14719
|
+
console.log(chalk.yellow("\uD83D\uDCE6 Installing dependencies..."));
|
|
14720
|
+
if (dryRun) {
|
|
14721
|
+
console.log(chalk.gray("[DRY RUN] Would install: tidewave, @opentelemetry/sdk-node"));
|
|
14722
|
+
return;
|
|
14723
|
+
}
|
|
14724
|
+
const pm = detectPackageManager(dir);
|
|
14725
|
+
const devDepCommands = {
|
|
14726
|
+
npm: ["install", "-D", "tidewave"],
|
|
14727
|
+
yarn: ["add", "-D", "tidewave"],
|
|
14728
|
+
pnpm: ["add", "--save-dev", "tidewave"],
|
|
14729
|
+
bun: ["add", "--dev", "tidewave"]
|
|
14730
|
+
};
|
|
14731
|
+
const depCommands = {
|
|
14732
|
+
npm: ["install", "@opentelemetry/sdk-node"],
|
|
14733
|
+
yarn: ["add", "@opentelemetry/sdk-node"],
|
|
14734
|
+
pnpm: ["add", "@opentelemetry/sdk-node"],
|
|
14735
|
+
bun: ["add", "@opentelemetry/sdk-node"]
|
|
14736
|
+
};
|
|
14737
|
+
const devCmds = devDepCommands[pm];
|
|
14738
|
+
const depCmds = depCommands[pm];
|
|
14739
|
+
if (!devCmds || !depCmds) {
|
|
14740
|
+
console.error(chalk.red(`
|
|
14741
|
+
❌ Unknown package manager: ${pm}`));
|
|
14742
|
+
process.exit(1);
|
|
14743
|
+
}
|
|
14744
|
+
try {
|
|
14745
|
+
child_process.execSync(`${pm} ${devCmds.join(" ")}`, {
|
|
14746
|
+
cwd: dir,
|
|
14747
|
+
stdio: "inherit"
|
|
14748
|
+
});
|
|
14749
|
+
child_process.execSync(`${pm} ${depCmds.join(" ")}`, {
|
|
14750
|
+
cwd: dir,
|
|
14751
|
+
stdio: "inherit"
|
|
14752
|
+
});
|
|
14753
|
+
console.log(chalk.green("✅ Dependencies installed"));
|
|
14754
|
+
} catch (_error) {
|
|
14755
|
+
console.error(chalk.red(`
|
|
14756
|
+
❌ Failed to install dependencies`));
|
|
14757
|
+
console.log(chalk.gray(`
|
|
14758
|
+
Please install manually:
|
|
14759
|
+
${pm} ${devCmds.join(" ")}
|
|
14760
|
+
${pm} ${depCmds.join(" ")}
|
|
14761
|
+
`));
|
|
14762
|
+
process.exit(1);
|
|
14763
|
+
}
|
|
14764
|
+
}
|
|
14765
|
+
async function createApiHandler(dir, dryRun) {
|
|
14766
|
+
const apiDir = path4.join(dir, "pages", "api");
|
|
14767
|
+
const handlerPath = path4.join(apiDir, "tidewave.ts");
|
|
14768
|
+
const handlerContent = `import type { NextApiRequest, NextApiResponse } from 'next';
|
|
14769
|
+
|
|
14770
|
+
export default async function handler(
|
|
14771
|
+
req: NextApiRequest,
|
|
14772
|
+
res: NextApiResponse,
|
|
14773
|
+
) {
|
|
14774
|
+
if (process.env.NODE_ENV === 'development') {
|
|
14775
|
+
const { tidewaveHandler } = await import('tidewave/next-js/handler');
|
|
14776
|
+
const handler = await tidewaveHandler();
|
|
14777
|
+
return handler(req, res);
|
|
14778
|
+
} else {
|
|
14779
|
+
res.status(404).end();
|
|
14780
|
+
}
|
|
14781
|
+
}
|
|
14782
|
+
|
|
14783
|
+
export const config = {
|
|
14784
|
+
runtime: 'nodejs',
|
|
14785
|
+
api: {
|
|
14786
|
+
bodyParser: false, // Tidewave already parses the body internally
|
|
14787
|
+
},
|
|
14788
|
+
};
|
|
14789
|
+
`;
|
|
14790
|
+
if (fs.existsSync(handlerPath)) {
|
|
14791
|
+
if (dryRun) {
|
|
14792
|
+
console.log(chalk.gray(`[DRY RUN] Would ask to overwrite: ${path4.relative(dir, handlerPath)}`));
|
|
14793
|
+
return;
|
|
14794
|
+
}
|
|
14795
|
+
const shouldOverwrite = await promptUser(chalk.yellow(`
|
|
14796
|
+
⚠️ ${path4.relative(dir, handlerPath)} already exists. Overwrite? (Y/n): `));
|
|
14797
|
+
if (!shouldOverwrite) {
|
|
14798
|
+
console.log(chalk.gray(`⏭️ Skipping: ${path4.relative(dir, handlerPath)}`));
|
|
14799
|
+
return;
|
|
14800
|
+
}
|
|
14801
|
+
}
|
|
14802
|
+
if (dryRun) {
|
|
14803
|
+
console.log(chalk.gray(`[DRY RUN] Would create: ${path4.relative(dir, handlerPath)}`));
|
|
14804
|
+
return;
|
|
14805
|
+
}
|
|
14806
|
+
fs.mkdirSync(apiDir, { recursive: true });
|
|
14807
|
+
fs.writeFileSync(handlerPath, handlerContent, "utf-8");
|
|
14808
|
+
console.log(chalk.green(`✅ Created: ${path4.relative(dir, handlerPath)}`));
|
|
14809
|
+
}
|
|
14810
|
+
async function createMiddleware(dir, nextVersion, dryRun) {
|
|
14811
|
+
const isNext16Plus = nextVersion.major >= 16;
|
|
14812
|
+
const fileName = isNext16Plus ? "proxy.ts" : "middleware.ts";
|
|
14813
|
+
const filePath = path4.join(dir, fileName);
|
|
14814
|
+
if (fs.existsSync(filePath)) {
|
|
14815
|
+
console.log(chalk.yellow(`⏭️ ${fileName} already exists`));
|
|
14816
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
14817
|
+
if (content.includes("/tidewave") && content.includes("/api/tidewave")) {
|
|
14818
|
+
console.log(chalk.green(`✅ ${fileName} already configured for Tidewave`));
|
|
14819
|
+
return;
|
|
14820
|
+
}
|
|
14821
|
+
console.log(chalk.gray(`
|
|
14822
|
+
Please manually add the following to your ${fileName}:
|
|
14823
|
+
`));
|
|
14824
|
+
printMiddlewareInstructions(isNext16Plus);
|
|
14825
|
+
return;
|
|
14826
|
+
}
|
|
14827
|
+
const middlewareContent = isNext16Plus ? `import { NextRequest, NextResponse } from 'next/server';
|
|
14828
|
+
|
|
14829
|
+
export function proxy(req: NextRequest): NextResponse {
|
|
14830
|
+
if (req.nextUrl.pathname.startsWith('/tidewave')) {
|
|
14831
|
+
return NextResponse.rewrite(new URL('/api/tidewave', req.url));
|
|
14832
|
+
}
|
|
14833
|
+
|
|
14834
|
+
// Here you could add your own logic or different middlewares.
|
|
14835
|
+
return NextResponse.next();
|
|
14836
|
+
}
|
|
14837
|
+
` : `import { NextRequest, NextResponse } from 'next/server';
|
|
14838
|
+
|
|
14839
|
+
export function middleware(req: NextRequest): NextResponse {
|
|
14840
|
+
if (req.nextUrl.pathname.startsWith('/tidewave')) {
|
|
14841
|
+
return NextResponse.rewrite(new URL('/api/tidewave', req.url));
|
|
14842
|
+
}
|
|
14843
|
+
|
|
14844
|
+
// Here you could add your own logic or different middlewares.
|
|
14845
|
+
return NextResponse.next();
|
|
14846
|
+
}
|
|
14847
|
+
|
|
14848
|
+
export const config = {
|
|
14849
|
+
matcher: ['/tidewave/:path*'],
|
|
14850
|
+
};
|
|
14851
|
+
`;
|
|
14852
|
+
if (dryRun) {
|
|
14853
|
+
console.log(chalk.gray(`[DRY RUN] Would create: ${fileName}`));
|
|
14854
|
+
return;
|
|
14855
|
+
}
|
|
14856
|
+
fs.writeFileSync(filePath, middlewareContent, "utf-8");
|
|
14857
|
+
console.log(chalk.green(`✅ Created: ${fileName}`));
|
|
14858
|
+
}
|
|
14859
|
+
function printMiddlewareInstructions(isNext16Plus) {
|
|
14860
|
+
if (isNext16Plus) {
|
|
14861
|
+
console.log(chalk.cyan(` if (req.nextUrl.pathname.startsWith('/tidewave')) {
|
|
14862
|
+
return NextResponse.rewrite(new URL('/api/tidewave', req.url));
|
|
14863
|
+
}`));
|
|
14864
|
+
} else {
|
|
14865
|
+
console.log(chalk.cyan(` if (req.nextUrl.pathname.startsWith('/tidewave')) {
|
|
14866
|
+
return NextResponse.rewrite(new URL('/api/tidewave', req.url));
|
|
14867
|
+
}
|
|
14868
|
+
|
|
14869
|
+
// Also add to config.matcher:
|
|
14870
|
+
export const config = {
|
|
14871
|
+
matcher: ['/tidewave/:path*'],
|
|
14872
|
+
};`));
|
|
14873
|
+
}
|
|
14874
|
+
console.log();
|
|
14875
|
+
}
|
|
14876
|
+
async function createInstrumentation(dir, dryRun) {
|
|
14877
|
+
const rootPath = path4.join(dir, "instrumentation.ts");
|
|
14878
|
+
const srcPath = path4.join(dir, "src", "instrumentation.ts");
|
|
14879
|
+
const hasSrcDir = fs.existsSync(path4.join(dir, "src"));
|
|
14880
|
+
const instrumentationPath = hasSrcDir ? srcPath : rootPath;
|
|
14881
|
+
if (fs.existsSync(rootPath) || fs.existsSync(srcPath)) {
|
|
14882
|
+
const existingPath = fs.existsSync(rootPath) ? rootPath : srcPath;
|
|
14883
|
+
const existingFile = fs.existsSync(rootPath) ? "instrumentation.ts" : "src/instrumentation.ts";
|
|
14884
|
+
console.log(chalk.yellow(`⏭️ ${existingFile} already exists`));
|
|
14885
|
+
const content = fs.readFileSync(existingPath, "utf-8");
|
|
14886
|
+
if (content.includes("TidewaveSpanProcessor") && content.includes("TidewaveLogRecordProcessor")) {
|
|
14887
|
+
console.log(chalk.green(`✅ ${existingFile} already configured for Tidewave`));
|
|
14888
|
+
return;
|
|
14889
|
+
}
|
|
14890
|
+
console.log(chalk.gray(`
|
|
14891
|
+
Please manually add the following to your instrumentation.ts:
|
|
14892
|
+
`));
|
|
14893
|
+
printInstrumentationInstructions();
|
|
14894
|
+
return;
|
|
14895
|
+
}
|
|
14896
|
+
const instrumentationContent = `// instrumentation.ts
|
|
14897
|
+
import { NodeSDK } from '@opentelemetry/sdk-node';
|
|
14898
|
+
import type { SpanProcessor } from '@opentelemetry/sdk-trace-base';
|
|
14899
|
+
import type { LogRecordProcessor } from '@opentelemetry/sdk-logs';
|
|
14900
|
+
|
|
14901
|
+
export async function register() {
|
|
14902
|
+
const runtime = process.env.NEXT_RUNTIME;
|
|
14903
|
+
const env = process.env.NODE_ENV;
|
|
14904
|
+
|
|
14905
|
+
// Add your app own processes here existing configuration
|
|
14906
|
+
const sdkConfig: {
|
|
14907
|
+
spanProcessors: SpanProcessor[];
|
|
14908
|
+
logRecordProcessors: LogRecordProcessor[];
|
|
14909
|
+
} = {
|
|
14910
|
+
spanProcessors: [],
|
|
14911
|
+
logRecordProcessors: [],
|
|
14912
|
+
};
|
|
14913
|
+
|
|
14914
|
+
// Conditionally add Tidewave processors in development
|
|
14915
|
+
if (runtime === 'nodejs' && env === 'development') {
|
|
14916
|
+
const { TidewaveSpanProcessor, TidewaveLogRecordProcessor } = await import(
|
|
14917
|
+
'tidewave/next-js/instrumentation'
|
|
14918
|
+
);
|
|
14919
|
+
|
|
14920
|
+
sdkConfig.spanProcessors.push(new TidewaveSpanProcessor());
|
|
14921
|
+
sdkConfig.logRecordProcessors.push(new TidewaveLogRecordProcessor());
|
|
14922
|
+
}
|
|
14923
|
+
|
|
14924
|
+
const sdk = new NodeSDK(sdkConfig);
|
|
14925
|
+
sdk.start();
|
|
14926
|
+
}
|
|
14927
|
+
`;
|
|
14928
|
+
if (dryRun) {
|
|
14929
|
+
console.log(chalk.gray(`[DRY RUN] Would create: ${path4.relative(dir, instrumentationPath)}`));
|
|
14930
|
+
return;
|
|
14931
|
+
}
|
|
14932
|
+
if (hasSrcDir) {
|
|
14933
|
+
fs.mkdirSync(path4.dirname(instrumentationPath), { recursive: true });
|
|
14934
|
+
}
|
|
14935
|
+
fs.writeFileSync(instrumentationPath, instrumentationContent, "utf-8");
|
|
14936
|
+
console.log(chalk.green(`✅ Created: ${path4.relative(dir, instrumentationPath)}`));
|
|
14937
|
+
}
|
|
14938
|
+
function printInstrumentationInstructions() {
|
|
14939
|
+
console.log(chalk.cyan(` // Inside your register() function:
|
|
14940
|
+
const runtime = process.env.NEXT_RUNTIME;
|
|
14941
|
+
const env = process.env.NODE_ENV;
|
|
14942
|
+
|
|
14943
|
+
if (runtime === 'nodejs' && env === 'development') {
|
|
14944
|
+
const { TidewaveSpanProcessor, TidewaveLogRecordProcessor } = await import(
|
|
14945
|
+
'tidewave/next-js/instrumentation'
|
|
14946
|
+
);
|
|
14947
|
+
|
|
14948
|
+
sdkConfig.spanProcessors.push(new TidewaveSpanProcessor());
|
|
14949
|
+
sdkConfig.logRecordProcessors.push(new TidewaveLogRecordProcessor());
|
|
14950
|
+
}`));
|
|
14951
|
+
console.log();
|
|
14952
|
+
}
|
|
14953
|
+
|
|
14954
|
+
// src/cli/index.ts
|
|
14955
|
+
function chdir(path5) {
|
|
14629
14956
|
try {
|
|
14630
|
-
process.chdir(
|
|
14957
|
+
process.chdir(path5);
|
|
14631
14958
|
} catch (e) {
|
|
14632
|
-
console.error(
|
|
14959
|
+
console.error(chalk2.red(`Failed to apply given prefix: ${e}`));
|
|
14633
14960
|
}
|
|
14634
14961
|
}
|
|
14635
14962
|
program.name(name).description("Universal documentation and source extraction tool for TypeScript and JavaScript").version(version);
|
|
@@ -14638,7 +14965,7 @@ async function handleGetDocs2(modulePath, options) {
|
|
|
14638
14965
|
chdir(options.prefix);
|
|
14639
14966
|
const docsResult = await Tidewave.extractDocs(modulePath);
|
|
14640
14967
|
if (isExtractError(docsResult)) {
|
|
14641
|
-
console.error(
|
|
14968
|
+
console.error(chalk2.red(`Error: ${docsResult.error.message}`));
|
|
14642
14969
|
process.exit(1);
|
|
14643
14970
|
}
|
|
14644
14971
|
if (options.json) {
|
|
@@ -14652,7 +14979,7 @@ async function handleGetSourcePath2(moduleName, options) {
|
|
|
14652
14979
|
chdir(options.prefix);
|
|
14653
14980
|
const sourceResult = await Tidewave.getSourceLocation(moduleName);
|
|
14654
14981
|
if (isResolveError(sourceResult)) {
|
|
14655
|
-
console.error(
|
|
14982
|
+
console.error(chalk2.red(`Error: ${sourceResult.error.message}`));
|
|
14656
14983
|
process.exit(1);
|
|
14657
14984
|
}
|
|
14658
14985
|
console.log(sourceResult.path);
|
|
@@ -14668,6 +14995,7 @@ var {
|
|
|
14668
14995
|
docs: { cli: docsCli },
|
|
14669
14996
|
source: { cli: sourceCli }
|
|
14670
14997
|
} = tools;
|
|
14998
|
+
program.command("install").description("Install Tidewave in a Next.js project").option("--prefix <path>", "Specify the directory containing package.json").option("--dry-run", "Preview changes without creating files").action(handleInstall);
|
|
14671
14999
|
program.command("mcp").description("Starts a MCP server for tidewave (stdio)").option(docsCli.options.prefix.flag, docsCli.options.prefix.desc).action(handleMcp);
|
|
14672
15000
|
program.command(docsCli.command).description(docsCli.description).argument(docsCli.argument, docsCli.argumentDescription).option(docsCli.options.prefix.flag, docsCli.options.prefix.desc).option(docsCli.options.json.flag, docsCli.options.json.desc).action(handleGetDocs2);
|
|
14673
15001
|
program.command(sourceCli.command).description(sourceCli.description).argument(sourceCli.argument, sourceCli.argumentDescription).option(sourceCli.options.prefix.flag, sourceCli.options.prefix.desc).action(handleGetSourcePath2);
|