@ketrics/ketrics-cli 0.2.2 → 0.3.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.
Files changed (37) hide show
  1. package/README.md +623 -607
  2. package/dist/src/cli.d.ts.map +1 -1
  3. package/dist/src/cli.js +2 -2
  4. package/dist/src/cli.js.map +1 -1
  5. package/dist/src/version.d.ts +2 -0
  6. package/dist/src/version.d.ts.map +1 -0
  7. package/dist/src/version.js +6 -0
  8. package/dist/src/version.js.map +1 -0
  9. package/package.json +3 -2
  10. package/templates/HelloWorld/README.md +83 -106
  11. package/templates/HelloWorld/backend/package.json +1 -1
  12. package/templates/HelloWorld/backend/src/database.ts +108 -0
  13. package/templates/HelloWorld/backend/src/excel.ts +118 -0
  14. package/templates/HelloWorld/backend/src/http.ts +22 -0
  15. package/templates/HelloWorld/backend/src/index.ts +105 -29
  16. package/templates/HelloWorld/backend/src/jobs.ts +47 -0
  17. package/templates/HelloWorld/backend/src/messages.ts +59 -0
  18. package/templates/HelloWorld/backend/src/pdf.ts +212 -0
  19. package/templates/HelloWorld/backend/src/secrets.ts +21 -14
  20. package/templates/HelloWorld/backend/src/volumes.ts +107 -0
  21. package/templates/HelloWorld/frontend/package.json +1 -3
  22. package/templates/HelloWorld/frontend/src/App.css +62 -37
  23. package/templates/HelloWorld/frontend/src/App.tsx +131 -111
  24. package/templates/HelloWorld/frontend/src/services/index.ts +11 -11
  25. package/templates/HelloWorld/tests/test.createInvoicePdf.json +18 -0
  26. package/templates/HelloWorld/tests/{test.getSecretWithoutGrant.json → test.createSimplePdf.json} +4 -2
  27. package/templates/HelloWorld/tests/test.createSpreadsheet.json +11 -0
  28. package/templates/HelloWorld/tests/test.echo.json +2 -2
  29. package/templates/HelloWorld/tests/test.fetchExternalApi.json +13 -0
  30. package/templates/HelloWorld/tests/test.getSecret.json +5 -1
  31. package/templates/HelloWorld/tests/test.info.json +3 -1
  32. package/templates/HelloWorld/tests/test.listFiles.json +13 -0
  33. package/templates/HelloWorld/tests/{test.echo2.json → test.queryUsers.json} +3 -3
  34. package/templates/HelloWorld/tests/{test.greet.json → test.readFile.json} +2 -2
  35. package/templates/HelloWorld/tests/{test.testWriteFileWithoutVolumeGrant.json → test.saveFile.json} +4 -2
  36. package/templates/HelloWorld/tests/test.sendNotification.json +14 -0
  37. package/templates/HelloWorld/backend/src/volume.ts +0 -55
@@ -1,57 +1,133 @@
1
1
  /**
2
2
  * Ketrics Application Backend
3
3
  *
4
- * Exports handler functions compatible with Ketrics data-plane-api.
4
+ * Exports handler functions compatible with Ketrics Runtime API.
5
5
  *
6
- * The `ketrics` global object is automatically typed via @ketrics/sdk.
6
+ * The `ketrics` global object is automatically typed via @ketrics/sdk-backend.
7
7
  * No imports needed - just use `ketrics.*` directly.
8
8
  *
9
9
  * Available SDK features:
10
- * - ketrics.tenant, ketrics.application, ketrics.requestor, ketrics.env (context)
10
+ * - ketrics.tenant, ketrics.application, ketrics.requestor, ketrics.runtime, ketrics.environment (context)
11
11
  * - ketrics.console (logging to CloudWatch)
12
12
  * - ketrics.http (HTTP client for external APIs)
13
- * - ketrics.Volume.connect(code) (S3-backed storage)
14
- * - ketrics.DatabaseConnection.connect(code) (external databases)
13
+ * - ketrics.Volume.connect(code) (S3-backed file storage)
14
+ * - ketrics.Database.connect(code) (external SQL databases)
15
15
  * - ketrics.Secret.get(code) (encrypted secrets)
16
+ * - ketrics.Excel.create() / ketrics.Excel.read(buffer) (Excel workbooks)
17
+ * - ketrics.Pdf.create() / ketrics.Pdf.read(buffer) (PDF documents)
18
+ * - ketrics.Job.runInBackground(params) (background job execution)
19
+ * - ketrics.Messages.send(params) (user messaging)
16
20
  */
17
21
 
22
+ // Volume examples: save, read, list, download URL, copy files
23
+ import {
24
+ saveFile,
25
+ readFile,
26
+ listFiles,
27
+ generateDownloadUrl,
28
+ copyFile,
29
+ } from "./volumes";
30
+
31
+ // Database examples: query, insert, transaction
32
+ import {
33
+ queryUsers,
34
+ insertRecord,
35
+ transferFunds,
36
+ } from "./database";
37
+
38
+ // PDF examples: create invoice, create report
39
+ import {
40
+ createInvoicePdf,
41
+ createSimplePdf,
42
+ } from "./pdf";
43
+
44
+ // Excel examples: create spreadsheet, export data
45
+ import {
46
+ createSpreadsheet,
47
+ exportDataToExcel,
48
+ } from "./excel";
49
+
50
+ // Secret management examples
51
+ import { getSecret } from "./secrets";
52
+
53
+ // Messaging examples
54
+ import { sendNotification, sendBulkNotification } from "./messages";
55
+
56
+ // Background job examples
57
+ import { scheduleBackgroundJob, getJobStatus } from "./jobs";
58
+
59
+ // HTTP client examples
60
+ import { fetchExternalApi } from "./http";
61
+
18
62
  // ============================================================================
19
63
  // Basic Handlers
20
64
  // ============================================================================
21
65
 
22
- import { saveFile, readFile, generateDownloadUrl, testWriteFileWithoutVolumeGrant } from "./volume";
23
- import { getSecret, getSecretWithoutGrant } from "./secrets";
24
-
25
66
  /**
26
- * Echo handler - returns payload with context info
27
- *
28
- * @param payload - Any payload to echo back
29
- * @returns Payload with additional context information
67
+ * Echo handler - returns the payload along with full context info.
68
+ * Useful for debugging and verifying SDK access.
30
69
  */
31
-
32
70
  const echo = async (payload: unknown) => {
33
71
  ketrics.console.log(
34
- `Echo was called by ${ketrics.requestor.type}:${ketrics.requestor.userId || ketrics.requestor.serviceAccountCode} in tenant ${ketrics.tenant.id}`,
72
+ `Echo called by ${ketrics.requestor.type}:${ketrics.requestor.userId || ketrics.requestor.serviceAccountCode}`,
35
73
  );
36
74
 
37
- // Only send message if requestor is a user
38
-
39
- if (ketrics.requestor.type === "USER") {
40
- await ketrics.Messages.send({
41
- userId: ketrics.requestor.userId!,
42
- type: "notification",
43
- subject: "Echo called",
44
- body: `Echo was called by ${ketrics.requestor.type}:${ketrics.requestor.email} in tenant ${ketrics.tenant.id}`,
45
- });
46
- }
75
+ return {
76
+ payload,
77
+ context: {
78
+ tenant: ketrics.tenant,
79
+ application: ketrics.application,
80
+ requestor: ketrics.requestor,
81
+ runtime: ketrics.runtime,
82
+ environment: ketrics.environment,
83
+ },
84
+ };
85
+ };
47
86
 
87
+ /**
88
+ * Info handler - returns runtime environment details.
89
+ */
90
+ const info = async () => {
48
91
  return {
49
- tenant: ketrics.tenant,
50
- requestor: ketrics.requestor,
51
- application: ketrics.application,
52
- environment: ketrics.environment,
92
+ tenant: { id: ketrics.tenant.id, code: ketrics.tenant.code, name: ketrics.tenant.name },
93
+ application: {
94
+ id: ketrics.application.id,
95
+ code: ketrics.application.code,
96
+ name: ketrics.application.name,
97
+ version: ketrics.application.version,
98
+ },
53
99
  runtime: ketrics.runtime,
54
100
  };
55
101
  };
56
102
 
57
- export { echo, saveFile, readFile, generateDownloadUrl, testWriteFileWithoutVolumeGrant, getSecret, getSecretWithoutGrant };
103
+ export {
104
+ // Basic
105
+ echo,
106
+ info,
107
+ // Volumes
108
+ saveFile,
109
+ readFile,
110
+ listFiles,
111
+ generateDownloadUrl,
112
+ copyFile,
113
+ // Database
114
+ queryUsers,
115
+ insertRecord,
116
+ transferFunds,
117
+ // PDF
118
+ createInvoicePdf,
119
+ createSimplePdf,
120
+ // Excel
121
+ createSpreadsheet,
122
+ exportDataToExcel,
123
+ // Secrets
124
+ getSecret,
125
+ // Messages
126
+ sendNotification,
127
+ sendBulkNotification,
128
+ // Jobs
129
+ scheduleBackgroundJob,
130
+ getJobStatus,
131
+ // HTTP
132
+ fetchExternalApi,
133
+ };
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Background Job Examples
3
+ *
4
+ * Demonstrates scheduling and monitoring background jobs using ketrics.Job.
5
+ * Background jobs run asynchronously and can have longer timeouts (up to 15 minutes).
6
+ */
7
+
8
+ /**
9
+ * Schedule a function to run in the background.
10
+ */
11
+ const scheduleBackgroundJob = async (payload: {
12
+ functionName?: string;
13
+ data?: Record<string, unknown>;
14
+ }) => {
15
+ const jobId = await ketrics.Job.runInBackground({
16
+ function: payload?.functionName || "echo",
17
+ payload: payload?.data || { source: "background-job" },
18
+ options: {
19
+ timeout: 60000, // 1 minute timeout
20
+ },
21
+ });
22
+
23
+ return { jobId, status: "scheduled" };
24
+ };
25
+
26
+ /**
27
+ * Check the status of a background job.
28
+ */
29
+ const getJobStatus = async (payload: { jobId: string }) => {
30
+ if (!payload?.jobId) {
31
+ throw new Error("jobId is required");
32
+ }
33
+
34
+ const status = await ketrics.Job.getStatus(payload.jobId);
35
+
36
+ return {
37
+ jobId: status.jobId,
38
+ functionName: status.functionName,
39
+ status: status.status,
40
+ createdAt: status.createdAt,
41
+ startedAt: status.startedAt,
42
+ completedAt: status.completedAt,
43
+ error: status.error,
44
+ };
45
+ };
46
+
47
+ export { scheduleBackgroundJob, getJobStatus };
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Messages Examples
3
+ *
4
+ * Demonstrates sending notifications to users via ketrics.Messages.
5
+ * Messages appear in the user's inbox within the Ketrics portal.
6
+ */
7
+
8
+ /**
9
+ * Send a notification to the current user.
10
+ */
11
+ const sendNotification = async (payload: { subject?: string; body?: string }) => {
12
+ if (ketrics.requestor.type !== "USER") {
13
+ throw new Error("This function can only be called by a user");
14
+ }
15
+
16
+ const result = await ketrics.Messages.send({
17
+ userId: ketrics.requestor.userId!,
18
+ type: "notification",
19
+ subject: payload?.subject || "Hello from your app!",
20
+ body: payload?.body || `This notification was sent by **${ketrics.application.name}**.`,
21
+ priority: "MEDIUM",
22
+ channels: { inbox: true, push: false },
23
+ });
24
+
25
+ return {
26
+ messageId: result.messageId,
27
+ status: result.status,
28
+ };
29
+ };
30
+
31
+ /**
32
+ * Send a notification to multiple users.
33
+ */
34
+ const sendBulkNotification = async (payload: {
35
+ userIds: string[];
36
+ subject: string;
37
+ body: string;
38
+ }) => {
39
+ if (!payload?.userIds?.length) {
40
+ throw new Error("userIds array is required");
41
+ }
42
+
43
+ const result = await ketrics.Messages.sendBulk({
44
+ userIds: payload.userIds,
45
+ type: "announcement",
46
+ subject: payload.subject,
47
+ body: payload.body,
48
+ priority: "HIGH",
49
+ channels: { inbox: true, push: true },
50
+ });
51
+
52
+ return {
53
+ total: result.total,
54
+ sent: result.sent,
55
+ failed: result.failed,
56
+ };
57
+ };
58
+
59
+ export { sendNotification, sendBulkNotification };
@@ -0,0 +1,212 @@
1
+ /**
2
+ * PDF Examples
3
+ *
4
+ * Demonstrates PDF document creation using ketrics.Pdf.
5
+ * Generated PDFs can be saved to a volume for download.
6
+ */
7
+
8
+ /**
9
+ * Create a simple PDF document and save it to a volume.
10
+ */
11
+ const createSimplePdf = async () => {
12
+ const doc = await ketrics.Pdf.create();
13
+
14
+ // Set document metadata
15
+ doc.setTitle("Sample Document");
16
+ doc.setAuthor(ketrics.tenant.name);
17
+ doc.setCreator(ketrics.application.name);
18
+
19
+ // Add a page
20
+ const page = doc.addPage({ size: "A4" });
21
+
22
+ // Embed a standard font
23
+ const font = await doc.embedStandardFont("Helvetica");
24
+ const boldFont = await doc.embedStandardFont("Helvetica-Bold");
25
+
26
+ // Draw title
27
+ page.drawText("Hello from Ketrics!", {
28
+ x: 50,
29
+ y: 780,
30
+ size: 28,
31
+ font: boldFont,
32
+ color: ketrics.Pdf.rgb(0.2, 0.2, 0.6),
33
+ });
34
+
35
+ // Draw subtitle
36
+ page.drawText(`Generated by ${ketrics.application.name} for ${ketrics.tenant.name}`, {
37
+ x: 50,
38
+ y: 750,
39
+ size: 12,
40
+ font,
41
+ color: ketrics.Pdf.rgb(0.4, 0.4, 0.4),
42
+ });
43
+
44
+ // Draw a decorative line
45
+ page.drawLine({
46
+ start: { x: 50, y: 740 },
47
+ end: { x: 545, y: 740 },
48
+ thickness: 2,
49
+ color: ketrics.Pdf.rgb(0.2, 0.2, 0.6),
50
+ });
51
+
52
+ // Draw body text
53
+ page.drawText("This PDF was generated dynamically using the Ketrics PDF SDK.", {
54
+ x: 50,
55
+ y: 710,
56
+ size: 14,
57
+ font,
58
+ color: ketrics.Pdf.rgb(0, 0, 0),
59
+ });
60
+
61
+ page.drawText(`Date: ${new Date().toISOString()}`, {
62
+ x: 50,
63
+ y: 685,
64
+ size: 11,
65
+ font,
66
+ color: ketrics.Pdf.rgb(0.3, 0.3, 0.3),
67
+ });
68
+
69
+ // Save to volume
70
+ const buffer = await doc.toBuffer();
71
+ const volume = await ketrics.Volume.connect("test-volume");
72
+ const result = await volume.put("documents/sample.pdf", buffer, {
73
+ contentType: "application/pdf",
74
+ });
75
+
76
+ // Generate download URL
77
+ const downloadUrl = await volume.generateDownloadUrl("documents/sample.pdf", {
78
+ expiresIn: 3600,
79
+ });
80
+
81
+ return {
82
+ file: { key: result.key, size: result.size },
83
+ downloadUrl: downloadUrl.url,
84
+ pageCount: doc.getPageCount(),
85
+ };
86
+ };
87
+
88
+ /**
89
+ * Create an invoice-style PDF with structured data.
90
+ */
91
+ const createInvoicePdf = async (payload: {
92
+ invoiceNumber?: string;
93
+ customerName?: string;
94
+ items?: Array<{ description: string; quantity: number; price: number }>;
95
+ }) => {
96
+ const invoiceNumber = payload?.invoiceNumber || "INV-001";
97
+ const customerName = payload?.customerName || "Sample Customer";
98
+ const items = payload?.items || [
99
+ { description: "Web Development", quantity: 40, price: 150 },
100
+ { description: "Design Services", quantity: 20, price: 120 },
101
+ { description: "Consulting", quantity: 10, price: 200 },
102
+ ];
103
+
104
+ const doc = await ketrics.Pdf.create();
105
+ doc.setTitle(`Invoice ${invoiceNumber}`);
106
+ doc.setAuthor(ketrics.tenant.name);
107
+
108
+ const page = doc.addPage({ size: "A4" });
109
+ const font = await doc.embedStandardFont("Helvetica");
110
+ const boldFont = await doc.embedStandardFont("Helvetica-Bold");
111
+
112
+ let y = 780;
113
+
114
+ // Header
115
+ page.drawText("INVOICE", {
116
+ x: 50, y, size: 32, font: boldFont,
117
+ color: ketrics.Pdf.rgb(0.2, 0.2, 0.6),
118
+ });
119
+
120
+ y -= 35;
121
+ page.drawText(`#${invoiceNumber}`, {
122
+ x: 50, y, size: 14, font,
123
+ color: ketrics.Pdf.rgb(0.4, 0.4, 0.4),
124
+ });
125
+
126
+ // Company info (right side)
127
+ page.drawText(ketrics.tenant.name, {
128
+ x: 400, y: 780, size: 14, font: boldFont,
129
+ color: ketrics.Pdf.rgb(0, 0, 0),
130
+ });
131
+
132
+ page.drawText(new Date().toLocaleDateString(), {
133
+ x: 400, y: 762, size: 11, font,
134
+ color: ketrics.Pdf.rgb(0.4, 0.4, 0.4),
135
+ });
136
+
137
+ // Divider
138
+ y -= 20;
139
+ page.drawLine({
140
+ start: { x: 50, y },
141
+ end: { x: 545, y },
142
+ thickness: 1,
143
+ color: ketrics.Pdf.rgb(0.8, 0.8, 0.8),
144
+ });
145
+
146
+ // Bill To
147
+ y -= 30;
148
+ page.drawText("Bill To:", { x: 50, y, size: 10, font, color: ketrics.Pdf.rgb(0.5, 0.5, 0.5) });
149
+ y -= 18;
150
+ page.drawText(customerName, { x: 50, y, size: 14, font: boldFont, color: ketrics.Pdf.rgb(0, 0, 0) });
151
+
152
+ // Table header
153
+ y -= 40;
154
+ page.drawRectangle({
155
+ x: 50, y: y - 5, width: 495, height: 25,
156
+ color: ketrics.Pdf.rgb(0.93, 0.93, 0.97),
157
+ });
158
+
159
+ page.drawText("Description", { x: 60, y, size: 10, font: boldFont, color: ketrics.Pdf.rgb(0.3, 0.3, 0.3) });
160
+ page.drawText("Qty", { x: 330, y, size: 10, font: boldFont, color: ketrics.Pdf.rgb(0.3, 0.3, 0.3) });
161
+ page.drawText("Price", { x: 400, y, size: 10, font: boldFont, color: ketrics.Pdf.rgb(0.3, 0.3, 0.3) });
162
+ page.drawText("Total", { x: 480, y, size: 10, font: boldFont, color: ketrics.Pdf.rgb(0.3, 0.3, 0.3) });
163
+
164
+ // Table rows
165
+ let grandTotal = 0;
166
+ for (const item of items) {
167
+ y -= 25;
168
+ const lineTotal = item.quantity * item.price;
169
+ grandTotal += lineTotal;
170
+
171
+ page.drawText(item.description, { x: 60, y, size: 11, font, color: ketrics.Pdf.rgb(0, 0, 0) });
172
+ page.drawText(String(item.quantity), { x: 335, y, size: 11, font, color: ketrics.Pdf.rgb(0, 0, 0) });
173
+ page.drawText(`$${item.price.toFixed(2)}`, { x: 395, y, size: 11, font, color: ketrics.Pdf.rgb(0, 0, 0) });
174
+ page.drawText(`$${lineTotal.toFixed(2)}`, { x: 475, y, size: 11, font, color: ketrics.Pdf.rgb(0, 0, 0) });
175
+ }
176
+
177
+ // Total
178
+ y -= 15;
179
+ page.drawLine({
180
+ start: { x: 380, y },
181
+ end: { x: 545, y },
182
+ thickness: 1,
183
+ color: ketrics.Pdf.rgb(0.8, 0.8, 0.8),
184
+ });
185
+
186
+ y -= 20;
187
+ page.drawText("Total:", { x: 400, y, size: 14, font: boldFont, color: ketrics.Pdf.rgb(0, 0, 0) });
188
+ page.drawText(`$${grandTotal.toFixed(2)}`, {
189
+ x: 470, y, size: 14, font: boldFont,
190
+ color: ketrics.Pdf.rgb(0.2, 0.2, 0.6),
191
+ });
192
+
193
+ // Save to volume
194
+ const buffer = await doc.toBuffer();
195
+ const volume = await ketrics.Volume.connect("test-volume");
196
+ const fileName = `invoices/${invoiceNumber}.pdf`;
197
+ const result = await volume.put(fileName, buffer, {
198
+ contentType: "application/pdf",
199
+ });
200
+
201
+ const downloadUrl = await volume.generateDownloadUrl(fileName, { expiresIn: 3600 });
202
+
203
+ return {
204
+ file: { key: result.key, size: result.size },
205
+ downloadUrl: downloadUrl.url,
206
+ invoiceNumber,
207
+ total: grandTotal,
208
+ itemCount: items.length,
209
+ };
210
+ };
211
+
212
+ export { createSimplePdf, createInvoicePdf };
@@ -1,17 +1,24 @@
1
- const getSecret = async (key: string): Promise<{ value: string }> => {
2
- const value = await ketrics.Secret.get("apikey");
3
- if (!value) {
4
- throw new Error(`Secret with key "${key}" not found`);
5
- }
6
- return { value };
7
- };
1
+ /**
2
+ * Secret Examples
3
+ *
4
+ * Demonstrates encrypted secret retrieval using ketrics.Secret.
5
+ * Secrets must be created and granted to the application in the Ketrics portal.
6
+ */
7
+
8
+ /**
9
+ * Retrieve an encrypted secret by code.
10
+ */
11
+ const getSecret = async (payload: { code?: string }) => {
12
+ const secretCode = payload?.code || "apikey";
13
+ const value = await ketrics.Secret.get(secretCode);
8
14
 
9
- const getSecretWithoutGrant = async (key: string): Promise<{ value: string }> => {
10
- const value = await ketrics.Secret.get("missing-grant-secret");
11
- if (!value) {
12
- throw new Error(`Secret with key "${key}" not found`);
13
- }
14
- return { value };
15
+ // In production, never return the secret value directly.
16
+ // This is only for demonstration purposes.
17
+ return {
18
+ code: secretCode,
19
+ retrieved: true,
20
+ valueLength: value.length,
21
+ };
15
22
  };
16
23
 
17
- export { getSecret, getSecretWithoutGrant };
24
+ export { getSecret };
@@ -0,0 +1,107 @@
1
+ /**
2
+ * Volume Examples
3
+ *
4
+ * Demonstrates S3-backed file storage operations using ketrics.Volume.
5
+ * Volumes must be granted to the application in the Ketrics portal before use.
6
+ */
7
+
8
+ /**
9
+ * Save files to a volume - demonstrates writing JSON and binary data.
10
+ */
11
+ const saveFile = async () => {
12
+ const volume = await ketrics.Volume.connect("test-volume");
13
+
14
+ // Write JSON content
15
+ const jsonData = {
16
+ generatedBy: ketrics.application.code,
17
+ generatedAt: new Date().toISOString(),
18
+ tenant: ketrics.tenant.code,
19
+ };
20
+ const jsonResult = await volume.put("output/data.json", JSON.stringify(jsonData), {
21
+ contentType: "application/json",
22
+ });
23
+
24
+ // Write plain text content
25
+ const textResult = await volume.put("output/hello.txt", Buffer.from("Hello from Ketrics!"), {
26
+ contentType: "text/plain",
27
+ });
28
+
29
+ return {
30
+ jsonFile: { key: jsonResult.key, etag: jsonResult.etag, size: jsonResult.size },
31
+ textFile: { key: textResult.key, etag: textResult.etag, size: textResult.size },
32
+ };
33
+ };
34
+
35
+ /**
36
+ * Read a file from a volume - demonstrates reading and parsing stored data.
37
+ */
38
+ const readFile = async () => {
39
+ const volume = await ketrics.Volume.connect("test-volume");
40
+
41
+ const exists = await volume.exists("output/data.json");
42
+ if (!exists) {
43
+ return { error: "File not found. Run saveFile first." };
44
+ }
45
+
46
+ const file = await volume.get("output/data.json");
47
+ const content = file.content.toString();
48
+
49
+ return {
50
+ contentType: file.contentType,
51
+ contentLength: file.contentLength,
52
+ lastModified: file.lastModified,
53
+ parsed: JSON.parse(content),
54
+ };
55
+ };
56
+
57
+ /**
58
+ * List files in a volume - demonstrates pagination and prefix filtering.
59
+ */
60
+ const listFiles = async (payload: { prefix?: string }) => {
61
+ const volume = await ketrics.Volume.connect("test-volume");
62
+
63
+ const result = await volume.list({
64
+ prefix: payload?.prefix || "output/",
65
+ maxResults: 50,
66
+ });
67
+
68
+ return {
69
+ files: result.files.map((f) => ({
70
+ key: f.key,
71
+ size: f.size,
72
+ lastModified: f.lastModified,
73
+ contentType: f.contentType,
74
+ })),
75
+ count: result.count,
76
+ isTruncated: result.isTruncated,
77
+ };
78
+ };
79
+
80
+ /**
81
+ * Generate a temporary download URL for a file.
82
+ */
83
+ const generateDownloadUrl = async () => {
84
+ const volume = await ketrics.Volume.connect("test-volume");
85
+ const result = await volume.generateDownloadUrl("output/data.json", {
86
+ expiresIn: 3600, // 1 hour
87
+ });
88
+
89
+ return { url: result.url, expiresAt: result.expiresAt };
90
+ };
91
+
92
+ /**
93
+ * Copy a file within a volume.
94
+ */
95
+ const copyFile = async () => {
96
+ const volume = await ketrics.Volume.connect("test-volume");
97
+
98
+ const result = await volume.copy("output/data.json", "backup/data-backup.json");
99
+
100
+ return {
101
+ sourceKey: result.sourceKey,
102
+ destinationKey: result.destinationKey,
103
+ etag: result.etag,
104
+ };
105
+ };
106
+
107
+ export { saveFile, readFile, listFiles, generateDownloadUrl, copyFile };
@@ -9,10 +9,8 @@
9
9
  },
10
10
  "dependencies": {
11
11
  "@ketrics/sdk-frontend": "^0.1.1",
12
- "axios": "^1.13.2",
13
12
  "react": "^18.2.0",
14
- "react-dom": "^18.2.0",
15
- "zod": "^3.22.4"
13
+ "react-dom": "^18.2.0"
16
14
  },
17
15
  "devDependencies": {
18
16
  "@types/react": "^18.2.0",