dremiojs 1.0.0 → 1.1.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.
- package/README.md +19 -0
- package/docs/catalog.md +76 -0
- package/docs/client.md +55 -0
- package/docs/configuration.md +54 -0
- package/docs/governance_collaboration.md +41 -0
- package/docs/provisioning.md +15 -0
- package/docs/reflections.md +54 -0
- package/docs/scripts_lineage_tokens.md +45 -0
- package/docs/service_users.md +77 -0
- package/docs/sources.md +53 -0
- package/docs/sql_and_jobs.md +59 -0
- package/docs/users.md +19 -0
- package/package.json +7 -3
- package/src/api/collaboration.ts +55 -0
- package/src/api/credentials.ts +74 -0
- package/src/api/governance.ts +52 -0
- package/src/api/lineage.ts +19 -0
- package/src/api/provisioning.ts +32 -0
- package/src/api/scripts.ts +64 -0
- package/src/api/token.ts +50 -0
- package/src/api/user.ts +39 -3
- package/src/client/base.ts +25 -0
- package/src/client/cloud.ts +4 -0
- package/tests/integration_manual.ts +49 -0
package/README.md
CHANGED
|
@@ -57,3 +57,22 @@ async function main() {
|
|
|
57
57
|
- **SQL Helper**: Easy `executeQuery` method that handles job submission and polling.
|
|
58
58
|
- **Catalog Management**: Create, update, delete Spaces, Sources, Folders, and Datasets.
|
|
59
59
|
- **Reflections**: Manage reflections programmatically.
|
|
60
|
+
|
|
61
|
+
## Documentation
|
|
62
|
+
|
|
63
|
+
- [Configuration & Environment Variables](docs/configuration.md)
|
|
64
|
+
- [Client Usage](docs/client.md)
|
|
65
|
+
- [Catalog API](docs/catalog.md)
|
|
66
|
+
## Documentation
|
|
67
|
+
|
|
68
|
+
- [Configuration & Environment Variables](docs/configuration.md)
|
|
69
|
+
- [Client Usage](docs/client.md)
|
|
70
|
+
- [Catalog API](docs/catalog.md)
|
|
71
|
+
- [SQL & Jobs API](docs/sql_and_jobs.md)
|
|
72
|
+
- [Reflections API](docs/reflections.md)
|
|
73
|
+
- [Sources API](docs/sources.md)
|
|
74
|
+
- [Users API](docs/users.md)
|
|
75
|
+
- [Governance & Collaboration](docs/governance_collaboration.md)
|
|
76
|
+
- [Scripts, Lineage & Tokens](docs/scripts_lineage_tokens.md)
|
|
77
|
+
- [Provisioning (Engines)](docs/provisioning.md)
|
|
78
|
+
- [Service Users & Credentials](docs/service_users.md)
|
package/docs/catalog.md
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# Catalog API Guide
|
|
2
|
+
|
|
3
|
+
The Catalog API is the primary way to interact with Dremio's semantic layer (Spaces, Folders, Virtual Datasets) and physical sources.
|
|
4
|
+
|
|
5
|
+
## Accessing the Catalog
|
|
6
|
+
|
|
7
|
+
### Listing the Root
|
|
8
|
+
To list the top-level items (Spaces and Sources):
|
|
9
|
+
|
|
10
|
+
```typescript
|
|
11
|
+
const root = await client.catalog.getByPath([]);
|
|
12
|
+
console.log(root.children);
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
### Getting Items by Path
|
|
16
|
+
You can traverse the catalog hierarchy using an array of path segments.
|
|
17
|
+
|
|
18
|
+
```typescript
|
|
19
|
+
// Get a specific dataset: "MarketingSpace.Campaigns.Q1_Results"
|
|
20
|
+
const dataset = await client.catalog.getByPath(['MarketingSpace', 'Campaigns', 'Q1_Results']);
|
|
21
|
+
console.log(dataset.id, dataset.type);
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### Getting Items by ID
|
|
25
|
+
If you already have the immutable ID of an object (e.g., from a search or list operation):
|
|
26
|
+
|
|
27
|
+
```typescript
|
|
28
|
+
const item = await client.catalog.get('dremio-dataset-uuid-1234');
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Creating Items
|
|
32
|
+
|
|
33
|
+
### Creating a Space
|
|
34
|
+
```typescript
|
|
35
|
+
await client.catalog.create({
|
|
36
|
+
type: 'SPACE',
|
|
37
|
+
name: 'NewMarketingSpace'
|
|
38
|
+
});
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Creating a Folder
|
|
42
|
+
```typescript
|
|
43
|
+
await client.catalog.create({
|
|
44
|
+
type: 'FOLDER',
|
|
45
|
+
path: ['NewMarketingSpace', 'Folder A']
|
|
46
|
+
});
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Creating a Virtual Dataset (View)
|
|
50
|
+
To create a VDS, you must provide the SQL definition and the context (path).
|
|
51
|
+
|
|
52
|
+
```typescript
|
|
53
|
+
await client.catalog.create({
|
|
54
|
+
type: 'DATASET',
|
|
55
|
+
path: ['NewMarketingSpace', 'MyView'],
|
|
56
|
+
sql: 'SELECT * FROM "Samples"."samples.dremio.com"."SF_incidents"',
|
|
57
|
+
format: { type: 'VIRTUAL_DATASET' } // Required specific to API v3/Cloud
|
|
58
|
+
});
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Updating Items
|
|
62
|
+
|
|
63
|
+
```typescript
|
|
64
|
+
// Rename or Move (check API specifics for move vs update)
|
|
65
|
+
await client.catalog.update('item-id', {
|
|
66
|
+
...item,
|
|
67
|
+
tag: item.tag, // Optimistic locking tag is often required
|
|
68
|
+
sql: 'SELECT * FROM new_table' // Updating SQL of a view
|
|
69
|
+
});
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Deleting Items
|
|
73
|
+
|
|
74
|
+
```typescript
|
|
75
|
+
await client.catalog.delete('item-id');
|
|
76
|
+
```
|
package/docs/client.md
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# Client Instance Guide
|
|
2
|
+
|
|
3
|
+
The library provides two distinct clients to handle the subtle differences between Dremio Cloud and Dremio Software APIs. Both clients share a common interface for most resources, making it easy to switch between them or support hybrid deployments.
|
|
4
|
+
|
|
5
|
+
## Dremio Cloud Client
|
|
6
|
+
|
|
7
|
+
The `DremioCloudClient` is optimized for Dremio Cloud's multi-tenant architecture. It automatically handles the `projectId` context required for most API calls.
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
import { DremioCloudClient } from 'dremiojs';
|
|
11
|
+
|
|
12
|
+
const cloudClient = new DremioCloudClient({
|
|
13
|
+
baseUrl: 'https://api.dremio.cloud/v0',
|
|
14
|
+
authToken: process.env.DREMIO_CLOUD_TOKEN,
|
|
15
|
+
projectId: process.env.DREMIO_CLOUD_PROJECT_ID
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
// The client automatically appends /projects/{id} to relevant paths
|
|
19
|
+
await cloudClient.catalog.getByPath(['space', 'dataset']);
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Dremio Software Client
|
|
23
|
+
|
|
24
|
+
The `DremioSoftwareClient` supports standard Dremio Software deployments (Docker, K8s, RPM). It includes logic for:
|
|
25
|
+
- API v2 Login (username/password) exchange for tokens.
|
|
26
|
+
- Automatic token management (if using username/pass).
|
|
27
|
+
- Standard v3 API usage.
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
import { DremioSoftwareClient } from 'dremiojs';
|
|
31
|
+
|
|
32
|
+
const softwareClient = new DremioSoftwareClient({
|
|
33
|
+
baseUrl: 'http://localhost:9047/api/v3',
|
|
34
|
+
authToken: process.env.DREMIO_PAT
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
// Or using Login
|
|
38
|
+
const legacyClient = new DremioSoftwareClient({
|
|
39
|
+
baseUrl: 'http://localhost:9047/api/v3',
|
|
40
|
+
username: 'admin',
|
|
41
|
+
password: 'password123'
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
// The client performs login on the first request if no token is present
|
|
45
|
+
await legacyClient.jobs.executeQuery('SELECT 1');
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Shared Capabilities
|
|
49
|
+
|
|
50
|
+
Both clients extend `BaseClient` and expose:
|
|
51
|
+
- `catalog`: Manage datasets, spaces, folders.
|
|
52
|
+
- `jobs`: Execute SQL and track jobs.
|
|
53
|
+
- `reflections`: specific Reflection management.
|
|
54
|
+
- `sources`: specific Source management.
|
|
55
|
+
- `users`: User and Role lookups.
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Configuration & Environment Variables
|
|
2
|
+
|
|
3
|
+
`dremiojs` is designed to be flexible and secure. It supports configuration via a typed configuration object passed to the client constructor. While it does not automatically read environment variables (to avoid strict dependency on `dotenv` in client-side bundling scenarios), we recommend using standard environment variables in your application.
|
|
4
|
+
|
|
5
|
+
## Best Practices
|
|
6
|
+
|
|
7
|
+
Store your sensitive credentials in a `.env` file and use a library like `dotenv` to load them.
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
# .env example
|
|
11
|
+
DREMIO_CLOUD_TOKEN=your_pat_here
|
|
12
|
+
DREMIO_CLOUD_PROJECT_ID=your_project_id
|
|
13
|
+
DREMIO_SOFTWARE_URL=http://dremio:9047/api/v3
|
|
14
|
+
DREMIO_SOFTWARE_USER=admin
|
|
15
|
+
DREMIO_SOFTWARE_PASS=password123
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Configuration Interfaces
|
|
19
|
+
|
|
20
|
+
### Dremio Cloud Config
|
|
21
|
+
|
|
22
|
+
```typescript
|
|
23
|
+
interface DremioCloudConfig {
|
|
24
|
+
baseUrl: string; // Usually 'https://api.dremio.cloud/v0'
|
|
25
|
+
authToken: string; // Your Personal Access Token
|
|
26
|
+
projectId: string; // The Project ID provided in the Cloud Console URL
|
|
27
|
+
timeout?: number; // Request timeout in ms (default: 30000)
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Dremio Software Config
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
interface DremioSoftwareConfig {
|
|
35
|
+
baseUrl: string; // e.g. 'http://localhost:9047/api/v3'
|
|
36
|
+
authToken?: string; // PAT (Recommended)
|
|
37
|
+
username?: string; // For legacy auth
|
|
38
|
+
password?: string; // For legacy auth
|
|
39
|
+
checkSSLCerts?: boolean; // Set to false for self-signed certs (Node.js only)
|
|
40
|
+
timeout?: number; // Request timeout in ms
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## SSL/TLS Configuration (Self-Signed Certs)
|
|
45
|
+
|
|
46
|
+
If you are connecting to a Dremio Software instance with a self-signed certificate, you may need to disable SSL verification in Node.js.
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
const client = new DremioSoftwareClient({
|
|
50
|
+
baseUrl: 'https://dremio.local:9047/api/v3',
|
|
51
|
+
authToken: '...',
|
|
52
|
+
checkSSLCerts: false // WARNING: Use only for development
|
|
53
|
+
});
|
|
54
|
+
```
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Governance & Collaboration API Guide
|
|
2
|
+
|
|
3
|
+
## Governance (Grants)
|
|
4
|
+
|
|
5
|
+
Manage access control lists (ACLs) and grants for Catalog entities.
|
|
6
|
+
|
|
7
|
+
### Getting Grants
|
|
8
|
+
```typescript
|
|
9
|
+
const grants = await client.governance.getGrants('entity-id');
|
|
10
|
+
// Output: [{ granteeType: 'USER', id: '...', privileges: ['SELECT'] }]
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
### Updating Grants
|
|
14
|
+
```typescript
|
|
15
|
+
await client.governance.updateGrants('entity-id', [
|
|
16
|
+
{ granteeType: 'ROLE', id: 'role-id', privileges: ['SELECT', 'ALTER'] }
|
|
17
|
+
]);
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Collaboration (Tags & Wiki)
|
|
21
|
+
|
|
22
|
+
Manage metadata that helps users discover and understand data.
|
|
23
|
+
|
|
24
|
+
### Tags
|
|
25
|
+
```typescript
|
|
26
|
+
// Get Tags
|
|
27
|
+
const tags = await client.collaboration.getTags('dataset-id');
|
|
28
|
+
|
|
29
|
+
// Set Tags
|
|
30
|
+
await client.collaboration.setTags('dataset-id', ['marketing', 'q1-2024']);
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Wiki
|
|
34
|
+
```typescript
|
|
35
|
+
// Get Wiki Markdown
|
|
36
|
+
const wiki = await client.collaboration.getWiki('dataset-id');
|
|
37
|
+
console.log(wiki.text);
|
|
38
|
+
|
|
39
|
+
// Set Wiki
|
|
40
|
+
await client.collaboration.setWiki('dataset-id', '# Sales Data\n\nThis dataset contains...');
|
|
41
|
+
```
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Provisioning API Guide
|
|
2
|
+
|
|
3
|
+
Manage Dremio Engines (Cloud) or Queues (Software WLM).
|
|
4
|
+
|
|
5
|
+
## Engines (Dremio Cloud)
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
// List available engines
|
|
9
|
+
const engines = await client.provisioning.listEngines();
|
|
10
|
+
engines.forEach(engine => {
|
|
11
|
+
console.log(`Engine: ${engine.name} (${engine.size}) - ${engine.status}`);
|
|
12
|
+
});
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
*Note: Software WLM Queue management is structurally different and may be added to this namespace in future updates.*
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Reflections API Guide
|
|
2
|
+
|
|
3
|
+
Reflections are Dremio's query acceleration technology. This API allows you to manage raw and aggregation reflections programmatically.
|
|
4
|
+
|
|
5
|
+
## Listing Reflections
|
|
6
|
+
|
|
7
|
+
You can list all reflections or filter by dataset.
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
// List all accessible reflections
|
|
11
|
+
const allReflections = await client.reflections.list();
|
|
12
|
+
|
|
13
|
+
// List reflections for a specific dataset
|
|
14
|
+
const datasetReflections = await client.reflections.list({
|
|
15
|
+
datasetId: 'dataset-uuid-123'
|
|
16
|
+
});
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Getting a Reflection
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
const reflection = await client.reflections.get('reflection-uuid');
|
|
23
|
+
console.log(reflection.name, reflection.status);
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Creating a Reflection
|
|
27
|
+
|
|
28
|
+
Creating a reflection implies defining which dataset it accelerates and its configuration (dimensions, measures, etc.).
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
await client.reflections.create({
|
|
32
|
+
type: 'RAW',
|
|
33
|
+
name: 'Raw_Acceleration',
|
|
34
|
+
datasetId: 'dataset-uuid-123',
|
|
35
|
+
enabled: true,
|
|
36
|
+
displayFieldIds: ['col1', 'col2'] // Fields to include
|
|
37
|
+
});
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Updating a Reflection
|
|
41
|
+
|
|
42
|
+
Commonly used to enable/disable reflections or update their definition.
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
await client.reflections.update('reflection-uuid', {
|
|
46
|
+
enabled: false // Disable reflection
|
|
47
|
+
});
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Deleting a Reflection
|
|
51
|
+
|
|
52
|
+
```typescript
|
|
53
|
+
await client.reflections.delete('reflection-uuid');
|
|
54
|
+
```
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Scripts, Lineage & Tokens Guide
|
|
2
|
+
|
|
3
|
+
## Scripts API
|
|
4
|
+
|
|
5
|
+
Manage saved SQL scripts (Dremio Cloud & Software).
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
// List Scripts
|
|
9
|
+
const scripts = await client.scripts.list({ maxResults: 10 });
|
|
10
|
+
|
|
11
|
+
// Get a Script
|
|
12
|
+
const myScript = await client.scripts.get('script-id');
|
|
13
|
+
|
|
14
|
+
// Create a Script
|
|
15
|
+
const newScript = await client.scripts.create({
|
|
16
|
+
name: 'Daily Report',
|
|
17
|
+
content: 'SELECT count(*) FROM sales',
|
|
18
|
+
context: ['Marketing']
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
// Update
|
|
22
|
+
await client.scripts.update('script-id', { content: 'SELECT * FROM sales' });
|
|
23
|
+
|
|
24
|
+
// Delete
|
|
25
|
+
await client.scripts.delete('script-id');
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Lineage API
|
|
29
|
+
|
|
30
|
+
Explore the data lineage graph for a dataset.
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
const graph = await client.lineage.get('dataset-id');
|
|
34
|
+
console.log(graph);
|
|
35
|
+
// Returns nodes and edges representing parent/child relationships
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Token Management
|
|
39
|
+
|
|
40
|
+
Programmatically generate Personal Access Tokens (PATs) (where supported).
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
const tokenResponse = await client.tokens.createToken('user-id', 'My New Token');
|
|
44
|
+
console.log('New PAT:', tokenResponse.token);
|
|
45
|
+
```
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# Service Users & Credentials Guide
|
|
2
|
+
|
|
3
|
+
Managing non-human accounts (Service Users) is essential for CI/CD and automated workflows. dremiojs provides full lifecycle management for Service Users and their OAuth credentials.
|
|
4
|
+
|
|
5
|
+
> **Note**: Service Users are primarily a **Dremio Enterprise** feature. Calls to these endpoints may fail on Community Edition.
|
|
6
|
+
|
|
7
|
+
## Service User Lifecycle
|
|
8
|
+
|
|
9
|
+
### 1. Create a Service User
|
|
10
|
+
|
|
11
|
+
```typescript
|
|
12
|
+
const serviceUser = await client.users.create({
|
|
13
|
+
name: 'ci_pipeline_bot',
|
|
14
|
+
identityType: 'SERVICE_USER',
|
|
15
|
+
active: true
|
|
16
|
+
});
|
|
17
|
+
console.log('Service User Created:', serviceUser.id);
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
### 2. Create Client Credentials (Secret)
|
|
21
|
+
|
|
22
|
+
Generate a Client ID and Secret for this user. This secret is only shown ONCE.
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
const credential = await client.credentials.create(
|
|
26
|
+
serviceUser.id,
|
|
27
|
+
'gitlab-access-token',
|
|
28
|
+
180 // Lifetime in days
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
console.log('Client ID:', credential.clientSecretConfig.clientId);
|
|
32
|
+
console.log('Client Secret:', credential.clientSecretConfig.clientSecret);
|
|
33
|
+
// SAVE THE SECRET NOW! It cannot be retrieved again.
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### 3. List Credentials
|
|
37
|
+
|
|
38
|
+
View active credentials for a user.
|
|
39
|
+
|
|
40
|
+
```typescript
|
|
41
|
+
const creds = await client.credentials.list(serviceUser.id);
|
|
42
|
+
creds.forEach(c => console.log(c.name, c.credentialType));
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### 4. Delete Credentials
|
|
46
|
+
|
|
47
|
+
Revoke a specific credential.
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
await client.credentials.delete(serviceUser.id, credential.id);
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### 5. Delete Service User
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
await client.users.delete(serviceUser.id, serviceUser.tag);
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Dremio Cloud Service Accounts
|
|
60
|
+
|
|
61
|
+
In Dremio Cloud, "Service Users" are typically handled as regular users with **Personal Access Tokens (PATs)**.
|
|
62
|
+
|
|
63
|
+
### Creating a Token Programmatically
|
|
64
|
+
|
|
65
|
+
You can generate tokens for users (if you have permissions) using the `TokensResource`.
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
// Create a token for a specific user ID
|
|
69
|
+
const { token } = await client.tokens.createToken(
|
|
70
|
+
'user-uuid-1234',
|
|
71
|
+
'ci-pipeline-token',
|
|
72
|
+
90 // Lifetime in days (default 30)
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
console.log('Generated PAT:', token);
|
|
76
|
+
```
|
|
77
|
+
|
package/docs/sources.md
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Sources API Guide
|
|
2
|
+
|
|
3
|
+
Sources are the physical connections to your data lakes and databases (e.g., S3, HDFS, PostgreSQL, Snowflake).
|
|
4
|
+
|
|
5
|
+
## Listing Sources
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
const sources = await client.sources.list();
|
|
9
|
+
sources.forEach(source => {
|
|
10
|
+
console.log(source.name, source.type); // e.g. "MyS3", "S3"
|
|
11
|
+
});
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Getting a Source
|
|
15
|
+
|
|
16
|
+
```typescript
|
|
17
|
+
const source = await client.sources.get('source-id');
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Creating a Source
|
|
21
|
+
|
|
22
|
+
Creating a source requires a specific configuration object that varies by source type (S3, Nessie, etc.). *Note: The specific config payload structure depends on the Dremio version and source type.*
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
// Example: Creating an S3 Source
|
|
26
|
+
await client.sources.create({
|
|
27
|
+
name: 'MyS3Source',
|
|
28
|
+
type: 'S3',
|
|
29
|
+
config: {
|
|
30
|
+
bucketName: 'my-bucket',
|
|
31
|
+
accessKey: '...',
|
|
32
|
+
accessSecret: '...'
|
|
33
|
+
// ... other S3 specific props
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Updating a Source
|
|
39
|
+
|
|
40
|
+
```typescript
|
|
41
|
+
await client.sources.update('source-id', {
|
|
42
|
+
config: {
|
|
43
|
+
...oldConfig,
|
|
44
|
+
accessSecret: 'NEW_SECRET'
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Deleting a Source
|
|
50
|
+
|
|
51
|
+
```typescript
|
|
52
|
+
await client.sources.delete('source-id');
|
|
53
|
+
```
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# SQL & Jobs API Guide
|
|
2
|
+
|
|
3
|
+
Executing SQL in Dremio is an asynchronous process involving job submission, polling, and result retrieval. `dremiojs` simplifies this with a helper method while still exposing raw controls.
|
|
4
|
+
|
|
5
|
+
## The Easy Way: `executeQuery`
|
|
6
|
+
|
|
7
|
+
The `executeQuery` method handles the entire lifecycle: submitting the job, polling for completion, and fetching results.
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
const rows = await client.jobs.executeQuery('SELECT * FROM sys.version');
|
|
11
|
+
console.log(rows);
|
|
12
|
+
// Output: [{ version: '24.2.0', ... }]
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
### Context
|
|
16
|
+
You can provide a context for the query (e.g., to simplify table names).
|
|
17
|
+
|
|
18
|
+
```typescript
|
|
19
|
+
// Queries table inside 'MarketingSpace' without full qualification
|
|
20
|
+
const rows = await client.jobs.executeQuery('SELECT * FROM "Campaigns"', {
|
|
21
|
+
context: ['MarketingSpace']
|
|
22
|
+
});
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## The Query Lifecycle (Manual Control)
|
|
26
|
+
|
|
27
|
+
For long-running queries or advanced UI integration (like progress bars), you may want to manage the lifecycle yourself.
|
|
28
|
+
|
|
29
|
+
### 1. Submit Job
|
|
30
|
+
```typescript
|
|
31
|
+
const jobStub = await client.jobs.submitSQL('SELECT count(*) FROM big_table');
|
|
32
|
+
const jobId = jobStub.id;
|
|
33
|
+
console.log('Job submitted:', jobId);
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### 2. Check Status
|
|
37
|
+
Poll the job status until it reaches a terminal state (`COMPLETED`, `FAILED`, `CANCELED`).
|
|
38
|
+
|
|
39
|
+
```typescript
|
|
40
|
+
const status = await client.jobs.getJobStatus(jobId);
|
|
41
|
+
console.log('Current State:', status.jobState); // e.g., 'RUNNING'
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### 3. Get Results
|
|
45
|
+
Once the job is `COMPLETED`, fetch the results.
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
// Fetch first 100 rows
|
|
49
|
+
const results = await client.jobs.getJobResults(jobId, 0, 100);
|
|
50
|
+
console.log('Rows:', results.rows);
|
|
51
|
+
console.log('Schema:', results.schema);
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### 4. Cancel Job
|
|
55
|
+
If the user wants to stop the query:
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
await client.jobs.cancelJob(jobId);
|
|
59
|
+
```
|
package/docs/users.md
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Users API Guide
|
|
2
|
+
|
|
3
|
+
The Users API allows you to lookup user information. This is useful for administration and governance workflows.
|
|
4
|
+
|
|
5
|
+
## Getting a User by ID
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
const user = await client.users.get('user-guid');
|
|
9
|
+
console.log(user.name, user.email);
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Getting a User by Name
|
|
13
|
+
|
|
14
|
+
```typescript
|
|
15
|
+
const user = await client.users.getByName('admin');
|
|
16
|
+
console.log(user.id);
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
*Note: User management capabilities (Create/Update/Delete) are typically restricted to administrative APIs and may differ significantly between Software and Cloud. The current library focuses on lookup/retrieval.*
|
package/package.json
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dremiojs",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "",
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "A TypeScript client library for Dremio Cloud and Software.",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "git+https://github.com/developer-advocacy-dremio/dremiojs.git"
|
|
8
|
+
},
|
|
5
9
|
"main": "index.js",
|
|
6
10
|
"scripts": {
|
|
7
11
|
"test": "echo \"Error: no test specified\" && exit 1"
|
|
@@ -22,4 +26,4 @@
|
|
|
22
26
|
"ts-node": "^10.9.2",
|
|
23
27
|
"typescript": "^5.9.3"
|
|
24
28
|
}
|
|
25
|
-
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { BaseClient } from '../client/base';
|
|
2
|
+
|
|
3
|
+
export interface Tag {
|
|
4
|
+
tags: string[];
|
|
5
|
+
version?: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface Wiki {
|
|
9
|
+
text: string;
|
|
10
|
+
version?: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export class CollaborationResource {
|
|
14
|
+
private client: BaseClient;
|
|
15
|
+
|
|
16
|
+
constructor(client: BaseClient) {
|
|
17
|
+
this.client = client;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async getTags(catalogId: string): Promise<Tag> {
|
|
21
|
+
return this.client.request<Tag>({
|
|
22
|
+
method: 'GET',
|
|
23
|
+
url: `/catalog/${encodeURIComponent(catalogId)}/collaboration/tag`
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async setTags(catalogId: string, tags: string[], version?: string): Promise<void> {
|
|
28
|
+
const data: any = { tags };
|
|
29
|
+
if (version) data.version = version;
|
|
30
|
+
|
|
31
|
+
await this.client.request({
|
|
32
|
+
method: 'POST',
|
|
33
|
+
url: `/catalog/${encodeURIComponent(catalogId)}/collaboration/tag`,
|
|
34
|
+
data
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async getWiki(catalogId: string): Promise<Wiki> {
|
|
39
|
+
return this.client.request<Wiki>({
|
|
40
|
+
method: 'GET',
|
|
41
|
+
url: `/catalog/${encodeURIComponent(catalogId)}/collaboration/wiki`
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async setWiki(catalogId: string, text: string, version?: string): Promise<void> {
|
|
46
|
+
const data: any = { text };
|
|
47
|
+
if (version) data.version = version;
|
|
48
|
+
|
|
49
|
+
await this.client.request({
|
|
50
|
+
method: 'POST',
|
|
51
|
+
url: `/catalog/${encodeURIComponent(catalogId)}/collaboration/wiki`,
|
|
52
|
+
data
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { BaseClient } from '../client/base';
|
|
2
|
+
|
|
3
|
+
export interface Credential {
|
|
4
|
+
id: string;
|
|
5
|
+
name: string;
|
|
6
|
+
credentialType: 'CLIENT_SECRET' | 'EXTERNAL_JWT';
|
|
7
|
+
clientSecretConfig?: {
|
|
8
|
+
clientId: string;
|
|
9
|
+
clientSecret?: string; // Only returned on creation
|
|
10
|
+
createdAt?: string;
|
|
11
|
+
expiresAt?: string;
|
|
12
|
+
};
|
|
13
|
+
// ... External JWT config properties could be added here
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export class CredentialsResource {
|
|
17
|
+
private client: BaseClient;
|
|
18
|
+
|
|
19
|
+
constructor(client: BaseClient) {
|
|
20
|
+
this.client = client;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* List credentials for a Service User.
|
|
25
|
+
*/
|
|
26
|
+
async list(userId: string): Promise<Credential[]> {
|
|
27
|
+
const response = await this.client.request<Credential[]>({
|
|
28
|
+
method: 'GET',
|
|
29
|
+
url: `/user/${encodeURIComponent(userId)}/oauth/credentials`
|
|
30
|
+
});
|
|
31
|
+
// Response might be wrapped or array, usually array for list endpoints but docs example showed {id...} which is odd for a list.
|
|
32
|
+
// Re-reading docs: GET /user/{id}/oauth/credentials returns A LIST?
|
|
33
|
+
// Actually the doc example showed `curl -X GET .../credentials` returning a SINGLE object?
|
|
34
|
+
// Wait, normally `credentials` implies list. Let's assume list for now or container.
|
|
35
|
+
// Actually, if it returns a single object it might be 'get by id'.
|
|
36
|
+
// Correction: The docs show GET .../credentials returning ONE credential object in the example?
|
|
37
|
+
// That implies you might only have one? Or the doc example is misleading/specific ID.
|
|
38
|
+
// Let's assume it returns an array for safety or we handle both.
|
|
39
|
+
return Array.isArray(response) ? response : [response];
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Create a Client Secret for a Service User.
|
|
44
|
+
* @param userId Service User ID
|
|
45
|
+
* @param name Name for the credential
|
|
46
|
+
* @param lifetimeDays Duration in days (max 180)
|
|
47
|
+
*/
|
|
48
|
+
async create(userId: string, name: string, lifetimeDays: number = 180): Promise<Credential> {
|
|
49
|
+
return this.client.request<Credential>({
|
|
50
|
+
method: 'POST',
|
|
51
|
+
url: `/user/${encodeURIComponent(userId)}/oauth/credentials`,
|
|
52
|
+
data: {
|
|
53
|
+
name,
|
|
54
|
+
credentialType: 'CLIENT_SECRET',
|
|
55
|
+
clientSecretConfig: {
|
|
56
|
+
lifetime: {
|
|
57
|
+
quantity: lifetimeDays,
|
|
58
|
+
units: 'DAYS'
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Delete a credential.
|
|
67
|
+
*/
|
|
68
|
+
async delete(userId: string, credentialId: string): Promise<void> {
|
|
69
|
+
await this.client.request({
|
|
70
|
+
method: 'DELETE',
|
|
71
|
+
url: `/user/${encodeURIComponent(userId)}/oauth/credentials/${encodeURIComponent(credentialId)}`
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { BaseClient } from '../client/base';
|
|
2
|
+
|
|
3
|
+
export interface Grant {
|
|
4
|
+
id: string; // User or Role ID
|
|
5
|
+
granteeType: 'USER' | 'ROLE';
|
|
6
|
+
privileges: string[]; // e.g. ['SELECT', 'ALTER']
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface AccessControlList {
|
|
10
|
+
users?: { id: string, permissions: string[] }[];
|
|
11
|
+
roles?: { id: string, permissions: string[] }[];
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export class GovernanceResource {
|
|
15
|
+
private client: BaseClient;
|
|
16
|
+
|
|
17
|
+
constructor(client: BaseClient) {
|
|
18
|
+
this.client = client;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Dremio Cloud: Get Grants for a catalog entity.
|
|
23
|
+
* Dremio Software: Typically uses ACLs embedded in Catalog.
|
|
24
|
+
* This method targets the /grants endpoints primarily used in Cloud/Newer Software.
|
|
25
|
+
*/
|
|
26
|
+
async getGrants(catalogId: string): Promise<Grant[]> {
|
|
27
|
+
// Dremio Cloud: /v0/projects/{id}/catalog/{id}/grants
|
|
28
|
+
// Note: ProjectId is handled by client base url interceptor/logic usually.
|
|
29
|
+
const response = await this.client.request<{ grants: Grant[] }>({
|
|
30
|
+
method: 'GET',
|
|
31
|
+
url: `/catalog/${encodeURIComponent(catalogId)}/grants`
|
|
32
|
+
});
|
|
33
|
+
return response.grants || [];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Dremio Cloud: Update Grants.
|
|
38
|
+
*/
|
|
39
|
+
async updateGrants(catalogId: string, grants: Grant[]): Promise<void> {
|
|
40
|
+
await this.client.request({
|
|
41
|
+
method: 'PUT',
|
|
42
|
+
url: `/catalog/${encodeURIComponent(catalogId)}/grants`,
|
|
43
|
+
data: { grants }
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Dremio Software: Set ACL (Software v3 style) on an entity.
|
|
49
|
+
* Technically this usually goes via Catalog Update, but we provide a helper here if beneficial.
|
|
50
|
+
* For now, we'll focus on the 'Grants' endpoint which is cleaner if supported.
|
|
51
|
+
*/
|
|
52
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { BaseClient } from '../client/base';
|
|
2
|
+
|
|
3
|
+
export class LineageResource {
|
|
4
|
+
private client: BaseClient;
|
|
5
|
+
|
|
6
|
+
constructor(client: BaseClient) {
|
|
7
|
+
this.client = client;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
async get(catalogId: string): Promise<any> {
|
|
11
|
+
return this.client.request({
|
|
12
|
+
method: 'GET',
|
|
13
|
+
url: `/catalog/${encodeURIComponent(catalogId)}/graph`
|
|
14
|
+
});
|
|
15
|
+
// Note: Graph/Lineage endpoints can vary.
|
|
16
|
+
// Software v3 doc: GET /api/v3/catalog/{id}/graph
|
|
17
|
+
// Cloud doc checks: /v0/projects/{id}/catalog/{id}/graph
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { BaseClient } from '../client/base';
|
|
2
|
+
|
|
3
|
+
// Simplified Engine/Queue types
|
|
4
|
+
export interface Engine {
|
|
5
|
+
id: string;
|
|
6
|
+
name: string;
|
|
7
|
+
size?: string;
|
|
8
|
+
status?: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export class ProvisioningResource {
|
|
12
|
+
private client: BaseClient;
|
|
13
|
+
|
|
14
|
+
constructor(client: BaseClient) {
|
|
15
|
+
this.client = client;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Dremio Cloud: List Engines
|
|
20
|
+
*/
|
|
21
|
+
async listEngines(): Promise<Engine[]> {
|
|
22
|
+
// Cloud: /v0/projects/{id}/engines
|
|
23
|
+
const response = await this.client.request<any>({
|
|
24
|
+
method: 'GET',
|
|
25
|
+
url: '/engines'
|
|
26
|
+
});
|
|
27
|
+
// Normalize response
|
|
28
|
+
return response.data || (Array.isArray(response) ? response : []);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Additional methods for start/stop engines or queue management could be added here
|
|
32
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { BaseClient } from '../client/base';
|
|
2
|
+
|
|
3
|
+
export interface Script {
|
|
4
|
+
id: string;
|
|
5
|
+
name: string;
|
|
6
|
+
description?: string;
|
|
7
|
+
content: string; // SQL
|
|
8
|
+
context?: string[];
|
|
9
|
+
createdAt?: string;
|
|
10
|
+
modifiedAt?: string;
|
|
11
|
+
createdBy?: string;
|
|
12
|
+
modifiedBy?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export class ScriptsResource {
|
|
16
|
+
private client: BaseClient;
|
|
17
|
+
|
|
18
|
+
constructor(client: BaseClient) {
|
|
19
|
+
this.client = client;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async list(options: { maxResults?: number, ownedBy?: string } = {}): Promise<Script[]> {
|
|
23
|
+
const params: any = {};
|
|
24
|
+
if (options.maxResults) params.maxResults = options.maxResults;
|
|
25
|
+
if (options.ownedBy) params.ownedBy = options.ownedBy;
|
|
26
|
+
|
|
27
|
+
const response = await this.client.request<{ data: Script[] }>({
|
|
28
|
+
method: 'GET',
|
|
29
|
+
url: '/scripts',
|
|
30
|
+
params
|
|
31
|
+
});
|
|
32
|
+
return response.data || [];
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async get(id: string): Promise<Script> {
|
|
36
|
+
return this.client.request<Script>({
|
|
37
|
+
method: 'GET',
|
|
38
|
+
url: `/scripts/${encodeURIComponent(id)}`
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async create(script: Partial<Script>): Promise<Script> {
|
|
43
|
+
return this.client.request<Script>({
|
|
44
|
+
method: 'POST',
|
|
45
|
+
url: '/scripts',
|
|
46
|
+
data: script
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
async update(id: string, script: Partial<Script>): Promise<Script> {
|
|
51
|
+
return this.client.request<Script>({
|
|
52
|
+
method: 'PUT',
|
|
53
|
+
url: `/scripts/${encodeURIComponent(id)}`,
|
|
54
|
+
data: script
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async delete(id: string): Promise<void> {
|
|
59
|
+
return this.client.request({
|
|
60
|
+
method: 'DELETE',
|
|
61
|
+
url: `/scripts/${encodeURIComponent(id)}`
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
}
|
package/src/api/token.ts
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { BaseClient } from '../client/base';
|
|
2
|
+
|
|
3
|
+
export class TokenResource {
|
|
4
|
+
private client: BaseClient;
|
|
5
|
+
|
|
6
|
+
constructor(client: BaseClient) {
|
|
7
|
+
this.client = client;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
// Usually administrative
|
|
11
|
+
// Implement standard PAT creation endpoints if available/documented for target version
|
|
12
|
+
|
|
13
|
+
// Dremio Software: POST /api/v3/user/{uid}/token
|
|
14
|
+
// Dremio Cloud: /v0/projects/{id}/users/{uid}/token ? (Check docs)
|
|
15
|
+
// Often PAT management is done via specialized internal APIs or different paths.
|
|
16
|
+
// We will provide a placeholder that attempts the standard V3 path.
|
|
17
|
+
|
|
18
|
+
// Supports Dremio Cloud (PAT) and Software (PAT) creation
|
|
19
|
+
async createToken(userId: string, label: string, lifetimeDays: number = 30): Promise<{ token: string }> {
|
|
20
|
+
const config = this.client.getConfig();
|
|
21
|
+
let baseUrl = config.baseUrl.replace(/\/$/, '');
|
|
22
|
+
|
|
23
|
+
// Ensure we target the correct API root
|
|
24
|
+
// Cloud: https://api.dremio.cloud/v0/user/{id}/token
|
|
25
|
+
// Software: http://host:9047/api/v3/user/{id}/token
|
|
26
|
+
|
|
27
|
+
// If the client is Cloud, the getConfig() returns the raw URL (without project),
|
|
28
|
+
// effectively handling the path correctly.
|
|
29
|
+
|
|
30
|
+
const fullUrl = `${baseUrl}/user/${encodeURIComponent(userId)}/token`;
|
|
31
|
+
|
|
32
|
+
const millisecondsToExpire = lifetimeDays * 24 * 60 * 60 * 1000;
|
|
33
|
+
|
|
34
|
+
const response = await this.client.request({
|
|
35
|
+
method: 'POST',
|
|
36
|
+
url: fullUrl, // Absolute URL to bypass axios baseURL prefix
|
|
37
|
+
data: {
|
|
38
|
+
label,
|
|
39
|
+
millisecondsToExpire
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
// Cloud API returns the token string directly in some contexts, or JSON?
|
|
44
|
+
// Based on docs example, checking if response is string or object.
|
|
45
|
+
if (typeof response === 'string') {
|
|
46
|
+
return { token: response };
|
|
47
|
+
}
|
|
48
|
+
return response; // Assuming { token: ... } or similar JSON
|
|
49
|
+
}
|
|
50
|
+
}
|
package/src/api/user.ts
CHANGED
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
import { BaseClient } from '../client/base';
|
|
2
2
|
|
|
3
|
+
// Basic types
|
|
3
4
|
export interface User {
|
|
4
5
|
id: string;
|
|
5
6
|
name: string;
|
|
6
7
|
firstName?: string;
|
|
7
8
|
lastName?: string;
|
|
8
9
|
email?: string;
|
|
9
|
-
|
|
10
|
+
tag?: string;
|
|
11
|
+
identityType?: 'REGULAR_USER' | 'SERVICE_USER';
|
|
12
|
+
active?: boolean;
|
|
13
|
+
roles?: { id: string, name: string, type: string }[];
|
|
14
|
+
oauthClientId?: string; // For Service Users
|
|
10
15
|
}
|
|
11
16
|
|
|
12
17
|
export class UserResource {
|
|
@@ -17,16 +22,47 @@ export class UserResource {
|
|
|
17
22
|
}
|
|
18
23
|
|
|
19
24
|
async get(id: string): Promise<User> {
|
|
20
|
-
return this.client.request({
|
|
25
|
+
return this.client.request<User>({
|
|
21
26
|
method: 'GET',
|
|
22
27
|
url: `/user/${encodeURIComponent(id)}`
|
|
23
28
|
});
|
|
24
29
|
}
|
|
25
30
|
|
|
26
31
|
async getByName(name: string): Promise<User> {
|
|
27
|
-
return this.client.request({
|
|
32
|
+
return this.client.request<User>({
|
|
28
33
|
method: 'GET',
|
|
29
34
|
url: `/user/by-name/${encodeURIComponent(name)}`
|
|
30
35
|
});
|
|
31
36
|
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Create a new user (Regular or Service).
|
|
40
|
+
* @param user User definition. For Service Users, set identityType to 'SERVICE_USER'.
|
|
41
|
+
*/
|
|
42
|
+
async create(user: Partial<User>): Promise<User> {
|
|
43
|
+
return this.client.request<User>({
|
|
44
|
+
method: 'POST',
|
|
45
|
+
url: '/user',
|
|
46
|
+
data: user
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
async update(id: string, user: Partial<User>): Promise<User> {
|
|
51
|
+
return this.client.request<User>({
|
|
52
|
+
method: 'PUT',
|
|
53
|
+
url: `/user/${encodeURIComponent(id)}`,
|
|
54
|
+
data: user
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async delete(id: string, versionTag?: string): Promise<void> {
|
|
59
|
+
const config: any = {
|
|
60
|
+
method: 'DELETE',
|
|
61
|
+
url: `/user/${encodeURIComponent(id)}`
|
|
62
|
+
};
|
|
63
|
+
if (versionTag) {
|
|
64
|
+
config.params = { version: versionTag };
|
|
65
|
+
}
|
|
66
|
+
await this.client.request(config);
|
|
67
|
+
}
|
|
32
68
|
}
|
package/src/client/base.ts
CHANGED
|
@@ -5,6 +5,13 @@ import { JobResource } from '../api/jobs';
|
|
|
5
5
|
import { ReflectionResource } from '../api/reflection';
|
|
6
6
|
import { SourceResource } from '../api/source';
|
|
7
7
|
import { UserResource } from '../api/user';
|
|
8
|
+
import { GovernanceResource } from '../api/governance';
|
|
9
|
+
import { CollaborationResource } from '../api/collaboration';
|
|
10
|
+
import { ScriptsResource } from '../api/scripts';
|
|
11
|
+
import { LineageResource } from '../api/lineage';
|
|
12
|
+
import { ProvisioningResource } from '../api/provisioning';
|
|
13
|
+
import { TokenResource } from '../api/token';
|
|
14
|
+
import { CredentialsResource } from '../api/credentials';
|
|
8
15
|
|
|
9
16
|
export abstract class BaseClient {
|
|
10
17
|
protected axiosInstance: AxiosInstance;
|
|
@@ -14,6 +21,13 @@ export abstract class BaseClient {
|
|
|
14
21
|
public reflections: ReflectionResource;
|
|
15
22
|
public sources: SourceResource;
|
|
16
23
|
public users: UserResource;
|
|
24
|
+
public governance: GovernanceResource;
|
|
25
|
+
public collaboration: CollaborationResource;
|
|
26
|
+
public scripts: ScriptsResource;
|
|
27
|
+
public lineage: LineageResource;
|
|
28
|
+
public provisioning: ProvisioningResource;
|
|
29
|
+
public tokens: TokenResource;
|
|
30
|
+
public credentials: CredentialsResource;
|
|
17
31
|
|
|
18
32
|
constructor(config: BaseDremioConfig) {
|
|
19
33
|
this.config = config;
|
|
@@ -30,6 +44,13 @@ export abstract class BaseClient {
|
|
|
30
44
|
this.reflections = new ReflectionResource(this);
|
|
31
45
|
this.sources = new SourceResource(this);
|
|
32
46
|
this.users = new UserResource(this);
|
|
47
|
+
this.governance = new GovernanceResource(this);
|
|
48
|
+
this.collaboration = new CollaborationResource(this);
|
|
49
|
+
this.scripts = new ScriptsResource(this);
|
|
50
|
+
this.lineage = new LineageResource(this);
|
|
51
|
+
this.provisioning = new ProvisioningResource(this);
|
|
52
|
+
this.tokens = new TokenResource(this);
|
|
53
|
+
this.credentials = new CredentialsResource(this);
|
|
33
54
|
|
|
34
55
|
// Add generic interceptors if needed
|
|
35
56
|
this.axiosInstance.interceptors.response.use(
|
|
@@ -41,6 +62,10 @@ export abstract class BaseClient {
|
|
|
41
62
|
);
|
|
42
63
|
}
|
|
43
64
|
|
|
65
|
+
public getConfig(): BaseDremioConfig {
|
|
66
|
+
return this.config;
|
|
67
|
+
}
|
|
68
|
+
|
|
44
69
|
protected abstract getAuthHeaders(): Record<string, string> | Promise<Record<string, string>>;
|
|
45
70
|
|
|
46
71
|
public async request<T = any>(config: AxiosRequestConfig): Promise<T> {
|
package/src/client/cloud.ts
CHANGED
|
@@ -39,6 +39,22 @@ const runTests = async () => {
|
|
|
39
39
|
console.warn(' Warning: Could not list reflections:', e.message);
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
+
console.log(' - Validating Provisioning (Engines)...');
|
|
43
|
+
try {
|
|
44
|
+
const engines = await cloudClient.provisioning.listEngines();
|
|
45
|
+
console.log(' Success! Found', engines.length, 'engines');
|
|
46
|
+
} catch (e: any) {
|
|
47
|
+
console.warn(' Warning: Could not list engines:', e.message);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
console.log(' - Validating Scripts...');
|
|
51
|
+
try {
|
|
52
|
+
const scripts = await cloudClient.scripts.list();
|
|
53
|
+
console.log(' Success! Found', scripts.length, 'scripts');
|
|
54
|
+
} catch (e: any) {
|
|
55
|
+
console.warn(' Warning: Could not list scripts:', e.message);
|
|
56
|
+
}
|
|
57
|
+
|
|
42
58
|
console.log(' - Running Test Query: SELECT 1');
|
|
43
59
|
const results = await cloudClient.jobs.executeQuery('SELECT 1');
|
|
44
60
|
console.log(' Query Success! Result:', results);
|
|
@@ -80,6 +96,39 @@ const runTests = async () => {
|
|
|
80
96
|
console.warn(' Warning: Could not list reflections:', e.message);
|
|
81
97
|
}
|
|
82
98
|
|
|
99
|
+
console.log(' - Validating Scripts...');
|
|
100
|
+
try {
|
|
101
|
+
const scripts = await softwareClient.scripts.list();
|
|
102
|
+
console.log(' Success! Found', scripts.length, 'scripts');
|
|
103
|
+
} catch (e: any) {
|
|
104
|
+
console.warn(' Warning: Could not list scripts (Check if supported/enabled in this version):', e.message);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
console.log(' - Validating Service User Lifecycle...');
|
|
108
|
+
try {
|
|
109
|
+
// 1. Create Service User
|
|
110
|
+
const userName = `test_svc_${Date.now()}`;
|
|
111
|
+
console.log(` Creating Service User: ${userName}...`);
|
|
112
|
+
const newUser = await softwareClient.users.create({
|
|
113
|
+
name: userName,
|
|
114
|
+
identityType: 'SERVICE_USER'
|
|
115
|
+
});
|
|
116
|
+
console.log(' Success! Created User ID:', newUser.id);
|
|
117
|
+
|
|
118
|
+
// 2. Create Credential
|
|
119
|
+
console.log(' Creating Credential...');
|
|
120
|
+
const cred = await softwareClient.credentials.create(newUser.id, 'test-secret', 30);
|
|
121
|
+
console.log(' Success! Created Credential ID:', cred.id);
|
|
122
|
+
|
|
123
|
+
// 3. Delete User
|
|
124
|
+
console.log(' Deleting User...');
|
|
125
|
+
await softwareClient.users.delete(newUser.id, newUser.tag);
|
|
126
|
+
console.log(' Success! User Deleted.');
|
|
127
|
+
|
|
128
|
+
} catch (e: any) {
|
|
129
|
+
console.warn(' Warning: Service User test failed (Admin privileges required?):', e.message);
|
|
130
|
+
}
|
|
131
|
+
|
|
83
132
|
console.log(' - Running Test Query: SELECT 1');
|
|
84
133
|
const results = await softwareClient.jobs.executeQuery('SELECT 1');
|
|
85
134
|
console.log(' Query Success! Result:', results);
|