@hot-updater/postgres 0.17.0 → 0.18.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/index.cjs +2073 -2116
- package/dist/index.d.cts +22 -0
- package/dist/index.d.ts +22 -2
- package/dist/index.js +2052 -2068
- package/package.json +5 -5
- package/sql/bundles.sql +10 -2
- package/sql/get_update_info.spec.ts +35 -7
- package/sql/{get_update_info.sql → get_update_info_by_app_version.sql} +9 -5
- package/sql/get_update_info_by_fingerprint_hash.sql +87 -0
- package/dist/getUpdateInfo.d.ts +0 -3
- package/dist/postgres.d.ts +0 -5
- package/dist/types.d.ts +0 -4
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hot-updater/postgres",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.18.0",
|
|
5
5
|
"description": "React Native OTA solution for self-hosted",
|
|
6
6
|
"main": "dist/index.cjs",
|
|
7
7
|
"module": "dist/index.js",
|
|
@@ -31,18 +31,18 @@
|
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"kysely": "^0.27.5",
|
|
33
33
|
"pg": "^8.13.1",
|
|
34
|
-
"@hot-updater/
|
|
35
|
-
"@hot-updater/core": "0.
|
|
34
|
+
"@hot-updater/core": "0.18.0",
|
|
35
|
+
"@hot-updater/plugin-core": "0.18.0"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
38
|
"@electric-sql/pglite": "^0.2.15",
|
|
39
39
|
"@types/pg": "^8.11.10",
|
|
40
40
|
"camelcase-keys": "^9.1.3",
|
|
41
41
|
"pg-minify": "^1.6.5",
|
|
42
|
-
"@hot-updater/js": "0.
|
|
42
|
+
"@hot-updater/js": "0.18.0"
|
|
43
43
|
},
|
|
44
44
|
"scripts": {
|
|
45
|
-
"build": "
|
|
45
|
+
"build": "tsdown",
|
|
46
46
|
"test:type": "tsc --noEmit"
|
|
47
47
|
}
|
|
48
48
|
}
|
package/sql/bundles.sql
CHANGED
|
@@ -5,13 +5,21 @@ CREATE TYPE platforms AS ENUM ('ios', 'android');
|
|
|
5
5
|
CREATE TABLE bundles (
|
|
6
6
|
id uuid PRIMARY KEY,
|
|
7
7
|
platform platforms NOT NULL,
|
|
8
|
-
target_app_version text NOT NULL,
|
|
9
8
|
should_force_update boolean NOT NULL,
|
|
10
9
|
enabled boolean NOT NULL,
|
|
11
10
|
file_hash text NOT NULL,
|
|
12
11
|
git_commit_hash text,
|
|
13
12
|
message text,
|
|
14
|
-
channel text NOT NULL DEFAULT 'production'
|
|
13
|
+
channel text NOT NULL DEFAULT 'production',
|
|
14
|
+
storage_uri text NOT NULL,
|
|
15
|
+
target_app_version text,
|
|
16
|
+
fingerprint_hash text,
|
|
17
|
+
CONSTRAINT check_version_or_fingerprint CHECK (
|
|
18
|
+
(target_app_version IS NOT NULL) OR (fingerprint_hash IS NOT NULL)
|
|
19
|
+
),
|
|
20
|
+
metadata jsonb DEFAULT '{}'::jsonb
|
|
15
21
|
);
|
|
16
22
|
|
|
17
23
|
CREATE INDEX bundles_target_app_version_idx ON bundles(target_app_version);
|
|
24
|
+
CREATE INDEX bundles_fingerprint_hash_idx ON bundles(fingerprint_hash);
|
|
25
|
+
CREATE INDEX bundles_channel_idx ON bundles(channel);
|
|
@@ -15,7 +15,7 @@ const createInsertBundleQuery = (bundle: Bundle) => {
|
|
|
15
15
|
return `
|
|
16
16
|
INSERT INTO bundles (
|
|
17
17
|
id, file_hash, platform, target_app_version,
|
|
18
|
-
should_force_update, enabled, git_commit_hash, message, channel
|
|
18
|
+
should_force_update, enabled, git_commit_hash, message, channel, storage_uri, fingerprint_hash
|
|
19
19
|
) VALUES (
|
|
20
20
|
'${bundle.id}',
|
|
21
21
|
'${bundle.fileHash}',
|
|
@@ -25,7 +25,9 @@ const createInsertBundleQuery = (bundle: Bundle) => {
|
|
|
25
25
|
${bundle.enabled},
|
|
26
26
|
${bundle.gitCommitHash ? `'${bundle.gitCommitHash}'` : "null"},
|
|
27
27
|
${bundle.message ? `'${bundle.message}'` : "null"},
|
|
28
|
-
'${bundle.channel}'
|
|
28
|
+
'${bundle.channel}',
|
|
29
|
+
'${bundle.storageUri}',
|
|
30
|
+
'${bundle.fingerprintHash}'
|
|
29
31
|
);
|
|
30
32
|
`;
|
|
31
33
|
};
|
|
@@ -34,16 +36,42 @@ const createGetUpdateInfo =
|
|
|
34
36
|
(db: PGlite) =>
|
|
35
37
|
async (
|
|
36
38
|
bundles: Bundle[],
|
|
37
|
-
|
|
38
|
-
|
|
39
|
+
args: GetBundlesArgs,
|
|
40
|
+
): Promise<UpdateInfo | null> => {
|
|
41
|
+
const {
|
|
39
42
|
bundleId,
|
|
40
43
|
platform,
|
|
41
44
|
minBundleId = NIL_UUID,
|
|
42
45
|
channel = "production",
|
|
43
|
-
|
|
44
|
-
|
|
46
|
+
_updateStrategy,
|
|
47
|
+
} = args;
|
|
45
48
|
await db.exec(createInsertBundleQuerys(bundles));
|
|
46
49
|
|
|
50
|
+
if (_updateStrategy === "fingerprint") {
|
|
51
|
+
const fingerprintHash = args.fingerprintHash;
|
|
52
|
+
const result = await db.query<{
|
|
53
|
+
id: string;
|
|
54
|
+
should_force_update: boolean;
|
|
55
|
+
message: string;
|
|
56
|
+
status: string;
|
|
57
|
+
}>(
|
|
58
|
+
`
|
|
59
|
+
SELECT * FROM get_update_info_by_fingerprint_hash(
|
|
60
|
+
'${platform}',
|
|
61
|
+
'${bundleId}',
|
|
62
|
+
'${minBundleId}',
|
|
63
|
+
'${channel}',
|
|
64
|
+
'${fingerprintHash}'
|
|
65
|
+
);
|
|
66
|
+
`,
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
return result.rows[0]
|
|
70
|
+
? (camelcaseKeys(result.rows[0]) as UpdateInfo)
|
|
71
|
+
: null;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const appVersion = args.appVersion;
|
|
47
75
|
const { rows: appVersionList } = await db.query<{
|
|
48
76
|
target_app_version: string;
|
|
49
77
|
}>(
|
|
@@ -64,7 +92,7 @@ const createGetUpdateInfo =
|
|
|
64
92
|
status: string;
|
|
65
93
|
}>(
|
|
66
94
|
`
|
|
67
|
-
SELECT * FROM
|
|
95
|
+
SELECT * FROM get_update_info_by_app_version(
|
|
68
96
|
'${platform}',
|
|
69
97
|
'${appVersion}',
|
|
70
98
|
'${bundleId}',
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
-- HotUpdater.get_update_info
|
|
2
2
|
|
|
3
|
-
CREATE OR REPLACE FUNCTION
|
|
3
|
+
CREATE OR REPLACE FUNCTION get_update_info_by_app_version (
|
|
4
4
|
app_platform platforms,
|
|
5
5
|
app_version text,
|
|
6
6
|
bundle_id uuid,
|
|
@@ -12,7 +12,8 @@ RETURNS TABLE (
|
|
|
12
12
|
id uuid,
|
|
13
13
|
should_force_update boolean,
|
|
14
14
|
message text,
|
|
15
|
-
status text
|
|
15
|
+
status text,
|
|
16
|
+
storage_uri text
|
|
16
17
|
)
|
|
17
18
|
LANGUAGE plpgsql
|
|
18
19
|
AS
|
|
@@ -26,7 +27,8 @@ BEGIN
|
|
|
26
27
|
b.id,
|
|
27
28
|
b.should_force_update,
|
|
28
29
|
b.message,
|
|
29
|
-
'UPDATE' AS status
|
|
30
|
+
'UPDATE' AS status,
|
|
31
|
+
b.storage_uri
|
|
30
32
|
FROM bundles b
|
|
31
33
|
WHERE b.enabled = TRUE
|
|
32
34
|
AND b.platform = app_platform
|
|
@@ -42,7 +44,8 @@ BEGIN
|
|
|
42
44
|
b.id,
|
|
43
45
|
TRUE AS should_force_update,
|
|
44
46
|
b.message,
|
|
45
|
-
'ROLLBACK' AS status
|
|
47
|
+
'ROLLBACK' AS status,
|
|
48
|
+
b.storage_uri
|
|
46
49
|
FROM bundles b
|
|
47
50
|
WHERE b.enabled = TRUE
|
|
48
51
|
AND b.platform = app_platform
|
|
@@ -67,7 +70,8 @@ BEGIN
|
|
|
67
70
|
NIL_UUID AS id,
|
|
68
71
|
TRUE AS should_force_update,
|
|
69
72
|
NULL AS message,
|
|
70
|
-
'ROLLBACK' AS status
|
|
73
|
+
'ROLLBACK' AS status,
|
|
74
|
+
NULL AS storage_uri
|
|
71
75
|
WHERE (SELECT COUNT(*) FROM final_result) = 0
|
|
72
76
|
AND bundle_id != NIL_UUID
|
|
73
77
|
AND bundle_id > min_bundle_id
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
-- HotUpdater.get_update_info
|
|
2
|
+
|
|
3
|
+
CREATE OR REPLACE FUNCTION get_update_info_by_fingerprint_hash (
|
|
4
|
+
app_platform platforms,
|
|
5
|
+
bundle_id uuid,
|
|
6
|
+
min_bundle_id uuid,
|
|
7
|
+
target_channel text,
|
|
8
|
+
target_fingerprint_hash text
|
|
9
|
+
)
|
|
10
|
+
RETURNS TABLE (
|
|
11
|
+
id uuid,
|
|
12
|
+
should_force_update boolean,
|
|
13
|
+
message text,
|
|
14
|
+
status text,
|
|
15
|
+
storage_uri text
|
|
16
|
+
)
|
|
17
|
+
LANGUAGE plpgsql
|
|
18
|
+
AS
|
|
19
|
+
$$
|
|
20
|
+
DECLARE
|
|
21
|
+
NIL_UUID CONSTANT uuid := '00000000-0000-0000-0000-000000000000';
|
|
22
|
+
BEGIN
|
|
23
|
+
RETURN QUERY
|
|
24
|
+
WITH update_candidate AS (
|
|
25
|
+
SELECT
|
|
26
|
+
b.id,
|
|
27
|
+
b.should_force_update,
|
|
28
|
+
b.message,
|
|
29
|
+
'UPDATE' AS status,
|
|
30
|
+
b.storage_uri
|
|
31
|
+
FROM bundles b
|
|
32
|
+
WHERE b.enabled = TRUE
|
|
33
|
+
AND b.platform = app_platform
|
|
34
|
+
AND b.id >= bundle_id
|
|
35
|
+
AND b.id > min_bundle_id
|
|
36
|
+
AND b.channel = target_channel
|
|
37
|
+
AND b.fingerprint_hash = target_fingerprint_hash
|
|
38
|
+
ORDER BY b.id DESC
|
|
39
|
+
LIMIT 1
|
|
40
|
+
),
|
|
41
|
+
rollback_candidate AS (
|
|
42
|
+
SELECT
|
|
43
|
+
b.id,
|
|
44
|
+
TRUE AS should_force_update,
|
|
45
|
+
b.message,
|
|
46
|
+
'ROLLBACK' AS status,
|
|
47
|
+
b.storage_uri
|
|
48
|
+
FROM bundles b
|
|
49
|
+
WHERE b.enabled = TRUE
|
|
50
|
+
AND b.platform = app_platform
|
|
51
|
+
AND b.id < bundle_id
|
|
52
|
+
AND b.id > min_bundle_id
|
|
53
|
+
AND b.channel = target_channel
|
|
54
|
+
AND b.fingerprint_hash = target_fingerprint_hash
|
|
55
|
+
ORDER BY b.id DESC
|
|
56
|
+
LIMIT 1
|
|
57
|
+
),
|
|
58
|
+
final_result AS (
|
|
59
|
+
SELECT * FROM update_candidate
|
|
60
|
+
UNION ALL
|
|
61
|
+
SELECT * FROM rollback_candidate
|
|
62
|
+
WHERE NOT EXISTS (SELECT 1 FROM update_candidate)
|
|
63
|
+
)
|
|
64
|
+
SELECT *
|
|
65
|
+
FROM final_result
|
|
66
|
+
WHERE final_result.id != bundle_id
|
|
67
|
+
|
|
68
|
+
UNION ALL
|
|
69
|
+
|
|
70
|
+
SELECT
|
|
71
|
+
NIL_UUID AS id,
|
|
72
|
+
TRUE AS should_force_update,
|
|
73
|
+
NULL AS message,
|
|
74
|
+
'ROLLBACK' AS status,
|
|
75
|
+
NULL AS storage_uri
|
|
76
|
+
WHERE (SELECT COUNT(*) FROM final_result) = 0
|
|
77
|
+
AND bundle_id != NIL_UUID
|
|
78
|
+
AND bundle_id > min_bundle_id
|
|
79
|
+
AND NOT EXISTS (
|
|
80
|
+
SELECT 1
|
|
81
|
+
FROM bundles b
|
|
82
|
+
WHERE b.id = bundle_id
|
|
83
|
+
AND b.enabled = TRUE
|
|
84
|
+
AND b.platform = app_platform
|
|
85
|
+
);
|
|
86
|
+
END;
|
|
87
|
+
$$;
|
package/dist/getUpdateInfo.d.ts
DELETED
package/dist/postgres.d.ts
DELETED
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import type { DatabasePluginHooks } from "@hot-updater/plugin-core";
|
|
2
|
-
import { type PoolConfig } from "pg";
|
|
3
|
-
export interface PostgresConfig extends PoolConfig {
|
|
4
|
-
}
|
|
5
|
-
export declare const postgres: (config: PostgresConfig, hooks?: DatabasePluginHooks) => (options: import("@hot-updater/plugin-core").BasePluginArgs) => import("@hot-updater/plugin-core").DatabasePlugin;
|
package/dist/types.d.ts
DELETED