@detiq/crawler 1.1.16 → 1.1.18

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@detiq/crawler",
3
- "version": "1.1.16",
3
+ "version": "1.1.18",
4
4
  "private": false,
5
5
  "publishConfig": {
6
6
  "access": "public",
package/src/job-queue.ts CHANGED
@@ -1064,19 +1064,25 @@ async function processFigmaImportJob(jobId: string, config: any) {
1064
1064
  tx.platformJob.update({ where: { id: jobId }, data: { status: 'RUNNING', startedAt: new Date() } })
1065
1065
  );
1066
1066
  try {
1067
- const connector = await withTenant(tenantId, (tx) =>
1068
- (tx as any).connector.findFirst({ where: { projectId, kind: 'FIGMA', tenantId } })
1069
- ) as any;
1070
- if (!connector) throw new Error('Figma connector not configured. Add your Figma token in Project Settings → Integrations.');
1071
-
1072
- const cfg = connector.config as Record<string, string>;
1073
- const accessToken = cfg.accessToken_enc ? decrypt(cfg.accessToken_enc) : '';
1074
- if (!accessToken) throw new Error('Figma access token missing. Edit the Figma connector and add your Personal Access Token.');
1075
-
1076
- const resolvedFileKey = fileKey ?? cfg.fileKey ?? '';
1067
+ // Prefer OAuth token (connected via Figma OAuth flow), fall back to PAT connector.
1068
+ const oauthConn = await AppBrain.getOAuthConnection(tenantId, projectId, 'FIGMA');
1069
+ let creds: figma.FigmaCredentials;
1070
+ const resolvedFileKey = fileKey ?? '';
1077
1071
  if (!resolvedFileKey) throw new Error('No Figma file key. Paste the full Figma file URL as the App URL.');
1078
1072
 
1079
- const creds: figma.FigmaCredentials = { accessToken, fileKey: resolvedFileKey };
1073
+ if (oauthConn?.accessToken && oauthConn.status === 'CONNECTED') {
1074
+ // OAuth token must use Authorization: Bearer header (oauthToken field), not X-Figma-Token
1075
+ creds = { accessToken: '', oauthToken: oauthConn.accessToken, fileKey: resolvedFileKey };
1076
+ } else {
1077
+ const connector = await withTenant(tenantId, (tx) =>
1078
+ (tx as any).connector.findFirst({ where: { projectId, kind: 'FIGMA', tenantId } })
1079
+ ) as any;
1080
+ if (!connector) throw new Error('Figma connector not configured. Add your Figma token in Project Settings → Integrations.');
1081
+ const cfg = connector.config as Record<string, string>;
1082
+ const pat = cfg.accessToken_enc ? decrypt(cfg.accessToken_enc) : '';
1083
+ if (!pat) throw new Error('Figma access token missing. Edit the Figma connector and add your Personal Access Token.');
1084
+ creds = { accessToken: pat, fileKey: resolvedFileKey };
1085
+ }
1080
1086
 
1081
1087
  await updateJobProgress(tenantId, jobId, 5, 'Listing frames from Figma file…');
1082
1088
  const frames = await figma.listScreens(creds, resolvedFileKey);
@@ -1118,7 +1124,9 @@ async function processFigmaImportJob(jobId: string, config: any) {
1118
1124
  console.warn('[figma-import] cloud upload failed:', e);
1119
1125
  }
1120
1126
  }
1121
- await AppBrain.saveScreenshot(tenantId, projectId, screen.id, storagePath, 1, 'DESKTOP', cloudUrl);
1127
+ const w = (frame as any).boundingBox?.width ?? 1440;
1128
+ const viewport = w <= 480 ? 'MOBILE_PORTRAIT' : w <= 1024 ? 'TABLET' : 'DESKTOP';
1129
+ await AppBrain.saveScreenshot(tenantId, projectId, screen.id, storagePath, 1, viewport, cloudUrl);
1122
1130
  }
1123
1131
  }
1124
1132
 
@@ -3092,7 +3100,7 @@ async function processCreatePRJob(jobId: string, config: any) {
3092
3100
  const { decrypt } = await import('@detiq/core');
3093
3101
  const token = decrypt(conn.tokenEnc);
3094
3102
 
3095
- const { pushScriptsAsPR } = await import('@detiq/agents');
3103
+ const { pushScriptsAsPR, getFileContent, mergeSpecContent } = await import('@detiq/agents');
3096
3104
 
3097
3105
  const framework = conn.detectedFramework ?? 'playwright-ts';
3098
3106
 
@@ -3117,11 +3125,24 @@ async function processCreatePRJob(jobId: string, config: any) {
3117
3125
 
3118
3126
  if (scripts.length === 0) throw new Error('No generated scripts found to push.');
3119
3127
 
3120
- const files = scripts.map((s: any) => {
3128
+ // For each file, check if it already exists in the repo and merge if so
3129
+ const files = await Promise.all(scripts.map(async (s: any) => {
3121
3130
  const path = s.testCase?.repoTargetPath
3122
3131
  ?? deriveFallbackTargetPath(s.testCase?.ref ?? s.testCase?.title ?? s.id, framework);
3123
- return { path, content: s.code };
3124
- });
3132
+ let content = s.code;
3133
+
3134
+ // Spec files: attempt to merge with existing content
3135
+ const isSpecFile = /\.(spec|test|cy)\.(ts|js|py|java)$/.test(path) || /_test\.py$/.test(path);
3136
+ if (isSpecFile) {
3137
+ const existing = await getFileContent(token, conn.repoFullName, path, conn.defaultBranch).catch(() => null);
3138
+ if (existing && existing.trim().length > 0) {
3139
+ logger.info({ path }, '[create-pr] merging new tests into existing spec file');
3140
+ content = mergeSpecContent(existing, s.code);
3141
+ }
3142
+ }
3143
+
3144
+ return { path, content };
3145
+ }));
3125
3146
 
3126
3147
  if (files.length === 0) throw new Error('No scripts to push.');
3127
3148