create-bw-app 0.18.6 → 0.20.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.
- package/README.md +7 -1
- package/package.json +3 -2
- package/src/add.mjs +10 -2
- package/src/admin.mjs +204 -0
- package/src/app-manifest.mjs +31 -2
- package/src/bw.mjs +3 -1
- package/src/constants.mjs +11 -9
- package/src/diff.mjs +3 -3
- package/src/doctor.mjs +151 -9
- package/src/env.mjs +43 -0
- package/src/generator.mjs +291 -9
- package/src/migrations.mjs +4 -1
- package/src/regions.mjs +60 -0
- package/src/remove.mjs +18 -2
- package/src/safe-path.mjs +46 -0
- package/src/scaffold-cmd.mjs +3 -10
- package/src/scaffold.mjs +3 -2
- package/src/update.mjs +35 -0
- package/src/upgrade.mjs +5 -3
- package/template/base/app/(auth)/login/page.tsx +5 -1
- package/template/base/app/(shell)/shell-layout-client.tsx +29 -15
- package/template/base/app/layout.tsx +12 -4
- package/template/base/config/module-toolbar-controls.tsx +6 -0
- package/template/supabase/modules/admin/migrations/20260729120000_bootstrap_first_admin.sql +114 -0
- package/template/supabase/modules/admin/migrations/20260729150000_bootstrap_first_admin_remove_force.sql +116 -0
- package/template/supabase/modules/marketing/migrations/20260729170000_marketing_webhook_transaction.sql +106 -0
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
create or replace function public.process_marketing_resend_webhook(
|
|
2
|
+
p_provider_event_id text,
|
|
3
|
+
p_event_type text,
|
|
4
|
+
p_provider_message_id text,
|
|
5
|
+
p_payload jsonb,
|
|
6
|
+
p_occurred_at timestamptz
|
|
7
|
+
)
|
|
8
|
+
returns table (duplicate boolean, event_type text, recipient_id uuid)
|
|
9
|
+
language plpgsql
|
|
10
|
+
security definer
|
|
11
|
+
set search_path = public
|
|
12
|
+
as $$
|
|
13
|
+
declare
|
|
14
|
+
recipient public.marketing_campaign_recipients%rowtype;
|
|
15
|
+
inserted_event_id uuid;
|
|
16
|
+
suppression_reason text;
|
|
17
|
+
normalized_email text;
|
|
18
|
+
begin
|
|
19
|
+
if nullif(trim(p_provider_message_id), '') is not null then
|
|
20
|
+
select * into recipient
|
|
21
|
+
from public.marketing_campaign_recipients
|
|
22
|
+
where provider_message_id = p_provider_message_id
|
|
23
|
+
order by id
|
|
24
|
+
limit 1;
|
|
25
|
+
end if;
|
|
26
|
+
|
|
27
|
+
insert into public.marketing_message_events (
|
|
28
|
+
campaign_id,
|
|
29
|
+
recipient_id,
|
|
30
|
+
contact_id,
|
|
31
|
+
provider,
|
|
32
|
+
event_type,
|
|
33
|
+
provider_event_id,
|
|
34
|
+
payload,
|
|
35
|
+
occurred_at
|
|
36
|
+
) values (
|
|
37
|
+
recipient.campaign_id,
|
|
38
|
+
recipient.id,
|
|
39
|
+
recipient.contact_id,
|
|
40
|
+
'resend',
|
|
41
|
+
p_event_type,
|
|
42
|
+
nullif(trim(p_provider_event_id), ''),
|
|
43
|
+
p_payload,
|
|
44
|
+
coalesce(p_occurred_at, now())
|
|
45
|
+
)
|
|
46
|
+
on conflict (provider, provider_event_id) where provider_event_id is not null
|
|
47
|
+
do nothing
|
|
48
|
+
returning id into inserted_event_id;
|
|
49
|
+
|
|
50
|
+
if inserted_event_id is null then
|
|
51
|
+
return query select true, p_event_type, recipient.id;
|
|
52
|
+
return;
|
|
53
|
+
end if;
|
|
54
|
+
|
|
55
|
+
if recipient.id is not null and p_event_type in ('delivered', 'sent') then
|
|
56
|
+
update public.marketing_campaign_recipients
|
|
57
|
+
set status = 'sent',
|
|
58
|
+
sent_at = coalesce(p_occurred_at, now()),
|
|
59
|
+
error = null
|
|
60
|
+
where id = recipient.id;
|
|
61
|
+
elsif recipient.id is not null and p_event_type = 'failed' then
|
|
62
|
+
update public.marketing_campaign_recipients
|
|
63
|
+
set status = 'failed',
|
|
64
|
+
error = 'Resend reported delivery failure.'
|
|
65
|
+
where id = recipient.id;
|
|
66
|
+
elsif recipient.id is not null and p_event_type in ('bounced', 'complained', 'unsubscribed') then
|
|
67
|
+
suppression_reason := case p_event_type
|
|
68
|
+
when 'bounced' then 'bounced'
|
|
69
|
+
when 'complained' then 'complained'
|
|
70
|
+
else 'unsubscribed_all'
|
|
71
|
+
end;
|
|
72
|
+
normalized_email := lower(trim(recipient.email));
|
|
73
|
+
|
|
74
|
+
update public.marketing_campaign_recipients
|
|
75
|
+
set status = 'suppressed',
|
|
76
|
+
error = 'Resend reported ' || p_event_type || '.',
|
|
77
|
+
next_attempt_at = null
|
|
78
|
+
where id = recipient.id;
|
|
79
|
+
|
|
80
|
+
insert into public.marketing_suppressions (email, reason, source)
|
|
81
|
+
values (normalized_email, suppression_reason, 'resend_webhook')
|
|
82
|
+
on conflict (email) do update
|
|
83
|
+
set reason = excluded.reason,
|
|
84
|
+
source = excluded.source;
|
|
85
|
+
|
|
86
|
+
update public.marketing_campaign_recipients
|
|
87
|
+
set status = 'suppressed',
|
|
88
|
+
error = 'Email suppressed: ' || suppression_reason || '.',
|
|
89
|
+
next_attempt_at = null
|
|
90
|
+
where lower(trim(email)) = normalized_email
|
|
91
|
+
and status in ('queued', 'sending');
|
|
92
|
+
|
|
93
|
+
if recipient.contact_id is not null then
|
|
94
|
+
update public.marketing_subscriptions
|
|
95
|
+
set status = 'unsubscribed',
|
|
96
|
+
unsubscribed_at = coalesce(p_occurred_at, now())
|
|
97
|
+
where contact_id = recipient.contact_id;
|
|
98
|
+
end if;
|
|
99
|
+
end if;
|
|
100
|
+
|
|
101
|
+
return query select false, p_event_type, recipient.id;
|
|
102
|
+
end;
|
|
103
|
+
$$;
|
|
104
|
+
|
|
105
|
+
revoke all on function public.process_marketing_resend_webhook(text, text, text, jsonb, timestamptz) from public;
|
|
106
|
+
grant execute on function public.process_marketing_resend_webhook(text, text, text, jsonb, timestamptz) to service_role;
|