Skip to content

Commit bf1f8fa

Browse files
1.2.0 (#1032)
Merging Next (1.2.0) into --> Main
2 parents 39e8c59 + 71f5517 commit bf1f8fa

File tree

30 files changed

+2933
-274
lines changed

30 files changed

+2933
-274
lines changed

apps/api/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@impler/api",
3-
"version": "1.1.1",
3+
"version": "1.2.0",
44
"author": "implerhq",
55
"license": "MIT",
66
"private": true,
@@ -43,7 +43,7 @@
4343
"ajv-formats": "^2.1.1",
4444
"ajv-keywords": "^5.1.0",
4545
"async-mutex": "^0.4.0",
46-
"axios": "1.6.2",
46+
"axios": "1.8.2",
4747
"bcryptjs": "^2.4.3",
4848
"body-parser": "^1.20.0",
4949
"class-transformer": "^0.5.1",

apps/api/src/app/import-jobs/usecase/create-userjob/create-userjob.usecase.ts

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
1-
import { Injectable } from '@nestjs/common';
1+
import { BadRequestException, Injectable } from '@nestjs/common';
22
import { UserJobEntity, UserJobRepository } from '@impler/dal';
33
import { CreateUserJobCommand } from './create-userjob.command';
44
import { APIMessages } from '@shared/constants';
5-
import { BadRequestException } from '@nestjs/common';
65
import { RSSXMLService } from '@impler/services';
7-
import { isValidXMLMimeType } from '@shared/helpers/common.helper';
6+
import { getMimeType, isValidXMLMimeType } from '@shared/helpers/common.helper';
87
import { WebSocketService } from '@shared/services';
98

109
@Injectable()
@@ -24,10 +23,11 @@ export class CreateUserJob {
2423
}: CreateUserJobCommand): Promise<UserJobEntity> {
2524
const rssService = new RSSXMLService(url);
2625

27-
const mimeType = await rssService.getMimeType(url);
26+
try {
27+
const mimeType = await getMimeType(url);
28+
console.log('mime type is >>', mimeType);
2829

29-
if (isValidXMLMimeType(mimeType)) {
30-
try {
30+
if (isValidXMLMimeType(mimeType)) {
3131
const abortController = new AbortController();
3232

3333
this.webSocketService.registerSessionAbort(webSocketSessionId, abortController);
@@ -54,9 +54,11 @@ export class CreateUserJob {
5454
_templateId: _templateId,
5555
externalUserId: externalUserId || (formattedExtra as unknown as Record<string, any>)?.externalUserId,
5656
});
57-
} catch (error) {}
58-
} else {
59-
throw new BadRequestException(APIMessages.INVALID_RSS_URL);
57+
} else {
58+
throw new BadRequestException(APIMessages.INVALID_RSS_URL);
59+
}
60+
} catch (error) {
61+
throw new BadRequestException(error);
6062
}
6163
}
6264
}

apps/api/src/app/shared/helpers/common.helper.ts

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import * as Sentry from '@sentry/node';
2+
import axios from 'axios';
23
import { BadRequestException } from '@nestjs/common';
34
import { APIMessages } from '../constants';
45
import { PaginationResult, Defaults, FileMimeTypesEnum } from '@impler/shared';
@@ -95,3 +96,56 @@ export function isValidXMLMimeType(mimeType: string): boolean {
9596

9697
return false;
9798
}
99+
100+
export const getMimeType = async (url: string): Promise<string | null> => {
101+
try {
102+
if (!isUrlSafe(url)) {
103+
throw new BadRequestException('Invalid URL');
104+
}
105+
106+
const response = await axios.head(url, {
107+
timeout: 10000,
108+
maxRedirects: 3,
109+
});
110+
111+
const mimeType = response.headers['content-type'] || null;
112+
113+
return mimeType?.split(';')[0] || null;
114+
} catch (error) {
115+
throw error;
116+
}
117+
};
118+
119+
export function isUrlSafe(url: string): boolean {
120+
try {
121+
const parsedUrl = new URL(url);
122+
123+
// Only allow HTTP and HTTPS
124+
if (!['http:', 'https:'].includes(parsedUrl.protocol)) {
125+
return false;
126+
}
127+
128+
// Block localhost and private IPs (except in development)
129+
const hostname = parsedUrl.hostname.toLowerCase();
130+
const isDevelopment = process.env.NODE_ENV === 'dev';
131+
132+
if (!isDevelopment && ['localhost', '127.0.0.1', '::1'].includes(hostname)) {
133+
return false;
134+
}
135+
136+
if (
137+
hostname.startsWith('10.') ||
138+
hostname.startsWith('192.168.') ||
139+
hostname.startsWith('169.254.') ||
140+
/^172\.(1[6-9]|2[0-9]|3[01])\./.test(hostname)
141+
) {
142+
return false;
143+
}
144+
145+
return true;
146+
} catch (error) {
147+
return false;
148+
}
149+
}
150+
151+
export default { getMimeType };

apps/queue-manager/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@impler/queue-manager",
3-
"version": "1.1.1",
3+
"version": "1.2.0",
44
"author": "implerhq",
55
"license": "MIT",
66
"private": true,
@@ -20,7 +20,7 @@
2020
"@impler/services": "workspace:^",
2121
"@impler/shared": "workspace:^",
2222
"@sentry/node": "^7.112.2",
23-
"axios": "1.6.2",
23+
"axios": "1.8.2",
2424
"dayjs": "^1.11.11",
2525
"dotenv": "^16.0.2",
2626
"envalid": "^7.3.1",

apps/web/components/imports/editor/Editor.tsx

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ export function OutputEditor({ templateId, switchToDestination }: OutputEditorPr
4949
isSyncCustomizationLoading,
5050
isCustomizationLoading,
5151
isDestinationLoading,
52+
allVariables,
53+
formatVariableDisplay,
54+
isSystemVariable,
5255
} = useEditor({
5356
templateId,
5457
});
@@ -98,7 +101,7 @@ export function OutputEditor({ templateId, switchToDestination }: OutputEditorPr
98101
id="format"
99102
value={field.value}
100103
onChange={field.onChange}
101-
variables={[...(customization?.recordVariables || []), ...(customization?.chunkVariables || [])]}
104+
variables={allVariables}
102105
/>
103106
)}
104107
/>
@@ -107,14 +110,16 @@ export function OutputEditor({ templateId, switchToDestination }: OutputEditorPr
107110
</div>
108111
<div style={{ width: '20%', display: 'flex', flexDirection: 'column', gap: '5' }}>
109112
<VarLabel label="System Variables">
110-
{customization?.chunkVariables.map((variable) => (
111-
<VarItemWrapper key={variable} name={variable} copyText={'"' + variable + '"'} />
113+
{allVariables.filter(isSystemVariable).map((variable) => (
114+
<VarItemWrapper key={variable} name={variable} copyText={formatVariableDisplay(variable)} />
112115
))}
113116
</VarLabel>
114117
<VarLabel label="Schema Variables">
115-
{customization?.recordVariables.map((variable) => (
116-
<VarItemWrapper key={variable} name={variable} copyText={'"' + variable + '"'} />
117-
))}
118+
{allVariables
119+
.filter((variable) => !isSystemVariable(variable))
120+
.map((variable) => (
121+
<VarItemWrapper key={variable} name={variable} copyText={formatVariableDisplay(variable)} />
122+
))}
118123
</VarLabel>
119124
</div>
120125
</Flex>

apps/web/components/imports/validator/Validator.tsx

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,26 +20,46 @@ import { useValidator } from '@hooks/useValidator';
2020
import { VarItemWrapper } from '../editor/VarItemWrapper';
2121
import { InformationIcon } from '@assets/icons/Information.icon';
2222
import { TooltipLink } from '@components/guide-point';
23+
import { useMemo } from 'react';
24+
import { useEditor } from '@hooks/useEditor';
25+
import { DestinationsEnum } from '@impler/shared';
2326

2427
interface ValidatorProps {
2528
templateId: string;
2629
}
2730

2831
export function Validator({ templateId }: ValidatorProps) {
29-
const systemVariables = [
32+
const { destination } = useEditor({ templateId });
33+
34+
// Existing system variables
35+
const baseSystemVariables = [
3036
'params.uploadId',
3137
'params.fileName',
3238
'params.data',
3339
'params.extra',
3440
'params.totalRecords',
3541
'params.chunkSize',
3642
];
43+
44+
// Bubble.io specific system variables
45+
const bubbleIoSystemVariables = ['extra.uploadId', 'extra.userId'];
46+
3747
const { colorScheme } = useMantineColorScheme();
3848
const { control, editorVariables, onSave, isUpdateValidationsLoading, isValidationsLoading, testCodeResult } =
3949
useValidator({
4050
templateId,
4151
});
4252

53+
// Combine all variables: base system variables + editor variables + Bubble.io variables (if applicable)
54+
const allVariables = useMemo(() => {
55+
const variables = [...baseSystemVariables, ...editorVariables];
56+
if (destination?.destination === DestinationsEnum.BUBBLEIO) {
57+
variables.push(...bubbleIoSystemVariables);
58+
}
59+
60+
return variables;
61+
}, [destination?.destination, editorVariables]);
62+
4363
return (
4464
<div style={{ position: 'relative' }}>
4565
<LoadingOverlay visible={isValidationsLoading} />
@@ -124,7 +144,7 @@ export function Validator({ templateId }: ValidatorProps) {
124144
mode="javascript"
125145
value={field.value}
126146
onChange={field.onChange}
127-
variables={[...systemVariables]}
147+
variables={allVariables}
128148
/>
129149
)}
130150
/>
@@ -134,15 +154,10 @@ export function Validator({ templateId }: ValidatorProps) {
134154
</div>
135155
<div style={{ width: '20%', display: 'flex', flexDirection: 'column', gap: '5' }}>
136156
<VarLabel label="System Variables">
137-
{systemVariables.map((variable) => (
157+
{allVariables.map((variable) => (
138158
<VarItemWrapper key={variable} name={variable} copyText={variable} />
139159
))}
140160
</VarLabel>
141-
<VarLabel label="Schema Variables">
142-
{editorVariables.map((variable) => (
143-
<VarItemWrapper key={variable} name={variable} copyText={'"' + variable + '"'} />
144-
))}
145-
</VarLabel>
146161
</div>
147162
</Flex>
148163
</Stack>

apps/web/hooks/useEditor.tsx

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useEffect } from 'react';
1+
import { useEffect, useMemo } from 'react';
22
import { useForm } from 'react-hook-form';
33
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
44

@@ -83,6 +83,38 @@ export function useEditor({ templateId }: UseEditorProps) {
8383
}
8484
);
8585

86+
// Combine all variables: record variables + chunk variables + system variables
87+
const allVariables = useMemo(() => {
88+
const variables = [];
89+
90+
// Add schema variables (from record format)
91+
if (customization?.recordVariables) {
92+
variables.push(...customization.recordVariables.map((variable) => variable.substring(2, variable.length - 2)));
93+
}
94+
95+
// Add system variables (from chunk format)
96+
if (customization?.chunkVariables) {
97+
variables.push(...customization.chunkVariables);
98+
}
99+
100+
// Add Bubble.io specific system variables
101+
if (destination?.destination === DestinationsEnum.BUBBLEIO) {
102+
variables.push('extra.uploadId', 'extra.userId');
103+
}
104+
105+
return variables;
106+
}, [customization?.recordVariables, customization?.chunkVariables, destination?.destination]);
107+
108+
// Helper function to format variable display
109+
const formatVariableDisplay = (variable: string) => {
110+
return `"${variable}"`;
111+
};
112+
113+
// Helper function to categorize variables
114+
const isSystemVariable = (variable: string) => {
115+
return variable.startsWith('extra.') || variable.startsWith('params.');
116+
};
117+
86118
const validateFormat = (data: string): boolean => {
87119
try {
88120
JSON.parse(data);
@@ -137,10 +169,13 @@ export function useEditor({ templateId }: UseEditorProps) {
137169
onSaveClick,
138170
destination,
139171
handleSubmit,
172+
allVariables,
140173
customization,
174+
isSystemVariable,
141175
syncCustomization,
142176
updateCustomization,
143177
isDestinationLoading,
178+
formatVariableDisplay,
144179
isCustomizationLoading,
145180
isSyncCustomizationLoading,
146181
isUpdateCustomizationLoading,

apps/web/hooks/useValidator.tsx

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { notify } from '@libs/notify';
77
import { commonApi } from '@libs/api';
88
import { track } from '@libs/amplitude';
99
import { API_KEYS, MODAL_KEYS, MODAL_TITLES } from '@config';
10-
import { ICustomization, IErrorObject, IValidator } from '@impler/shared';
10+
import { ICustomization, IErrorObject, IValidator, DestinationsEnum } from '@impler/shared';
1111
import { CodeOutput } from '@components/imports/validator/CodeOutput';
1212

1313
interface UseSchemaProps {
@@ -43,9 +43,14 @@ export function useValidator({ templateId }: UseSchemaProps) {
4343
() => commonApi<ICustomization>(API_KEYS.TEMPLATE_CUSTOMIZATION_GET as any, { parameters: [templateId] }),
4444
{
4545
onSuccess(data) {
46-
setEditorVariables([
47-
...(data.recordVariables.map((variable) => variable.substring(2, variable.length - 2)) || []),
48-
]);
46+
// Get base variables from customization
47+
const baseVariables = data.recordVariables?.map((variable) => variable.substring(2, variable.length - 2)) || [];
48+
49+
// Add static Bubble.io variables if destination is Bubble.io
50+
const bubbleIoVariables =
51+
data.destination === DestinationsEnum.BUBBLEIO ? ['extra.uploadId', 'extra.userId'] : [];
52+
53+
setEditorVariables([...baseVariables, ...bubbleIoVariables]);
4954
},
5055
}
5156
);

apps/web/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@impler/web",
3-
"version": "1.1.1",
3+
"version": "1.2.0",
44
"author": "implerhq",
55
"license": "MIT",
66
"private": true,
@@ -43,7 +43,7 @@
4343
"embla-carousel-react": "^7.0.9",
4444
"jwt-decode": "^3.1.2",
4545
"lottie-react": "^2.4.0",
46-
"next": "14.2.21",
46+
"next": "14.2.30",
4747
"react": "18.2.0",
4848
"react-ace": "^10.1.0",
4949
"react-chartjs-2": "^5.2.0",

apps/widget/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@impler/widget",
3-
"version": "1.1.1",
3+
"version": "1.2.0",
44
"author": "implerhq",
55
"license": "MIT",
66
"private": true,
@@ -52,7 +52,7 @@
5252
"@storybook/addon-essentials": "^6.5.13",
5353
"@storybook/react": "^6.5.13",
5454
"@tanstack/react-query": "^4.14.5",
55-
"axios": "1.6.2",
55+
"axios": "1.8.2",
5656
"cooltipz-css": "^2.3.0",
5757
"cross-env": "^7.0.3",
5858
"file-saver": "^2.0.5",

0 commit comments

Comments
 (0)