tidewave 0.4.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/dist/cli/index.js CHANGED
@@ -4007,12 +4007,12 @@ Module reference format:
4007
4007
 
4008
4008
  Examples:
4009
4009
  - src/types.ts:SymbolInfo (local file symbol)
4010
- - lodash:isEmpty (dependency function)
4010
+ - lodash:isEmpty (dependency function)
4011
4011
  - react:Component#render (instance method)
4012
4012
  - node:Math.max (builtin static method)`, docsInputSchema, sourceInputSchema, getLogsInputSchema, tools;
4013
4013
  var init_tools = __esm(() => {
4014
4014
  init_zod();
4015
- projectEvalDescription = `
4015
+ projectEvalDescription = `
4016
4016
  Evaluates JavaScript/TypeScript code in the context of the project.
4017
4017
 
4018
4018
  The current NodeJS version is: ${process.version}
@@ -4039,7 +4039,7 @@ Defaults to 30000 (30 seconds).`),
4039
4039
  reference: exports_external.string().describe(referenceDescription)
4040
4040
  });
4041
4041
  getLogsInputSchema = exports_external.object({
4042
- tail: exports_external.number().min(1).max(1e4).default(100).describe("Number of log entries to return from the end"),
4042
+ tail: exports_external.number().describe("Number of log entries to return from the end"),
4043
4043
  grep: exports_external.string().optional().describe("Filter logs with regex pattern (case insensitive)"),
4044
4044
  level: exports_external.enum(["DEBUG", "INFO", "WARN", "ERROR"]).optional().describe("Filter by log severity level"),
4045
4045
  since: exports_external.string().optional().describe("ISO 8601 timestamp - return logs after this time")
@@ -4924,12 +4924,12 @@ var init_src = __esm(() => {
4924
4924
  });
4925
4925
 
4926
4926
  // package.json
4927
- var name = "tidewave", version = "0.4.0", package_default;
4927
+ var name = "tidewave", version = "0.5.1", package_default;
4928
4928
  var init_package = __esm(() => {
4929
4929
  package_default = {
4930
4930
  name,
4931
4931
  version,
4932
- description: "Tidewave JavaScript CLI for documentation extraction and MCP server",
4932
+ description: "Tidewave for JavaScript/Next.js",
4933
4933
  keywords: [
4934
4934
  "typescript",
4935
4935
  "documentation",
@@ -4940,7 +4940,7 @@ var init_package = __esm(() => {
4940
4940
  homepage: "https://tidewave.ai",
4941
4941
  repository: {
4942
4942
  type: "git",
4943
- url: "git+https://github.com/dashbit/tidewave_javascript.git"
4943
+ url: "git+https://github.com/tidewave-ai/tidewave_js.git"
4944
4944
  },
4945
4945
  license: "Apache-2.0",
4946
4946
  author: "Dashbit",
@@ -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 chalk from "chalk";
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
- function chdir(path4) {
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(path4);
14957
+ process.chdir(path5);
14631
14958
  } catch (e) {
14632
- console.error(chalk.red(`Failed to apply given prefix: ${e}`));
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(chalk.red(`Error: ${docsResult.error.message}`));
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(chalk.red(`Error: ${sourceResult.error.message}`));
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);
@@ -0,0 +1,7 @@
1
+ interface InstallOptions {
2
+ prefix?: string;
3
+ dryRun?: boolean;
4
+ skipDeps?: boolean;
5
+ }
6
+ export declare function handleInstall(options: InstallOptions): Promise<void>;
7
+ export {};