create-dovite 2.0.0 → 2.2.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.
@@ -0,0 +1,338 @@
1
+ import domo from "ryuu.js";
2
+ import axios from "axios";
3
+
4
+ // --- Type Definitions ---
5
+
6
+ // Quick module declaration for ryuu.js if missing types
7
+ declare module "ryuu.js" {
8
+ export function get(path: string): Promise<unknown>;
9
+ export function post(
10
+ path: string,
11
+ body: unknown,
12
+ options?: unknown
13
+ ): Promise<unknown>;
14
+ }
15
+
16
+ interface DomoSqlResponse {
17
+ columns: string[];
18
+ rows: unknown[][];
19
+ metadata?: unknown;
20
+ }
21
+
22
+ interface AIResponse {
23
+ output?: string;
24
+ choices?: Array<{ output: string }>;
25
+ }
26
+
27
+ interface EmailAttachment {
28
+ filename: string;
29
+ contentType: string;
30
+ base64: string;
31
+ }
32
+
33
+ interface DomoUser {
34
+ id: number;
35
+ email: string;
36
+ role: string;
37
+ [key: string]: unknown;
38
+ }
39
+
40
+ interface DomoDataset {
41
+ id: string;
42
+ name: string;
43
+ rows: number;
44
+ columns: number;
45
+ [key: string]: unknown;
46
+ }
47
+
48
+ // --- API Functions ---
49
+
50
+ /**
51
+ * Fetches generated text from the Domo AI service.
52
+ */
53
+ export async function fetchAIData(
54
+ prompt: string,
55
+ template?: string,
56
+ maxWords?: number | string
57
+ ): Promise<string | null> {
58
+ try {
59
+ // Validate the required "prompt" parameter
60
+ if (!prompt || typeof prompt !== "string") {
61
+ throw new Error(
62
+ "The 'prompt' parameter is required and must be a string."
63
+ );
64
+ }
65
+
66
+ // Construct the body dynamically
67
+ const body: Record<string, unknown> = {
68
+ input: prompt,
69
+ };
70
+
71
+ if (template && typeof template === "string") {
72
+ body.promptTemplate = { template };
73
+ }
74
+
75
+ if (maxWords && !isNaN(Number(maxWords))) {
76
+ body.parameters = { max_words: maxWords.toString() };
77
+ }
78
+
79
+ // Send the POST request
80
+ const response = (await domo.post(
81
+ `/domo/ai/v1/text/generation`,
82
+ body
83
+ )) as AIResponse;
84
+
85
+ // console.log("AI Response:", response);
86
+
87
+ if (response?.output) {
88
+ return response.output;
89
+ }
90
+ if (response?.choices?.[0]?.output) {
91
+ return response.choices[0].output;
92
+ }
93
+
94
+ return null;
95
+ } catch (error) {
96
+ console.error("Error fetching AI data:", error);
97
+ throw error;
98
+ }
99
+ }
100
+
101
+ /**
102
+ * Simple fetch for a dataset.
103
+ */
104
+ export async function fetchData(dataset: string): Promise<unknown> {
105
+ try {
106
+ const response = await domo.get(`/data/v1/${dataset}`);
107
+ return response;
108
+ } catch (error) {
109
+ console.error(`Error fetching dataset ${dataset}:`, error);
110
+ throw error;
111
+ }
112
+ }
113
+
114
+ /**
115
+ * Executes a SQL query against a Domo dataset and returns a mapped JSON array.
116
+ * @template T - The expected shape of the row data.
117
+ */
118
+ export async function fetchSqlData<T = Record<string, unknown>>(
119
+ dataset: string,
120
+ query: string
121
+ ): Promise<T[]> {
122
+ // Ensure the query is a string
123
+ if (typeof query !== "string") {
124
+ throw new Error("Query must be a string");
125
+ }
126
+
127
+ try {
128
+ // Fetch data from the API
129
+ const apiData = (await domo.post(`/sql/v1/${dataset}`, query, {
130
+ contentType: "text/plain",
131
+ })) as DomoSqlResponse;
132
+
133
+ // Validate the fetched data
134
+ if (
135
+ !apiData ||
136
+ !Array.isArray(apiData.columns) ||
137
+ !Array.isArray(apiData.rows)
138
+ ) {
139
+ throw new Error("Invalid data received from the API");
140
+ }
141
+
142
+ // Extract and clean column names
143
+ const cleanedColumns = apiData.columns.map((column: string) => {
144
+ return column
145
+ .replace(/`/g, "")
146
+ .replace(/T1\./g, "")
147
+ .replace(/avg\((.*?)\)/i, "$1")
148
+ .trim();
149
+ });
150
+
151
+ // Map rows to cleaned column names
152
+ const jsonResult = apiData.rows.map((row: unknown[]) => {
153
+ const jsonObject: Record<string, unknown> = {};
154
+ cleanedColumns.forEach((cleanedColumn: string, index: number) => {
155
+ jsonObject[cleanedColumn] = row[index];
156
+ });
157
+ return jsonObject as T;
158
+ });
159
+
160
+ // console.log("Mapped SQL DATA", jsonResult);
161
+ return jsonResult;
162
+ } catch (error) {
163
+ console.error("Error fetching or processing SQL data:", error);
164
+ throw error;
165
+ }
166
+ }
167
+
168
+ /**
169
+ * Triggers a Domo Workflow email.
170
+ */
171
+ export async function sendEmail(
172
+ to: string | string[],
173
+ subject: string,
174
+ body: string,
175
+ attachment?: EmailAttachment
176
+ ): Promise<void> {
177
+ const data: Record<string, unknown> = {
178
+ to,
179
+ subject,
180
+ body,
181
+ };
182
+
183
+ if (attachment) {
184
+ data.attachment = [attachment];
185
+ }
186
+
187
+ try {
188
+ const response = await domo.post(
189
+ `/domo/workflow/v1/models/email/start`,
190
+ data
191
+ );
192
+ if (response) {
193
+ console.log("Email sent successfully:", response);
194
+ }
195
+ } catch (err) {
196
+ console.error("Error sending email:", err);
197
+ throw err;
198
+ }
199
+ }
200
+
201
+ /**
202
+ * Triggers a Dataflow action.
203
+ */
204
+ export const DataflowsActions = async (
205
+ action: string,
206
+ dataflowId: string | number
207
+ ): Promise<void> => {
208
+ const data = {
209
+ action,
210
+ dataflowId,
211
+ result: true,
212
+ };
213
+
214
+ try {
215
+ const response = await domo.post(
216
+ `/domo/workflow/v1/models/dataflow/start`,
217
+ data
218
+ );
219
+ if (response) {
220
+ console.log("Dataflow action response:", response);
221
+ }
222
+ } catch (err) {
223
+ console.error("Error triggering dataflow:", err);
224
+ throw err;
225
+ }
226
+ };
227
+
228
+ /**
229
+ * Generates an OAuth Access Token.
230
+ */
231
+ export const generateAccessToken = async (
232
+ clientId: string,
233
+ clientSecret: string
234
+ ): Promise<string> => {
235
+ if (!clientId || !clientSecret) {
236
+ throw new Error("Client ID and Secret are required to generate a token.");
237
+ }
238
+
239
+ const tokenUrl = "https://api.domo.com/oauth/token";
240
+
241
+ try {
242
+ const response = await axios.post<{ access_token: string }>(
243
+ tokenUrl,
244
+ new URLSearchParams({
245
+ grant_type: "client_credentials",
246
+ scope: "user",
247
+ }).toString(),
248
+ {
249
+ headers: {
250
+ "Content-Type": "application/x-www-form-urlencoded",
251
+ },
252
+ auth: {
253
+ username: clientId,
254
+ password: clientSecret,
255
+ },
256
+ }
257
+ );
258
+
259
+ // console.log("Access Token generated successfully");
260
+ return response.data.access_token;
261
+ } catch (err) {
262
+ console.error("Error generating access token:", err);
263
+ throw err;
264
+ }
265
+ };
266
+
267
+ // --- Admin/Management Functions ---
268
+
269
+ export const fetchUsers = async (
270
+ accessToken: string
271
+ ): Promise<DomoUser[] | undefined> => {
272
+ if (!accessToken) {
273
+ console.error("Access token missing in fetchUsers");
274
+ return;
275
+ }
276
+
277
+ const userUrl = `https://api.domo.com/v1/users?limit=500`;
278
+
279
+ try {
280
+ const response = await axios.get<DomoUser[]>(userUrl, {
281
+ headers: {
282
+ Authorization: `Bearer ${accessToken}`,
283
+ },
284
+ });
285
+ console.log(`Fetched ${response.data.length} users`);
286
+ return response.data;
287
+ } catch (err) {
288
+ console.error("Error fetching User details:", err);
289
+ throw err;
290
+ }
291
+ };
292
+
293
+ export const fetchDatasets = async (
294
+ accessToken: string
295
+ ): Promise<DomoDataset[] | undefined> => {
296
+ if (!accessToken) {
297
+ console.error("Access token missing in fetchDatasets");
298
+ return;
299
+ }
300
+
301
+ const datasetUrl = `https://api.domo.com/v1/datasets`;
302
+
303
+ try {
304
+ const response = await axios.get<DomoDataset[]>(datasetUrl, {
305
+ headers: {
306
+ Authorization: `Bearer ${accessToken}`,
307
+ },
308
+ });
309
+ return response.data;
310
+ } catch (err) {
311
+ console.error("Error fetching dataset details:", err);
312
+ throw err;
313
+ }
314
+ };
315
+
316
+ export const fetchDatasetDetails = async (
317
+ accessToken: string,
318
+ datasetId: string
319
+ ): Promise<DomoDataset | undefined> => {
320
+ if (!accessToken) {
321
+ console.error("Access token missing in fetchDatasetDetails");
322
+ return;
323
+ }
324
+
325
+ const datasetUrl = `https://api.domo.com/v1/datasets/${datasetId}`;
326
+
327
+ try {
328
+ const response = await axios.get<DomoDataset>(datasetUrl, {
329
+ headers: {
330
+ Authorization: `Bearer ${accessToken}`,
331
+ },
332
+ });
333
+ return response.data;
334
+ } catch (err) {
335
+ console.error("Error fetching dataset details:", err);
336
+ throw err;
337
+ }
338
+ };
@@ -0,0 +1,355 @@
1
+ // @ts-ignore
2
+ import domo from "ryuu.js";
3
+
4
+ const BASE_URL = "/domo/datastores/v1";
5
+
6
+ export interface User {
7
+ userId: string;
8
+ userName: string;
9
+ displayName: string;
10
+ avatarKey?: string;
11
+ [key: string]: any;
12
+ }
13
+
14
+ export interface Document {
15
+ [key: string]: any;
16
+ }
17
+
18
+ export interface Aggregations {
19
+ groupby?: string[];
20
+ count?: string;
21
+ avg?: Record<string, string>;
22
+ min?: Record<string, string>;
23
+ max?: Record<string, string>;
24
+ sum?: Record<string, string>;
25
+ unwind?: string[];
26
+ }
27
+
28
+ export interface QueryOptions {
29
+ orderby?: string;
30
+ limit?: number;
31
+ offset?: number;
32
+ }
33
+
34
+ const GetCurrentUser = (): Promise<User> => {
35
+ return domo
36
+ .get("/domo/environment/v1")
37
+ .then((user: any) => ({
38
+ ...user,
39
+ displayName: user.userName,
40
+ avatarKey: `/domo/avatars/v2/USER/${user.userId}`,
41
+ }))
42
+ .catch((error: any) => {
43
+ console.error("Error getting current user:", error);
44
+ throw error;
45
+ });
46
+ };
47
+
48
+ const GetAllUser = (): Promise<any> => {
49
+ return domo
50
+ .get(`/domo/users/v1?limit={500}`)
51
+ .then((response: any) => response)
52
+ .catch((error: any) => {
53
+ console.error("Error getting All users:", error);
54
+ throw error;
55
+ });
56
+ };
57
+
58
+ const GetUser = (userId: string): Promise<User> => {
59
+ return domo
60
+ .get(`/domo/users/v1/${userId}?includeDetails=true`)
61
+ .then((user: any) => ({ ...user, userName: user.displayName }))
62
+ .catch((error: any) => {
63
+ console.error("Error getting user:", error);
64
+ throw error;
65
+ });
66
+ };
67
+
68
+ const CreateDocument = (
69
+ collectionName: string,
70
+ document: Document
71
+ ): Promise<any> => {
72
+ console.log(document);
73
+ console.log(collectionName);
74
+
75
+ return domo
76
+ .post(`${BASE_URL}/collections/${collectionName}/documents/`, {
77
+ content: document,
78
+ })
79
+ .then((response: any) => response)
80
+ .catch((error: any) => {
81
+ console.error("Error creating document:", error);
82
+ throw error;
83
+ });
84
+ };
85
+
86
+ const ListDocuments = (collectionName: string): Promise<any> => {
87
+ return domo
88
+ .get(`${BASE_URL}/collections/${collectionName}/documents/`)
89
+ .then((response: any) => response)
90
+ .catch((error: any) => {
91
+ console.error("Error listing documents:", error);
92
+ throw error;
93
+ });
94
+ };
95
+
96
+ const GetDocument = (
97
+ collectionName: string,
98
+ documentId: string
99
+ ): Promise<any> => {
100
+ return domo
101
+ .get(`${BASE_URL}/collections/${collectionName}/documents/${documentId}`)
102
+ .then((response: any) => response)
103
+ .catch((error: any) => {
104
+ console.error("Error getting document:", error);
105
+ throw error;
106
+ });
107
+ };
108
+
109
+ const UpdateDocument = (
110
+ collectionName: string,
111
+ documentId: string,
112
+ document: Document
113
+ ): Promise<any> => {
114
+ return domo
115
+ .put(`${BASE_URL}/collections/${collectionName}/documents/${documentId}`, {
116
+ content: document,
117
+ })
118
+ .then((response: any) => response)
119
+ .catch((error: any) => {
120
+ console.error("Error updating document:", error);
121
+ throw error;
122
+ });
123
+ };
124
+
125
+ const queryDocumentsWithAggregations = (
126
+ collectionName: string,
127
+ query: any = {},
128
+ aggregations: Aggregations = {},
129
+ options: QueryOptions = {}
130
+ ): Promise<any> => {
131
+ // Base URL for the query
132
+ let url = `${BASE_URL}/collections/${collectionName}/documents/query?`;
133
+
134
+ // Helper function to format aggregation parameters
135
+ const formatAggregationParams = (params: Record<string, string>) => {
136
+ return Object.entries(params)
137
+ .map(([property, alias]) => `${property} ${alias}`)
138
+ .join(", ");
139
+ };
140
+
141
+ // Append aggregation parameters to URL
142
+ if (aggregations.groupby) url += `groupby=${aggregations.groupby.join(",")}&`;
143
+ if (aggregations.count) url += `count=${aggregations.count}&`;
144
+ if (aggregations.avg)
145
+ url += `avg=${formatAggregationParams(aggregations.avg)}&`;
146
+ if (aggregations.min)
147
+ url += `min=${formatAggregationParams(aggregations.min)}&`;
148
+ if (aggregations.max)
149
+ url += `max=${formatAggregationParams(aggregations.max)}&`;
150
+ if (aggregations.sum)
151
+ url += `sum=${formatAggregationParams(aggregations.sum)}&`;
152
+ if (aggregations.unwind) url += `unwind=${aggregations.unwind.join(",")}&`;
153
+
154
+ // Append options to the URL
155
+ if (options.orderby) url += `orderby=${options.orderby}&`;
156
+ if (options.limit !== undefined) url += `limit=${options.limit}&`;
157
+ if (options.offset !== undefined) url += `offset=${options.offset}&`;
158
+
159
+ // Remove trailing "&" or "?" from the URL
160
+ url = url.replace(/[&?]$/, "");
161
+
162
+ return domo
163
+ .post(url, query)
164
+ .then((response: any) => {
165
+ console.log("Query successful:", response);
166
+ return response;
167
+ })
168
+ .catch((error: any) => {
169
+ console.error("Error querying documents with aggregations:", error);
170
+ throw error;
171
+ });
172
+ };
173
+
174
+ const DeleteDocument = (
175
+ collectionName: string,
176
+ documentId: string
177
+ ): Promise<any> => {
178
+ return domo
179
+ .delete(`${BASE_URL}/collections/${collectionName}/documents/${documentId}`)
180
+ .then((response: any) => response.data)
181
+ .catch((error: any) => {
182
+ console.error("Error deleting document:", error);
183
+ throw error;
184
+ });
185
+ };
186
+
187
+ const QueryDocument = (
188
+ collectionName: string,
189
+ query: any = {},
190
+ options: QueryOptions = {}
191
+ ): Promise<any> => {
192
+ // Base URL for querying documents
193
+ let url = `${BASE_URL}/collections/${collectionName}/documents/query?`;
194
+
195
+ // Append optional parameters to the URL
196
+ if (options.limit !== undefined) url += `limit=${options.limit}&`;
197
+ if (options.offset !== undefined) url += `offset=${options.offset}&`;
198
+ if (options.orderby) url += `orderby=${options.orderby}&`;
199
+
200
+ // Remove trailing "&" or "?" from the URL
201
+ url = url.replace(/[&?]$/, "");
202
+
203
+ return domo
204
+ .post(url, query)
205
+ .then((response: any) => {
206
+ // console.log("Query successful:", response);
207
+ return response;
208
+ })
209
+ .catch((error: any) => {
210
+ console.error("Error querying documents:", error);
211
+ throw error;
212
+ });
213
+ };
214
+
215
+ // Query documents based on a specific date range
216
+ const queryDocumentsByDate = (
217
+ collectionName: string,
218
+ dateString: string,
219
+ options: QueryOptions = {}
220
+ ): Promise<any> => {
221
+ const query = {
222
+ createdOn: {
223
+ $lte: { $date: dateString },
224
+ },
225
+ };
226
+ return QueryDocument(collectionName, query, options);
227
+ };
228
+
229
+ const BulkDeleteDocuments = (
230
+ collectionName: string,
231
+ ids: string[]
232
+ ): Promise<any> => {
233
+ return domo
234
+ .delete(
235
+ `${BASE_URL}/collections/${collectionName}/documents/bulk?ids=${ids}`
236
+ )
237
+ .then((response: any) => response)
238
+ .catch((error: any) => {
239
+ console.error("Error bulk deleting documents:", error);
240
+ throw error;
241
+ });
242
+ };
243
+
244
+ const UploadFile = (
245
+ file: File,
246
+ name: string,
247
+ description: string = "",
248
+ isPublic: boolean = false
249
+ ): Promise<any> => {
250
+ const formData = new FormData();
251
+ formData.append("file", file);
252
+ const url = `/domo/data-files/v1?name=
253
+ ${name}&description=${description}&public=${isPublic}`;
254
+ const options = { contentType: "multipart" };
255
+ return domo
256
+ .post(url, formData, options)
257
+ .then((response: any) => response)
258
+ .catch((err: any) => {
259
+ console.log(err);
260
+ throw err;
261
+ });
262
+ };
263
+
264
+ const UploadRevision = (file: File, fileId: string): Promise<any> => {
265
+ const formData = new FormData();
266
+ formData.append("file", file);
267
+ const url = `/domo/data-files/v1/${fileId}`;
268
+ const options = { contentType: "multipart" };
269
+ return domo
270
+ .put(url, formData, options)
271
+ .then((response: any) => response)
272
+ .catch((err: any) => {
273
+ console.log(err);
274
+ throw err;
275
+ });
276
+ };
277
+
278
+ const GetFile = (fileId: string, revisionId?: string): Promise<any> => {
279
+ const options: any = { responseType: "blob" };
280
+ const url = `/domo/data-files/v1/${fileId}${
281
+ revisionId ? `/revisions/${revisionId}` : ""
282
+ }`;
283
+ return domo
284
+ .get(url, options)
285
+ .then((data: any) => data)
286
+ .catch((err: any) => {
287
+ console.log(err);
288
+ throw err;
289
+ });
290
+ };
291
+
292
+ const ListAllUsers = async (
293
+ includeDetails: boolean = false,
294
+ limit: number = 100,
295
+ offset: number = 0
296
+ ): Promise<any> => {
297
+ try {
298
+ const response = await domo.get(
299
+ `/domo/users/v1?includeDetails=${includeDetails}&limit=${limit}&offset=${offset}`
300
+ );
301
+ return response;
302
+ } catch (error) {
303
+ console.error("Error listing users:", error);
304
+ throw error;
305
+ }
306
+ };
307
+
308
+ const partialupdateDocument = (
309
+ collectionName: string,
310
+ query: any,
311
+ operation: any
312
+ ): Promise<any> => {
313
+ const requestBody = {
314
+ query: query,
315
+ operation: operation,
316
+ };
317
+
318
+ console.log("Request body:", requestBody);
319
+
320
+ return domo
321
+ .put(
322
+ `${BASE_URL}/collections/${collectionName}/documents/update`,
323
+ requestBody
324
+ )
325
+ .then((response: any) => {
326
+ console.log("Document updated successfully:", response);
327
+ return response;
328
+ })
329
+ .catch((error: any) => {
330
+ console.error("Error updating document:", error);
331
+ throw error;
332
+ });
333
+ };
334
+
335
+ const DomoApi = {
336
+ GetCurrentUser,
337
+ GetAllUser,
338
+ GetUser,
339
+ CreateDocument,
340
+ ListDocuments,
341
+ DeleteDocument,
342
+ BulkDeleteDocuments,
343
+ GetDocument,
344
+ UpdateDocument,
345
+ QueryDocument,
346
+ queryDocumentsByDate,
347
+ UploadFile,
348
+ UploadRevision,
349
+ GetFile,
350
+ queryDocumentsWithAggregations,
351
+ ListAllUsers,
352
+ partialupdateDocument,
353
+ };
354
+
355
+ export default DomoApi;
@@ -0,0 +1,7 @@
1
+ import DefaultPage from "./pages/index";
2
+
3
+ function App() {
4
+ return <DefaultPage />;
5
+ }
6
+
7
+ export default App;
@@ -0,0 +1 @@
1
+ @import "tailwindcss";