Vanshik Waghela commited on
Commit
b86ec3d
·
1 Parent(s): 63c2316

fix: allow non-email action types (generate_packet, manual_packet, etc.) without external adapter

Browse files
apps/worker/src/lib/action-executor.ts CHANGED
@@ -179,29 +179,39 @@ export async function executeAction(
179
  return { attemptId: attempt.id, attemptNo: (latestAttempt?.attemptNo ?? 0) + 1 };
180
  });
181
 
182
- const submissionResult = await emailAdapter.submit({
183
- missionId: action.missionId,
184
- actionId,
185
- destination: inputPayload.destination,
186
- subject: inputPayload.subject,
187
- body: inputPayload.body,
188
- attachments: await (async () => {
189
- if (inputPayload.attachments.length === 0) return [];
190
- // Look up actual storage keys from evidence files table
191
- const evidenceRows = await txDb
192
- .select({ id: schema.evidenceItems.id, storageKey: schema.files.storageKey })
193
- .from(schema.evidenceItems)
194
- .innerJoin(schema.files, eq(schema.evidenceItems.fileId, schema.files.id))
195
- .where(eq(schema.evidenceItems.missionId, action.missionId));
196
- const storageKeyMap = new Map(evidenceRows.map((r) => [r.id, r.storageKey]));
197
- return inputPayload.attachments.map((a) => ({
198
- id: a.id,
199
- storageKey: storageKeyMap.get(a.id) ?? a.sha256,
200
- filename: a.id || "attachment",
201
- }));
202
- })(),
203
- idempotencyKey: action.idempotencyKey ?? `action-${actionId}`,
204
- });
 
 
 
 
 
 
 
 
 
 
205
 
206
  const succeeded = submissionResult.proofState !== "failed";
207
 
 
179
  return { attemptId: attempt.id, attemptNo: (latestAttempt?.attemptNo ?? 0) + 1 };
180
  });
181
 
182
+ // Determine submission strategy based on action type.
183
+ // Email-type actions use the email adapter; local/user-driven actions mark as
184
+ // ready_for_user_submission (no external call).
185
+ const isEmailAction = action.actionType === "send_email" || action.actionType === "takedown";
186
+ const submissionResult = isEmailAction
187
+ ? await emailAdapter.submit({
188
+ missionId: action.missionId,
189
+ actionId,
190
+ destination: inputPayload.destination,
191
+ subject: inputPayload.subject,
192
+ body: inputPayload.body,
193
+ attachments: await (async () => {
194
+ if (inputPayload.attachments.length === 0) return [];
195
+ const evidenceRows = await txDb
196
+ .select({ id: schema.evidenceItems.id, storageKey: schema.files.storageKey })
197
+ .from(schema.evidenceItems)
198
+ .innerJoin(schema.files, eq(schema.evidenceItems.fileId, schema.files.id))
199
+ .where(eq(schema.evidenceItems.missionId, action.missionId));
200
+ const storageKeyMap = new Map(evidenceRows.map((r) => [r.id, r.storageKey]));
201
+ return inputPayload.attachments.map((a) => ({
202
+ id: a.id,
203
+ storageKey: storageKeyMap.get(a.id) ?? a.sha256,
204
+ filename: a.id || "attachment",
205
+ }));
206
+ })(),
207
+ idempotencyKey: action.idempotencyKey ?? `action-${actionId}`,
208
+ })
209
+ : {
210
+ proofState: "ready_for_user_submission" as const,
211
+ proofRef: { note: "Local action — user must submit manually." },
212
+ providerMessageId: null,
213
+ externalReference: null,
214
+ };
215
 
216
  const succeeded = submissionResult.proofState !== "failed";
217
 
packages/domain/src/policies/action-execution-policy.ts CHANGED
@@ -33,16 +33,12 @@ export type CanExecuteResult = ExecutionRefusal | ExecutionAllowance;
33
  // ---------------------------------------------------------------------------
34
 
35
  function adapterForAction(action: Action): string | null {
36
- switch (action.actionType) {
37
- case "send_email":
38
- return "resend_email";
39
- case "post_social":
40
- return "social_publisher";
41
- case "generate_packet":
42
- return "packet_generator";
43
- default:
44
- return null;
45
- }
46
  }
47
 
48
  function capabilityIsAvailable(cap: AdapterCapability): boolean {
 
33
  // ---------------------------------------------------------------------------
34
 
35
  function adapterForAction(action: Action): string | null {
36
+ const t = action.actionType;
37
+ if (t === "send_email" || t === "takedown") return "resend_email";
38
+ if (t === "post_social") return "social_publisher";
39
+ // All other types (generate_packet, manual_packet, prepare_portal,
40
+ // submit_portal, inform_user, etc.) are local/user-driven — no adapter needed.
41
+ return null;
 
 
 
 
42
  }
43
 
44
  function capabilityIsAvailable(cap: AdapterCapability): boolean {