@hot-updater/supabase 0.36.7 → 1.0.0-rc.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/dist/edge.cjs +6 -3
- package/dist/edge.d.cts +14 -2
- package/dist/edge.d.mts +14 -2
- package/dist/edge.mjs +5 -2
- package/dist/iac/index.cjs +607 -50
- package/dist/iac/index.d.cts +26 -8
- package/dist/iac/index.d.mts +26 -8
- package/dist/iac/index.mjs +604 -52
- package/dist/index.cjs +3 -145
- package/dist/index.d.cts +7 -24
- package/dist/index.d.mts +7 -24
- package/dist/index.mjs +2 -117
- package/dist/init/index.cjs +5 -2
- package/dist/init/index.d.cts +2 -2
- package/dist/init/index.d.mts +2 -2
- package/dist/init/index.mjs +5 -2
- package/dist/supabaseDatabase-BDIBsXpz.d.cts +13 -0
- package/dist/supabaseDatabase-CP9WalBi.d.mts +13 -0
- package/dist/supabaseStorage-Cw294tR4.mjs +557 -0
- package/dist/supabaseStorage-yP7u4m7E.cjs +568 -0
- package/package.json +9 -9
- package/supabase/edge-functions/index.ts +9 -13
- package/supabase/edge-functions/runtime.docker.integration.spec.ts +417 -202
- package/supabase/migrations/20260818000000_hot-updater_1.0.0.sql +583 -0
- package/supabase/migrations.spec.ts +127 -46
- package/dist/supabaseEdgeFunctionStorage-BRxGvt-r.d.mts +0 -19
- package/dist/supabaseEdgeFunctionStorage-BSLlUeqi.cjs +0 -386
- package/dist/supabaseEdgeFunctionStorage-CU396KO3.d.cts +0 -19
- package/dist/supabaseEdgeFunctionStorage-pV0s_mTF.mjs +0 -356
- package/supabase/migrations/20250103114225_init.sql +0 -228
- package/supabase/migrations/20250314000000_hot-updater_0.13.0.sql +0 -134
- package/supabase/migrations/20250516000000_hot-updater_0.18.0.sql +0 -194
- package/supabase/migrations/20251014000000_hot-updater_0.21.0.sql +0 -184
- package/supabase/migrations/20260401000000_hot-updater_0.29.0.sql +0 -503
- package/supabase/migrations/20260414000000_hot-updater_0.30.0.sql +0 -50
- package/supabase/migrations/20260422000000_hot-updater_0.31.0.sql +0 -20
- package/supabase/migrations/20260520014100_hot-updater_rls.sql +0 -48
|
@@ -0,0 +1,583 @@
|
|
|
1
|
+
-- HotUpdater.schema
|
|
2
|
+
|
|
3
|
+
CREATE TABLE public.hot_updater_v1_channels (
|
|
4
|
+
id text COLLATE "C" PRIMARY KEY NOT NULL
|
|
5
|
+
CHECK (pg_catalog.char_length(id) BETWEEN 1 AND 255),
|
|
6
|
+
name text COLLATE "C" NOT NULL UNIQUE
|
|
7
|
+
CHECK (pg_catalog.char_length(name) BETWEEN 1 AND 255)
|
|
8
|
+
);
|
|
9
|
+
|
|
10
|
+
CREATE TABLE public.hot_updater_v1_bundles (
|
|
11
|
+
id uuid PRIMARY KEY NOT NULL,
|
|
12
|
+
platform text NOT NULL,
|
|
13
|
+
file_hash text NOT NULL,
|
|
14
|
+
git_commit_hash text,
|
|
15
|
+
storage_uri text NOT NULL,
|
|
16
|
+
archive_byte_size double precision NOT NULL CHECK (
|
|
17
|
+
archive_byte_size BETWEEN 0 AND 9007199254740991
|
|
18
|
+
),
|
|
19
|
+
metadata jsonb NOT NULL DEFAULT '{}'::jsonb,
|
|
20
|
+
manifest_storage_uri text,
|
|
21
|
+
manifest_file_hash text,
|
|
22
|
+
asset_base_storage_uri text
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
CREATE TABLE public.hot_updater_v1_bundle_patches (
|
|
26
|
+
id varchar(255) PRIMARY KEY NOT NULL,
|
|
27
|
+
bundle_id uuid NOT NULL,
|
|
28
|
+
base_bundle_id uuid NOT NULL,
|
|
29
|
+
base_file_hash text NOT NULL,
|
|
30
|
+
patch_file_hash text NOT NULL,
|
|
31
|
+
patch_storage_uri text NOT NULL,
|
|
32
|
+
byte_size double precision NOT NULL CHECK (
|
|
33
|
+
byte_size BETWEEN 0 AND 9007199254740991
|
|
34
|
+
),
|
|
35
|
+
order_index integer NOT NULL DEFAULT 0,
|
|
36
|
+
CONSTRAINT hot_updater_v1_bundle_patches_bundle_id_fk FOREIGN KEY (bundle_id)
|
|
37
|
+
REFERENCES public.hot_updater_v1_bundles(id) ON UPDATE RESTRICT ON DELETE CASCADE,
|
|
38
|
+
CONSTRAINT hot_updater_v1_bundle_patches_base_bundle_id_fk FOREIGN KEY (base_bundle_id)
|
|
39
|
+
REFERENCES public.hot_updater_v1_bundles(id) ON UPDATE RESTRICT ON DELETE CASCADE
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
CREATE TABLE public.hot_updater_v1_releases (
|
|
43
|
+
id uuid PRIMARY KEY NOT NULL,
|
|
44
|
+
revision integer NOT NULL CHECK (revision >= 1),
|
|
45
|
+
scope_key varchar(2048) COLLATE "C" NOT NULL,
|
|
46
|
+
channel_id text COLLATE "C" NOT NULL,
|
|
47
|
+
platform text NOT NULL,
|
|
48
|
+
kind text NOT NULL CHECK (
|
|
49
|
+
(kind = 'BUNDLE' AND bundle_id IS NOT NULL)
|
|
50
|
+
OR (kind = 'EMBEDDED' AND bundle_id IS NULL)
|
|
51
|
+
),
|
|
52
|
+
bundle_id uuid,
|
|
53
|
+
strategy text NOT NULL,
|
|
54
|
+
target_app_version text,
|
|
55
|
+
fingerprint_hash text,
|
|
56
|
+
enabled boolean NOT NULL,
|
|
57
|
+
should_force_update boolean NOT NULL,
|
|
58
|
+
message text,
|
|
59
|
+
rollout_cohort_count integer NOT NULL DEFAULT 1000
|
|
60
|
+
CHECK (rollout_cohort_count BETWEEN 0 AND 1000),
|
|
61
|
+
target_cohorts jsonb NOT NULL DEFAULT '[]'::jsonb,
|
|
62
|
+
operation text NOT NULL CHECK (operation IN ('DEPLOY', 'PROMOTE', 'ROLLBACK')),
|
|
63
|
+
source_release_id uuid,
|
|
64
|
+
created_at_ms double precision NOT NULL,
|
|
65
|
+
updated_at_ms double precision NOT NULL,
|
|
66
|
+
CONSTRAINT hot_updater_v1_releases_strategy_target_check CHECK (
|
|
67
|
+
(strategy = 'APP_VERSION' AND target_app_version IS NOT NULL AND fingerprint_hash IS NULL)
|
|
68
|
+
OR (strategy = 'FINGERPRINT' AND target_app_version IS NULL AND fingerprint_hash IS NOT NULL)
|
|
69
|
+
),
|
|
70
|
+
CONSTRAINT hot_updater_v1_releases_channel_id_fk FOREIGN KEY (channel_id)
|
|
71
|
+
REFERENCES public.hot_updater_v1_channels(id) ON UPDATE RESTRICT ON DELETE RESTRICT,
|
|
72
|
+
CONSTRAINT hot_updater_v1_releases_bundle_id_fk FOREIGN KEY (bundle_id)
|
|
73
|
+
REFERENCES public.hot_updater_v1_bundles(id) ON UPDATE RESTRICT ON DELETE RESTRICT,
|
|
74
|
+
CONSTRAINT hot_updater_v1_releases_source_release_id_fk FOREIGN KEY (source_release_id)
|
|
75
|
+
REFERENCES public.hot_updater_v1_releases(id) ON UPDATE RESTRICT ON DELETE SET NULL
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
CREATE TABLE public.hot_updater_v1_release_catalogs (
|
|
79
|
+
scope_key varchar(2048) COLLATE "C" PRIMARY KEY NOT NULL,
|
|
80
|
+
catalog_id varchar(255) COLLATE "C" NOT NULL,
|
|
81
|
+
strategy text NOT NULL,
|
|
82
|
+
channel_id text COLLATE "C" NOT NULL,
|
|
83
|
+
channel_key varchar(1400) COLLATE "C" NOT NULL,
|
|
84
|
+
platform text NOT NULL,
|
|
85
|
+
fingerprint_hash text,
|
|
86
|
+
generation double precision NOT NULL
|
|
87
|
+
CHECK (generation BETWEEN 1 AND 9007199254740991),
|
|
88
|
+
payload text NOT NULL,
|
|
89
|
+
catalog_hash varchar(71) COLLATE "C" NOT NULL,
|
|
90
|
+
byte_size integer NOT NULL CHECK (byte_size BETWEEN 0 AND 262144),
|
|
91
|
+
is_tombstone boolean NOT NULL,
|
|
92
|
+
updated_at_ms double precision NOT NULL,
|
|
93
|
+
CONSTRAINT hot_updater_v1_release_catalogs_strategy_target_check CHECK (
|
|
94
|
+
(strategy = 'APP_VERSION' AND fingerprint_hash IS NULL)
|
|
95
|
+
OR (strategy = 'FINGERPRINT' AND fingerprint_hash IS NOT NULL)
|
|
96
|
+
),
|
|
97
|
+
CONSTRAINT hot_updater_v1_release_catalogs_channel_id_fk FOREIGN KEY (channel_id)
|
|
98
|
+
REFERENCES public.hot_updater_v1_channels(id) ON UPDATE RESTRICT ON DELETE RESTRICT
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
CREATE TABLE public.hot_updater_v1_bundle_events (
|
|
102
|
+
id uuid PRIMARY KEY NOT NULL,
|
|
103
|
+
type text NOT NULL,
|
|
104
|
+
install_id text NOT NULL,
|
|
105
|
+
user_id text,
|
|
106
|
+
username text,
|
|
107
|
+
from_release_id uuid,
|
|
108
|
+
from_bundle_id uuid,
|
|
109
|
+
to_release_id uuid,
|
|
110
|
+
to_bundle_id uuid NOT NULL,
|
|
111
|
+
platform text NOT NULL,
|
|
112
|
+
app_version text NOT NULL,
|
|
113
|
+
channel text NOT NULL,
|
|
114
|
+
cohort text NOT NULL,
|
|
115
|
+
update_strategy text,
|
|
116
|
+
fingerprint_hash text,
|
|
117
|
+
sdk_version text,
|
|
118
|
+
received_at_ms double precision NOT NULL,
|
|
119
|
+
CONSTRAINT hot_updater_v1_bundle_events_type_check CHECK (
|
|
120
|
+
type IN ('UPDATE_APPLIED', 'RECOVERED', 'RELEASE_ADOPTED', 'UNCHANGED')
|
|
121
|
+
),
|
|
122
|
+
CONSTRAINT hot_updater_v1_bundle_events_platform_check CHECK (
|
|
123
|
+
platform IN ('ios', 'android')
|
|
124
|
+
),
|
|
125
|
+
CONSTRAINT hot_updater_v1_bundle_events_shape_check CHECK (
|
|
126
|
+
(type IN ('UPDATE_APPLIED', 'RECOVERED', 'RELEASE_ADOPTED')
|
|
127
|
+
AND from_bundle_id IS NOT NULL
|
|
128
|
+
AND update_strategy IS NOT NULL
|
|
129
|
+
AND update_strategy IN ('fingerprint', 'appVersion'))
|
|
130
|
+
OR (type = 'UNCHANGED'
|
|
131
|
+
AND from_bundle_id IS NULL
|
|
132
|
+
AND update_strategy IS NULL)
|
|
133
|
+
),
|
|
134
|
+
CONSTRAINT hot_updater_v1_bundle_events_received_at_check CHECK (received_at_ms >= 0)
|
|
135
|
+
);
|
|
136
|
+
|
|
137
|
+
CREATE TABLE public.hot_updater_v1_api_keys (
|
|
138
|
+
id text PRIMARY KEY NOT NULL,
|
|
139
|
+
hash text NOT NULL,
|
|
140
|
+
name text NOT NULL,
|
|
141
|
+
prefix text NOT NULL,
|
|
142
|
+
role text NOT NULL CHECK (role = 'client'),
|
|
143
|
+
created_at_ms double precision NOT NULL CHECK (created_at_ms >= 0),
|
|
144
|
+
revoked_at_ms double precision CHECK (
|
|
145
|
+
revoked_at_ms IS NULL OR revoked_at_ms >= 0
|
|
146
|
+
)
|
|
147
|
+
);
|
|
148
|
+
|
|
149
|
+
CREATE TABLE public.hot_updater_v1_private_settings (
|
|
150
|
+
key varchar(255) PRIMARY KEY NOT NULL,
|
|
151
|
+
value text NOT NULL DEFAULT '1.0.0'
|
|
152
|
+
);
|
|
153
|
+
|
|
154
|
+
CREATE INDEX hot_updater_v1_releases_scope_order_idx ON public.hot_updater_v1_releases(scope_key, id);
|
|
155
|
+
CREATE INDEX hot_updater_v1_releases_channel_platform_order_idx
|
|
156
|
+
ON public.hot_updater_v1_releases(channel_id, platform, id);
|
|
157
|
+
CREATE INDEX hot_updater_v1_releases_bundle_id_idx ON public.hot_updater_v1_releases(bundle_id);
|
|
158
|
+
CREATE INDEX hot_updater_v1_releases_fingerprint_hash_idx ON public.hot_updater_v1_releases(fingerprint_hash);
|
|
159
|
+
CREATE INDEX hot_updater_v1_releases_enabled_idx ON public.hot_updater_v1_releases(enabled);
|
|
160
|
+
CREATE INDEX hot_updater_v1_release_catalogs_channel_idx ON public.hot_updater_v1_release_catalogs(channel_id);
|
|
161
|
+
CREATE INDEX hot_updater_v1_bundle_patches_bundle_id_idx ON public.hot_updater_v1_bundle_patches(bundle_id);
|
|
162
|
+
CREATE INDEX hot_updater_v1_bundle_patches_base_bundle_id_idx
|
|
163
|
+
ON public.hot_updater_v1_bundle_patches(base_bundle_id);
|
|
164
|
+
CREATE INDEX hot_updater_v1_bundle_events_received_at_idx
|
|
165
|
+
ON public.hot_updater_v1_bundle_events(received_at_ms, id);
|
|
166
|
+
CREATE INDEX hot_updater_v1_bundle_events_install_idx
|
|
167
|
+
ON public.hot_updater_v1_bundle_events(install_id, received_at_ms, id);
|
|
168
|
+
CREATE INDEX hot_updater_v1_bundle_events_user_id_idx
|
|
169
|
+
ON public.hot_updater_v1_bundle_events(user_id, received_at_ms, id);
|
|
170
|
+
CREATE INDEX hot_updater_v1_bundle_events_username_idx
|
|
171
|
+
ON public.hot_updater_v1_bundle_events(username, received_at_ms, id);
|
|
172
|
+
CREATE INDEX hot_updater_v1_bundle_events_to_bundle_idx
|
|
173
|
+
ON public.hot_updater_v1_bundle_events(type, to_bundle_id, received_at_ms, id);
|
|
174
|
+
CREATE INDEX hot_updater_v1_bundle_events_from_bundle_idx
|
|
175
|
+
ON public.hot_updater_v1_bundle_events(type, from_bundle_id, received_at_ms, id);
|
|
176
|
+
CREATE INDEX hot_updater_v1_bundle_events_to_release_idx
|
|
177
|
+
ON public.hot_updater_v1_bundle_events(type, to_release_id, received_at_ms, id);
|
|
178
|
+
CREATE INDEX hot_updater_v1_bundle_events_from_release_idx
|
|
179
|
+
ON public.hot_updater_v1_bundle_events(type, from_release_id, received_at_ms, id);
|
|
180
|
+
CREATE UNIQUE INDEX hot_updater_v1_api_keys_hash_key
|
|
181
|
+
ON public.hot_updater_v1_api_keys(hash);
|
|
182
|
+
CREATE INDEX hot_updater_v1_api_keys_created_at_idx
|
|
183
|
+
ON public.hot_updater_v1_api_keys(created_at_ms, id);
|
|
184
|
+
|
|
185
|
+
ALTER TABLE public.hot_updater_v1_channels ENABLE ROW LEVEL SECURITY;
|
|
186
|
+
ALTER TABLE public.hot_updater_v1_bundles ENABLE ROW LEVEL SECURITY;
|
|
187
|
+
ALTER TABLE public.hot_updater_v1_bundle_patches ENABLE ROW LEVEL SECURITY;
|
|
188
|
+
ALTER TABLE public.hot_updater_v1_releases ENABLE ROW LEVEL SECURITY;
|
|
189
|
+
ALTER TABLE public.hot_updater_v1_release_catalogs ENABLE ROW LEVEL SECURITY;
|
|
190
|
+
ALTER TABLE public.hot_updater_v1_bundle_events ENABLE ROW LEVEL SECURITY;
|
|
191
|
+
ALTER TABLE public.hot_updater_v1_api_keys ENABLE ROW LEVEL SECURITY;
|
|
192
|
+
ALTER TABLE public.hot_updater_v1_private_settings ENABLE ROW LEVEL SECURITY;
|
|
193
|
+
|
|
194
|
+
INSERT INTO public.hot_updater_v1_private_settings (key, value)
|
|
195
|
+
VALUES ('schema.core', '1.0.0')
|
|
196
|
+
ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value;
|
|
197
|
+
CREATE FUNCTION public.hot_updater_v1_commit(p_commit jsonb)
|
|
198
|
+
RETURNS jsonb
|
|
199
|
+
LANGUAGE plpgsql
|
|
200
|
+
SECURITY INVOKER
|
|
201
|
+
SET search_path = pg_catalog
|
|
202
|
+
AS $$
|
|
203
|
+
DECLARE
|
|
204
|
+
v_change jsonb;
|
|
205
|
+
v_change_index integer := -1;
|
|
206
|
+
v_expectation jsonb;
|
|
207
|
+
v_expected double precision;
|
|
208
|
+
v_actual double precision;
|
|
209
|
+
v_found boolean;
|
|
210
|
+
v_bundle public.hot_updater_v1_bundles;
|
|
211
|
+
v_patch public.hot_updater_v1_bundle_patches;
|
|
212
|
+
v_release public.hot_updater_v1_releases;
|
|
213
|
+
v_catalog public.hot_updater_v1_release_catalogs;
|
|
214
|
+
v_channel public.hot_updater_v1_channels;
|
|
215
|
+
v_event public.hot_updater_v1_bundle_events;
|
|
216
|
+
v_api_key public.hot_updater_v1_api_keys;
|
|
217
|
+
BEGIN
|
|
218
|
+
IF pg_catalog.jsonb_typeof(p_commit) IS DISTINCT FROM 'object'
|
|
219
|
+
OR pg_catalog.jsonb_typeof(p_commit->'changes') IS DISTINCT FROM 'array'
|
|
220
|
+
OR (
|
|
221
|
+
p_commit ? 'expectations'
|
|
222
|
+
AND pg_catalog.jsonb_typeof(p_commit->'expectations') IS DISTINCT FROM 'array'
|
|
223
|
+
)
|
|
224
|
+
THEN
|
|
225
|
+
RAISE EXCEPTION 'Hot Updater commit has an invalid envelope'
|
|
226
|
+
USING ERRCODE = '22023';
|
|
227
|
+
END IF;
|
|
228
|
+
|
|
229
|
+
FOR v_expectation IN
|
|
230
|
+
SELECT value
|
|
231
|
+
FROM pg_catalog.jsonb_array_elements(
|
|
232
|
+
COALESCE(p_commit->'expectations', '[]'::jsonb)
|
|
233
|
+
) AS expectation(value)
|
|
234
|
+
LOOP
|
|
235
|
+
IF v_expectation->>'model' = 'releases' THEN
|
|
236
|
+
PERFORM pg_catalog.pg_advisory_xact_lock(
|
|
237
|
+
pg_catalog.hashtextextended(
|
|
238
|
+
'hot_updater_v1:release:' || (v_expectation->>'id'),
|
|
239
|
+
0
|
|
240
|
+
)
|
|
241
|
+
);
|
|
242
|
+
SELECT release.revision::double precision
|
|
243
|
+
INTO v_actual
|
|
244
|
+
FROM public.hot_updater_v1_releases AS release
|
|
245
|
+
WHERE release.id = (v_expectation->>'id')::uuid
|
|
246
|
+
FOR UPDATE;
|
|
247
|
+
v_found := FOUND;
|
|
248
|
+
v_expected := (v_expectation->>'revision')::double precision;
|
|
249
|
+
ELSIF v_expectation->>'model' = 'releaseCatalogs' THEN
|
|
250
|
+
PERFORM pg_catalog.pg_advisory_xact_lock(
|
|
251
|
+
pg_catalog.hashtextextended(
|
|
252
|
+
'hot_updater_v1:catalog:' || (v_expectation->>'scopeKey'),
|
|
253
|
+
0
|
|
254
|
+
)
|
|
255
|
+
);
|
|
256
|
+
SELECT catalog.generation
|
|
257
|
+
INTO v_actual
|
|
258
|
+
FROM public.hot_updater_v1_release_catalogs AS catalog
|
|
259
|
+
WHERE catalog.scope_key = v_expectation->>'scopeKey'
|
|
260
|
+
FOR UPDATE;
|
|
261
|
+
v_found := FOUND;
|
|
262
|
+
v_expected := (v_expectation->>'generation')::double precision;
|
|
263
|
+
ELSE
|
|
264
|
+
RAISE EXCEPTION 'Unsupported Hot Updater commit expectation'
|
|
265
|
+
USING ERRCODE = '22023';
|
|
266
|
+
END IF;
|
|
267
|
+
|
|
268
|
+
IF (v_expected IS NULL AND v_found)
|
|
269
|
+
OR (v_expected IS NOT NULL AND (NOT v_found OR v_actual <> v_expected))
|
|
270
|
+
THEN
|
|
271
|
+
RETURN pg_catalog.jsonb_build_object(
|
|
272
|
+
'committed', false,
|
|
273
|
+
'conflict', pg_catalog.jsonb_build_object(
|
|
274
|
+
'changeIndex', -1,
|
|
275
|
+
'reason', 'version_conflict',
|
|
276
|
+
'model', v_expectation->>'model',
|
|
277
|
+
'key', COALESCE(
|
|
278
|
+
v_expectation->>'id',
|
|
279
|
+
v_expectation->>'scopeKey'
|
|
280
|
+
),
|
|
281
|
+
'expectedVersion', v_expected,
|
|
282
|
+
'actualVersion', CASE WHEN v_found THEN v_actual ELSE NULL END
|
|
283
|
+
)
|
|
284
|
+
);
|
|
285
|
+
END IF;
|
|
286
|
+
END LOOP;
|
|
287
|
+
|
|
288
|
+
BEGIN
|
|
289
|
+
FOR v_change_index, v_change IN
|
|
290
|
+
SELECT ordinal - 1, value
|
|
291
|
+
FROM pg_catalog.jsonb_array_elements(p_commit->'changes')
|
|
292
|
+
WITH ORDINALITY AS change(value, ordinal)
|
|
293
|
+
ORDER BY ordinal
|
|
294
|
+
LOOP
|
|
295
|
+
CASE v_change->>'model'
|
|
296
|
+
WHEN 'channels' THEN
|
|
297
|
+
CASE v_change->>'operation'
|
|
298
|
+
WHEN 'insert' THEN
|
|
299
|
+
IF v_change->>'onConflict' <> 'ignore' THEN
|
|
300
|
+
RAISE EXCEPTION 'Channel insert requires onConflict ignore'
|
|
301
|
+
USING ERRCODE = '22023';
|
|
302
|
+
END IF;
|
|
303
|
+
v_channel := pg_catalog.jsonb_populate_record(
|
|
304
|
+
NULL::public.hot_updater_v1_channels,
|
|
305
|
+
v_change->'row'
|
|
306
|
+
);
|
|
307
|
+
INSERT INTO public.hot_updater_v1_channels (id, name)
|
|
308
|
+
VALUES (v_channel.id, v_channel.name)
|
|
309
|
+
ON CONFLICT (name) DO NOTHING;
|
|
310
|
+
WHEN 'delete' THEN
|
|
311
|
+
BEGIN
|
|
312
|
+
DELETE FROM public.hot_updater_v1_channels
|
|
313
|
+
WHERE id = v_change->'where'->>'id';
|
|
314
|
+
IF NOT FOUND THEN RAISE no_data_found; END IF;
|
|
315
|
+
EXCEPTION
|
|
316
|
+
WHEN foreign_key_violation THEN RAISE SQLSTATE 'HU001';
|
|
317
|
+
END;
|
|
318
|
+
ELSE
|
|
319
|
+
RAISE EXCEPTION 'Unsupported Channel change'
|
|
320
|
+
USING ERRCODE = '22023';
|
|
321
|
+
END CASE;
|
|
322
|
+
|
|
323
|
+
WHEN 'bundles' THEN
|
|
324
|
+
CASE v_change->>'operation'
|
|
325
|
+
WHEN 'insert' THEN
|
|
326
|
+
v_bundle := pg_catalog.jsonb_populate_record(
|
|
327
|
+
NULL::public.hot_updater_v1_bundles,
|
|
328
|
+
v_change->'row'
|
|
329
|
+
);
|
|
330
|
+
INSERT INTO public.hot_updater_v1_bundles (
|
|
331
|
+
id, platform, file_hash, git_commit_hash, storage_uri,
|
|
332
|
+
archive_byte_size, metadata, manifest_storage_uri, manifest_file_hash,
|
|
333
|
+
asset_base_storage_uri
|
|
334
|
+
) VALUES (
|
|
335
|
+
v_bundle.id, v_bundle.platform, v_bundle.file_hash,
|
|
336
|
+
v_bundle.git_commit_hash, v_bundle.storage_uri,
|
|
337
|
+
v_bundle.archive_byte_size, v_bundle.metadata,
|
|
338
|
+
v_bundle.manifest_storage_uri,
|
|
339
|
+
v_bundle.manifest_file_hash, v_bundle.asset_base_storage_uri
|
|
340
|
+
);
|
|
341
|
+
WHEN 'update' THEN
|
|
342
|
+
SELECT bundle.* INTO v_bundle
|
|
343
|
+
FROM public.hot_updater_v1_bundles AS bundle
|
|
344
|
+
WHERE bundle.id = (v_change->'where'->>'id')::uuid
|
|
345
|
+
FOR UPDATE;
|
|
346
|
+
IF NOT FOUND THEN RAISE no_data_found; END IF;
|
|
347
|
+
v_bundle := pg_catalog.jsonb_populate_record(
|
|
348
|
+
v_bundle,
|
|
349
|
+
v_change->'update'
|
|
350
|
+
);
|
|
351
|
+
UPDATE public.hot_updater_v1_bundles SET
|
|
352
|
+
platform = v_bundle.platform,
|
|
353
|
+
file_hash = v_bundle.file_hash,
|
|
354
|
+
git_commit_hash = v_bundle.git_commit_hash,
|
|
355
|
+
storage_uri = v_bundle.storage_uri,
|
|
356
|
+
archive_byte_size = v_bundle.archive_byte_size,
|
|
357
|
+
metadata = v_bundle.metadata,
|
|
358
|
+
manifest_storage_uri = v_bundle.manifest_storage_uri,
|
|
359
|
+
manifest_file_hash = v_bundle.manifest_file_hash,
|
|
360
|
+
asset_base_storage_uri = v_bundle.asset_base_storage_uri
|
|
361
|
+
WHERE id = v_bundle.id;
|
|
362
|
+
WHEN 'delete' THEN
|
|
363
|
+
BEGIN
|
|
364
|
+
DELETE FROM public.hot_updater_v1_bundles
|
|
365
|
+
WHERE id = (v_change->'where'->>'id')::uuid;
|
|
366
|
+
IF NOT FOUND THEN RAISE no_data_found; END IF;
|
|
367
|
+
EXCEPTION
|
|
368
|
+
WHEN foreign_key_violation THEN RAISE SQLSTATE 'HU001';
|
|
369
|
+
END;
|
|
370
|
+
ELSE
|
|
371
|
+
RAISE EXCEPTION 'Unsupported Bundle change'
|
|
372
|
+
USING ERRCODE = '22023';
|
|
373
|
+
END CASE;
|
|
374
|
+
|
|
375
|
+
WHEN 'bundlePatches' THEN
|
|
376
|
+
CASE v_change->>'operation'
|
|
377
|
+
WHEN 'insert' THEN
|
|
378
|
+
v_patch := pg_catalog.jsonb_populate_record(
|
|
379
|
+
NULL::public.hot_updater_v1_bundle_patches,
|
|
380
|
+
v_change->'row'
|
|
381
|
+
);
|
|
382
|
+
INSERT INTO public.hot_updater_v1_bundle_patches (
|
|
383
|
+
id, bundle_id, base_bundle_id, base_file_hash,
|
|
384
|
+
patch_file_hash, patch_storage_uri, byte_size, order_index
|
|
385
|
+
) VALUES (
|
|
386
|
+
v_patch.id, v_patch.bundle_id, v_patch.base_bundle_id,
|
|
387
|
+
v_patch.base_file_hash, v_patch.patch_file_hash,
|
|
388
|
+
v_patch.patch_storage_uri, v_patch.byte_size,
|
|
389
|
+
v_patch.order_index
|
|
390
|
+
);
|
|
391
|
+
WHEN 'delete' THEN
|
|
392
|
+
DELETE FROM public.hot_updater_v1_bundle_patches
|
|
393
|
+
WHERE bundle_id = (v_change->'where'->>'bundleId')::uuid;
|
|
394
|
+
ELSE
|
|
395
|
+
RAISE EXCEPTION 'Unsupported Bundle patch change'
|
|
396
|
+
USING ERRCODE = '22023';
|
|
397
|
+
END CASE;
|
|
398
|
+
|
|
399
|
+
WHEN 'releases' THEN
|
|
400
|
+
CASE v_change->>'operation'
|
|
401
|
+
WHEN 'insert' THEN
|
|
402
|
+
v_release := pg_catalog.jsonb_populate_record(
|
|
403
|
+
NULL::public.hot_updater_v1_releases,
|
|
404
|
+
v_change->'row'
|
|
405
|
+
);
|
|
406
|
+
INSERT INTO public.hot_updater_v1_releases SELECT v_release.*;
|
|
407
|
+
WHEN 'update' THEN
|
|
408
|
+
SELECT release.* INTO v_release
|
|
409
|
+
FROM public.hot_updater_v1_releases AS release
|
|
410
|
+
WHERE release.id = (v_change->'where'->>'id')::uuid
|
|
411
|
+
FOR UPDATE;
|
|
412
|
+
IF NOT FOUND THEN RAISE no_data_found; END IF;
|
|
413
|
+
v_release := pg_catalog.jsonb_populate_record(
|
|
414
|
+
v_release,
|
|
415
|
+
v_change->'update'
|
|
416
|
+
);
|
|
417
|
+
UPDATE public.hot_updater_v1_releases SET
|
|
418
|
+
revision = v_release.revision,
|
|
419
|
+
scope_key = v_release.scope_key,
|
|
420
|
+
target_app_version = v_release.target_app_version,
|
|
421
|
+
fingerprint_hash = v_release.fingerprint_hash,
|
|
422
|
+
enabled = v_release.enabled,
|
|
423
|
+
should_force_update = v_release.should_force_update,
|
|
424
|
+
message = v_release.message,
|
|
425
|
+
rollout_cohort_count = v_release.rollout_cohort_count,
|
|
426
|
+
target_cohorts = v_release.target_cohorts,
|
|
427
|
+
updated_at_ms = v_release.updated_at_ms
|
|
428
|
+
WHERE id = v_release.id;
|
|
429
|
+
WHEN 'delete' THEN
|
|
430
|
+
DELETE FROM public.hot_updater_v1_releases
|
|
431
|
+
WHERE id = (v_change->'where'->>'id')::uuid;
|
|
432
|
+
IF NOT FOUND THEN RAISE no_data_found; END IF;
|
|
433
|
+
ELSE
|
|
434
|
+
RAISE EXCEPTION 'Unsupported Release change'
|
|
435
|
+
USING ERRCODE = '22023';
|
|
436
|
+
END CASE;
|
|
437
|
+
|
|
438
|
+
WHEN 'releaseCatalogs' THEN
|
|
439
|
+
IF v_change->>'operation' <> 'put' THEN
|
|
440
|
+
RAISE EXCEPTION 'Unsupported Release catalog change'
|
|
441
|
+
USING ERRCODE = '22023';
|
|
442
|
+
END IF;
|
|
443
|
+
v_catalog := pg_catalog.jsonb_populate_record(
|
|
444
|
+
NULL::public.hot_updater_v1_release_catalogs,
|
|
445
|
+
v_change->'row'
|
|
446
|
+
);
|
|
447
|
+
INSERT INTO public.hot_updater_v1_release_catalogs SELECT v_catalog.*
|
|
448
|
+
ON CONFLICT (scope_key) DO UPDATE SET
|
|
449
|
+
catalog_id = EXCLUDED.catalog_id,
|
|
450
|
+
strategy = EXCLUDED.strategy,
|
|
451
|
+
channel_id = EXCLUDED.channel_id,
|
|
452
|
+
channel_key = EXCLUDED.channel_key,
|
|
453
|
+
platform = EXCLUDED.platform,
|
|
454
|
+
fingerprint_hash = EXCLUDED.fingerprint_hash,
|
|
455
|
+
generation = EXCLUDED.generation,
|
|
456
|
+
payload = EXCLUDED.payload,
|
|
457
|
+
catalog_hash = EXCLUDED.catalog_hash,
|
|
458
|
+
byte_size = EXCLUDED.byte_size,
|
|
459
|
+
is_tombstone = EXCLUDED.is_tombstone,
|
|
460
|
+
updated_at_ms = EXCLUDED.updated_at_ms;
|
|
461
|
+
|
|
462
|
+
WHEN 'analytics' THEN
|
|
463
|
+
IF v_change->>'operation' <> 'insert' THEN
|
|
464
|
+
RAISE EXCEPTION 'Unsupported analytics change'
|
|
465
|
+
USING ERRCODE = '22023';
|
|
466
|
+
END IF;
|
|
467
|
+
v_event := pg_catalog.jsonb_populate_record(
|
|
468
|
+
NULL::public.hot_updater_v1_bundle_events,
|
|
469
|
+
v_change->'row'
|
|
470
|
+
);
|
|
471
|
+
INSERT INTO public.hot_updater_v1_bundle_events (
|
|
472
|
+
id, type, install_id, user_id, username, from_release_id,
|
|
473
|
+
from_bundle_id, to_release_id, to_bundle_id, platform,
|
|
474
|
+
app_version, channel, cohort, update_strategy, fingerprint_hash,
|
|
475
|
+
sdk_version, received_at_ms
|
|
476
|
+
) VALUES (
|
|
477
|
+
v_event.id, v_event.type, v_event.install_id, v_event.user_id,
|
|
478
|
+
v_event.username, v_event.from_release_id, v_event.from_bundle_id,
|
|
479
|
+
v_event.to_release_id, v_event.to_bundle_id, v_event.platform,
|
|
480
|
+
v_event.app_version, v_event.channel, v_event.cohort,
|
|
481
|
+
v_event.update_strategy, v_event.fingerprint_hash,
|
|
482
|
+
v_event.sdk_version, v_event.received_at_ms
|
|
483
|
+
);
|
|
484
|
+
|
|
485
|
+
WHEN 'apiKeys' THEN
|
|
486
|
+
CASE v_change->>'operation'
|
|
487
|
+
WHEN 'insert' THEN
|
|
488
|
+
IF v_change->>'onConflict' <> 'ignore' THEN
|
|
489
|
+
RAISE EXCEPTION
|
|
490
|
+
'API key insert requires onConflict ignore'
|
|
491
|
+
USING ERRCODE = '22023';
|
|
492
|
+
END IF;
|
|
493
|
+
v_api_key := pg_catalog.jsonb_populate_record(
|
|
494
|
+
NULL::public.hot_updater_v1_api_keys,
|
|
495
|
+
v_change->'row'
|
|
496
|
+
);
|
|
497
|
+
INSERT INTO public.hot_updater_v1_api_keys (
|
|
498
|
+
id, hash, name, prefix, role, created_at_ms, revoked_at_ms
|
|
499
|
+
) VALUES (
|
|
500
|
+
v_api_key.id, v_api_key.hash, v_api_key.name,
|
|
501
|
+
v_api_key.prefix, v_api_key.role,
|
|
502
|
+
v_api_key.created_at_ms, v_api_key.revoked_at_ms
|
|
503
|
+
) ON CONFLICT (hash) DO NOTHING;
|
|
504
|
+
WHEN 'update' THEN
|
|
505
|
+
UPDATE public.hot_updater_v1_api_keys
|
|
506
|
+
SET revoked_at_ms = (
|
|
507
|
+
v_change->'update'->>'revokedAtMs'
|
|
508
|
+
)::double precision
|
|
509
|
+
WHERE id = v_change->'where'->>'id';
|
|
510
|
+
IF NOT FOUND THEN RAISE no_data_found; END IF;
|
|
511
|
+
ELSE
|
|
512
|
+
RAISE EXCEPTION 'Unsupported API key change'
|
|
513
|
+
USING ERRCODE = '22023';
|
|
514
|
+
END CASE;
|
|
515
|
+
|
|
516
|
+
ELSE
|
|
517
|
+
RAISE EXCEPTION 'Unsupported commit model at index %', v_change_index
|
|
518
|
+
USING ERRCODE = '22023';
|
|
519
|
+
END CASE;
|
|
520
|
+
END LOOP;
|
|
521
|
+
EXCEPTION
|
|
522
|
+
WHEN no_data_found THEN
|
|
523
|
+
RETURN pg_catalog.jsonb_build_object(
|
|
524
|
+
'committed', false,
|
|
525
|
+
'conflict', pg_catalog.jsonb_build_object(
|
|
526
|
+
'changeIndex', v_change_index,
|
|
527
|
+
'reason', 'not_found'
|
|
528
|
+
)
|
|
529
|
+
);
|
|
530
|
+
WHEN SQLSTATE 'HU001' THEN
|
|
531
|
+
RETURN pg_catalog.jsonb_build_object(
|
|
532
|
+
'committed', false,
|
|
533
|
+
'conflict', pg_catalog.jsonb_build_object(
|
|
534
|
+
'changeIndex', v_change_index,
|
|
535
|
+
'reason', 'referenced'
|
|
536
|
+
)
|
|
537
|
+
);
|
|
538
|
+
END;
|
|
539
|
+
|
|
540
|
+
RETURN pg_catalog.jsonb_build_object('committed', true);
|
|
541
|
+
END;
|
|
542
|
+
$$;
|
|
543
|
+
|
|
544
|
+
REVOKE EXECUTE ON FUNCTION public.hot_updater_v1_commit(jsonb)
|
|
545
|
+
FROM PUBLIC, anon, authenticated;
|
|
546
|
+
GRANT EXECUTE ON FUNCTION public.hot_updater_v1_commit(jsonb)
|
|
547
|
+
TO service_role;
|
|
548
|
+
|
|
549
|
+
CREATE FUNCTION public.hot_updater_v1_delete_channel(p_id text)
|
|
550
|
+
RETURNS jsonb
|
|
551
|
+
LANGUAGE plpgsql
|
|
552
|
+
SECURITY INVOKER
|
|
553
|
+
SET search_path = pg_catalog
|
|
554
|
+
AS $$
|
|
555
|
+
BEGIN
|
|
556
|
+
BEGIN
|
|
557
|
+
DELETE FROM public.hot_updater_v1_channels
|
|
558
|
+
WHERE id = p_id;
|
|
559
|
+
|
|
560
|
+
IF NOT FOUND THEN
|
|
561
|
+
RETURN pg_catalog.jsonb_build_object(
|
|
562
|
+
'deleted', false,
|
|
563
|
+
'reason', 'not_found'
|
|
564
|
+
);
|
|
565
|
+
END IF;
|
|
566
|
+
EXCEPTION
|
|
567
|
+
WHEN foreign_key_violation THEN
|
|
568
|
+
RETURN pg_catalog.jsonb_build_object(
|
|
569
|
+
'deleted', false,
|
|
570
|
+
'reason', 'not_empty'
|
|
571
|
+
);
|
|
572
|
+
END;
|
|
573
|
+
|
|
574
|
+
RETURN pg_catalog.jsonb_build_object('deleted', true);
|
|
575
|
+
END;
|
|
576
|
+
$$;
|
|
577
|
+
|
|
578
|
+
REVOKE EXECUTE ON FUNCTION public.hot_updater_v1_delete_channel(text)
|
|
579
|
+
FROM PUBLIC, anon, authenticated;
|
|
580
|
+
GRANT EXECUTE ON FUNCTION public.hot_updater_v1_delete_channel(text)
|
|
581
|
+
TO service_role;
|
|
582
|
+
|
|
583
|
+
NOTIFY pgrst, 'reload schema';
|