@hot-updater/server 0.30.12 → 0.31.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/_virtual/_rolldown/runtime.cjs +25 -0
- package/dist/_virtual/_rolldown/runtime.mjs +6 -0
- package/dist/adapters/drizzle.cjs +6 -9
- package/dist/adapters/drizzle.d.cts +8 -1
- package/dist/adapters/drizzle.d.mts +8 -1
- package/dist/adapters/drizzle.mjs +5 -2
- package/dist/adapters/kysely.cjs +7 -9
- package/dist/adapters/kysely.d.cts +14 -1
- package/dist/adapters/kysely.d.mts +14 -1
- package/dist/adapters/kysely.mjs +6 -2
- package/dist/adapters/mongodb.cjs +7 -9
- package/dist/adapters/mongodb.d.cts +9 -1
- package/dist/adapters/mongodb.d.mts +9 -1
- package/dist/adapters/mongodb.mjs +5 -2
- package/dist/adapters/prisma.cjs +6 -9
- package/dist/adapters/prisma.d.cts +8 -1
- package/dist/adapters/prisma.d.mts +8 -1
- package/dist/adapters/prisma.mjs +5 -2
- package/dist/db/createBundleDiff.cjs +166 -0
- package/dist/db/createBundleDiff.d.cts +20 -0
- package/dist/db/createBundleDiff.d.mts +20 -0
- package/dist/db/createBundleDiff.mjs +161 -0
- package/dist/db/index.cjs +15 -16
- package/dist/db/index.d.cts +5 -4
- package/dist/db/index.d.mts +5 -4
- package/dist/db/index.mjs +14 -16
- package/dist/db/ormCore.cjs +173 -65
- package/dist/db/ormCore.d.cts +100 -34
- package/dist/db/ormCore.d.mts +100 -34
- package/dist/db/ormCore.mjs +171 -64
- package/dist/db/pluginCore.cjs +37 -3
- package/dist/db/pluginCore.mjs +36 -3
- package/dist/db/schemaEnhancements.cjs +171 -0
- package/dist/db/schemaEnhancements.mjs +167 -0
- package/dist/db/types.cjs +6 -0
- package/dist/db/types.d.cts +19 -7
- package/dist/db/types.d.mts +22 -10
- package/dist/db/types.mjs +6 -1
- package/dist/db/updateArtifacts.cjs +127 -0
- package/dist/db/updateArtifacts.mjs +125 -0
- package/dist/handler.cjs +61 -5
- package/dist/handler.d.cts +2 -2
- package/dist/handler.d.mts +5 -5
- package/dist/handler.mjs +59 -5
- package/dist/index.cjs +2 -0
- package/dist/index.d.cts +3 -2
- package/dist/index.d.mts +3 -2
- package/dist/index.mjs +2 -1
- package/dist/node.d.cts +0 -1
- package/dist/node.d.mts +0 -1
- package/dist/node_modules/.pnpm/@noble_hashes@1.8.0/node_modules/@noble/hashes/_u64.cjs +112 -0
- package/dist/node_modules/.pnpm/@noble_hashes@1.8.0/node_modules/@noble/hashes/_u64.mjs +108 -0
- package/dist/node_modules/.pnpm/@noble_hashes@1.8.0/node_modules/@noble/hashes/cryptoNode.cjs +22 -0
- package/dist/node_modules/.pnpm/@noble_hashes@1.8.0/node_modules/@noble/hashes/cryptoNode.mjs +18 -0
- package/dist/node_modules/.pnpm/@noble_hashes@1.8.0/node_modules/@noble/hashes/sha3.cjs +219 -0
- package/dist/node_modules/.pnpm/@noble_hashes@1.8.0/node_modules/@noble/hashes/sha3.mjs +214 -0
- package/dist/node_modules/.pnpm/@noble_hashes@1.8.0/node_modules/@noble/hashes/utils.cjs +275 -0
- package/dist/node_modules/.pnpm/@noble_hashes@1.8.0/node_modules/@noble/hashes/utils.mjs +270 -0
- package/dist/node_modules/.pnpm/@paralleldrive_cuid2@2.3.1/node_modules/@paralleldrive/cuid2/index.cjs +17 -0
- package/dist/node_modules/.pnpm/@paralleldrive_cuid2@2.3.1/node_modules/@paralleldrive/cuid2/index.mjs +13 -0
- package/dist/node_modules/.pnpm/@paralleldrive_cuid2@2.3.1/node_modules/@paralleldrive/cuid2/src/index.cjs +69 -0
- package/dist/node_modules/.pnpm/@paralleldrive_cuid2@2.3.1/node_modules/@paralleldrive/cuid2/src/index.mjs +65 -0
- package/dist/node_modules/.pnpm/drizzle-orm@0.44.7_@cloudflare_workers-types@4.20260313.1_@electric-sql_pglite@0.2.17_@_31f44b782f9321d71f3ce9d35aa1edf7/node_modules/drizzle-orm/column.cjs +52 -0
- package/dist/node_modules/.pnpm/drizzle-orm@0.44.7_@cloudflare_workers-types@4.20260313.1_@electric-sql_pglite@0.2.17_@_31f44b782f9321d71f3ce9d35aa1edf7/node_modules/drizzle-orm/column.mjs +52 -0
- package/dist/node_modules/.pnpm/drizzle-orm@0.44.7_@cloudflare_workers-types@4.20260313.1_@electric-sql_pglite@0.2.17_@_31f44b782f9321d71f3ce9d35aa1edf7/node_modules/drizzle-orm/entity.cjs +16 -0
- package/dist/node_modules/.pnpm/drizzle-orm@0.44.7_@cloudflare_workers-types@4.20260313.1_@electric-sql_pglite@0.2.17_@_31f44b782f9321d71f3ce9d35aa1edf7/node_modules/drizzle-orm/entity.mjs +15 -0
- package/dist/node_modules/.pnpm/drizzle-orm@0.44.7_@cloudflare_workers-types@4.20260313.1_@electric-sql_pglite@0.2.17_@_31f44b782f9321d71f3ce9d35aa1edf7/node_modules/drizzle-orm/pg-core/columns/enum.cjs +7 -0
- package/dist/node_modules/.pnpm/drizzle-orm@0.44.7_@cloudflare_workers-types@4.20260313.1_@electric-sql_pglite@0.2.17_@_31f44b782f9321d71f3ce9d35aa1edf7/node_modules/drizzle-orm/pg-core/columns/enum.mjs +7 -0
- package/dist/node_modules/.pnpm/drizzle-orm@0.44.7_@cloudflare_workers-types@4.20260313.1_@electric-sql_pglite@0.2.17_@_31f44b782f9321d71f3ce9d35aa1edf7/node_modules/drizzle-orm/sql/expressions/conditions.cjs +92 -0
- package/dist/node_modules/.pnpm/drizzle-orm@0.44.7_@cloudflare_workers-types@4.20260313.1_@electric-sql_pglite@0.2.17_@_31f44b782f9321d71f3ce9d35aa1edf7/node_modules/drizzle-orm/sql/expressions/conditions.mjs +78 -0
- package/dist/node_modules/.pnpm/drizzle-orm@0.44.7_@cloudflare_workers-types@4.20260313.1_@electric-sql_pglite@0.2.17_@_31f44b782f9321d71f3ce9d35aa1edf7/node_modules/drizzle-orm/sql/expressions/select.cjs +11 -0
- package/dist/node_modules/.pnpm/drizzle-orm@0.44.7_@cloudflare_workers-types@4.20260313.1_@electric-sql_pglite@0.2.17_@_31f44b782f9321d71f3ce9d35aa1edf7/node_modules/drizzle-orm/sql/expressions/select.mjs +10 -0
- package/dist/node_modules/.pnpm/drizzle-orm@0.44.7_@cloudflare_workers-types@4.20260313.1_@electric-sql_pglite@0.2.17_@_31f44b782f9321d71f3ce9d35aa1edf7/node_modules/drizzle-orm/sql/sql.cjs +383 -0
- package/dist/node_modules/.pnpm/drizzle-orm@0.44.7_@cloudflare_workers-types@4.20260313.1_@electric-sql_pglite@0.2.17_@_31f44b782f9321d71f3ce9d35aa1edf7/node_modules/drizzle-orm/sql/sql.mjs +366 -0
- package/dist/node_modules/.pnpm/drizzle-orm@0.44.7_@cloudflare_workers-types@4.20260313.1_@electric-sql_pglite@0.2.17_@_31f44b782f9321d71f3ce9d35aa1edf7/node_modules/drizzle-orm/subquery.cjs +17 -0
- package/dist/node_modules/.pnpm/drizzle-orm@0.44.7_@cloudflare_workers-types@4.20260313.1_@electric-sql_pglite@0.2.17_@_31f44b782f9321d71f3ce9d35aa1edf7/node_modules/drizzle-orm/subquery.mjs +17 -0
- package/dist/node_modules/.pnpm/drizzle-orm@0.44.7_@cloudflare_workers-types@4.20260313.1_@electric-sql_pglite@0.2.17_@_31f44b782f9321d71f3ce9d35aa1edf7/node_modules/drizzle-orm/table.cjs +60 -0
- package/dist/node_modules/.pnpm/drizzle-orm@0.44.7_@cloudflare_workers-types@4.20260313.1_@electric-sql_pglite@0.2.17_@_31f44b782f9321d71f3ce9d35aa1edf7/node_modules/drizzle-orm/table.mjs +59 -0
- package/dist/node_modules/.pnpm/drizzle-orm@0.44.7_@cloudflare_workers-types@4.20260313.1_@electric-sql_pglite@0.2.17_@_31f44b782f9321d71f3ce9d35aa1edf7/node_modules/drizzle-orm/table.utils.cjs +4 -0
- package/dist/node_modules/.pnpm/drizzle-orm@0.44.7_@cloudflare_workers-types@4.20260313.1_@electric-sql_pglite@0.2.17_@_31f44b782f9321d71f3ce9d35aa1edf7/node_modules/drizzle-orm/table.utils.mjs +4 -0
- package/dist/node_modules/.pnpm/drizzle-orm@0.44.7_@cloudflare_workers-types@4.20260313.1_@electric-sql_pglite@0.2.17_@_31f44b782f9321d71f3ce9d35aa1edf7/node_modules/drizzle-orm/tracing.cjs +6 -0
- package/dist/node_modules/.pnpm/drizzle-orm@0.44.7_@cloudflare_workers-types@4.20260313.1_@electric-sql_pglite@0.2.17_@_31f44b782f9321d71f3ce9d35aa1edf7/node_modules/drizzle-orm/tracing.mjs +6 -0
- package/dist/node_modules/.pnpm/drizzle-orm@0.44.7_@cloudflare_workers-types@4.20260313.1_@electric-sql_pglite@0.2.17_@_31f44b782f9321d71f3ce9d35aa1edf7/node_modules/drizzle-orm/view-common.cjs +4 -0
- package/dist/node_modules/.pnpm/drizzle-orm@0.44.7_@cloudflare_workers-types@4.20260313.1_@electric-sql_pglite@0.2.17_@_31f44b782f9321d71f3ce9d35aa1edf7/node_modules/drizzle-orm/view-common.mjs +4 -0
- package/dist/node_modules/.pnpm/fumadb@0.2.2_drizzle-orm@0.44.7_@cloudflare_workers-types@4.20260313.1_@electric-sql_pg_c72c8c754becd21f6d6662e8fbd28e7f/node_modules/fumadb/dist/adapters/drizzle/index.cjs +383 -0
- package/dist/node_modules/.pnpm/fumadb@0.2.2_drizzle-orm@0.44.7_@cloudflare_workers-types@4.20260313.1_@electric-sql_pg_c72c8c754becd21f6d6662e8fbd28e7f/node_modules/fumadb/dist/adapters/drizzle/index.d.cts +12 -0
- package/dist/node_modules/.pnpm/fumadb@0.2.2_drizzle-orm@0.44.7_@cloudflare_workers-types@4.20260313.1_@electric-sql_pg_c72c8c754becd21f6d6662e8fbd28e7f/node_modules/fumadb/dist/adapters/drizzle/index.d.mts +12 -0
- package/dist/node_modules/.pnpm/fumadb@0.2.2_drizzle-orm@0.44.7_@cloudflare_workers-types@4.20260313.1_@electric-sql_pg_c72c8c754becd21f6d6662e8fbd28e7f/node_modules/fumadb/dist/adapters/drizzle/index.mjs +383 -0
- package/dist/node_modules/.pnpm/fumadb@0.2.2_drizzle-orm@0.44.7_@cloudflare_workers-types@4.20260313.1_@electric-sql_pg_c72c8c754becd21f6d6662e8fbd28e7f/node_modules/fumadb/dist/adapters/kysely/index.cjs +4 -0
- package/dist/node_modules/.pnpm/fumadb@0.2.2_drizzle-orm@0.44.7_@cloudflare_workers-types@4.20260313.1_@electric-sql_pg_c72c8c754becd21f6d6662e8fbd28e7f/node_modules/fumadb/dist/adapters/kysely/index.mjs +5 -0
- package/dist/node_modules/.pnpm/fumadb@0.2.2_drizzle-orm@0.44.7_@cloudflare_workers-types@4.20260313.1_@electric-sql_pg_c72c8c754becd21f6d6662e8fbd28e7f/node_modules/fumadb/dist/adapters/prisma/index.cjs +339 -0
- package/dist/node_modules/.pnpm/fumadb@0.2.2_drizzle-orm@0.44.7_@cloudflare_workers-types@4.20260313.1_@electric-sql_pg_c72c8c754becd21f6d6662e8fbd28e7f/node_modules/fumadb/dist/adapters/prisma/index.d.cts +70 -0
- package/dist/node_modules/.pnpm/fumadb@0.2.2_drizzle-orm@0.44.7_@cloudflare_workers-types@4.20260313.1_@electric-sql_pg_c72c8c754becd21f6d6662e8fbd28e7f/node_modules/fumadb/dist/adapters/prisma/index.d.mts +70 -0
- package/dist/node_modules/.pnpm/fumadb@0.2.2_drizzle-orm@0.44.7_@cloudflare_workers-types@4.20260313.1_@electric-sql_pg_c72c8c754becd21f6d6662e8fbd28e7f/node_modules/fumadb/dist/adapters/prisma/index.mjs +339 -0
- package/dist/node_modules/.pnpm/fumadb@0.2.2_drizzle-orm@0.44.7_@cloudflare_workers-types@4.20260313.1_@electric-sql_pg_c72c8c754becd21f6d6662e8fbd28e7f/node_modules/fumadb/dist/chunk-7PZK4ONR.cjs +57 -0
- package/dist/node_modules/.pnpm/fumadb@0.2.2_drizzle-orm@0.44.7_@cloudflare_workers-types@4.20260313.1_@electric-sql_pg_c72c8c754becd21f6d6662e8fbd28e7f/node_modules/fumadb/dist/chunk-7PZK4ONR.mjs +56 -0
- package/dist/node_modules/.pnpm/fumadb@0.2.2_drizzle-orm@0.44.7_@cloudflare_workers-types@4.20260313.1_@electric-sql_pg_c72c8c754becd21f6d6662e8fbd28e7f/node_modules/fumadb/dist/chunk-C6OTUURW.cjs +330 -0
- package/dist/node_modules/.pnpm/fumadb@0.2.2_drizzle-orm@0.44.7_@cloudflare_workers-types@4.20260313.1_@electric-sql_pg_c72c8c754becd21f6d6662e8fbd28e7f/node_modules/fumadb/dist/chunk-C6OTUURW.mjs +326 -0
- package/dist/node_modules/.pnpm/fumadb@0.2.2_drizzle-orm@0.44.7_@cloudflare_workers-types@4.20260313.1_@electric-sql_pg_c72c8c754becd21f6d6662e8fbd28e7f/node_modules/fumadb/dist/chunk-CHTIKPQU.cjs +166 -0
- package/dist/node_modules/.pnpm/fumadb@0.2.2_drizzle-orm@0.44.7_@cloudflare_workers-types@4.20260313.1_@electric-sql_pg_c72c8c754becd21f6d6662e8fbd28e7f/node_modules/fumadb/dist/chunk-CHTIKPQU.mjs +163 -0
- package/dist/node_modules/.pnpm/fumadb@0.2.2_drizzle-orm@0.44.7_@cloudflare_workers-types@4.20260313.1_@electric-sql_pg_c72c8c754becd21f6d6662e8fbd28e7f/node_modules/fumadb/dist/chunk-GUE4GMNC.cjs +14 -0
- package/dist/node_modules/.pnpm/fumadb@0.2.2_drizzle-orm@0.44.7_@cloudflare_workers-types@4.20260313.1_@electric-sql_pg_c72c8c754becd21f6d6662e8fbd28e7f/node_modules/fumadb/dist/chunk-GUE4GMNC.mjs +13 -0
- package/dist/node_modules/.pnpm/fumadb@0.2.2_drizzle-orm@0.44.7_@cloudflare_workers-types@4.20260313.1_@electric-sql_pg_c72c8c754becd21f6d6662e8fbd28e7f/node_modules/fumadb/dist/chunk-LHHP6UVP.cjs +24 -0
- package/dist/node_modules/.pnpm/fumadb@0.2.2_drizzle-orm@0.44.7_@cloudflare_workers-types@4.20260313.1_@electric-sql_pg_c72c8c754becd21f6d6662e8fbd28e7f/node_modules/fumadb/dist/chunk-LHHP6UVP.mjs +24 -0
- package/dist/node_modules/.pnpm/fumadb@0.2.2_drizzle-orm@0.44.7_@cloudflare_workers-types@4.20260313.1_@electric-sql_pg_c72c8c754becd21f6d6662e8fbd28e7f/node_modules/fumadb/dist/chunk-LVCPMTAT.cjs +1190 -0
- package/dist/node_modules/.pnpm/fumadb@0.2.2_drizzle-orm@0.44.7_@cloudflare_workers-types@4.20260313.1_@electric-sql_pg_c72c8c754becd21f6d6662e8fbd28e7f/node_modules/fumadb/dist/chunk-LVCPMTAT.mjs +1189 -0
- package/dist/node_modules/.pnpm/fumadb@0.2.2_drizzle-orm@0.44.7_@cloudflare_workers-types@4.20260313.1_@electric-sql_pg_c72c8c754becd21f6d6662e8fbd28e7f/node_modules/fumadb/dist/chunk-PK2W2SQ7.cjs +197 -0
- package/dist/node_modules/.pnpm/fumadb@0.2.2_drizzle-orm@0.44.7_@cloudflare_workers-types@4.20260313.1_@electric-sql_pg_c72c8c754becd21f6d6662e8fbd28e7f/node_modules/fumadb/dist/chunk-PK2W2SQ7.mjs +197 -0
- package/dist/node_modules/.pnpm/fumadb@0.2.2_drizzle-orm@0.44.7_@cloudflare_workers-types@4.20260313.1_@electric-sql_pg_c72c8c754becd21f6d6662e8fbd28e7f/node_modules/fumadb/dist/chunk-ZEQMAIFI.cjs +410 -0
- package/dist/node_modules/.pnpm/fumadb@0.2.2_drizzle-orm@0.44.7_@cloudflare_workers-types@4.20260313.1_@electric-sql_pg_c72c8c754becd21f6d6662e8fbd28e7f/node_modules/fumadb/dist/chunk-ZEQMAIFI.mjs +400 -0
- package/dist/node_modules/.pnpm/fumadb@0.2.2_drizzle-orm@0.44.7_@cloudflare_workers-types@4.20260313.1_@electric-sql_pg_c72c8c754becd21f6d6662e8fbd28e7f/node_modules/fumadb/dist/chunk-ZOCGSAWS.cjs +213 -0
- package/dist/node_modules/.pnpm/fumadb@0.2.2_drizzle-orm@0.44.7_@cloudflare_workers-types@4.20260313.1_@electric-sql_pg_c72c8c754becd21f6d6662e8fbd28e7f/node_modules/fumadb/dist/chunk-ZOCGSAWS.mjs +212 -0
- package/dist/node_modules/.pnpm/fumadb@0.2.2_drizzle-orm@0.44.7_@cloudflare_workers-types@4.20260313.1_@electric-sql_pg_c72c8c754becd21f6d6662e8fbd28e7f/node_modules/fumadb/dist/create-tg0451Y_.d.cts +285 -0
- package/dist/node_modules/.pnpm/fumadb@0.2.2_drizzle-orm@0.44.7_@cloudflare_workers-types@4.20260313.1_@electric-sql_pg_c72c8c754becd21f6d6662e8fbd28e7f/node_modules/fumadb/dist/create-tg0451Y_.d.mts +285 -0
- package/dist/node_modules/.pnpm/fumadb@0.2.2_drizzle-orm@0.44.7_@cloudflare_workers-types@4.20260313.1_@electric-sql_pg_c72c8c754becd21f6d6662e8fbd28e7f/node_modules/fumadb/dist/index-CMqePMTF.d.cts +45 -0
- package/dist/node_modules/.pnpm/fumadb@0.2.2_drizzle-orm@0.44.7_@cloudflare_workers-types@4.20260313.1_@electric-sql_pg_c72c8c754becd21f6d6662e8fbd28e7f/node_modules/fumadb/dist/index-CMqePMTF.d.mts +45 -0
- package/dist/node_modules/.pnpm/fumadb@0.2.2_drizzle-orm@0.44.7_@cloudflare_workers-types@4.20260313.1_@electric-sql_pg_c72c8c754becd21f6d6662e8fbd28e7f/node_modules/fumadb/dist/index.cjs +69 -0
- package/dist/node_modules/.pnpm/fumadb@0.2.2_drizzle-orm@0.44.7_@cloudflare_workers-types@4.20260313.1_@electric-sql_pg_c72c8c754becd21f6d6662e8fbd28e7f/node_modules/fumadb/dist/index.d.cts +49 -0
- package/dist/node_modules/.pnpm/fumadb@0.2.2_drizzle-orm@0.44.7_@cloudflare_workers-types@4.20260313.1_@electric-sql_pg_c72c8c754becd21f6d6662e8fbd28e7f/node_modules/fumadb/dist/index.d.mts +49 -0
- package/dist/node_modules/.pnpm/fumadb@0.2.2_drizzle-orm@0.44.7_@cloudflare_workers-types@4.20260313.1_@electric-sql_pg_c72c8c754becd21f6d6662e8fbd28e7f/node_modules/fumadb/dist/index.mjs +67 -0
- package/dist/node_modules/.pnpm/fumadb@0.2.2_drizzle-orm@0.44.7_@cloudflare_workers-types@4.20260313.1_@electric-sql_pg_c72c8c754becd21f6d6662e8fbd28e7f/node_modules/fumadb/dist/query/index.d.cts +156 -0
- package/dist/node_modules/.pnpm/fumadb@0.2.2_drizzle-orm@0.44.7_@cloudflare_workers-types@4.20260313.1_@electric-sql_pg_c72c8c754becd21f6d6662e8fbd28e7f/node_modules/fumadb/dist/query/index.d.mts +156 -0
- package/dist/node_modules/.pnpm/fumadb@0.2.2_drizzle-orm@0.44.7_@cloudflare_workers-types@4.20260313.1_@electric-sql_pg_c72c8c754becd21f6d6662e8fbd28e7f/node_modules/fumadb/dist/schema/index.cjs +1 -0
- package/dist/node_modules/.pnpm/fumadb@0.2.2_drizzle-orm@0.44.7_@cloudflare_workers-types@4.20260313.1_@electric-sql_pg_c72c8c754becd21f6d6662e8fbd28e7f/node_modules/fumadb/dist/schema/index.mjs +2 -0
- package/dist/{package.cjs → packages/server/package.cjs} +1 -1
- package/dist/{package.mjs → packages/server/package.mjs} +1 -1
- package/dist/runtime.cjs +13 -13
- package/dist/runtime.d.cts +4 -4
- package/dist/runtime.d.mts +4 -4
- package/dist/runtime.mjs +12 -13
- package/dist/schema/v0_21_0.cjs +16 -15
- package/dist/schema/v0_21_0.mjs +3 -2
- package/dist/schema/v0_29_0.cjs +18 -17
- package/dist/schema/v0_29_0.mjs +3 -2
- package/dist/schema/v0_31_0.cjs +48 -0
- package/dist/schema/v0_31_0.mjs +48 -0
- package/dist/storageAccess.cjs +44 -0
- package/dist/storageAccess.mjs +44 -0
- package/dist/version.cjs +1 -1
- package/dist/version.mjs +1 -1
- package/package.json +15 -7
- package/src/adapters/drizzle.ts +15 -1
- package/src/adapters/kysely.ts +24 -1
- package/src/adapters/mongodb.ts +19 -1
- package/src/adapters/prisma.ts +15 -1
- package/src/db/createBundleDiff.spec.ts +402 -0
- package/src/db/createBundleDiff.ts +375 -0
- package/src/db/index.spec.ts +528 -27
- package/src/db/index.ts +22 -36
- package/src/db/ormCore.ts +308 -75
- package/src/db/pluginCore.spec.ts +385 -0
- package/src/db/pluginCore.ts +45 -4
- package/src/db/schemaEnhancements.ts +460 -0
- package/src/db/types.ts +38 -7
- package/src/db/updateArtifacts.ts +388 -0
- package/src/handler-standalone.integration.spec.ts +1 -0
- package/src/handler.spec.ts +121 -0
- package/src/handler.ts +117 -5
- package/src/runtime.spec.ts +287 -55
- package/src/runtime.ts +21 -37
- package/src/schema/v0_21_0.ts +1 -1
- package/src/schema/v0_29_0.ts +1 -1
- package/src/schema/v0_31_0.ts +58 -0
- package/src/storageAccess.spec.ts +57 -0
- package/src/storageAccess.ts +90 -0
package/src/handler.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type {
|
|
2
|
+
AppUpdateAvailableInfo,
|
|
2
3
|
AppUpdateInfo,
|
|
3
4
|
AppVersionGetBundlesArgs,
|
|
4
5
|
Bundle,
|
|
@@ -9,6 +10,7 @@ import type {
|
|
|
9
10
|
DatabaseBundleQueryOptions,
|
|
10
11
|
HotUpdaterContext,
|
|
11
12
|
} from "@hot-updater/plugin-core";
|
|
13
|
+
import semver from "semver";
|
|
12
14
|
|
|
13
15
|
import { addRoute, createRouter, findRoute } from "./internalRouter";
|
|
14
16
|
import type { ChannelsResponse, PaginatedResult } from "./types";
|
|
@@ -19,7 +21,7 @@ export interface HandlerAPI<TContext = unknown> {
|
|
|
19
21
|
getAppUpdateInfo: (
|
|
20
22
|
args: AppVersionGetBundlesArgs | FingerprintGetBundlesArgs,
|
|
21
23
|
context?: HotUpdaterContext<TContext>,
|
|
22
|
-
) => Promise<
|
|
24
|
+
) => Promise<AppUpdateAvailableInfo | null>;
|
|
23
25
|
getBundleById: (
|
|
24
26
|
id: string,
|
|
25
27
|
context?: HotUpdaterContext<TContext>,
|
|
@@ -88,6 +90,37 @@ class HandlerBadRequestError extends Error {
|
|
|
88
90
|
}
|
|
89
91
|
}
|
|
90
92
|
|
|
93
|
+
const SDK_VERSION_HEADER = "Hot-Updater-SDK-Version";
|
|
94
|
+
const EXPLICIT_NO_UPDATE_MIN_SDK_VERSION = "0.31.0";
|
|
95
|
+
|
|
96
|
+
const supportsExplicitNoUpdateResponse = (request: Request) => {
|
|
97
|
+
const sdkVersion = request.headers.get(SDK_VERSION_HEADER)?.trim();
|
|
98
|
+
if (!sdkVersion) {
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const normalizedSdkVersion = semver.valid(sdkVersion);
|
|
103
|
+
return (
|
|
104
|
+
normalizedSdkVersion !== null &&
|
|
105
|
+
semver.gte(normalizedSdkVersion, EXPLICIT_NO_UPDATE_MIN_SDK_VERSION)
|
|
106
|
+
);
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
const serializeUpdateInfo = (
|
|
110
|
+
updateInfo: AppUpdateAvailableInfo | null,
|
|
111
|
+
request: Request,
|
|
112
|
+
): string => {
|
|
113
|
+
if (updateInfo) {
|
|
114
|
+
return JSON.stringify(updateInfo satisfies AppUpdateInfo);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (supportsExplicitNoUpdateResponse(request)) {
|
|
118
|
+
return JSON.stringify({ status: "UP_TO_DATE" } satisfies AppUpdateInfo);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return JSON.stringify(null);
|
|
122
|
+
};
|
|
123
|
+
|
|
91
124
|
// Route handlers
|
|
92
125
|
const handleVersion: RouteHandler = async () => {
|
|
93
126
|
return new Response(JSON.stringify({ version: HOT_UPDATER_SERVER_VERSION }), {
|
|
@@ -121,6 +154,43 @@ const requireRouteParam = (
|
|
|
121
154
|
return value;
|
|
122
155
|
};
|
|
123
156
|
|
|
157
|
+
const parseBooleanSearchParam = (
|
|
158
|
+
url: URL,
|
|
159
|
+
key: string,
|
|
160
|
+
): boolean | undefined => {
|
|
161
|
+
const value = url.searchParams.get(key);
|
|
162
|
+
if (value === null) {
|
|
163
|
+
return undefined;
|
|
164
|
+
}
|
|
165
|
+
if (value === "true") {
|
|
166
|
+
return true;
|
|
167
|
+
}
|
|
168
|
+
if (value === "false") {
|
|
169
|
+
return false;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
throw new HandlerBadRequestError(
|
|
173
|
+
`The '${key}' query parameter must be 'true' or 'false'.`,
|
|
174
|
+
);
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
const parseNullableStringSearchParam = (
|
|
178
|
+
url: URL,
|
|
179
|
+
key: string,
|
|
180
|
+
): string | null | undefined => {
|
|
181
|
+
const value = url.searchParams.get(key);
|
|
182
|
+
if (value === null) {
|
|
183
|
+
return undefined;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
return value === "null" ? null : value;
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
const parseStringArraySearchParam = (url: URL, key: string) => {
|
|
190
|
+
const values = url.searchParams.getAll(key);
|
|
191
|
+
return values.length > 0 ? values : undefined;
|
|
192
|
+
};
|
|
193
|
+
|
|
124
194
|
const requirePlatformParam = (params: Record<string, string>): Platform => {
|
|
125
195
|
const platform = requireRouteParam(params, "platform");
|
|
126
196
|
|
|
@@ -156,7 +226,7 @@ const requireBundlePatchPayload = (
|
|
|
156
226
|
|
|
157
227
|
const handleFingerprintUpdateWithCohort: RouteHandler = async (
|
|
158
228
|
params,
|
|
159
|
-
|
|
229
|
+
request,
|
|
160
230
|
api,
|
|
161
231
|
context,
|
|
162
232
|
) => {
|
|
@@ -179,7 +249,7 @@ const handleFingerprintUpdateWithCohort: RouteHandler = async (
|
|
|
179
249
|
context,
|
|
180
250
|
);
|
|
181
251
|
|
|
182
|
-
return new Response(
|
|
252
|
+
return new Response(serializeUpdateInfo(updateInfo, request), {
|
|
183
253
|
status: 200,
|
|
184
254
|
headers: { "Content-Type": "application/json" },
|
|
185
255
|
});
|
|
@@ -187,7 +257,7 @@ const handleFingerprintUpdateWithCohort: RouteHandler = async (
|
|
|
187
257
|
|
|
188
258
|
const handleAppVersionUpdateWithCohort: RouteHandler = async (
|
|
189
259
|
params,
|
|
190
|
-
|
|
260
|
+
request,
|
|
191
261
|
api,
|
|
192
262
|
context,
|
|
193
263
|
) => {
|
|
@@ -210,7 +280,7 @@ const handleAppVersionUpdateWithCohort: RouteHandler = async (
|
|
|
210
280
|
context,
|
|
211
281
|
);
|
|
212
282
|
|
|
213
|
-
return new Response(
|
|
283
|
+
return new Response(serializeUpdateInfo(updateInfo, request), {
|
|
214
284
|
status: 200,
|
|
215
285
|
headers: { "Content-Type": "application/json" },
|
|
216
286
|
});
|
|
@@ -252,6 +322,29 @@ const handleGetBundles: RouteHandler = async (
|
|
|
252
322
|
const offset = url.searchParams.get("offset");
|
|
253
323
|
const after = url.searchParams.get("after") ?? undefined;
|
|
254
324
|
const before = url.searchParams.get("before") ?? undefined;
|
|
325
|
+
const enabled = parseBooleanSearchParam(url, "enabled");
|
|
326
|
+
const targetAppVersion = parseNullableStringSearchParam(
|
|
327
|
+
url,
|
|
328
|
+
"targetAppVersion",
|
|
329
|
+
);
|
|
330
|
+
const targetAppVersionIn = parseStringArraySearchParam(
|
|
331
|
+
url,
|
|
332
|
+
"targetAppVersionIn",
|
|
333
|
+
);
|
|
334
|
+
const targetAppVersionNotNull = parseBooleanSearchParam(
|
|
335
|
+
url,
|
|
336
|
+
"targetAppVersionNotNull",
|
|
337
|
+
);
|
|
338
|
+
const fingerprintHash = parseNullableStringSearchParam(
|
|
339
|
+
url,
|
|
340
|
+
"fingerprintHash",
|
|
341
|
+
);
|
|
342
|
+
const idEq = url.searchParams.get("idEq") ?? undefined;
|
|
343
|
+
const idGt = url.searchParams.get("idGt") ?? undefined;
|
|
344
|
+
const idGte = url.searchParams.get("idGte") ?? undefined;
|
|
345
|
+
const idLt = url.searchParams.get("idLt") ?? undefined;
|
|
346
|
+
const idLte = url.searchParams.get("idLte") ?? undefined;
|
|
347
|
+
const idIn = parseStringArraySearchParam(url, "idIn");
|
|
255
348
|
const page =
|
|
256
349
|
pageParam === null
|
|
257
350
|
? undefined
|
|
@@ -282,6 +375,25 @@ const handleGetBundles: RouteHandler = async (
|
|
|
282
375
|
where: {
|
|
283
376
|
...(channel && { channel }),
|
|
284
377
|
...(platform && { platform }),
|
|
378
|
+
...(enabled !== undefined && { enabled }),
|
|
379
|
+
...(idEq || idGt || idGte || idLt || idLte || (idIn && idIn.length > 0)
|
|
380
|
+
? {
|
|
381
|
+
id: {
|
|
382
|
+
...(idEq && { eq: idEq }),
|
|
383
|
+
...(idGt && { gt: idGt }),
|
|
384
|
+
...(idGte && { gte: idGte }),
|
|
385
|
+
...(idLt && { lt: idLt }),
|
|
386
|
+
...(idLte && { lte: idLte }),
|
|
387
|
+
...(idIn && idIn.length > 0 && { in: idIn }),
|
|
388
|
+
},
|
|
389
|
+
}
|
|
390
|
+
: {}),
|
|
391
|
+
...(targetAppVersion !== undefined && { targetAppVersion }),
|
|
392
|
+
...(targetAppVersionIn && { targetAppVersionIn }),
|
|
393
|
+
...(targetAppVersionNotNull !== undefined && {
|
|
394
|
+
targetAppVersionNotNull,
|
|
395
|
+
}),
|
|
396
|
+
...(fingerprintHash !== undefined && { fingerprintHash }),
|
|
285
397
|
},
|
|
286
398
|
limit,
|
|
287
399
|
page,
|
package/src/runtime.spec.ts
CHANGED
|
@@ -3,7 +3,8 @@ import { NIL_UUID } from "@hot-updater/core";
|
|
|
3
3
|
import type {
|
|
4
4
|
DatabasePlugin,
|
|
5
5
|
RequestEnvContext,
|
|
6
|
-
|
|
6
|
+
RuntimeStoragePlugin,
|
|
7
|
+
RuntimeStorageProfile,
|
|
7
8
|
} from "@hot-updater/plugin-core";
|
|
8
9
|
import { createDatabasePlugin } from "@hot-updater/plugin-core";
|
|
9
10
|
import { describe, expect, expectTypeOf, it, vi } from "vitest";
|
|
@@ -31,7 +32,71 @@ type TestEnv = {
|
|
|
31
32
|
|
|
32
33
|
type TestContext = RequestEnvContext<TestEnv>;
|
|
33
34
|
|
|
35
|
+
const createRuntimeStorage = (
|
|
36
|
+
getDownloadUrl: RuntimeStorageProfile<TestContext>["getDownloadUrl"],
|
|
37
|
+
readText: RuntimeStorageProfile<TestContext>["readText"] = async () => null,
|
|
38
|
+
): RuntimeStoragePlugin<TestContext> => ({
|
|
39
|
+
name: "testStorage",
|
|
40
|
+
supportedProtocol: "s3",
|
|
41
|
+
profiles: {
|
|
42
|
+
runtime: {
|
|
43
|
+
getDownloadUrl,
|
|
44
|
+
readText,
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
});
|
|
48
|
+
|
|
34
49
|
describe("runtime createHotUpdater", () => {
|
|
50
|
+
it("requires storages to implement the runtime profile", () => {
|
|
51
|
+
const database: DatabasePlugin<TestContext> = {
|
|
52
|
+
name: "testDatabase",
|
|
53
|
+
async appendBundle() {},
|
|
54
|
+
async commitBundle() {},
|
|
55
|
+
async deleteBundle() {},
|
|
56
|
+
async getBundleById() {
|
|
57
|
+
return null;
|
|
58
|
+
},
|
|
59
|
+
async getBundles() {
|
|
60
|
+
return {
|
|
61
|
+
data: [],
|
|
62
|
+
pagination: {
|
|
63
|
+
currentPage: 1,
|
|
64
|
+
hasNextPage: false,
|
|
65
|
+
hasPreviousPage: false,
|
|
66
|
+
total: 0,
|
|
67
|
+
totalPages: 0,
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
},
|
|
71
|
+
async getChannels() {
|
|
72
|
+
return [];
|
|
73
|
+
},
|
|
74
|
+
async updateBundle() {},
|
|
75
|
+
};
|
|
76
|
+
const nodeOnlyStorage = {
|
|
77
|
+
name: "nodeOnlyStorage",
|
|
78
|
+
supportedProtocol: "s3",
|
|
79
|
+
profiles: {
|
|
80
|
+
node: {
|
|
81
|
+
delete: vi.fn(),
|
|
82
|
+
downloadFile: vi.fn(),
|
|
83
|
+
upload: vi.fn(),
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
expect(() =>
|
|
89
|
+
createHotUpdater({
|
|
90
|
+
database,
|
|
91
|
+
storages: [
|
|
92
|
+
nodeOnlyStorage as unknown as RuntimeStoragePlugin<TestContext>,
|
|
93
|
+
],
|
|
94
|
+
}),
|
|
95
|
+
).toThrow(
|
|
96
|
+
'nodeOnlyStorage does not implement the runtime storage profile for protocol "s3".',
|
|
97
|
+
);
|
|
98
|
+
});
|
|
99
|
+
|
|
35
100
|
it("resolves storage URLs with handler context when database fast-path is used", async () => {
|
|
36
101
|
const request = new Request(
|
|
37
102
|
"https://updates.example.com/api/check-update/app-version/ios/1.0.0/production/" +
|
|
@@ -48,13 +113,13 @@ describe("runtime createHotUpdater", () => {
|
|
|
48
113
|
status: "UPDATE",
|
|
49
114
|
storageUri: bundle.storageUri,
|
|
50
115
|
}));
|
|
51
|
-
const getDownloadUrl = vi.fn<
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
}
|
|
57
|
-
);
|
|
116
|
+
const getDownloadUrl = vi.fn<
|
|
117
|
+
RuntimeStorageProfile<TestContext>["getDownloadUrl"]
|
|
118
|
+
>(async (_storageUri, context) => {
|
|
119
|
+
return {
|
|
120
|
+
fileUrl: new URL("/bundle.zip", context?.env?.assetHost).toString(),
|
|
121
|
+
};
|
|
122
|
+
});
|
|
58
123
|
|
|
59
124
|
const database: DatabasePlugin<TestContext> = {
|
|
60
125
|
name: "testDatabase",
|
|
@@ -72,15 +137,7 @@ describe("runtime createHotUpdater", () => {
|
|
|
72
137
|
async onUnmount() {},
|
|
73
138
|
async updateBundle() {},
|
|
74
139
|
};
|
|
75
|
-
const storage
|
|
76
|
-
name: "testStorage",
|
|
77
|
-
supportedProtocol: "s3",
|
|
78
|
-
async upload(key) {
|
|
79
|
-
return { storageUri: `s3://test-bucket/${key}` };
|
|
80
|
-
},
|
|
81
|
-
async delete() {},
|
|
82
|
-
getDownloadUrl,
|
|
83
|
-
};
|
|
140
|
+
const storage = createRuntimeStorage(getDownloadUrl);
|
|
84
141
|
|
|
85
142
|
const hotUpdater = createHotUpdater({
|
|
86
143
|
database,
|
|
@@ -156,13 +213,13 @@ describe("runtime createHotUpdater", () => {
|
|
|
156
213
|
};
|
|
157
214
|
},
|
|
158
215
|
);
|
|
159
|
-
const getDownloadUrl = vi.fn<
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
}
|
|
165
|
-
);
|
|
216
|
+
const getDownloadUrl = vi.fn<
|
|
217
|
+
RuntimeStorageProfile<TestContext>["getDownloadUrl"]
|
|
218
|
+
>(async (_storageUri, context) => {
|
|
219
|
+
return {
|
|
220
|
+
fileUrl: new URL("/bundle.zip", context?.env?.assetHost).toString(),
|
|
221
|
+
};
|
|
222
|
+
});
|
|
166
223
|
|
|
167
224
|
const database: DatabasePlugin<TestContext> = {
|
|
168
225
|
name: "testDatabase",
|
|
@@ -179,15 +236,7 @@ describe("runtime createHotUpdater", () => {
|
|
|
179
236
|
async onUnmount() {},
|
|
180
237
|
async updateBundle() {},
|
|
181
238
|
};
|
|
182
|
-
const storage
|
|
183
|
-
name: "testStorage",
|
|
184
|
-
supportedProtocol: "s3",
|
|
185
|
-
async upload(key) {
|
|
186
|
-
return { storageUri: `s3://test-bucket/${key}` };
|
|
187
|
-
},
|
|
188
|
-
async delete() {},
|
|
189
|
-
getDownloadUrl,
|
|
190
|
-
};
|
|
239
|
+
const storage = createRuntimeStorage(getDownloadUrl);
|
|
191
240
|
|
|
192
241
|
const hotUpdater = createHotUpdater({
|
|
193
242
|
database,
|
|
@@ -239,6 +288,205 @@ describe("runtime createHotUpdater", () => {
|
|
|
239
288
|
);
|
|
240
289
|
});
|
|
241
290
|
|
|
291
|
+
it("returns bsdiff patch metadata when the full asset fallback URL is unavailable", async () => {
|
|
292
|
+
const currentManifestStorageUri =
|
|
293
|
+
"s3://test-bucket/releases/00000000-0000-0000-0000-000000000001/manifest.json";
|
|
294
|
+
const nextManifestStorageUri =
|
|
295
|
+
"s3://test-bucket/releases/00000000-0000-0000-0000-000000000002/manifest.json";
|
|
296
|
+
const currentBundle: Bundle = {
|
|
297
|
+
...bundle,
|
|
298
|
+
id: "00000000-0000-0000-0000-000000000001",
|
|
299
|
+
assetBaseStorageUri:
|
|
300
|
+
"s3://test-bucket/releases/00000000-0000-0000-0000-000000000001/files",
|
|
301
|
+
manifestFileHash: "sig:current-manifest",
|
|
302
|
+
manifestStorageUri: currentManifestStorageUri,
|
|
303
|
+
storageUri:
|
|
304
|
+
"s3://test-bucket/releases/00000000-0000-0000-0000-000000000001/bundle.zip",
|
|
305
|
+
};
|
|
306
|
+
const nextBundle: Bundle = {
|
|
307
|
+
...bundle,
|
|
308
|
+
id: "00000000-0000-0000-0000-000000000002",
|
|
309
|
+
assetBaseStorageUri:
|
|
310
|
+
"s3://test-bucket/releases/00000000-0000-0000-0000-000000000002/files",
|
|
311
|
+
manifestFileHash: "sig:next-manifest",
|
|
312
|
+
manifestStorageUri: nextManifestStorageUri,
|
|
313
|
+
patches: [
|
|
314
|
+
{
|
|
315
|
+
baseBundleId: currentBundle.id,
|
|
316
|
+
baseFileHash: "hash-old-bundle",
|
|
317
|
+
patchFileHash: "hash-bsdiff",
|
|
318
|
+
patchStorageUri:
|
|
319
|
+
"s3://test-bucket/releases/00000000-0000-0000-0000-000000000002/patches/00000000-0000-0000-0000-000000000001/index.ios.bundle.bsdiff",
|
|
320
|
+
},
|
|
321
|
+
],
|
|
322
|
+
storageUri:
|
|
323
|
+
"s3://test-bucket/releases/00000000-0000-0000-0000-000000000002/bundle.zip",
|
|
324
|
+
};
|
|
325
|
+
const request = new Request(
|
|
326
|
+
"https://updates.example.com/api/check-update/app-version/ios/1.0.0/production/" +
|
|
327
|
+
`${NIL_UUID}/${currentBundle.id}`,
|
|
328
|
+
);
|
|
329
|
+
const getBundles = vi.fn<DatabasePlugin<TestContext>["getBundles"]>(
|
|
330
|
+
async () => ({
|
|
331
|
+
data: [nextBundle],
|
|
332
|
+
pagination: {
|
|
333
|
+
hasNextPage: false,
|
|
334
|
+
hasPreviousPage: false,
|
|
335
|
+
currentPage: 1,
|
|
336
|
+
totalPages: 1,
|
|
337
|
+
total: 1,
|
|
338
|
+
},
|
|
339
|
+
}),
|
|
340
|
+
);
|
|
341
|
+
const getDownloadUrl = vi.fn<
|
|
342
|
+
RuntimeStorageProfile<TestContext>["getDownloadUrl"]
|
|
343
|
+
>(async (storageUri, context) => {
|
|
344
|
+
if (storageUri.endsWith("/files/index.ios.bundle")) {
|
|
345
|
+
throw new Error("full asset fallback is unavailable");
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
const storageUrl = new URL(storageUri);
|
|
349
|
+
return {
|
|
350
|
+
fileUrl: new URL(
|
|
351
|
+
storageUrl.pathname,
|
|
352
|
+
context?.env?.assetHost,
|
|
353
|
+
).toString(),
|
|
354
|
+
};
|
|
355
|
+
});
|
|
356
|
+
const manifests = new Map([
|
|
357
|
+
[
|
|
358
|
+
currentManifestStorageUri,
|
|
359
|
+
JSON.stringify({
|
|
360
|
+
assets: {
|
|
361
|
+
"assets/logo.png": {
|
|
362
|
+
fileHash: "hash-logo",
|
|
363
|
+
},
|
|
364
|
+
"index.ios.bundle": {
|
|
365
|
+
fileHash: "hash-old-bundle",
|
|
366
|
+
},
|
|
367
|
+
},
|
|
368
|
+
bundleId: currentBundle.id,
|
|
369
|
+
}),
|
|
370
|
+
],
|
|
371
|
+
[
|
|
372
|
+
nextManifestStorageUri,
|
|
373
|
+
JSON.stringify({
|
|
374
|
+
assets: {
|
|
375
|
+
"assets/logo.png": {
|
|
376
|
+
fileHash: "hash-logo",
|
|
377
|
+
},
|
|
378
|
+
"index.ios.bundle": {
|
|
379
|
+
fileHash: "hash-new-bundle",
|
|
380
|
+
},
|
|
381
|
+
},
|
|
382
|
+
bundleId: nextBundle.id,
|
|
383
|
+
}),
|
|
384
|
+
],
|
|
385
|
+
]);
|
|
386
|
+
const readText = vi.fn<RuntimeStorageProfile<TestContext>["readText"]>(
|
|
387
|
+
async (storageUri) => manifests.get(storageUri) ?? null,
|
|
388
|
+
);
|
|
389
|
+
const fetchMock = vi.fn<typeof fetch>(async () => {
|
|
390
|
+
return new Response("manifest fetch should not be used", {
|
|
391
|
+
status: 500,
|
|
392
|
+
});
|
|
393
|
+
});
|
|
394
|
+
vi.stubGlobal("fetch", fetchMock);
|
|
395
|
+
|
|
396
|
+
const database: DatabasePlugin<TestContext> = {
|
|
397
|
+
name: "testDatabase",
|
|
398
|
+
async appendBundle() {},
|
|
399
|
+
async commitBundle() {},
|
|
400
|
+
async deleteBundle() {},
|
|
401
|
+
async getBundleById(id) {
|
|
402
|
+
if (id === currentBundle.id) {
|
|
403
|
+
return currentBundle;
|
|
404
|
+
}
|
|
405
|
+
if (id === nextBundle.id) {
|
|
406
|
+
return nextBundle;
|
|
407
|
+
}
|
|
408
|
+
return null;
|
|
409
|
+
},
|
|
410
|
+
getBundles,
|
|
411
|
+
async getChannels() {
|
|
412
|
+
return ["production"];
|
|
413
|
+
},
|
|
414
|
+
async onUnmount() {},
|
|
415
|
+
async updateBundle() {},
|
|
416
|
+
};
|
|
417
|
+
const storage = createRuntimeStorage(getDownloadUrl, readText);
|
|
418
|
+
|
|
419
|
+
try {
|
|
420
|
+
const hotUpdater = createHotUpdater({
|
|
421
|
+
database,
|
|
422
|
+
storages: [storage],
|
|
423
|
+
basePath: "/api/check-update",
|
|
424
|
+
routes: {
|
|
425
|
+
updateCheck: true,
|
|
426
|
+
bundles: false,
|
|
427
|
+
},
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
const response = await hotUpdater.handler(request, {
|
|
431
|
+
env: {
|
|
432
|
+
assetHost: "https://assets.example.com",
|
|
433
|
+
},
|
|
434
|
+
request,
|
|
435
|
+
});
|
|
436
|
+
|
|
437
|
+
await expect(response.json()).resolves.toEqual({
|
|
438
|
+
changedAssets: {
|
|
439
|
+
"index.ios.bundle": {
|
|
440
|
+
file: {
|
|
441
|
+
compression: "br",
|
|
442
|
+
url: "https://assets.example.com/releases/00000000-0000-0000-0000-000000000002/files/index.ios.bundle.br",
|
|
443
|
+
},
|
|
444
|
+
fileHash: "hash-new-bundle",
|
|
445
|
+
patch: {
|
|
446
|
+
algorithm: "bsdiff",
|
|
447
|
+
baseBundleId: "00000000-0000-0000-0000-000000000001",
|
|
448
|
+
baseFileHash: "hash-old-bundle",
|
|
449
|
+
patchFileHash: "hash-bsdiff",
|
|
450
|
+
patchUrl:
|
|
451
|
+
"https://assets.example.com/releases/00000000-0000-0000-0000-000000000002/patches/00000000-0000-0000-0000-000000000001/index.ios.bundle.bsdiff",
|
|
452
|
+
},
|
|
453
|
+
},
|
|
454
|
+
},
|
|
455
|
+
fileHash: "hash123",
|
|
456
|
+
fileUrl:
|
|
457
|
+
"https://assets.example.com/releases/00000000-0000-0000-0000-000000000002/bundle.zip",
|
|
458
|
+
id: "00000000-0000-0000-0000-000000000002",
|
|
459
|
+
manifestFileHash: "sig:next-manifest",
|
|
460
|
+
manifestUrl:
|
|
461
|
+
"https://assets.example.com/releases/00000000-0000-0000-0000-000000000002/manifest.json",
|
|
462
|
+
message: "Test bundle",
|
|
463
|
+
shouldForceUpdate: false,
|
|
464
|
+
status: "UPDATE",
|
|
465
|
+
});
|
|
466
|
+
expect(readText).toHaveBeenCalledWith(
|
|
467
|
+
nextManifestStorageUri,
|
|
468
|
+
expect.objectContaining({
|
|
469
|
+
env: {
|
|
470
|
+
assetHost: "https://assets.example.com",
|
|
471
|
+
},
|
|
472
|
+
request: expect.any(Request),
|
|
473
|
+
}),
|
|
474
|
+
);
|
|
475
|
+
expect(readText).toHaveBeenCalledWith(
|
|
476
|
+
currentManifestStorageUri,
|
|
477
|
+
expect.objectContaining({
|
|
478
|
+
env: {
|
|
479
|
+
assetHost: "https://assets.example.com",
|
|
480
|
+
},
|
|
481
|
+
request: expect.any(Request),
|
|
482
|
+
}),
|
|
483
|
+
);
|
|
484
|
+
expect(fetchMock).not.toHaveBeenCalled();
|
|
485
|
+
} finally {
|
|
486
|
+
vi.unstubAllGlobals();
|
|
487
|
+
}
|
|
488
|
+
});
|
|
489
|
+
|
|
242
490
|
it("does not inject the request into context unless explicitly provided", async () => {
|
|
243
491
|
const getBundles = vi.fn<DatabasePlugin<TestContext>["getBundles"]>(
|
|
244
492
|
async () => {
|
|
@@ -270,17 +518,9 @@ describe("runtime createHotUpdater", () => {
|
|
|
270
518
|
async onUnmount() {},
|
|
271
519
|
async updateBundle() {},
|
|
272
520
|
};
|
|
273
|
-
const storage
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
async upload(key) {
|
|
277
|
-
return { storageUri: `s3://test-bucket/${key}` };
|
|
278
|
-
},
|
|
279
|
-
async delete() {},
|
|
280
|
-
async getDownloadUrl() {
|
|
281
|
-
return { fileUrl: "https://assets.example.com/bundle.zip" };
|
|
282
|
-
},
|
|
283
|
-
};
|
|
521
|
+
const storage = createRuntimeStorage(async () => {
|
|
522
|
+
return { fileUrl: "https://assets.example.com/bundle.zip" };
|
|
523
|
+
});
|
|
284
524
|
|
|
285
525
|
const hotUpdater = createHotUpdater({
|
|
286
526
|
database,
|
|
@@ -343,17 +583,9 @@ describe("runtime createHotUpdater", () => {
|
|
|
343
583
|
async onUnmount() {},
|
|
344
584
|
async updateBundle() {},
|
|
345
585
|
};
|
|
346
|
-
const storage
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
async upload(key) {
|
|
350
|
-
return { storageUri: `s3://test-bucket/${key}` };
|
|
351
|
-
},
|
|
352
|
-
async delete() {},
|
|
353
|
-
async getDownloadUrl() {
|
|
354
|
-
return { fileUrl: "https://assets.example.com/bundle.zip" };
|
|
355
|
-
},
|
|
356
|
-
};
|
|
586
|
+
const storage = createRuntimeStorage(async () => {
|
|
587
|
+
return { fileUrl: "https://assets.example.com/bundle.zip" };
|
|
588
|
+
});
|
|
357
589
|
|
|
358
590
|
const hotUpdater = createHotUpdater({
|
|
359
591
|
database,
|
package/src/runtime.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
HotUpdaterContext,
|
|
3
|
-
|
|
3
|
+
RuntimeStoragePlugin,
|
|
4
4
|
} from "@hot-updater/plugin-core";
|
|
5
|
+
import { assertRuntimeStoragePlugin } from "@hot-updater/plugin-core";
|
|
5
6
|
|
|
6
7
|
import { createPluginDatabaseCore } from "./db/pluginCore";
|
|
7
8
|
import {
|
|
@@ -13,6 +14,7 @@ import {
|
|
|
13
14
|
} from "./db/types";
|
|
14
15
|
import { createHandler, type HandlerRoutes } from "./handler";
|
|
15
16
|
import { normalizeBasePath } from "./route";
|
|
17
|
+
import { createStorageAccess } from "./storageAccess";
|
|
16
18
|
|
|
17
19
|
export type HotUpdaterAPI<TContext = unknown> = DatabaseAPI<TContext> & {
|
|
18
20
|
basePath: string;
|
|
@@ -25,8 +27,14 @@ export type HotUpdaterAPI<TContext = unknown> = DatabaseAPI<TContext> & {
|
|
|
25
27
|
|
|
26
28
|
export interface CreateHotUpdaterOptions<TContext = unknown> {
|
|
27
29
|
database: DatabaseAdapter<TContext>;
|
|
28
|
-
storages?: (
|
|
29
|
-
|
|
30
|
+
storages?: (
|
|
31
|
+
| RuntimeStoragePlugin<TContext>
|
|
32
|
+
| StoragePluginFactory<TContext>
|
|
33
|
+
)[];
|
|
34
|
+
storagePlugins?: (
|
|
35
|
+
| RuntimeStoragePlugin<TContext>
|
|
36
|
+
| StoragePluginFactory<TContext>
|
|
37
|
+
)[];
|
|
30
38
|
basePath?: string;
|
|
31
39
|
cwd?: string;
|
|
32
40
|
routes?: HandlerRoutes;
|
|
@@ -38,39 +46,14 @@ export function createHotUpdater<TContext = unknown>(
|
|
|
38
46
|
const database = options.database;
|
|
39
47
|
const basePath = normalizeBasePath(options.basePath ?? "/api");
|
|
40
48
|
const storagePlugins = (options.storages ?? options.storagePlugins ?? []).map(
|
|
41
|
-
(plugin) =>
|
|
49
|
+
(plugin) => {
|
|
50
|
+
const storagePlugin = typeof plugin === "function" ? plugin() : plugin;
|
|
51
|
+
assertRuntimeStoragePlugin(storagePlugin);
|
|
52
|
+
return storagePlugin;
|
|
53
|
+
},
|
|
42
54
|
);
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
storageUri: string | null,
|
|
46
|
-
context?: HotUpdaterContext<TContext>,
|
|
47
|
-
): Promise<string | null> => {
|
|
48
|
-
if (!storageUri) {
|
|
49
|
-
return null;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
const url = new URL(storageUri);
|
|
53
|
-
const protocol = url.protocol.replace(":", "");
|
|
54
|
-
|
|
55
|
-
if (protocol === "http" || protocol === "https") {
|
|
56
|
-
return storageUri;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
const plugin = storagePlugins.find(
|
|
60
|
-
(item) => item.supportedProtocol === protocol,
|
|
61
|
-
);
|
|
62
|
-
|
|
63
|
-
if (!plugin) {
|
|
64
|
-
throw new Error(`No storage plugin for protocol: ${protocol}`);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
const { fileUrl } = await plugin.getDownloadUrl(storageUri, context);
|
|
68
|
-
if (!fileUrl) {
|
|
69
|
-
throw new Error("Storage plugin returned empty fileUrl");
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
return fileUrl;
|
|
73
|
-
};
|
|
55
|
+
const { readStorageText, resolveFileUrl } =
|
|
56
|
+
createStorageAccess(storagePlugins);
|
|
74
57
|
|
|
75
58
|
if (!isDatabasePluginFactory(database) && !isDatabasePlugin(database)) {
|
|
76
59
|
throw new Error(
|
|
@@ -81,12 +64,13 @@ export function createHotUpdater<TContext = unknown>(
|
|
|
81
64
|
const plugin = isDatabasePluginFactory(database) ? database() : database;
|
|
82
65
|
const core = createPluginDatabaseCore<TContext>(
|
|
83
66
|
() => plugin,
|
|
84
|
-
|
|
67
|
+
resolveFileUrl,
|
|
85
68
|
isDatabasePluginFactory(database)
|
|
86
69
|
? {
|
|
87
70
|
createMutationPlugin: () => database(),
|
|
71
|
+
readStorageText,
|
|
88
72
|
}
|
|
89
|
-
:
|
|
73
|
+
: { readStorageText },
|
|
90
74
|
);
|
|
91
75
|
|
|
92
76
|
const api = {
|
package/src/schema/v0_21_0.ts
CHANGED
|
@@ -11,7 +11,7 @@ export const v0_21_0 = schema({
|
|
|
11
11
|
file_hash: column("file_hash", "string"),
|
|
12
12
|
git_commit_hash: column("git_commit_hash", "string").nullable(),
|
|
13
13
|
message: column("message", "string").nullable(),
|
|
14
|
-
channel: column("channel", "string"),
|
|
14
|
+
channel: column("channel", "string").defaultTo("production"),
|
|
15
15
|
storage_uri: column("storage_uri", "string"),
|
|
16
16
|
target_app_version: column("target_app_version", "string").nullable(),
|
|
17
17
|
fingerprint_hash: column("fingerprint_hash", "string").nullable(),
|