@aravinthan_p/appnest-app-sdk-utils 0.0.1

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,212 @@
1
+ const { getParentLayerConfigObject, getTraceId } = require('../utils/contextWrapper');
2
+ const { makeSparrowAppAPICall } = require('../utils/axiosWrapper');
3
+ const { SCHEDULE_API } = require('../utils/apiConstants');
4
+
5
+ const { cronValidate } = require('cron-validate');
6
+
7
+ const validateScheduleTypeConfiguration = ({ type, cronExpression, repeat, runAt }) => {
8
+ validateScheduleType(type);
9
+ if (type === "ONE_TIME") {
10
+ if (!runAt) throw new Error("runAt is required for type ONE_TIME");
11
+ if (cronExpression) throw new Error("cronExpression is not allowed for type ONE_TIME");
12
+ if (repeat) throw new Error("repeat is not allowed for type ONE_TIME");
13
+ validateRunAt(runAt);
14
+ }
15
+ if (type === "CRON") {
16
+ if (!cronExpression) throw new Error("cronExpression is required for type CRON");
17
+ if (repeat) throw new Error("repeat is not allowed for type CRON");
18
+ if (runAt) throw new Error("runAt is not allowed for type CRON");
19
+ validCronExpression(cronExpression);
20
+ }
21
+ if (type === "RECURRING") {
22
+ if (!repeat) throw new Error("repeat is required for type RECURRING");
23
+ if (cronExpression) throw new Error("cronExpression is not allowed for type RECURRING");
24
+ if (runAt) throw new Error("runAt is not allowed for type RECURRING");
25
+ validateRepeat(repeat);
26
+ paramsData.repeat = transformRepeatConfig(repeat);
27
+ }
28
+ return true;
29
+ }
30
+
31
+ const validateRepeat = (repeat) => {
32
+ const { frequency, timeUnit } = repeat;
33
+ if (!frequency) throw new Error("repeat.frequency is required");
34
+ if (typeof frequency !== "number") throw new Error("repeat.frequency must be a number");
35
+ if (!Number.isInteger(frequency)) throw new Error("repeat.frequency must be an integer");
36
+ if (frequency <= 0) throw new Error("repeat.frequency must be greater than or equal to 1");
37
+
38
+ if (!timeUnit) throw new Error("repeat.timeUnit is required");
39
+ if (typeof timeUnit !== "string" || !["MINUTES", "HOURS", "DAYS", "WEEKS", "MONTHS", "YEARS"].includes(timeUnit)) {
40
+ throw new Error("repeat.timeUnit must be either MINUTES or HOURS or DAYS or WEEKS or MONTHS or YEARS");
41
+ }
42
+ if (timeUnit === "MINUTES" && frequency < 10) throw new Error("repeat.frequency must be greater than or equal to 10 for timeUnit MINUTES");
43
+ if (timeUnit === "HOURS" && frequency < 1) throw new Error("repeat.frequency must be greater than or equal to 1 for timeUnit HOURS");
44
+ if (timeUnit === "DAYS" && frequency < 1) throw new Error("repeat.frequency must be greater than or equal to 1 for timeUnit DAYS");
45
+ if (timeUnit === "WEEKS" && frequency < 1) throw new Error("repeat.frequency must be greater than or equal to 1 for timeUnit WEEKS");
46
+ if (timeUnit === "MONTHS" && frequency < 1) throw new Error("repeat.frequency must be greater than or equal to 1 for timeUnit MONTHS");
47
+ if (timeUnit === "YEARS" && frequency < 1) throw new Error("repeat.frequency must be greater than or equal to 1 for timeUnit YEARS");
48
+ }
49
+
50
+ const transformRepeatConfig = (repeat) => {
51
+ const { frequency, timeUnit } = repeat;
52
+ return {
53
+ every: frequency,
54
+ unit: timeUnit
55
+ }
56
+ }
57
+
58
+ const validateScheduleName = (name) => {
59
+ if (!name || typeof name !== "string" || name.trim().length === 0) {
60
+ throw new Error("name is required");
61
+ }
62
+ if (name.length > 30) throw new Error("name must be at most 30 characters");
63
+ }
64
+
65
+ const validateScheduleType = (type) => {
66
+ if (typeof type !== "string" || !["ONE_TIME", "RECURRING", "CRON"].includes(type)) {
67
+ throw new Error("type must be either ONE_TIME or RECURRING or CRON");
68
+ }
69
+ }
70
+
71
+ const validateScheduleData = (data) => {
72
+ if (!data) throw new Error("data is required");
73
+ if (typeof data !== "object") throw new Error("data must be an object");
74
+ if (Object.keys(data).length === 0) throw new Error("data must be an object with at least one key");
75
+ }
76
+
77
+ const validCronExpression = (expr) => {
78
+ const result = cronValidate(expr);
79
+ const isValid = result.isValid();
80
+ if (!isValid) throw new Error("cronExpression is not valid");
81
+ };
82
+
83
+ const validateRunAt = (runAt) => {
84
+ if (!runAt) throw new Error("runAt is required");
85
+ if (typeof runAt !== "string" || runAt.trim().length === 0) throw new Error("runAt must be a non-empty string");
86
+ const date = new Date(runAt);
87
+ if (isNaN(date.getTime())) throw new Error("runAt must be a valid date of format YYYY-MM-DD HH:MM:SS ISO 8601");
88
+ }
89
+
90
+ const create = async ({ data, name, runAt, cronExpression, repeat, type }) => {
91
+ try {
92
+ validateScheduleName(name);
93
+ validateScheduleTypeConfiguration({ type, cronExpression, repeat, runAt });
94
+ validateScheduleData(data);
95
+ const scheduleRequest = { method: "POST", data, runAt, name, type, cronExpression, repeat };
96
+ console.log("$Schedule - create - storagePayload:", JSON.stringify(scheduleRequest));
97
+ return await scheduleAPIWrapper({ apiMethod: SCHEDULE_API.CREATE.method, apiUrl: SCHEDULE_API.CREATE.endpoint, schedulePayload: scheduleRequest });
98
+ } catch (error) {
99
+ console.error("$Schedule - create - error:", error);
100
+ throw error;
101
+ }
102
+ };
103
+
104
+ const get = async ({ name, type }) => {
105
+ try {
106
+ validateScheduleName(name);
107
+ validateScheduleType(type);
108
+ const schedulePayload = { method: "GET", name, type };
109
+ console.log("$Schedule - get - storagePayload:", JSON.stringify(schedulePayload));
110
+ return await scheduleAPIWrapper({ apiMethod: SCHEDULE_API.GET.method, apiUrl: SCHEDULE_API.GET.endpoint, schedulePayload });
111
+ } catch (error) {
112
+ console.error("$Schedule - get - error:", error);
113
+ throw error;
114
+ }
115
+
116
+ }
117
+
118
+ const update = async ({ data, name, runAt, cronExpression, repeat, type }) => {
119
+ try {
120
+ validateScheduleName(name);
121
+ validateScheduleTypeConfiguration({ type, cronExpression, repeat, runAt });
122
+ validateScheduleData(data);
123
+ const request = { method: "PUT", data, runAt, name, type, cronExpression, repeat }
124
+ console.log("$Schedule - update - storagePayload:", JSON.stringify(request));
125
+ return await scheduleAPIWrapper({ apiMethod: SCHEDULE_API.UPDATE.method, apiUrl: SCHEDULE_API.UPDATE.endpoint, schedulePayload: request });
126
+ } catch (error) {
127
+ console.error("$Schedule - update - error:", error);
128
+ throw error;
129
+ }
130
+
131
+ }
132
+
133
+ const pause = async ({ name, type }) => {
134
+ try {
135
+ validateScheduleType(type);
136
+ validateScheduleName(name);
137
+ const request = { method: "PAUSE", name, type }
138
+ console.log("$Schedule - pause - storagePayload:", JSON.stringify(request));
139
+ return await scheduleAPIWrapper({ apiMethod: SCHEDULE_API.PAUSE.method, apiUrl: SCHEDULE_API.PAUSE.endpoint, schedulePayload: request });
140
+ } catch (error) {
141
+ console.error("$Schedule - pause - error:", error);
142
+ throw error;
143
+ }
144
+ }
145
+
146
+
147
+ const resume = async ({ name, type }) => {
148
+ try {
149
+ validateScheduleType(type);
150
+ validateScheduleName(name);
151
+ const request = { method: "RESUME", name, type }
152
+ console.log("$Schedule - resume - storagePayload:", JSON.stringify(request));
153
+ return await scheduleAPIWrapper({ apiMethod: SCHEDULE_API.RESUME.method, apiUrl: SCHEDULE_API.RESUME.endpoint, schedulePayload: request });
154
+ } catch (error) {
155
+ console.error("$Schedule - resume - error:", error);
156
+ throw error;
157
+ }
158
+ }
159
+
160
+ const deleteOperation = async ({ name, type }) => {
161
+ try {
162
+ validateScheduleName(name);
163
+ const schedulePayload = { method: "DELETE", name, type };
164
+ console.log("$Schedule - deleteOperation - storagePayload:", JSON.stringify(schedulePayload));
165
+ return await scheduleAPIWrapper({ apiMethod: SCHEDULE_API.DELETE.method, apiUrl: SCHEDULE_API.DELETE.endpoint, schedulePayload });
166
+ } catch (error) {
167
+ console.error("$Schedule - deleteOperation - error:", error);
168
+ throw error;
169
+ }
170
+
171
+ }
172
+
173
+
174
+ const scheduleAPIWrapper = async ({ apiMethod, apiUrl, schedulePayload }) => {
175
+ try {
176
+ const parentLayerConfigObject = getParentLayerConfigObject();
177
+ const requestBody = {
178
+ accountId: parentLayerConfigObject.accountId,
179
+ productId: parentLayerConfigObject.productId,
180
+ appId: parentLayerConfigObject.appId,
181
+ appVersionId: parentLayerConfigObject.userInstalledId,
182
+ userInstalledId: parentLayerConfigObject.userInstalledId,
183
+ ...schedulePayload
184
+ };
185
+ console.log("$Schedule - scheduleAPIWrapper - requestBody:", JSON.stringify(requestBody));
186
+ const response = await makeSparrowAppAPICall({
187
+ method: apiMethod,
188
+ endpoint: apiUrl,
189
+ requestBody
190
+ });
191
+ console.log("$Schedule - scheduleAPIWrapper - response:", JSON.stringify(response));
192
+ return { data: response?.data, status: response?.status };
193
+ } catch (error) {
194
+ console.error("$Schedule - scheduleAPIWrapper - error:", JSON.stringify(error));
195
+ throw error;
196
+ }
197
+ };
198
+
199
+
200
+
201
+ const $schedule = {
202
+ create,
203
+ delete: deleteOperation,
204
+ get,
205
+ update,
206
+ pause,
207
+ resume
208
+ };
209
+
210
+ module.exports = {
211
+ $schedule
212
+ };
@@ -0,0 +1,75 @@
1
+ const FILE_STORAGE_API = {
2
+ GET_SIGNED_URL: {
3
+ endpoint: '/get-signed-url',
4
+ method: 'POST',
5
+ },
6
+ OBJECT_EXISTS: {
7
+ endpoint: '/object-exists',
8
+ method: 'POST',
9
+ },
10
+ GET_OBJECTS: {
11
+ endpoint: '/get-objects',
12
+ method: 'POST',
13
+ },
14
+ DELETE_OBJECT: {
15
+ endpoint: '/delete-object',
16
+ method: 'POST',
17
+ },
18
+ }
19
+
20
+
21
+ const SCHEDULE_API = {
22
+ CREATE: {
23
+ endpoint: '/api/sparrow-apps/schedule',
24
+ method: 'POST',
25
+ },
26
+ GET: {
27
+ endpoint: '/api/sparrow-apps/schedule',
28
+ method: 'GET',
29
+ },
30
+ UPDATE: {
31
+ endpoint: '/api/sparrow-apps/schedule',
32
+ method: 'POST',
33
+ },
34
+ PAUSE: {
35
+ endpoint: '/api/sparrow-apps/schedule',
36
+ method: 'POST',
37
+ },
38
+ RESUME: {
39
+ endpoint: '/api/sparrow-apps/schedule',
40
+ method: 'POST',
41
+ },
42
+ DELETE: {
43
+ endpoint: '/api/sparrow-apps/schedule',
44
+ method: 'POST',
45
+ },
46
+ }
47
+
48
+ const DB_API = {
49
+ COMMON: {
50
+ endpoint: '/api/sparrow-apps/db',
51
+ method: 'POST',
52
+ }
53
+ }
54
+
55
+ const HTTP_API = {
56
+ COMMON: {
57
+ endpoint: '/v2/api/sparrow-apps/request',
58
+ method: 'POST',
59
+ }
60
+ }
61
+
62
+ const NEXT_API = {
63
+ COMMON: {
64
+ endpoint: '/api/sparrow-apps/next',
65
+ method: 'POST',
66
+ }
67
+ }
68
+
69
+ module.exports = {
70
+ FILE_STORAGE_API,
71
+ SCHEDULE_API,
72
+ DB_API,
73
+ HTTP_API,
74
+ NEXT_API
75
+ }
@@ -0,0 +1,80 @@
1
+ const axios = require('axios');
2
+ const { getParentLayerConfigObject, getTraceId } = require('./contextWrapper');
3
+
4
+ const C = {
5
+ reset: '\x1b[0m',
6
+ dim: '\x1b[2m',
7
+ red: '\x1b[31m',
8
+ green: '\x1b[32m',
9
+ yellow: '\x1b[33m',
10
+ cyan: '\x1b[36m',
11
+ };
12
+
13
+ const makeSparrowAppAPICall = async ({
14
+ method,
15
+ endpoint,
16
+ requestBody,
17
+ headers = {},
18
+ params = {},
19
+ }) => {
20
+ const parentLayerConfigObject = getParentLayerConfigObject();
21
+ const baseURL = parentLayerConfigObject.sparrowAppsDomain;
22
+ const token = parentLayerConfigObject.authToken;
23
+ if (!token) {
24
+ throw new Error('Auth token not found in request context.');
25
+ }
26
+ if (!baseURL) {
27
+ throw new Error('Sparrow App API base URL is not configured.');
28
+ }
29
+ const traceId = getTraceId();
30
+ if (traceId) {
31
+ headers['traceId'] = traceId;
32
+ }
33
+ try {
34
+ console.log(`${C.cyan}━━━ $AxiosWrapper │ makeSparrowAppAPICall ━━━${C.reset}`);
35
+ console.log(`${C.dim}📤 Request${C.reset} ${C.cyan}method${C.reset}:`, method, ` ${C.cyan}endpoint${C.reset}:`, endpoint);
36
+ console.log(`${C.dim}🔗 baseURL${C.reset}:`, baseURL);
37
+ console.log(`${C.dim}📋 requestBody${C.reset}:`, JSON.stringify(requestBody));
38
+ console.log(`${C.dim}📋 headers${C.reset}:`, JSON.stringify(headers));
39
+ console.log(`${C.dim}📋 params${C.reset}:`, JSON.stringify(params));
40
+
41
+ const response = await axios({
42
+ method,
43
+ url: `${baseURL}${endpoint}`,
44
+ headers: {
45
+ 'Content-Type': 'application/json',
46
+ auth: parentLayerConfigObject.authToken,
47
+ ...headers,
48
+ },
49
+ params: params,
50
+ data: requestBody,
51
+ });
52
+
53
+ console.log(`${C.green}━━━ $AxiosWrapper │ ✅ Response ${response.status} ${response.statusText} ━━━${C.reset}`);
54
+ console.log(`${C.dim}$AxiosWrapper │ 📥 status${C.reset}:`, response.status, response.statusText);
55
+ console.log(`${C.dim}$AxiosWrapper │ 📥 data${C.reset}:`, JSON.stringify(response.data));
56
+ console.log(`${C.dim}$AxiosWrapper │ 📥 headers${C.reset}:`, JSON.stringify(response.headers));
57
+ return response;
58
+ } catch (error) {
59
+ const res = error.response;
60
+ console.error(`${C.red}━━━ $AxiosWrapper │ ❌ Error makeSparrowAppAPICall ━━━${C.reset}`);
61
+ console.error(`${C.red} $AxiosWrapper │ 💬 error message${C.reset}:`, error.message);
62
+ console.error(`${C.dim}$AxiosWrapper │ 📍 stack${C.reset}:`, error.stack);
63
+ if (error.config) {
64
+ console.error(`${C.dim}$AxiosWrapper │ ⚙️ error config${C.reset}:`, error.config);
65
+ }
66
+ if (error.request) {
67
+ console.error(`${C.dim}$AxiosWrapper │ 📤 request${C.reset}:`, error.request);
68
+ }
69
+ if (res) {
70
+ console.error(`${C.yellow}$AxiosWrapper │ 📥 entire error response ${C.reset}:`, res);
71
+ console.error(`${C.yellow}$AxiosWrapper │ 📥 error response${C.reset} ${res.status} ${res.statusText}:`, res.data);
72
+ console.error(`${C.dim}$AxiosWrapper │ error headers${C.reset}:`, res.headers);
73
+ }
74
+ throw error;
75
+ }
76
+ };
77
+
78
+ module.exports = {
79
+ makeSparrowAppAPICall,
80
+ };
@@ -0,0 +1,12 @@
1
+ const {
2
+ getParentLayerConfigObject,
3
+ getTraceId,
4
+ getServerContext
5
+ } = require('@aravinthan_p/appnest-app-sdk-common');
6
+
7
+
8
+ module.exports = {
9
+ getParentLayerConfigObject,
10
+ getTraceId,
11
+ getServerContext
12
+ };
package/appnestSDK.MD ADDED
File without changes
@@ -0,0 +1,3 @@
1
+ const { ResultData } = require('@aravinthan_p/appnest-app-sdk-common');
2
+
3
+ module.exports = ResultData;
package/index.js ADDED
@@ -0,0 +1,7 @@
1
+ const AppnestFunctions = require('./appnestFunctions/index');
2
+ const ResultData = require('./appnestUtils/ResultData');
3
+
4
+ module.exports = {
5
+ AppnestFunctions,
6
+ ResultData
7
+ };
package/package.json ADDED
@@ -0,0 +1,10 @@
1
+ {
2
+ "name": "@aravinthan_p/appnest-app-sdk-utils",
3
+ "version": "0.0.1",
4
+ "main": "index.js",
5
+ "dependencies": {
6
+ "axios": "^1.2.1",
7
+ "cron-validate": "^1.5.3",
8
+ "@aravinthan_p/appnest-app-sdk-common": "^0.0.1"
9
+ }
10
+ }