@hot-updater/supabase 1.0.0-rc.2 → 1.0.0-rc.21
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 +4 -3
- package/dist/edge.d.cts +4 -4
- package/dist/edge.d.mts +4 -4
- package/dist/edge.mjs +2 -2
- package/dist/index.cjs +143 -3
- package/dist/index.d.cts +13 -4
- package/dist/index.d.mts +13 -4
- package/dist/index.mjs +141 -2
- package/dist/init/index.cjs +7593 -4
- package/dist/init/index.d.cts +97 -4
- package/dist/init/index.d.mts +97 -4
- package/dist/init/index.mjs +7578 -1
- package/dist/plugins-B8grmU79.mjs +209 -0
- package/dist/plugins-DJUmZYvT.cjs +238 -0
- package/dist/supabaseDatabase-DVb3-y2x.d.cts +726 -0
- package/dist/supabaseDatabase-DVb3-y2x.d.mts +726 -0
- package/package.json +9 -14
- package/supabase/edge-functions/index.ts +6 -2
- package/supabase/migrations/20260818000000_hot-updater_1.0.0.sql +190 -604
- package/dist/iac/index.cjs +0 -8096
- package/dist/iac/index.d.cts +0 -102
- package/dist/iac/index.d.mts +0 -102
- package/dist/iac/index.mjs +0 -8079
- package/dist/supabaseDatabase-3d90EtUD.d.cts +0 -11
- package/dist/supabaseDatabase-3d90EtUD.d.mts +0 -11
- package/dist/supabaseStorage-CbzHzqCa.cjs +0 -622
- package/dist/supabaseStorage-CjteZ2zX.mjs +0 -611
- package/supabase/edge-functions/runtime.docker.integration.spec.ts +0 -1183
- package/supabase/migrations.spec.ts +0 -281
|
@@ -1,281 +0,0 @@
|
|
|
1
|
-
import fs from "node:fs/promises";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
|
|
4
|
-
import { PGlite } from "@electric-sql/pglite";
|
|
5
|
-
import { toInsightsInstallationRow } from "@hot-updater/plugin-core";
|
|
6
|
-
import { describe, expect, it } from "vitest";
|
|
7
|
-
|
|
8
|
-
import { createBundleEventRowFixture } from "../../../packages/test-utils/src/databaseTestFixtures";
|
|
9
|
-
|
|
10
|
-
const migrationPath = path.resolve(
|
|
11
|
-
"plugins/supabase/supabase/migrations/20260818000000_hot-updater_1.0.0.sql",
|
|
12
|
-
);
|
|
13
|
-
|
|
14
|
-
const readMigrations = async () => {
|
|
15
|
-
const migrationDirectory = path.resolve(
|
|
16
|
-
"plugins/supabase/supabase/migrations",
|
|
17
|
-
);
|
|
18
|
-
const migrationFiles = (await fs.readdir(migrationDirectory))
|
|
19
|
-
.filter((file) => file.endsWith(".sql"))
|
|
20
|
-
.sort();
|
|
21
|
-
return Promise.all(
|
|
22
|
-
migrationFiles.map(async (file) => ({
|
|
23
|
-
file,
|
|
24
|
-
sql: await fs.readFile(path.join(migrationDirectory, file), "utf8"),
|
|
25
|
-
})),
|
|
26
|
-
);
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
describe("Supabase v1 schema", () => {
|
|
30
|
-
it("initializes 1.0.0 and atomically records retries through the service-role RPC", async () => {
|
|
31
|
-
const database = new PGlite();
|
|
32
|
-
const event = createBundleEventRowFixture("9301", 100);
|
|
33
|
-
const installation = toInsightsInstallationRow(event);
|
|
34
|
-
try {
|
|
35
|
-
await database.exec(
|
|
36
|
-
"CREATE ROLE anon; CREATE ROLE authenticated; CREATE ROLE service_role;",
|
|
37
|
-
);
|
|
38
|
-
const [initial] = await readMigrations();
|
|
39
|
-
await database.exec(initial!.sql);
|
|
40
|
-
expect(
|
|
41
|
-
(
|
|
42
|
-
await database.query(
|
|
43
|
-
"SELECT value FROM public.hot_updater_v1_private_settings WHERE key = 'schema.core'",
|
|
44
|
-
)
|
|
45
|
-
).rows,
|
|
46
|
-
).toEqual([{ value: "1.0.0" }]);
|
|
47
|
-
const record = (row: typeof event) =>
|
|
48
|
-
database.query(
|
|
49
|
-
"SELECT public.hot_updater_v1_record_insights($1::jsonb, $2::jsonb)",
|
|
50
|
-
[JSON.stringify(row), JSON.stringify(toInsightsInstallationRow(row))],
|
|
51
|
-
);
|
|
52
|
-
await record(event);
|
|
53
|
-
const reusedId = {
|
|
54
|
-
...event,
|
|
55
|
-
user_id: "duplicate-user",
|
|
56
|
-
received_at_ms: 200,
|
|
57
|
-
};
|
|
58
|
-
await record(reusedId);
|
|
59
|
-
expect(
|
|
60
|
-
(
|
|
61
|
-
await database.query(
|
|
62
|
-
"SELECT * FROM public.hot_updater_v1_bundle_installations",
|
|
63
|
-
)
|
|
64
|
-
).rows,
|
|
65
|
-
).toEqual([installation]);
|
|
66
|
-
const next = {
|
|
67
|
-
...event,
|
|
68
|
-
id: createBundleEventRowFixture("9302", 200).id,
|
|
69
|
-
received_at_ms: 200,
|
|
70
|
-
};
|
|
71
|
-
await database.exec(`
|
|
72
|
-
CREATE FUNCTION fail_insights_snapshot() RETURNS trigger LANGUAGE plpgsql AS $$
|
|
73
|
-
BEGIN RAISE EXCEPTION 'injected snapshot failure'; END; $$;
|
|
74
|
-
CREATE TRIGGER fail_insights_snapshot BEFORE INSERT ON public.hot_updater_v1_bundle_installations
|
|
75
|
-
FOR EACH ROW EXECUTE FUNCTION fail_insights_snapshot();
|
|
76
|
-
`);
|
|
77
|
-
await expect(record(next)).rejects.toThrow("injected snapshot failure");
|
|
78
|
-
expect(
|
|
79
|
-
(
|
|
80
|
-
await database.query(
|
|
81
|
-
"SELECT id FROM public.hot_updater_v1_bundle_events",
|
|
82
|
-
)
|
|
83
|
-
).rows,
|
|
84
|
-
).toEqual([{ id: event.id }]);
|
|
85
|
-
expect(
|
|
86
|
-
(
|
|
87
|
-
await database.query(
|
|
88
|
-
"SELECT * FROM public.hot_updater_v1_bundle_installations",
|
|
89
|
-
)
|
|
90
|
-
).rows,
|
|
91
|
-
).toEqual([installation]);
|
|
92
|
-
await database.exec(
|
|
93
|
-
"DROP TRIGGER fail_insights_snapshot ON public.hot_updater_v1_bundle_installations",
|
|
94
|
-
);
|
|
95
|
-
await record(next);
|
|
96
|
-
await record(next);
|
|
97
|
-
expect(
|
|
98
|
-
(
|
|
99
|
-
await database.query(
|
|
100
|
-
"SELECT * FROM public.hot_updater_v1_bundle_installations",
|
|
101
|
-
)
|
|
102
|
-
).rows,
|
|
103
|
-
).toEqual([toInsightsInstallationRow(next)]);
|
|
104
|
-
expect(
|
|
105
|
-
(
|
|
106
|
-
await database.query(
|
|
107
|
-
"SELECT COUNT(*)::integer AS count FROM public.hot_updater_v1_bundle_events",
|
|
108
|
-
)
|
|
109
|
-
).rows,
|
|
110
|
-
).toEqual([{ count: 2 }]);
|
|
111
|
-
expect(
|
|
112
|
-
(
|
|
113
|
-
await database.query(
|
|
114
|
-
"SELECT has_function_privilege('anon', 'public.hot_updater_v1_record_insights(jsonb,jsonb)', 'EXECUTE') AS allowed",
|
|
115
|
-
)
|
|
116
|
-
).rows,
|
|
117
|
-
).toEqual([{ allowed: false }]);
|
|
118
|
-
expect(
|
|
119
|
-
(
|
|
120
|
-
await database.query(
|
|
121
|
-
"SELECT has_function_privilege('service_role', 'public.hot_updater_v1_record_insights(jsonb,jsonb)', 'EXECUTE') AS allowed",
|
|
122
|
-
)
|
|
123
|
-
).rows,
|
|
124
|
-
).toEqual([{ allowed: true }]);
|
|
125
|
-
} finally {
|
|
126
|
-
await database.close();
|
|
127
|
-
}
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
it("ships a single 1.0.0 initialization migration", async () => {
|
|
131
|
-
const migrations = await readMigrations();
|
|
132
|
-
expect(migrations.map(({ file }) => file)).toEqual([
|
|
133
|
-
"20260818000000_hot-updater_1.0.0.sql",
|
|
134
|
-
]);
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
it("creates namespaced tables, RLS, and functions", async () => {
|
|
138
|
-
const sql = await fs.readFile(migrationPath, "utf8");
|
|
139
|
-
|
|
140
|
-
expect(sql).toContain("CREATE TABLE public.hot_updater_v1_channels");
|
|
141
|
-
expect(sql).toContain("CREATE TABLE public.hot_updater_v1_bundles");
|
|
142
|
-
expect(sql).toContain("CREATE TABLE public.hot_updater_v1_releases");
|
|
143
|
-
expect(sql).toContain(
|
|
144
|
-
"CREATE TABLE public.hot_updater_v1_release_catalogs",
|
|
145
|
-
);
|
|
146
|
-
expect(sql).toContain("CREATE TABLE public.hot_updater_v1_bundle_events");
|
|
147
|
-
expect(sql).toContain(
|
|
148
|
-
"CREATE TABLE public.hot_updater_v1_bundle_installations",
|
|
149
|
-
);
|
|
150
|
-
expect(sql).toContain(
|
|
151
|
-
"hot_updater_v1_bundle_installations(user_id, install_id)",
|
|
152
|
-
);
|
|
153
|
-
expect(sql).toContain(
|
|
154
|
-
"hot_updater_v1_bundle_installations(received_at_ms)",
|
|
155
|
-
);
|
|
156
|
-
expect(sql).toContain(
|
|
157
|
-
"hot_updater_v1_bundle_events(install_id, type, received_at_ms, id)",
|
|
158
|
-
);
|
|
159
|
-
expect(sql).toContain(
|
|
160
|
-
"hot_updater_v1_bundle_events(type, platform, channel, from_bundle_id, received_at_ms, id)",
|
|
161
|
-
);
|
|
162
|
-
expect(sql).toContain(
|
|
163
|
-
"hot_updater_v1_bundle_events(type, platform, channel, to_bundle_id, received_at_ms, id)",
|
|
164
|
-
);
|
|
165
|
-
expect(sql).toContain(
|
|
166
|
-
"hot_updater_v1_bundle_installations(platform, channel, received_at_ms)",
|
|
167
|
-
);
|
|
168
|
-
expect(sql).toContain(
|
|
169
|
-
"hot_updater_v1_bundle_installations(platform, channel, to_bundle_id, received_at_ms)",
|
|
170
|
-
);
|
|
171
|
-
expect(sql).toContain(
|
|
172
|
-
"CREATE FUNCTION public.hot_updater_v1_record_insights(p_event jsonb, p_installation jsonb)",
|
|
173
|
-
);
|
|
174
|
-
expect(sql).toContain("CREATE TABLE public.hot_updater_v1_api_keys");
|
|
175
|
-
expect(sql).toContain(
|
|
176
|
-
"ALTER TABLE public.hot_updater_v1_bundles ENABLE ROW LEVEL SECURITY",
|
|
177
|
-
);
|
|
178
|
-
expect(sql).toContain(
|
|
179
|
-
"CREATE FUNCTION public.hot_updater_v1_commit(p_commit jsonb)",
|
|
180
|
-
);
|
|
181
|
-
expect(sql).toContain(
|
|
182
|
-
"CREATE FUNCTION public.hot_updater_v1_delete_channel(p_id text)",
|
|
183
|
-
);
|
|
184
|
-
expect(sql).toContain("REVOKE EXECUTE ON FUNCTION");
|
|
185
|
-
expect(sql).toContain("TO service_role;");
|
|
186
|
-
expect(sql).toContain("archive_byte_size double precision NOT NULL CHECK");
|
|
187
|
-
expect(sql).toContain("byte_size double precision NOT NULL CHECK");
|
|
188
|
-
expect(sql).toContain("archive_byte_size = v_bundle.archive_byte_size");
|
|
189
|
-
expect(sql).toContain(
|
|
190
|
-
"patch_file_hash, patch_storage_uri, byte_size, order_index",
|
|
191
|
-
);
|
|
192
|
-
expect(sql).toContain("NOTIFY pgrst, 'reload schema'");
|
|
193
|
-
expect(sql).not.toContain("get_update_info");
|
|
194
|
-
expect(sql).not.toContain("ALTER TABLE public.bundles ADD COLUMN");
|
|
195
|
-
expect(sql).not.toContain("WHEN 'insights'");
|
|
196
|
-
expect(sql).not.toContain("v_event public.hot_updater_v1_bundle_events");
|
|
197
|
-
});
|
|
198
|
-
|
|
199
|
-
it("applies beside a v0 schema without modifying v0 data", async () => {
|
|
200
|
-
const database = new PGlite();
|
|
201
|
-
try {
|
|
202
|
-
await database.exec(
|
|
203
|
-
"CREATE ROLE anon; CREATE ROLE authenticated; CREATE ROLE service_role;",
|
|
204
|
-
);
|
|
205
|
-
await database.exec(`
|
|
206
|
-
CREATE TABLE public.channels (id text PRIMARY KEY, name text NOT NULL);
|
|
207
|
-
CREATE TABLE public.bundles (
|
|
208
|
-
id uuid PRIMARY KEY,
|
|
209
|
-
target_app_version text NOT NULL
|
|
210
|
-
);
|
|
211
|
-
INSERT INTO public.channels (id, name)
|
|
212
|
-
VALUES ('legacy-channel', 'legacy');
|
|
213
|
-
INSERT INTO public.bundles (id, target_app_version)
|
|
214
|
-
VALUES ('00000000-0000-0000-0000-000000000099', '0.85.0');
|
|
215
|
-
`);
|
|
216
|
-
for (const migration of await readMigrations()) {
|
|
217
|
-
await database.exec(migration.sql);
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
const tables = await database.query<{ tablename: string }>(`
|
|
221
|
-
select tablename from pg_tables
|
|
222
|
-
where schemaname = 'public'
|
|
223
|
-
order by tablename
|
|
224
|
-
`);
|
|
225
|
-
expect(tables.rows.map(({ tablename }) => tablename)).toEqual(
|
|
226
|
-
expect.arrayContaining([
|
|
227
|
-
"hot_updater_v1_bundles",
|
|
228
|
-
"hot_updater_v1_bundle_events",
|
|
229
|
-
"hot_updater_v1_bundle_installations",
|
|
230
|
-
"hot_updater_v1_bundle_patches",
|
|
231
|
-
"hot_updater_v1_channels",
|
|
232
|
-
"hot_updater_v1_api_keys",
|
|
233
|
-
"hot_updater_v1_private_settings",
|
|
234
|
-
"hot_updater_v1_release_catalogs",
|
|
235
|
-
"hot_updater_v1_releases",
|
|
236
|
-
]),
|
|
237
|
-
);
|
|
238
|
-
|
|
239
|
-
await database.exec(`
|
|
240
|
-
INSERT INTO public.hot_updater_v1_channels (id, name)
|
|
241
|
-
VALUES ('channel-1', 'production');
|
|
242
|
-
INSERT INTO public.hot_updater_v1_bundles (
|
|
243
|
-
id, platform, file_hash, storage_uri, archive_byte_size, metadata
|
|
244
|
-
) VALUES (
|
|
245
|
-
'00000000-0000-0000-0000-000000000001', 'ios', 'hash',
|
|
246
|
-
'storage://bundle', 3000000001, '{}'::jsonb
|
|
247
|
-
);
|
|
248
|
-
INSERT INTO public.hot_updater_v1_bundle_patches (
|
|
249
|
-
id, bundle_id, base_bundle_id, base_file_hash, patch_file_hash,
|
|
250
|
-
patch_storage_uri, byte_size
|
|
251
|
-
) VALUES (
|
|
252
|
-
'patch-1', '00000000-0000-0000-0000-000000000001',
|
|
253
|
-
'00000000-0000-0000-0000-000000000001', 'base-hash', 'patch-hash',
|
|
254
|
-
'storage://patch', 3000000002
|
|
255
|
-
);
|
|
256
|
-
`);
|
|
257
|
-
const channels = await database.query<{ name: string }>(
|
|
258
|
-
"SELECT name FROM public.hot_updater_v1_channels",
|
|
259
|
-
);
|
|
260
|
-
expect(channels.rows).toEqual([{ name: "production" }]);
|
|
261
|
-
const legacyChannels = await database.query<{ name: string }>(
|
|
262
|
-
"SELECT name FROM public.channels",
|
|
263
|
-
);
|
|
264
|
-
expect(legacyChannels.rows).toEqual([{ name: "legacy" }]);
|
|
265
|
-
const sizes = await database.query<{
|
|
266
|
-
archive_byte_size: number;
|
|
267
|
-
byte_size: number;
|
|
268
|
-
}>(`
|
|
269
|
-
SELECT bundle.archive_byte_size, patch.byte_size
|
|
270
|
-
FROM public.hot_updater_v1_bundles AS bundle
|
|
271
|
-
JOIN public.hot_updater_v1_bundle_patches AS patch
|
|
272
|
-
ON patch.bundle_id = bundle.id
|
|
273
|
-
`);
|
|
274
|
-
expect(sizes.rows).toEqual([
|
|
275
|
-
{ archive_byte_size: 3_000_000_001, byte_size: 3_000_000_002 },
|
|
276
|
-
]);
|
|
277
|
-
} finally {
|
|
278
|
-
await database.close();
|
|
279
|
-
}
|
|
280
|
-
});
|
|
281
|
-
});
|