@cognite/dune 0.2.0 → 0.2.2

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.
@@ -1,5 +1,5 @@
1
1
  ---
2
- to: <%= name %>/biome.json
2
+ to: '<%= useCurrentDir ? "" : ((directoryName || name) + "/") %>biome.json'
3
3
  ---
4
4
  {
5
5
  "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
@@ -1,5 +1,5 @@
1
1
  ---
2
- to: <%= name %>/components.json
2
+ to: '<%= useCurrentDir ? "" : ((directoryName || name) + "/") %>components.json'
3
3
  ---
4
4
  {
5
5
  "$schema": "https://ui.shadcn.com/schema.json",
@@ -1,5 +1,5 @@
1
1
  ---
2
- to: <%= name %>/tailwind.config.js
2
+ to: '<%= useCurrentDir ? "" : ((directoryName || name) + "/") %>tailwind.config.js'
3
3
  ---
4
4
  /** @type {import('tailwindcss').Config} */
5
5
  export default {
@@ -1,5 +1,5 @@
1
1
  ---
2
- to: <%= name %>/tsconfig.json
2
+ to: '<%= useCurrentDir ? "" : ((directoryName || name) + "/") %>tsconfig.json'
3
3
  ---
4
4
  {
5
5
  "compilerOptions": {
@@ -1,5 +1,5 @@
1
1
  ---
2
- to: <%= name %>/tsconfig.node.json
2
+ to: '<%= useCurrentDir ? "" : ((directoryName || name) + "/") %>tsconfig.node.json'
3
3
  ---
4
4
  {
5
5
  "compilerOptions": {
@@ -1,5 +1,5 @@
1
1
  ---
2
- to: <%= name %>/vite.config.ts
2
+ to: '<%= useCurrentDir ? "" : ((directoryName || name) + "/") %>vite.config.ts'
3
3
  ---
4
4
  import path from "node:path";
5
5
  import react from "@vitejs/plugin-react";
@@ -18,7 +18,7 @@ export default defineConfig({
18
18
  },
19
19
  },
20
20
  server: {
21
- port: 3000,
21
+ port: 3001,
22
22
  },
23
23
  worker: {
24
24
  format: "es",
@@ -1,5 +1,5 @@
1
1
  ---
2
- to: <%= name %>/vitest.config.ts
2
+ to: '<%= useCurrentDir ? "" : ((directoryName || name) + "/") %>vitest.config.ts'
3
3
  ---
4
4
  import react from "@vitejs/plugin-react";
5
5
  import { defineConfig } from "vitest/config";
@@ -1,5 +1,5 @@
1
1
  ---
2
- to: <%= name %>/vitest.setup.ts
2
+ to: '<%= useCurrentDir ? "" : ((directoryName || name) + "/") %>vitest.setup.ts'
3
3
  ---
4
4
  import "@testing-library/jest-dom/vitest";
5
5
 
@@ -1,5 +1,5 @@
1
1
  ---
2
- to: <%= name %>/.cursor/data-modeling.mdc
2
+ to: '<%= useCurrentDir ? "" : ((directoryName || name) + "/") %>.cursor/rules/data-modeling.mdc'
3
3
  ---
4
4
  ---
5
5
  alwaysApply: true
@@ -1992,3 +1992,5 @@ This example demonstrates:
1992
1992
  - Validate data before upserting
1993
1993
  - Log errors with context for debugging
1994
1994
 
1995
+
1996
+
@@ -1,5 +1,5 @@
1
1
  ---
2
- to: <%= name %>/.cursor/mcp.json
2
+ to: '<%= useCurrentDir ? "" : ((directoryName || name) + "/") %>.cursor/mcp.json'
3
3
  ---
4
4
  {
5
5
  "mcpServers": {
@@ -1,5 +1,5 @@
1
1
  ---
2
- to: <%= name %>/.cursor/rules.mdc
2
+ to: '<%= useCurrentDir ? "" : ((directoryName || name) + "/") %>.cursor/rules/rules.mdc'
3
3
  ---
4
4
  ---
5
5
  description: Describes global rules
@@ -1,5 +1,5 @@
1
1
  ---
2
- to: <%= name %>/PRD.md
2
+ to: '<%= useCurrentDir ? "" : ((directoryName || name) + "/") %>PRD.md'
3
3
  ---
4
4
 
5
5
  Add your product requirements here, or ask AI to collaborate on this file with you.
@@ -1,5 +1,5 @@
1
1
  ---
2
- to: <%= name %>/app.json
2
+ to: '<%= useCurrentDir ? "" : ((directoryName || name) + "/") %>app.json'
3
3
  ---
4
4
  {
5
5
  "name": "<%= displayName %>",
@@ -1,5 +1,5 @@
1
1
  ---
2
- to: <%= name %>/.gitignore
2
+ to: '<%= useCurrentDir ? "" : ((directoryName || name) + "/") %>.gitignore'
3
3
  ---
4
4
  # Dependencies
5
5
  node_modules
@@ -1,5 +1,5 @@
1
1
  ---
2
- to: <%= name %>/index.html
2
+ to: '<%= useCurrentDir ? "" : ((directoryName || name) + "/") %>index.html'
3
3
  ---
4
4
  <!DOCTYPE html>
5
5
  <html lang="en">
@@ -1,11 +1,12 @@
1
1
  ---
2
- to: <%= name %>/package.json
2
+ to: '<%= useCurrentDir ? "" : ((directoryName || name) + "/") %>package.json'
3
3
  ---
4
4
  {
5
5
  "name": "<%= name %>",
6
6
  "version": "0.0.0",
7
7
  "private": true,
8
8
  "type": "module",
9
+ "packageManager": "pnpm@10.26.2+sha512.0e308ff2005fc7410366f154f625f6631ab2b16b1d2e70238444dd6ae9d630a8482d92a451144debc492416896ed16f7b114a86ec68b8404b2443869e68ffda6",
9
10
  "scripts": {
10
11
  "start": "vite",
11
12
  "dev": "vite",
@@ -21,7 +22,7 @@ to: <%= name %>/package.json
21
22
  },
22
23
  "dependencies": {
23
24
  "@cognite/sdk": "^10.3.0",
24
- "@cognite/dune": "^0.1.2",
25
+ "@cognite/dune": "^0.2.2",
25
26
  "@tanstack/react-query": "^5.90.10",
26
27
  "clsx": "^2.1.1",
27
28
  "react": "^19.2.0",
@@ -1,5 +1,5 @@
1
1
  ---
2
- to: <%= name %>/src/App.test.tsx
2
+ to: '<%= useCurrentDir ? "" : ((directoryName || name) + "/") %>src/App.test.tsx'
3
3
  ---
4
4
  import * as duneAuth from "@cognite/dune";
5
5
  import { render, screen } from "@testing-library/react";
@@ -1,5 +1,5 @@
1
1
  ---
2
- to: <%= name %>/src/App.tsx
2
+ to: '<%= useCurrentDir ? "" : ((directoryName || name) + "/") %>src/App.tsx'
3
3
  ---
4
4
  import { useDune } from "@cognite/dune";
5
5
 
@@ -1,5 +1,5 @@
1
1
  ---
2
- to: <%= name %>/src/lib/utils.ts
2
+ to: '<%= useCurrentDir ? "" : ((directoryName || name) + "/") %>src/lib/utils.ts'
3
3
  ---
4
4
  import { type ClassValue, clsx } from "clsx";
5
5
  import { twMerge } from "tailwind-merge";
@@ -1,5 +1,5 @@
1
1
  ---
2
- to: <%= name %>/src/main.tsx
2
+ to: '<%= useCurrentDir ? "" : ((directoryName || name) + "/") %>src/main.tsx'
3
3
  ---
4
4
  import { DuneAuthProvider } from "@cognite/dune";
5
5
  import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
@@ -1,5 +1,5 @@
1
1
  ---
2
- to: <%= name %>/src/styles.css
2
+ to: '<%= useCurrentDir ? "" : ((directoryName || name) + "/") %>src/styles.css'
3
3
  ---
4
4
  @import "tailwindcss";
5
5
 
package/bin/cli.js CHANGED
@@ -1,17 +1,97 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import { dirname, resolve } from "node:path";
3
+ import { basename, dirname, normalize, resolve } from "node:path";
4
4
  import { fileURLToPath } from "node:url";
5
5
  import { Logger, runner } from "hygen";
6
6
 
7
7
  const defaultTemplates = resolve(dirname(fileURLToPath(import.meta.url)), "..", "_templates");
8
8
 
9
+ /**
10
+ * Creates a prompter function for hygen that handles useCurrentDir logic
11
+ * @param {boolean} isCurrentDir - Whether to create app in current directory
12
+ * @param {string|null} dirName - Directory name if creating in a subdirectory
13
+ * @param {object} enquirer - The enquirer module
14
+ * @param {Function} onAppName - Callback to track the app name
15
+ * @returns {() => object} Function that returns a prompter object with prompt method
16
+ */
17
+ export function createAppPrompter(isCurrentDir, dirName, enquirer, onAppName) {
18
+ // IMPORTANT: All code paths below must set useCurrentDir (true or false) because
19
+ // templates rely on it being defined. It's never undefined.
20
+ return () => ({
21
+ prompt: async (prompts) => {
22
+ // If using current directory, pre-fill the name with current directory name
23
+ if (isCurrentDir) {
24
+ const currentDirName = basename(process.cwd());
25
+ const modifiedPrompts = prompts.map((p) => {
26
+ if (p.name === "name") {
27
+ return {
28
+ ...p,
29
+ initial: currentDirName,
30
+ };
31
+ }
32
+ return p;
33
+ });
34
+ const result = await enquirer.default.prompt(modifiedPrompts);
35
+ if (result.name && onAppName) {
36
+ onAppName(result.name);
37
+ }
38
+ // Add useCurrentDir variable for templates
39
+ return { ...result, useCurrentDir: true, directoryName: undefined };
40
+ }
41
+ // If directory argument is provided, pre-fill the name prompt with directory name
42
+ if (dirName) {
43
+ // Pre-fill the name prompt with directory name (user can change it)
44
+ const modifiedPrompts = prompts.map((p) => {
45
+ if (p.name === "name") {
46
+ return {
47
+ ...p,
48
+ initial: dirName,
49
+ };
50
+ }
51
+ return p;
52
+ });
53
+ const result = await enquirer.default.prompt(modifiedPrompts);
54
+ if (result.name && onAppName) {
55
+ onAppName(result.name);
56
+ }
57
+ // Pass directoryName for folder structure, name for template content
58
+ return { ...result, directoryName: dirName, useCurrentDir: false };
59
+ }
60
+ const result = await enquirer.default.prompt(prompts);
61
+ if (result.name && onAppName) {
62
+ onAppName(result.name);
63
+ }
64
+ // No directory provided, so directoryName is undefined (templates will use name)
65
+ return { ...result, useCurrentDir: false, directoryName: undefined };
66
+ },
67
+ });
68
+ }
69
+
9
70
  async function main() {
10
71
  const args = process.argv.slice(2);
11
72
  const command = args[0];
12
73
 
13
74
  // Handle different commands
14
- if (command === "create" || command === "new" || !command) {
75
+ if (command === "create" || command === "new" || !command || command === ".") {
76
+ // Parse directory argument
77
+ // Support: npx @cognite/dune create . or npx @cognite/dune .
78
+ let dirArg;
79
+ if (command === ".") {
80
+ // If first arg is ".", treat it as directory argument with no command
81
+ dirArg = ".";
82
+ } else if (command === "create" || command === "new") {
83
+ dirArg = args[1];
84
+ }
85
+ // When !command: no args, dirArg stays undefined (create app interactively)
86
+ const isCurrentDir = dirArg === "." || dirArg === "./";
87
+
88
+ // Extract directory name from path (handles ./test-folder -> test-folder)
89
+ let dirName = null;
90
+ if (dirArg && !isCurrentDir) {
91
+ // Normalize the path and extract just the directory name
92
+ dirName = basename(normalize(dirArg));
93
+ }
94
+
15
95
  // Run the app generator
16
96
  const hygenArgs = ["app", "new"];
17
97
 
@@ -25,18 +105,9 @@ async function main() {
25
105
  templates: defaultTemplates,
26
106
  cwd: process.cwd(),
27
107
  logger: new Logger(console.log.bind(console)),
28
- createPrompter: () => {
29
- // Wrap enquirer to capture the app name
30
- return {
31
- prompt: async (prompts) => {
32
- const result = await enquirer.default.prompt(prompts);
33
- if (result.name) {
34
- appName = result.name;
35
- }
36
- return result;
37
- },
38
- };
39
- },
108
+ createPrompter: createAppPrompter(isCurrentDir, dirName, enquirer, (name) => {
109
+ appName = name;
110
+ }),
40
111
  exec: async (action, body) => {
41
112
  const { execa } = await import("execa");
42
113
  const opts = body && body.length > 0 ? { input: body } : {};
@@ -46,20 +117,36 @@ async function main() {
46
117
  });
47
118
 
48
119
  // Print success message with next steps
49
- console.log(`
120
+ const installAndDevSteps = " pnpm install\n pnpm dev";
121
+ const deployLabel = "To deploy your app:";
122
+ const deployCommand = "npx @cognite/dune deploy:interactive";
123
+
124
+ if (isCurrentDir) {
125
+ console.log(`
126
+ ✅ App created successfully in current directory!
127
+
128
+ Next steps:
129
+ ${installAndDevSteps}
130
+
131
+ ${deployLabel}
132
+ ${deployCommand}
133
+ `);
134
+ } else {
135
+ const appDir = appName || "your-app";
136
+ console.log(`
50
137
  ✅ App created successfully!
51
138
 
52
139
  To open in Cursor:
53
- cursor ${appName || "your-app"}
140
+ cursor ${appDir}
54
141
  Or:
55
- cd ${appName || "your-app"}
56
- pnpm install
57
- pnpm dev
142
+ cd ${appDir}
143
+ ${installAndDevSteps}
58
144
 
59
- To deploy your app:
60
- cd ${appName || "your-app"}
61
- npx @cognite/dune deploy:interactive
145
+ ${deployLabel}
146
+ cd ${appDir}
147
+ ${deployCommand}
62
148
  `);
149
+ }
63
150
  } catch (error) {
64
151
  console.error("Error:", error.message);
65
152
  process.exit(1);
@@ -75,7 +162,7 @@ To deploy your app:
75
162
  @cognite/dune - Build and deploy React apps to Cognite Data Fusion
76
163
 
77
164
  Usage:
78
- npx @cognite/dune [command]
165
+ npx @cognite/dune [command] [directory]
79
166
 
80
167
  Commands:
81
168
  create, new Create a new Dune application (default)
@@ -86,6 +173,8 @@ Commands:
86
173
  Examples:
87
174
  npx @cognite/dune # Create a new app (interactive)
88
175
  npx @cognite/dune create # Create a new app (interactive)
176
+ npx @cognite/dune create [directory] # Create app in [directory] subfolder
177
+ npx @cognite/dune create . # Create app in current directory (. is special)
89
178
  npx @cognite/dune deploy # Deploy with env credentials
90
179
  npx @cognite/dune deploy:interactive # Deploy with browser login
91
180
 
@@ -16,7 +16,7 @@ var fusionOpenPlugin = () => {
16
16
  configureServer(server) {
17
17
  server.httpServer?.on("listening", () => {
18
18
  const address = server.httpServer?.address();
19
- const port = address && typeof address === "object" ? address.port : 3e3;
19
+ const port = address && typeof address === "object" ? address.port : 3001;
20
20
  const appJsonPath = path.join(process.cwd(), "app.json");
21
21
  if (fs.existsSync(appJsonPath)) {
22
22
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cognite/dune",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "Build and deploy React apps to Cognite Data Fusion",
5
5
  "keywords": [
6
6
  "cognite",
@@ -50,7 +50,11 @@
50
50
  "dune": "./bin/cli.js"
51
51
  },
52
52
  "files": [
53
- "bin",
53
+ "bin/cli.js",
54
+ "bin/deploy-command.js",
55
+ "bin/deploy-interactive-command.js",
56
+ "bin/auth",
57
+ "bin/utils",
54
58
  "dist",
55
59
  "src",
56
60
  "_templates"
@@ -87,12 +91,15 @@
87
91
  "react": "^19.2.0",
88
92
  "react-dom": "^19.2.0",
89
93
  "tsup": "^8.4.0",
90
- "typescript": "^5.0.0"
94
+ "typescript": "^5.0.0",
95
+ "vitest": "^2.1.8"
91
96
  },
92
97
  "engines": {
93
98
  "node": ">=18"
94
99
  },
95
100
  "scripts": {
96
- "build": "tsup"
101
+ "build": "tsup",
102
+ "test": "vitest run",
103
+ "test:watch": "vitest"
97
104
  }
98
105
  }
@@ -25,7 +25,7 @@ export const fusionOpenPlugin = () => {
25
25
  configureServer(server: ViteDevServer) {
26
26
  server.httpServer?.on("listening", () => {
27
27
  const address = server.httpServer?.address();
28
- const port = address && typeof address === "object" ? address.port : 3000;
28
+ const port = address && typeof address === "object" ? address.port : 3001;
29
29
 
30
30
  const appJsonPath = path.join(process.cwd(), "app.json");
31
31
  if (fs.existsSync(appJsonPath)) {