@cognite/dune 0.3.6 → 0.4.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.
@@ -1,6 +1,7 @@
1
1
  ---
2
2
  to: '<%= useCurrentDir ? "" : ((directoryName || name) + "/") %>eslint.config.mjs'
3
3
  ---
4
+ import { auraEslintPlugin } from '@cognite/aura/eslint';
4
5
  import js from '@eslint/js';
5
6
  import importPlugin from 'eslint-plugin-import';
6
7
  import noOnlyTestsPlugin from 'eslint-plugin-no-only-tests';
@@ -80,6 +81,7 @@ export default tseslint.config(
80
81
  },
81
82
  },
82
83
  plugins: {
84
+ aura: auraEslintPlugin,
83
85
  'react-hooks': reactHooks,
84
86
  'react-refresh': reactRefresh,
85
87
  },
@@ -89,6 +91,7 @@ export default tseslint.config(
89
91
  '@typescript-eslint/no-explicit-any': 'error',
90
92
  '@typescript-eslint/no-non-null-assertion': 'off',
91
93
  '@typescript-eslint/no-unused-vars': ['error', noUnusedVarsOptions],
94
+ 'aura/no-overriding-styles': 'warn',
92
95
  'no-unused-vars': 'off',
93
96
  'react-refresh/only-export-components': ['error', { allowConstantExport: true }],
94
97
  },
@@ -6,6 +6,9 @@ to: '<%= useCurrentDir ? "" : ((directoryName || name) + "/") %>app.json'
6
6
  "description": "<%= description %>",
7
7
  "externalId": "<%= name %>",
8
8
  "versionTag": "0.0.1",
9
+ <% if (infra === 'appsApi') { -%>
10
+ "infra": "appsApi",
11
+ <% } -%>
9
12
  "deployments": [
10
13
  {
11
14
  "org": "<%= org %>",
@@ -21,9 +21,9 @@ to: '<%= useCurrentDir ? "" : ((directoryName || name) + "/") %>package.json'
21
21
  "deploy-preview": "dune deploy:interactive"
22
22
  },
23
23
  "dependencies": {
24
- "@cognite/aura": "^0.1.4",
24
+ "@cognite/aura": "^0.1.5",
25
25
  "@cognite/sdk": "^10.3.0",
26
- "@cognite/dune": "^0.3.6",
26
+ "@cognite/dune": "^0.3.7",
27
27
  "@tabler/icons-react": "^3.35.0",
28
28
  "@tanstack/react-query": "^5.90.10",
29
29
  "clsx": "^2.1.1",
@@ -61,7 +61,21 @@ const CHECKLIST_STEPS = [
61
61
  ] as const;
62
62
 
63
63
  function App() {
64
- const { sdk, isLoading } = useDune();
64
+ const { sdk, isLoading, error } = useDune();
65
+
66
+ if (error) {
67
+ return (
68
+ <main className="min-h-screen bg-muted/50 text-foreground">
69
+ <section className="mx-auto flex min-h-screen w-full max-w-lg flex-col justify-center p-4 sm:p-8">
70
+ <div className="mx-auto w-full max-w-sm">
71
+ <Alert variant="destructive" aria-label="Authentication error" aria-live="assertive">
72
+ <AlertDescription>{error}</AlertDescription>
73
+ </Alert>
74
+ </div>
75
+ </section>
76
+ </main>
77
+ );
78
+ }
65
79
 
66
80
  if (isLoading) {
67
81
  return (
@@ -92,8 +106,8 @@ function App() {
92
106
  <Card>
93
107
  <div className="p-15 gap-16">
94
108
  <CardHeader>
95
- <CardTitle as="h1" className="text-4xl">Welcome to Dune</CardTitle>
96
- <CardDescription className="text-xl">{INTRO_COPY}</CardDescription>
109
+ <CardTitle as="h1">Welcome to Dune</CardTitle>
110
+ <CardDescription>{INTRO_COPY}</CardDescription>
97
111
  </CardHeader>
98
112
 
99
113
  <CardContent>
@@ -119,34 +133,36 @@ function App() {
119
133
  </span>
120
134
  </div>
121
135
  </CollapsibleTrigger>
122
- <CollapsibleContent className="py-2">
123
- {step.body}
136
+ <CollapsibleContent>
137
+ <div className="py-2">{step.body}</div>
124
138
  </CollapsibleContent>
125
139
  </Collapsible>
126
140
  ))}
127
141
  </div>
128
142
 
129
- <Alert className="bg-mountain-50 mb-10">
130
- <AlertDescription>
131
- <div className="flex flex-wrap items-center gap-2 text-lg">
132
- <span>Your app will deploy to</span>
133
- {orgLabel ? (
134
- <>
135
- <span>org</span>
136
- <Badge variant="nordic" background>
137
- {orgLabel}
138
- </Badge>
139
- <span>and project</span>
140
- </>
141
- ) : (
142
- <span>project</span>
143
- )}
144
- <Badge variant="nordic" background>
145
- {projectLabel}
146
- </Badge>
147
- </div>
148
- </AlertDescription>
149
- </Alert>
143
+ <div className="mb-10">
144
+ <Alert variant="secondary">
145
+ <AlertDescription>
146
+ <div className="flex flex-wrap items-center gap-2 text-lg">
147
+ <span>Your app will deploy to</span>
148
+ {orgLabel ? (
149
+ <>
150
+ <span>org</span>
151
+ <Badge variant="nordic" background>
152
+ {orgLabel}
153
+ </Badge>
154
+ <span>and project</span>
155
+ </>
156
+ ) : (
157
+ <span>project</span>
158
+ )}
159
+ <Badge variant="nordic" background>
160
+ {projectLabel}
161
+ </Badge>
162
+ </div>
163
+ </AlertDescription>
164
+ </Alert>
165
+ </div>
150
166
 
151
167
  <Collapsible>
152
168
  <CollapsibleTrigger className="w-full">
@@ -160,20 +176,22 @@ function App() {
160
176
  </span>
161
177
  </div>
162
178
  </CollapsibleTrigger>
163
- <CollapsibleContent className="py-2">
164
- <p>
165
- For additional support and feedback, please head to{' '}
166
- <a
167
- href={DUNE_DOCUMENTATION_HREF}
168
- rel="noreferrer"
169
- style={{ color: '#486AED' }}
170
- target="_blank"
171
- >
172
- Dune documentation
173
- </a>{' '}
174
- or the{' '}
175
- <span style={{ color: '#486AED' }}>#Dune Slack channel</span>.
176
- </p>
179
+ <CollapsibleContent>
180
+ <div className="py-2">
181
+ <p>
182
+ For additional support and feedback, please head to{' '}
183
+ <a
184
+ href={DUNE_DOCUMENTATION_HREF}
185
+ rel="noreferrer"
186
+ style={{ color: '#486AED' }}
187
+ target="_blank"
188
+ >
189
+ Dune documentation
190
+ </a>{' '}
191
+ or the{' '}
192
+ <span style={{ color: '#486AED' }}>#Dune Slack channel</span>.
193
+ </p>
194
+ </div>
177
195
  </CollapsibleContent>
178
196
  </Collapsible>
179
197
  </div>
@@ -1,7 +1,11 @@
1
1
  ---
2
2
  to: '<%= useCurrentDir ? "" : ((directoryName || name) + "/") %>src/main.tsx'
3
3
  ---
4
+ <% if (infra === 'appsApi') { -%>
5
+ import { AppSdkAuthProvider } from '@cognite/dune';
6
+ <% } else { -%>
4
7
  import { DuneAuthProvider } from '@cognite/dune';
8
+ <% } -%>
5
9
  import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
6
10
  import React from 'react';
7
11
  import ReactDOM from 'react-dom/client';
@@ -22,9 +26,15 @@ const queryClient = new QueryClient({
22
26
  ReactDOM.createRoot(document.getElementById('root')!).render(
23
27
  <React.StrictMode>
24
28
  <QueryClientProvider client={queryClient}>
29
+ <% if (infra === 'appsApi') { -%>
30
+ <AppSdkAuthProvider>
31
+ <App />
32
+ </AppSdkAuthProvider>
33
+ <% } else { -%>
25
34
  <DuneAuthProvider>
26
35
  <App />
27
36
  </DuneAuthProvider>
37
+ <% } -%>
28
38
  </QueryClientProvider>
29
39
  </React.StrictMode>
30
40
  );
package/bin/cli.js CHANGED
@@ -31,7 +31,7 @@ const defaultTemplates = resolve(dirname(fileURLToPath(import.meta.url)), '..',
31
31
  * @param {Function} onAppName - Callback to track the app name
32
32
  * @returns {() => object} Function that returns a prompter object with prompt method
33
33
  */
34
- export function createAppPrompter(isCurrentDir, dirName, enquirer, onAppName) {
34
+ export function createAppPrompter(isCurrentDir, dirName, enquirer, onAppName, infra) {
35
35
  // IMPORTANT: All code paths below must set useCurrentDir (true or false) because
36
36
  // templates rely on it being defined. It's never undefined.
37
37
  return () => ({
@@ -52,8 +52,7 @@ export function createAppPrompter(isCurrentDir, dirName, enquirer, onAppName) {
52
52
  if (result.name && onAppName) {
53
53
  onAppName(result.name);
54
54
  }
55
- // Add useCurrentDir variable for templates
56
- return { ...result, useCurrentDir: true, directoryName: undefined };
55
+ return { ...result, useCurrentDir: true, directoryName: undefined, infra };
57
56
  }
58
57
  // If directory argument is provided, pre-fill the name prompt with directory name
59
58
  if (dirName) {
@@ -71,15 +70,13 @@ export function createAppPrompter(isCurrentDir, dirName, enquirer, onAppName) {
71
70
  if (result.name && onAppName) {
72
71
  onAppName(result.name);
73
72
  }
74
- // Pass directoryName for folder structure, name for template content
75
- return { ...result, directoryName: dirName, useCurrentDir: false };
73
+ return { ...result, directoryName: dirName, useCurrentDir: false, infra };
76
74
  }
77
75
  const result = await enquirer.default.prompt(prompts);
78
76
  if (result.name && onAppName) {
79
77
  onAppName(result.name);
80
78
  }
81
- // No directory provided, so directoryName is undefined (templates will use name)
82
- return { ...result, useCurrentDir: false, directoryName: undefined };
79
+ return { ...result, useCurrentDir: false, directoryName: undefined, infra };
83
80
  },
84
81
  });
85
82
  }
@@ -93,12 +90,15 @@ async function main() {
93
90
  // TODO(DUNE-362): simplify directory resolution logic
94
91
  // Parse directory argument
95
92
  // Support: npx @cognite/dune create . or npx @cognite/dune .
93
+ const useNewInfra = args.includes('--newinfra');
94
+ const filteredArgs = args.filter((a) => a !== '--newinfra');
95
+ const infra = useNewInfra ? 'appsApi' : undefined;
96
+
96
97
  let dirArg;
97
98
  if (command === '.') {
98
- // If first arg is ".", treat it as directory argument with no command
99
99
  dirArg = '.';
100
100
  } else if (command === 'create' || command === 'new') {
101
- dirArg = args[1];
101
+ dirArg = filteredArgs[1];
102
102
  }
103
103
  // When !command: no args, dirArg stays undefined (create app interactively)
104
104
  const isCurrentDir = dirArg === '.' || dirArg === './';
@@ -125,7 +125,7 @@ async function main() {
125
125
  logger: new Logger(console.log.bind(console)),
126
126
  createPrompter: createAppPrompter(isCurrentDir, dirName, enquirer, (name) => {
127
127
  appName = name;
128
- }),
128
+ }, infra),
129
129
  exec: async (action, body) => {
130
130
  const { execa } = await import('execa');
131
131
  const opts = body && body.length > 0 ? { input: body } : {};
@@ -210,14 +210,18 @@ Commands:
210
210
  skills Manage AI agent skills (pull, push, list)
211
211
  help Show this help message
212
212
 
213
+ Options:
214
+ --newinfra Use the new App Hosting infrastructure (create only)
215
+
213
216
  Examples:
214
- npx @cognite/dune # Create a new app (interactive)
215
- npx @cognite/dune create # Create a new app (interactive)
216
- npx @cognite/dune create [directory] # Create app in [directory] subfolder
217
- npx @cognite/dune create . # Create app in current directory (. is special)
218
- npx @cognite/dune deploy # Deploy with env credentials
219
- npx @cognite/dune deploy:interactive # Deploy with browser login
220
- npx @cognite/dune skills pull # Pull AI skills into your project
217
+ npx @cognite/dune # Create a new app (interactive)
218
+ npx @cognite/dune create # Create a new app (interactive)
219
+ npx @cognite/dune create --newinfra # Create app using new App Hosting infra
220
+ npx @cognite/dune create [directory] # Create app in [directory] subfolder
221
+ npx @cognite/dune create . # Create app in current directory (. is special)
222
+ npx @cognite/dune deploy # Deploy with env credentials
223
+ npx @cognite/dune deploy:interactive # Deploy with browser login
224
+ npx @cognite/dune skills pull # Pull AI skills into your project
221
225
 
222
226
  For programmatic usage:
223
227
  import { DuneAuthProvider, useDune } from "@cognite/dune/auth"
@@ -2,19 +2,7 @@ import { execSync } from 'node:child_process';
2
2
  import { existsSync, readFileSync } from 'node:fs';
3
3
  import { resolve } from 'node:path';
4
4
 
5
- /**
6
- * Generate Fusion app URL
7
- */
8
- function generateFusionUrl(deployment, appExternalId, versionTag) {
9
- const { org, project, baseUrl } = deployment;
10
- const cluster = baseUrl?.split('//')[1];
11
-
12
- if (!org || !project || !cluster) {
13
- return null;
14
- }
15
-
16
- return `https://${org}.fusion.cognite.com/${project}/streamlit-apps/dune/${appExternalId}-${versionTag}?cluster=${cluster}&workspace=industrial-tools`;
17
- }
5
+ import { generateFusionUrl } from './utils/fusion-url.js';
18
6
 
19
7
  /**
20
8
  * Load app.json from a directory
@@ -214,6 +202,7 @@ export async function handleDeploy(args) {
214
202
  name: appConfig.name,
215
203
  description: appConfig.description,
216
204
  versionTag: appConfig.versionTag,
205
+ infra: appConfig.infra,
217
206
  },
218
207
  cwd
219
208
  );
@@ -229,7 +218,7 @@ export async function handleDeploy(args) {
229
218
  }
230
219
 
231
220
  // Generate and display the app URL
232
- const appUrl = generateFusionUrl(deployment, appConfig.externalId, appConfig.versionTag);
221
+ const appUrl = generateFusionUrl(deployment, appConfig.externalId, appConfig.versionTag, appConfig.infra);
233
222
  if (appUrl) {
234
223
  console.log(`\n🔗 Open your app:\n ${appUrl}`);
235
224
  }
@@ -10,20 +10,7 @@ import os from 'node:os';
10
10
  import path, { resolve } from 'node:path';
11
11
 
12
12
  import { AuthenticationFlow } from './auth/authentication-flow.js';
13
-
14
- /**
15
- * Generate Fusion app URL
16
- */
17
- function generateFusionUrl(deployment, appExternalId, versionTag) {
18
- const { org, project, baseUrl } = deployment;
19
- const cluster = baseUrl?.split('//')[1];
20
-
21
- if (!org || !project || !cluster) {
22
- return null;
23
- }
24
-
25
- return `https://${org}.fusion.cognite.com/${project}/streamlit-apps/dune/${appExternalId}-${versionTag}?cluster=${cluster}&workspace=industrial-tools`;
26
- }
13
+ import { generateFusionUrl } from './utils/fusion-url.js';
27
14
 
28
15
  // Default OAuth configuration for CDF
29
16
  const DEFAULT_CONFIG = {
@@ -324,40 +311,52 @@ export async function handleDeployInteractive(args) {
324
311
  console.log('\n✅ Authentication successful!');
325
312
  console.log(`\n📤 Deploying to ${deployment.project}...`);
326
313
 
327
- // Import CogniteClient and deployer classes
328
- const { CogniteClient } = await import('@cognite/sdk');
329
- const { CdfApplicationDeployer, ApplicationPackager } = await import('../dist/deploy/index.js');
330
-
331
- // Create SDK with the obtained token
332
- const sdk = new CogniteClient({
333
- appId: appConfig.externalId,
334
- project: deployment.project,
335
- baseUrl: deployment.baseUrl,
336
- getToken: async () => tokens.access_token,
337
- });
338
- await sdk.authenticate();
314
+ const { ApplicationPackager } = await import('../dist/deploy/index.js');
339
315
 
340
316
  // Package the application
341
317
  const distPath = `${cwd}/dist`;
342
318
  const packager = new ApplicationPackager(distPath);
343
319
  const zipFilename = await packager.createZip('app.zip', true);
344
320
 
345
- // Deploy to CDF
346
- const deployer = new CdfApplicationDeployer(sdk);
347
- await deployer.deploy(
348
- appConfig.externalId,
349
- appConfig.name,
350
- appConfig.description,
351
- appConfig.versionTag,
352
- zipFilename,
353
- deployment.published
354
- );
355
-
356
- // Clean up zip file
357
321
  try {
358
- unlinkSync(zipFilename);
359
- } catch {
360
- // Ignore cleanup errors
322
+ const { CogniteClient } = await import('@cognite/sdk');
323
+ const sdk = new CogniteClient({
324
+ appId: appConfig.externalId,
325
+ project: deployment.project,
326
+ baseUrl: deployment.baseUrl,
327
+ getToken: async () => tokens.access_token,
328
+ });
329
+ await sdk.authenticate();
330
+
331
+ if (appConfig.infra === 'appsApi') {
332
+ const { AppHostingDeployer } = await import('../dist/deploy/index.js');
333
+ const deployer = new AppHostingDeployer(sdk);
334
+ await deployer.deploy(
335
+ appConfig.externalId,
336
+ appConfig.name,
337
+ appConfig.description,
338
+ appConfig.versionTag,
339
+ zipFilename,
340
+ deployment.published || published,
341
+ );
342
+ } else {
343
+ const { CdfApplicationDeployer } = await import('../dist/deploy/index.js');
344
+ const deployer = new CdfApplicationDeployer(sdk);
345
+ await deployer.deploy(
346
+ appConfig.externalId,
347
+ appConfig.name,
348
+ appConfig.description,
349
+ appConfig.versionTag,
350
+ zipFilename,
351
+ deployment.published || published,
352
+ );
353
+ }
354
+ } finally {
355
+ try {
356
+ unlinkSync(zipFilename);
357
+ } catch {
358
+ // Ignore cleanup errors
359
+ }
361
360
  }
362
361
 
363
362
  console.log(`\n✅ Successfully deployed ${appConfig.name} to ${deployment.project}`);
@@ -369,7 +368,7 @@ export async function handleDeployInteractive(args) {
369
368
  }
370
369
 
371
370
  // Generate and display the app URL
372
- const appUrl = generateFusionUrl(deployment, appConfig.externalId, appConfig.versionTag);
371
+ const appUrl = generateFusionUrl(deployment, appConfig.externalId, appConfig.versionTag, appConfig.infra);
373
372
  if (appUrl) {
374
373
  console.log(`\n🔗 Open your app:\n ${appUrl}`);
375
374
  }
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Generate a Fusion app URL from deployment config and app metadata.
3
+ *
4
+ * @param {object} deployment - Deployment config (org, project, baseUrl)
5
+ * @param {string} appExternalId - App external ID
6
+ * @param {string} versionTag - Version tag (used for legacy infra URL only)
7
+ * @param {string} [infra] - Infrastructure type; "appsApi" uses the new dune-app-host path
8
+ * @returns {string|null} URL, or null if required fields are missing
9
+ */
10
+ export function generateFusionUrl(deployment, appExternalId, versionTag, infra) {
11
+ const { org, project, baseUrl } = deployment;
12
+ let cluster = null;
13
+ try {
14
+ cluster = baseUrl ? new URL(baseUrl).host : null;
15
+ } catch {
16
+ // baseUrl is not a valid URL; cluster stays null and we return null below
17
+ }
18
+
19
+ if (!org || !project || !cluster) {
20
+ return null;
21
+ }
22
+
23
+ if (infra === 'appsApi') {
24
+ return `https://${org}.fusion.cognite.com/${project}/dune-app-host/app/${encodeURIComponent(appExternalId)}?cluster=${cluster}`;
25
+ }
26
+
27
+ return `https://${org}.fusion.cognite.com/${project}/streamlit-apps/dune/${encodeURIComponent(appExternalId)}-${versionTag}?cluster=${cluster}&workspace=industrial-tools`;
28
+ }
@@ -0,0 +1,50 @@
1
+ import { describe, expect, it } from 'vitest';
2
+
3
+ import { generateFusionUrl } from './fusion-url.js';
4
+
5
+ const BASE_DEPLOYMENT = {
6
+ org: 'acme',
7
+ project: 'my-project',
8
+ baseUrl: 'https://cognite.test',
9
+ };
10
+
11
+ describe(generateFusionUrl.name, () => {
12
+ it('returns null when org is missing', () => {
13
+ const result = generateFusionUrl({ ...BASE_DEPLOYMENT, org: '' }, 'app-id', '1.0.0');
14
+ expect(result).toBeNull();
15
+ });
16
+
17
+ it('returns null when project is missing', () => {
18
+ const result = generateFusionUrl({ ...BASE_DEPLOYMENT, project: '' }, 'app-id', '1.0.0');
19
+ expect(result).toBeNull();
20
+ });
21
+
22
+ it('returns null when baseUrl yields no cluster', () => {
23
+ // 'no-protocol' is not a valid URL, so new URL() throws and cluster stays null
24
+ const result = generateFusionUrl({ ...BASE_DEPLOYMENT, baseUrl: 'no-protocol' }, 'app-id', '1.0.0');
25
+ expect(result).toBeNull();
26
+ });
27
+
28
+ it('returns legacy URL when infra is undefined', () => {
29
+ const result = generateFusionUrl(BASE_DEPLOYMENT, 'my-app', '1.2.3');
30
+ expect(result).toBe(
31
+ 'https://acme.fusion.cognite.com/my-project/streamlit-apps/dune/my-app-1.2.3?cluster=cognite.test&workspace=industrial-tools'
32
+ );
33
+ });
34
+
35
+ it('returns App Hosting URL when infra is appsApi', () => {
36
+ const result = generateFusionUrl(BASE_DEPLOYMENT, 'my-app', '1.2.3', 'appsApi');
37
+ expect(result).toBe(
38
+ 'https://acme.fusion.cognite.com/my-project/dune-app-host/app/my-app?cluster=cognite.test'
39
+ );
40
+ });
41
+
42
+ it('extracts cluster from baseUrl hostname', () => {
43
+ const result = generateFusionUrl(
44
+ { ...BASE_DEPLOYMENT, baseUrl: 'https://az-ams-sp-002.cognitedata.com' },
45
+ 'my-app',
46
+ '1.0.0'
47
+ );
48
+ expect(result).toContain('cluster=az-ams-sp-002.cognitedata.com');
49
+ });
50
+ });
@@ -3,6 +3,19 @@ import * as react from 'react';
3
3
  import { ReactNode } from 'react';
4
4
  import { CogniteClient } from '@cognite/sdk';
5
5
 
6
+ interface AppSdkAuthProviderProps {
7
+ children: ReactNode;
8
+ loadingComponent?: ReactNode;
9
+ errorComponent?: (error: string) => ReactNode;
10
+ }
11
+ /**
12
+ * Auth provider for apps running in the new Fusion app host (dune-app-host).
13
+ * Uses @cognite/app-sdk's Comlink handshake to connect to the host and obtain
14
+ * tokens on-demand. Exposes the same DuneContextValue ({ sdk, isLoading,
15
+ * error }) as DuneAuthProvider so useDune() works unchanged.
16
+ */
17
+ declare const AppSdkAuthProvider: ({ children, loadingComponent, errorComponent, }: AppSdkAuthProviderProps) => react_jsx_runtime.JSX.Element;
18
+
6
19
  interface DuneContextValue {
7
20
  sdk: CogniteClient;
8
21
  isLoading: boolean;
@@ -35,4 +48,4 @@ declare const getToken: (clientId: string, clientSecret: string) => Promise<any>
35
48
  declare const createCDFSDK: (config: CDFConfig) => Promise<CogniteClient>;
36
49
  declare const EMPTY_SDK: CogniteClient;
37
50
 
38
- export { type CDFConfig, DuneAuthProvider, DuneAuthProviderContext, type DuneAuthProviderProps, type DuneContextValue, EMPTY_SDK, createCDFSDK, getToken, useDune };
51
+ export { AppSdkAuthProvider, type CDFConfig, DuneAuthProvider, DuneAuthProviderContext, type DuneAuthProviderProps, type DuneContextValue, EMPTY_SDK, createCDFSDK, getToken, useDune };
@@ -1,12 +1,14 @@
1
1
  import {
2
+ AppSdkAuthProvider,
2
3
  DuneAuthProvider,
3
4
  DuneAuthProviderContext,
4
5
  EMPTY_SDK,
5
6
  createCDFSDK,
6
7
  getToken,
7
8
  useDune
8
- } from "../chunk-53VTKDSC.js";
9
+ } from "../chunk-XWZCFZUH.js";
9
10
  export {
11
+ AppSdkAuthProvider,
10
12
  DuneAuthProvider,
11
13
  DuneAuthProviderContext,
12
14
  EMPTY_SDK,
@@ -1,3 +1,8 @@
1
+ // src/auth/app-sdk-auth-provider.tsx
2
+ import { connectToHostApp } from "@cognite/app-sdk";
3
+ import { CogniteClient as CogniteClient3 } from "@cognite/sdk";
4
+ import { useEffect as useEffect2, useState as useState2 } from "react";
5
+
1
6
  // src/auth/dune-auth-provider.tsx
2
7
  import { CogniteClient as CogniteClient2 } from "@cognite/sdk";
3
8
  import { createContext, useEffect, useState } from "react";
@@ -131,6 +136,50 @@ var FusionIframeAuthenticationInnerProvider = ({
131
136
  return /* @__PURE__ */ jsx(DuneAuthProviderContext.Provider, { value: { sdk, isLoading, error }, children });
132
137
  };
133
138
 
139
+ // src/auth/app-sdk-auth-provider.tsx
140
+ import { Fragment as Fragment2, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
141
+ var AppSdkAuthProvider = ({
142
+ children,
143
+ loadingComponent = /* @__PURE__ */ jsx2("div", { children: "Loading CDF authentication..." }),
144
+ errorComponent = (error) => /* @__PURE__ */ jsxs2("div", { children: [
145
+ "Authentication error: ",
146
+ error
147
+ ] })
148
+ }) => {
149
+ const [sdk, setSdk] = useState2(EMPTY_SDK);
150
+ const [isLoading, setIsLoading] = useState2(true);
151
+ const [error, setError] = useState2();
152
+ useEffect2(() => {
153
+ connectToHostApp().then(async ({ api }) => {
154
+ const [project, baseUrl] = await Promise.all([
155
+ api.getProject(),
156
+ api.getBaseUrl()
157
+ ]);
158
+ const client = new CogniteClient3({
159
+ appId: "dune-app",
160
+ project,
161
+ baseUrl,
162
+ oidcTokenProvider: async () => api.getAccessToken()
163
+ });
164
+ await client.authenticate();
165
+ setSdk(client);
166
+ setError(void 0);
167
+ }).catch((err) => {
168
+ const message = err instanceof Error ? err.message : String(err);
169
+ setError(message);
170
+ }).finally(() => {
171
+ setIsLoading(false);
172
+ });
173
+ }, []);
174
+ if (error && errorComponent) {
175
+ return /* @__PURE__ */ jsx2(Fragment2, { children: errorComponent(error) });
176
+ }
177
+ if (isLoading && loadingComponent) {
178
+ return /* @__PURE__ */ jsx2(Fragment2, { children: loadingComponent });
179
+ }
180
+ return /* @__PURE__ */ jsx2(DuneAuthProviderContext.Provider, { value: { sdk, isLoading, error }, children });
181
+ };
182
+
134
183
  // src/auth/use-dune.ts
135
184
  import { useContext } from "react";
136
185
  var useDune = () => {
@@ -147,5 +196,6 @@ export {
147
196
  EMPTY_SDK,
148
197
  DuneAuthProviderContext,
149
198
  DuneAuthProvider,
199
+ AppSdkAuthProvider,
150
200
  useDune
151
201
  };