@hot-updater/server 1.0.0-rc.18 → 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/LICENSE +12 -14
- package/dist/adapters/drizzle.cjs +6 -8
- package/dist/adapters/drizzle.d.cts +2 -2
- package/dist/adapters/drizzle.d.mts +2 -2
- package/dist/adapters/drizzle.mjs +1 -3
- package/dist/adapters/drizzleExecutor.d.cts +1 -1
- package/dist/adapters/drizzleExecutor.d.mts +1 -1
- package/dist/adapters/kysely.cjs +4 -6
- package/dist/adapters/kysely.d.cts +3 -3
- package/dist/adapters/kysely.d.mts +3 -3
- package/dist/adapters/kysely.mjs +1 -3
- package/dist/adapters/kyselyExecutor.d.cts +1 -2
- package/dist/adapters/kyselyExecutor.d.mts +1 -2
- package/dist/adapters/mongodb.cjs +10 -21
- package/dist/adapters/mongodb.d.cts +1 -1
- package/dist/adapters/mongodb.d.mts +1 -1
- package/dist/adapters/mongodb.mjs +9 -20
- package/dist/adapters/mongodbAdapter.cjs +11 -11
- package/dist/adapters/mongodbAdapter.d.cts +1 -1
- package/dist/adapters/mongodbAdapter.d.mts +1 -1
- package/dist/adapters/mongodbAdapter.mjs +1 -1
- package/dist/adapters/prisma.cjs +7 -9
- package/dist/adapters/prisma.d.cts +1 -1
- package/dist/adapters/prisma.d.mts +1 -1
- package/dist/adapters/prisma.mjs +1 -3
- package/dist/adapters/prismaExecutor.cjs +2 -3
- package/dist/adapters/prismaExecutor.mjs +1 -2
- package/dist/adapters/sqlProviders.cjs +7 -2
- package/dist/adapters/sqlProviders.mjs +6 -1
- package/dist/assembly/assemblePlugins.cjs +26 -48
- package/dist/assembly/assemblePlugins.d.cts +2 -5
- package/dist/assembly/assemblePlugins.d.mts +2 -5
- package/dist/assembly/assemblePlugins.mjs +19 -45
- package/dist/assembly/clientPlugins.cjs +6 -4
- package/dist/assembly/clientPlugins.mjs +2 -0
- package/dist/assembly/configError.d.cts +1 -6
- package/dist/assembly/configError.d.mts +1 -6
- package/dist/assembly/configError.mjs +1 -6
- package/dist/core/api.cjs +0 -40
- package/dist/core/api.d.cts +5 -16
- package/dist/core/api.d.mts +5 -16
- package/dist/core/api.mjs +1 -37
- package/dist/core/baseCandidates.cjs +0 -43
- package/dist/core/baseCandidates.mjs +2 -43
- package/dist/core/operations.cjs +13 -12
- package/dist/core/operations.mjs +6 -5
- package/dist/core/reads.cjs +4 -4
- package/dist/core/reads.d.cts +2 -41
- package/dist/core/reads.d.mts +2 -41
- package/dist/core/reads.mjs +3 -3
- package/dist/core/releases.cjs +6 -6
- package/dist/core/releases.mjs +1 -1
- package/dist/core/writes.cjs +2 -2
- package/dist/core/writes.mjs +1 -1
- package/dist/createHotUpdaterCore.cjs +39 -39
- package/dist/createHotUpdaterCore.d.cts +61 -8
- package/dist/createHotUpdaterCore.d.mts +61 -8
- package/dist/createHotUpdaterCore.mjs +35 -32
- package/dist/db/engineDrizzleSchema.cjs +3 -4
- package/dist/db/engineDrizzleSchema.mjs +1 -2
- package/dist/db/enginePrismaSchema.cjs +4 -5
- package/dist/db/enginePrismaSchema.d.cts +1 -1
- package/dist/db/enginePrismaSchema.d.mts +1 -1
- package/dist/db/enginePrismaSchema.mjs +1 -2
- package/dist/db/releaseCatalog.cjs +6 -6
- package/dist/db/releaseCatalog.mjs +1 -1
- package/dist/db/updateArtifacts.cjs +6 -6
- package/dist/db/updateArtifacts.mjs +1 -1
- package/dist/handler.cjs +3 -4
- package/dist/handler.mjs +1 -1
- package/dist/handlerAdminRoutes.cjs +1 -2
- package/dist/handlerAdminRoutes.mjs +1 -2
- package/dist/handlerVersionRoutes.cjs +2 -2
- package/dist/handlerVersionRoutes.mjs +2 -2
- package/dist/index.cjs +9 -2
- package/dist/index.d.cts +4 -3
- package/dist/index.d.mts +4 -3
- package/dist/index.mjs +2 -1
- package/dist/node.cjs +3 -6
- package/dist/node.d.cts +3 -3
- package/dist/node.d.mts +3 -3
- package/dist/node.mjs +4 -4
- package/dist/package.cjs +1 -1
- package/dist/package.mjs +1 -1
- package/dist/plugins/api-keys/index.cjs +8 -52
- package/dist/plugins/api-keys/index.d.cts +1 -84
- package/dist/plugins/api-keys/index.d.mts +1 -84
- package/dist/plugins/api-keys/index.mjs +2 -49
- package/dist/plugins/definePlugin.d.cts +2 -200
- package/dist/plugins/definePlugin.d.mts +2 -200
- package/dist/plugins/insights/index.cjs +7 -126
- package/dist/plugins/insights/index.d.cts +1 -398
- package/dist/plugins/insights/index.d.mts +1 -398
- package/dist/plugins/insights/index.mjs +2 -121
- package/dist/plugins/official.cjs +30 -0
- package/dist/plugins/official.mjs +29 -0
- package/dist/storageAccess.cjs +13 -10
- package/dist/storageAccess.mjs +13 -10
- package/dist/types/index.d.cts +1 -1
- package/dist/types/index.d.mts +1 -1
- package/package.json +15 -37
- package/dist/_virtual/_rolldown/runtime.cjs +0 -23
- package/dist/assembly/clientPlugins.d.cts +0 -16
- package/dist/assembly/clientPlugins.d.mts +0 -16
- package/dist/assembly/configError.cjs +0 -7
- package/dist/assembly/databasePlugins.cjs +0 -27
- package/dist/assembly/databasePlugins.d.cts +0 -43
- package/dist/assembly/databasePlugins.d.mts +0 -43
- package/dist/assembly/databasePlugins.mjs +0 -26
- package/dist/assembly/pluginCli.cjs +0 -125
- package/dist/assembly/pluginCli.d.cts +0 -59
- package/dist/assembly/pluginCli.d.mts +0 -59
- package/dist/assembly/pluginCli.mjs +0 -121
- package/dist/core/baseCandidates.d.cts +0 -17
- package/dist/core/baseCandidates.d.mts +0 -17
- package/dist/core/schema.cjs +0 -279
- package/dist/core/schema.d.cts +0 -307
- package/dist/core/schema.d.mts +0 -307
- package/dist/core/schema.mjs +0 -277
- package/dist/database/aggregateBatching.cjs +0 -626
- package/dist/database/aggregateBatching.d.cts +0 -10
- package/dist/database/aggregateBatching.d.mts +0 -10
- package/dist/database/aggregateBatching.mjs +0 -625
- package/dist/database/busy.cjs +0 -36
- package/dist/database/busy.d.cts +0 -12
- package/dist/database/busy.d.mts +0 -12
- package/dist/database/busy.mjs +0 -36
- package/dist/database/cursor.cjs +0 -44
- package/dist/database/cursor.d.cts +0 -7
- package/dist/database/cursor.d.mts +0 -7
- package/dist/database/cursor.mjs +0 -40
- package/dist/database/database.cjs +0 -63
- package/dist/database/database.d.cts +0 -136
- package/dist/database/database.d.mts +0 -136
- package/dist/database/database.mjs +0 -63
- package/dist/database/definitions.d.cts +0 -78
- package/dist/database/definitions.d.mts +0 -78
- package/dist/database/engine.cjs +0 -37
- package/dist/database/engine.d.cts +0 -41
- package/dist/database/engine.d.mts +0 -41
- package/dist/database/engine.mjs +0 -37
- package/dist/database/engineAggregates.cjs +0 -118
- package/dist/database/engineAggregates.mjs +0 -115
- package/dist/database/engineReads.cjs +0 -182
- package/dist/database/engineReads.d.cts +0 -35
- package/dist/database/engineReads.d.mts +0 -35
- package/dist/database/engineReads.mjs +0 -181
- package/dist/database/engineTransaction.cjs +0 -399
- package/dist/database/engineTransaction.d.cts +0 -26
- package/dist/database/engineTransaction.d.mts +0 -26
- package/dist/database/engineTransaction.mjs +0 -398
- package/dist/database/errors.cjs +0 -27
- package/dist/database/errors.d.cts +0 -21
- package/dist/database/errors.d.mts +0 -21
- package/dist/database/errors.mjs +0 -24
- package/dist/database/fence.cjs +0 -125
- package/dist/database/fence.d.cts +0 -42
- package/dist/database/fence.d.mts +0 -42
- package/dist/database/fence.mjs +0 -117
- package/dist/database/index.cjs +0 -136
- package/dist/database/index.d.cts +0 -18
- package/dist/database/index.d.mts +0 -18
- package/dist/database/index.mjs +0 -16
- package/dist/database/kv/kvAdapter.cjs +0 -285
- package/dist/database/kv/kvAdapter.d.cts +0 -109
- package/dist/database/kv/kvAdapter.d.mts +0 -109
- package/dist/database/kv/kvAdapter.mjs +0 -284
- package/dist/database/resolveSchema.cjs +0 -199
- package/dist/database/resolveSchema.d.cts +0 -42
- package/dist/database/resolveSchema.d.mts +0 -42
- package/dist/database/resolveSchema.mjs +0 -196
- package/dist/database/retention.cjs +0 -92
- package/dist/database/retention.mjs +0 -90
- package/dist/database/schema.cjs +0 -24
- package/dist/database/schema.d.cts +0 -90
- package/dist/database/schema.d.mts +0 -90
- package/dist/database/schema.mjs +0 -23
- package/dist/database/sql/sqlAdapter.cjs +0 -290
- package/dist/database/sql/sqlAdapter.d.cts +0 -46
- package/dist/database/sql/sqlAdapter.d.mts +0 -46
- package/dist/database/sql/sqlAdapter.mjs +0 -287
- package/dist/database/sql/sqlSchema.cjs +0 -171
- package/dist/database/sql/sqlSchema.d.cts +0 -8
- package/dist/database/sql/sqlSchema.d.mts +0 -8
- package/dist/database/sql/sqlSchema.mjs +0 -165
- package/dist/db/coreDatabase.cjs +0 -85
- package/dist/db/coreDatabase.d.cts +0 -57
- package/dist/db/coreDatabase.d.mts +0 -57
- package/dist/db/coreDatabase.mjs +0 -78
- package/dist/db/createBundleDiff.cjs +0 -144
- package/dist/db/createBundleDiff.d.cts +0 -17
- package/dist/db/createBundleDiff.d.mts +0 -17
- package/dist/db/createBundleDiff.mjs +0 -141
- package/dist/db/engineMigrator.cjs +0 -53
- package/dist/db/engineMigrator.mjs +0 -53
- package/dist/db/engineSql.cjs +0 -26
- package/dist/db/engineSql.d.cts +0 -17
- package/dist/db/engineSql.d.mts +0 -17
- package/dist/db/engineSql.mjs +0 -25
- package/dist/db/engineSqlMigrator.cjs +0 -66
- package/dist/db/engineSqlMigrator.mjs +0 -66
- package/dist/db/fixedMigratorShared.cjs +0 -12
- package/dist/db/fixedMigratorShared.mjs +0 -11
- package/dist/db/index.cjs +0 -50
- package/dist/db/index.d.cts +0 -23
- package/dist/db/index.d.mts +0 -23
- package/dist/db/index.mjs +0 -33
- package/dist/db/releaseCatalog.d.cts +0 -16
- package/dist/db/releaseCatalog.d.mts +0 -16
- package/dist/db/schemaSettings.cjs +0 -63
- package/dist/db/schemaSettings.d.cts +0 -12
- package/dist/db/schemaSettings.d.mts +0 -12
- package/dist/db/schemaSettings.mjs +0 -62
- package/dist/db/settingsMigrator.cjs +0 -92
- package/dist/db/settingsMigrator.mjs +0 -89
- package/dist/db/types.cjs +0 -11
- package/dist/db/types.d.cts +0 -78
- package/dist/db/types.d.mts +0 -78
- package/dist/db/types.mjs +0 -10
- package/dist/diff.cjs +0 -3
- package/dist/diff.d.cts +0 -2
- package/dist/diff.d.mts +0 -2
- package/dist/diff.mjs +0 -2
- package/dist/plugins/api-keys/apiKeys.cjs +0 -139
- package/dist/plugins/api-keys/apiKeys.d.cts +0 -27
- package/dist/plugins/api-keys/apiKeys.d.mts +0 -27
- package/dist/plugins/api-keys/apiKeys.mjs +0 -129
- package/dist/plugins/api-keys/cli.cjs +0 -115
- package/dist/plugins/api-keys/cli.mjs +0 -114
- package/dist/plugins/api-keys/model.cjs +0 -58
- package/dist/plugins/api-keys/model.d.cts +0 -26
- package/dist/plugins/api-keys/model.d.mts +0 -26
- package/dist/plugins/api-keys/model.mjs +0 -58
- package/dist/plugins/api-keys/schema.cjs +0 -38
- package/dist/plugins/api-keys/schema.d.cts +0 -44
- package/dist/plugins/api-keys/schema.d.mts +0 -44
- package/dist/plugins/api-keys/schema.mjs +0 -39
- package/dist/plugins/definePlugin.cjs +0 -5
- package/dist/plugins/definePlugin.mjs +0 -5
- package/dist/plugins/index.cjs +0 -38
- package/dist/plugins/index.d.cts +0 -12
- package/dist/plugins/index.d.mts +0 -12
- package/dist/plugins/index.mjs +0 -9
- package/dist/plugins/insights/contract.cjs +0 -193
- package/dist/plugins/insights/contract.mjs +0 -189
- package/dist/plugins/insights/domain.d.cts +0 -149
- package/dist/plugins/insights/domain.d.mts +0 -149
- package/dist/plugins/insights/errors.cjs +0 -15
- package/dist/plugins/insights/errors.mjs +0 -14
- package/dist/plugins/insights/eventInput.cjs +0 -284
- package/dist/plugins/insights/eventInput.mjs +0 -282
- package/dist/plugins/insights/eventRow.cjs +0 -49
- package/dist/plugins/insights/eventRow.d.cts +0 -64
- package/dist/plugins/insights/eventRow.d.mts +0 -64
- package/dist/plugins/insights/eventRow.mjs +0 -47
- package/dist/plugins/insights/model.cjs +0 -17
- package/dist/plugins/insights/model.d.cts +0 -10
- package/dist/plugins/insights/model.d.mts +0 -10
- package/dist/plugins/insights/model.mjs +0 -17
- package/dist/plugins/insights/modelTypes.d.cts +0 -176
- package/dist/plugins/insights/modelTypes.d.mts +0 -176
- package/dist/plugins/insights/overview.cjs +0 -109
- package/dist/plugins/insights/overview.d.cts +0 -15
- package/dist/plugins/insights/overview.d.mts +0 -15
- package/dist/plugins/insights/overview.mjs +0 -107
- package/dist/plugins/insights/provider.cjs +0 -375
- package/dist/plugins/insights/provider.d.cts +0 -6
- package/dist/plugins/insights/provider.d.mts +0 -6
- package/dist/plugins/insights/provider.mjs +0 -374
- package/dist/plugins/insights/queryInput.cjs +0 -93
- package/dist/plugins/insights/queryInput.mjs +0 -91
- package/dist/plugins/insights/reads.cjs +0 -681
- package/dist/plugins/insights/reads.d.cts +0 -61
- package/dist/plugins/insights/reads.d.mts +0 -61
- package/dist/plugins/insights/reads.mjs +0 -674
- package/dist/plugins/insights/recordEvent.cjs +0 -319
- package/dist/plugins/insights/recordEvent.d.cts +0 -18
- package/dist/plugins/insights/recordEvent.d.mts +0 -18
- package/dist/plugins/insights/recordEvent.mjs +0 -316
- package/dist/plugins/insights/routes.cjs +0 -96
- package/dist/plugins/insights/routes.mjs +0 -95
- package/dist/plugins/insights/schema.cjs +0 -489
- package/dist/plugins/insights/schema.d.cts +0 -698
- package/dist/plugins/insights/schema.d.mts +0 -698
- package/dist/plugins/insights/schema.mjs +0 -483
- package/dist/plugins/insights/testing/eventRow.d.mts +0 -64
- package/dist/plugins/insights/testing/expectInsightsIndex.mjs +0 -18
- package/dist/plugins/insights/testing/fixtures.d.mts +0 -8
- package/dist/plugins/insights/testing/fixtures.mjs +0 -25
- package/dist/plugins/insights/testing/index.d.mts +0 -24
- package/dist/plugins/insights/testing/index.mjs +0 -25
- package/dist/plugins/insights/testing/insightsModelTests.mjs +0 -714
- package/dist/plugins/insights/testing/modelTypes.d.mts +0 -176
- package/dist/plugins/insights/testing/setupInsightsHttpTestSuite.d.mts +0 -11
- package/dist/plugins/insights/testing/setupInsightsHttpTestSuite.mjs +0 -107
- package/dist/plugins/insights/testing/setupInsightsModelTestSuite.d.mts +0 -11
- package/dist/plugins/insights/testing/setupInsightsModelTestSuite.mjs +0 -31
- package/dist/plugins/insights/testing/types.d.mts +0 -26
- package/dist/plugins/insights/types.d.cts +0 -33
- package/dist/plugins/insights/types.d.mts +0 -33
- package/src/adapters/drizzle.conformance.integration.spec.ts +0 -34
- package/src/adapters/drizzle.readBudgets.integration.spec.ts +0 -43
- package/src/adapters/drizzle.spec.ts +0 -314
- package/src/adapters/drizzle.ts +0 -64
- package/src/adapters/drizzleExecutor.ts +0 -166
- package/src/adapters/kysely.conformance.integration.spec.ts +0 -36
- package/src/adapters/kysely.readBudgets.integration.spec.ts +0 -44
- package/src/adapters/kysely.spec.ts +0 -244
- package/src/adapters/kysely.ts +0 -46
- package/src/adapters/kyselyExecutor.ts +0 -53
- package/src/adapters/mongodb.integration.spec.ts +0 -271
- package/src/adapters/mongodb.readBudgets.integration.spec.ts +0 -61
- package/src/adapters/mongodb.ts +0 -45
- package/src/adapters/mongodbAdapter.ts +0 -307
- package/src/adapters/prisma.conformance.integration.spec.ts +0 -36
- package/src/adapters/prisma.integration.spec.ts +0 -146
- package/src/adapters/prisma.readBudgets.integration.spec.ts +0 -43
- package/src/adapters/prisma.spec.ts +0 -257
- package/src/adapters/prisma.ts +0 -74
- package/src/adapters/prismaExecutor.ts +0 -107
- package/src/adapters/prismaTestClients.ts +0 -182
- package/src/adapters/sqlProviders.ts +0 -14
- package/src/assembly/assemblePlugins.ts +0 -302
- package/src/assembly/assembly.spec.ts +0 -377
- package/src/assembly/assembly.types.spec.ts +0 -203
- package/src/assembly/clientPlugins.ts +0 -113
- package/src/assembly/configError.ts +0 -4
- package/src/assembly/databasePlugins.spec.ts +0 -71
- package/src/assembly/databasePlugins.ts +0 -102
- package/src/assembly/pluginCli.spec.ts +0 -254
- package/src/assembly/pluginCli.ts +0 -248
- package/src/assembly/pluginRoutes.spec.ts +0 -186
- package/src/core/api.ts +0 -139
- package/src/core/baseCandidates.spec.ts +0 -378
- package/src/core/baseCandidates.ts +0 -136
- package/src/core/index.ts +0 -44
- package/src/core/operations.spec.ts +0 -415
- package/src/core/operations.ts +0 -551
- package/src/core/reads.spec.ts +0 -300
- package/src/core/reads.ts +0 -417
- package/src/core/releases.spec.ts +0 -308
- package/src/core/releases.ts +0 -345
- package/src/core/schema.ts +0 -173
- package/src/core/writes.ts +0 -160
- package/src/createHotUpdaterCore.ts +0 -260
- package/src/database/aggregateBatching.spec.ts +0 -577
- package/src/database/aggregateBatching.ts +0 -803
- package/src/database/busy.spec.ts +0 -45
- package/src/database/busy.ts +0 -50
- package/src/database/cursor.ts +0 -65
- package/src/database/database.ts +0 -366
- package/src/database/database.types.spec.ts +0 -135
- package/src/database/definitions.ts +0 -76
- package/src/database/engine.ts +0 -62
- package/src/database/engineAggregates.spec.ts +0 -536
- package/src/database/engineAggregates.ts +0 -189
- package/src/database/engineReads.spec.ts +0 -219
- package/src/database/engineReads.ts +0 -304
- package/src/database/engineTransaction.spec.ts +0 -710
- package/src/database/engineTransaction.ts +0 -582
- package/src/database/errors.ts +0 -30
- package/src/database/fence.spec.ts +0 -223
- package/src/database/fence.ts +0 -175
- package/src/database/index.ts +0 -160
- package/src/database/kv/kvAdapter.batching.integration.spec.ts +0 -15
- package/src/database/kv/kvAdapter.conformance.integration.spec.ts +0 -19
- package/src/database/kv/kvAdapter.readBudgets.integration.spec.ts +0 -17
- package/src/database/kv/kvAdapter.spec.ts +0 -595
- package/src/database/kv/kvAdapter.ts +0 -479
- package/src/database/kv/kvTestStore.ts +0 -118
- package/src/database/memory.readBudgets.integration.spec.ts +0 -13
- package/src/database/resolveSchema.spec.ts +0 -230
- package/src/database/resolveSchema.ts +0 -375
- package/src/database/retention.spec.ts +0 -314
- package/src/database/retention.ts +0 -129
- package/src/database/schema.ts +0 -213
- package/src/database/schema.types.spec.ts +0 -94
- package/src/database/sql/docker-compose.yml +0 -36
- package/src/database/sql/sqlAdapter.integration.spec.ts +0 -145
- package/src/database/sql/sqlAdapter.readBudgets.integration.spec.ts +0 -123
- package/src/database/sql/sqlAdapter.spec.ts +0 -343
- package/src/database/sql/sqlAdapter.ts +0 -552
- package/src/database/sql/sqlSchema.ts +0 -286
- package/src/database/sql/sqlTestExecutors.ts +0 -183
- package/src/databaseTestSuite.spec.ts +0 -44
- package/src/db/bundleRows.spec.ts +0 -164
- package/src/db/bundleRows.ts +0 -10
- package/src/db/coreDatabase.ts +0 -153
- package/src/db/createBundleDiff.spec.ts +0 -464
- package/src/db/createBundleDiff.ts +0 -370
- package/src/db/engineDrizzleSchema.ts +0 -72
- package/src/db/engineMigrator.ts +0 -105
- package/src/db/enginePrismaSchema.ts +0 -147
- package/src/db/engineSql.spec.ts +0 -130
- package/src/db/engineSql.ts +0 -48
- package/src/db/engineSqlMigrator.ts +0 -116
- package/src/db/fixedMigratorShared.ts +0 -17
- package/src/db/index.spec.ts +0 -554
- package/src/db/index.ts +0 -93
- package/src/db/node-sqlite.d.ts +0 -25
- package/src/db/pluginTables.spec.ts +0 -248
- package/src/db/releaseCatalog.ts +0 -106
- package/src/db/schemaSettings.ts +0 -104
- package/src/db/settingsMigrator.spec.ts +0 -65
- package/src/db/settingsMigrator.ts +0 -152
- package/src/db/types.ts +0 -82
- package/src/db/updateArtifacts.spec.ts +0 -235
- package/src/db/updateArtifacts.ts +0 -473
- package/src/db/updateCheck.bench.ts +0 -47
- package/src/diff.ts +0 -6
- package/src/handler-standalone.integration.spec.ts +0 -321
- package/src/handler.spec.ts +0 -273
- package/src/handler.testFixtures.ts +0 -25
- package/src/handler.ts +0 -302
- package/src/handlerAdminRoutes.spec.ts +0 -183
- package/src/handlerAdminRoutes.ts +0 -536
- package/src/handlerAuth.integration.spec.ts +0 -33
- package/src/handlerErrors.ts +0 -7
- package/src/handlerManagement.spec.ts +0 -202
- package/src/handlerParameters.ts +0 -105
- package/src/handlerReleaseCatalogRoutes.ts +0 -176
- package/src/handlerTypes.ts +0 -19
- package/src/handlerVersionRoutes.ts +0 -25
- package/src/index.ts +0 -13
- package/src/internalRouter.ts +0 -104
- package/src/lintRules.spec.ts +0 -76
- package/src/node.spec.ts +0 -119
- package/src/node.ts +0 -111
- package/src/plugins/api-keys/apiKeys.integration.spec.ts +0 -92
- package/src/plugins/api-keys/apiKeys.spec.ts +0 -166
- package/src/plugins/api-keys/apiKeys.ts +0 -214
- package/src/plugins/api-keys/apiKeysPlugin.spec.ts +0 -168
- package/src/plugins/api-keys/cli.spec.ts +0 -187
- package/src/plugins/api-keys/cli.ts +0 -140
- package/src/plugins/api-keys/index.ts +0 -73
- package/src/plugins/api-keys/model.ts +0 -88
- package/src/plugins/api-keys/schema.ts +0 -22
- package/src/plugins/definePlugin.ts +0 -242
- package/src/plugins/index.ts +0 -73
- package/src/plugins/insights/contract.spec.ts +0 -285
- package/src/plugins/insights/contract.ts +0 -372
- package/src/plugins/insights/domain.ts +0 -176
- package/src/plugins/insights/errors.ts +0 -11
- package/src/plugins/insights/eventInput.ts +0 -381
- package/src/plugins/insights/eventRow.ts +0 -209
- package/src/plugins/insights/index.ts +0 -222
- package/src/plugins/insights/insights.integration.spec.ts +0 -921
- package/src/plugins/insights/insightsRollout.integration.spec.ts +0 -186
- package/src/plugins/insights/model.spec.ts +0 -64
- package/src/plugins/insights/model.ts +0 -18
- package/src/plugins/insights/modelTypes.ts +0 -197
- package/src/plugins/insights/overview.spec.ts +0 -64
- package/src/plugins/insights/overview.ts +0 -214
- package/src/plugins/insights/provider.spec.ts +0 -585
- package/src/plugins/insights/provider.ts +0 -704
- package/src/plugins/insights/queryInput.ts +0 -142
- package/src/plugins/insights/reads.spec.ts +0 -1013
- package/src/plugins/insights/reads.ts +0 -1037
- package/src/plugins/insights/recordEvent.spec.ts +0 -897
- package/src/plugins/insights/recordEvent.ts +0 -476
- package/src/plugins/insights/retention.spec.ts +0 -115
- package/src/plugins/insights/routes.ts +0 -149
- package/src/plugins/insights/schema.ts +0 -409
- package/src/plugins/insights/testing/expectInsightsIndex.spec.ts +0 -42
- package/src/plugins/insights/testing/expectInsightsIndex.ts +0 -20
- package/src/plugins/insights/testing/fixtures.ts +0 -30
- package/src/plugins/insights/testing/index.ts +0 -45
- package/src/plugins/insights/testing/insightsModelTests.ts +0 -860
- package/src/plugins/insights/testing/setupInsightsHttpTestSuite.ts +0 -152
- package/src/plugins/insights/testing/setupInsightsModelTestSuite.ts +0 -36
- package/src/plugins/insights/testing/types.ts +0 -30
- package/src/plugins/insights/types.ts +0 -55
- package/src/plugins/pluginTestHarness.spec.ts +0 -56
- package/src/readBudgets.testFixtures.ts +0 -15
- package/src/releaseCatalogRoutes.integration.spec.ts +0 -200
- package/src/retention.spec.ts +0 -73
- package/src/runtime.spec.ts +0 -207
- package/src/runtime.testFixtures.ts +0 -60
- package/src/runtimeBundles.integration.spec.ts +0 -112
- package/src/storageAccess.spec.ts +0 -152
- package/src/storageAccess.ts +0 -141
- package/src/testUtilsMutation.integration.spec.ts +0 -216
- package/src/testUtilsPackage.integration.spec.ts +0 -180
- package/src/types/index.ts +0 -2
- package/src/version.ts +0 -3
|
@@ -1,308 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
createReleaseCatalogScopeKey,
|
|
3
|
-
encodeChannelKey,
|
|
4
|
-
} from "@hot-updater/core";
|
|
5
|
-
import {
|
|
6
|
-
compileReleaseCatalog,
|
|
7
|
-
releaseRowToRelease,
|
|
8
|
-
type BundleRow,
|
|
9
|
-
type ReleaseCatalogScope,
|
|
10
|
-
type ReleaseRow,
|
|
11
|
-
} from "@hot-updater/plugin-core";
|
|
12
|
-
import { createMemoryAdapter } from "@hot-updater/plugin-core/internal";
|
|
13
|
-
import { describe, expect, it } from "vitest";
|
|
14
|
-
|
|
15
|
-
import {
|
|
16
|
-
createBundlePatchRowFixture,
|
|
17
|
-
createBundleRowFixture,
|
|
18
|
-
} from "../../../test-utils/src/databaseTestFixtures";
|
|
19
|
-
import { createDatabaseEngine } from "../database/database";
|
|
20
|
-
import { resolveSchema } from "../database/resolveSchema";
|
|
21
|
-
import {
|
|
22
|
-
changeReleases,
|
|
23
|
-
coreModule,
|
|
24
|
-
createCoreReads,
|
|
25
|
-
insertBundle,
|
|
26
|
-
insertChannel,
|
|
27
|
-
rebuildCatalog,
|
|
28
|
-
targetBaseCandidateKey,
|
|
29
|
-
type ReleaseChangeInput,
|
|
30
|
-
} from "./index";
|
|
31
|
-
|
|
32
|
-
const channel = { id: "channel-production", name: "production" };
|
|
33
|
-
const channelKey = encodeChannelKey(channel.name);
|
|
34
|
-
const scope: ReleaseCatalogScope = {
|
|
35
|
-
channelId: channel.id,
|
|
36
|
-
channelName: channel.name,
|
|
37
|
-
platform: "ios",
|
|
38
|
-
scopeKey: createReleaseCatalogScopeKey({
|
|
39
|
-
channelKey,
|
|
40
|
-
platform: "ios",
|
|
41
|
-
strategy: "APP_VERSION",
|
|
42
|
-
}),
|
|
43
|
-
strategy: "APP_VERSION",
|
|
44
|
-
fingerprintHash: null,
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
const releaseOf = (bundle: BundleRow): Omit<ReleaseRow, "id"> => ({
|
|
48
|
-
revision: 1,
|
|
49
|
-
scope_key: scope.scopeKey,
|
|
50
|
-
channel_id: channel.id,
|
|
51
|
-
platform: "ios",
|
|
52
|
-
kind: "BUNDLE",
|
|
53
|
-
bundle_id: bundle.id,
|
|
54
|
-
strategy: "APP_VERSION",
|
|
55
|
-
target_app_version: "1.0.0",
|
|
56
|
-
fingerprint_hash: null,
|
|
57
|
-
enabled: true,
|
|
58
|
-
should_force_update: false,
|
|
59
|
-
message: null,
|
|
60
|
-
rollout_cohort_count: 1000,
|
|
61
|
-
target_cohorts: [],
|
|
62
|
-
operation: "DEPLOY",
|
|
63
|
-
source_release_id: null,
|
|
64
|
-
created_at_ms: 1,
|
|
65
|
-
updated_at_ms: 1,
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
const deploy = (bundle: BundleRow): ReleaseChangeInput => ({
|
|
69
|
-
scope,
|
|
70
|
-
bundle: { row: bundle, patches: [] },
|
|
71
|
-
change: { operation: "insert", row: releaseOf(bundle) },
|
|
72
|
-
updatedAtMs: 10,
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
const setup = async () => {
|
|
76
|
-
const adapter = createMemoryAdapter();
|
|
77
|
-
const schema = resolveSchema([coreModule]);
|
|
78
|
-
const engine = createDatabaseEngine({ adapter, schema, verify: true });
|
|
79
|
-
const db = engine.database(coreModule);
|
|
80
|
-
await insertChannel(db, channel);
|
|
81
|
-
return {
|
|
82
|
-
adapter,
|
|
83
|
-
schema,
|
|
84
|
-
engine,
|
|
85
|
-
db,
|
|
86
|
-
reads: createCoreReads(db, { resolveFileUrl: async () => null }),
|
|
87
|
-
};
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
const baseKey = targetBaseCandidateKey({
|
|
91
|
-
channel: channel.name,
|
|
92
|
-
platform: "ios",
|
|
93
|
-
fingerprintHash: null,
|
|
94
|
-
appVersion: "1.0.0",
|
|
95
|
-
})!;
|
|
96
|
-
const NEWEST = "ffffffff-ffff-7fff-bfff-ffffffffffff";
|
|
97
|
-
|
|
98
|
-
describe("release changes rooted at the catalog", () => {
|
|
99
|
-
it("deploys a bundle with its release and compiles the scope's catalog in one transaction", async () => {
|
|
100
|
-
const { db, reads } = await setup();
|
|
101
|
-
const bundle = createBundleRowFixture("501");
|
|
102
|
-
const patchBase = createBundleRowFixture("500");
|
|
103
|
-
await db.transaction(async (tx) => insertBundle(tx, patchBase));
|
|
104
|
-
const patch = createBundlePatchRowFixture("1", bundle.id, patchBase.id);
|
|
105
|
-
const [result] = await changeReleases(db, [
|
|
106
|
-
{ ...deploy(bundle), bundle: { row: bundle, patches: [patch] } },
|
|
107
|
-
]);
|
|
108
|
-
const release = result!.release!;
|
|
109
|
-
expect(release.id > bundle.id).toBe(true);
|
|
110
|
-
const compiled = await compileReleaseCatalog({
|
|
111
|
-
strategy: "APP_VERSION",
|
|
112
|
-
releases: [releaseRowToRelease(release)],
|
|
113
|
-
});
|
|
114
|
-
expect(result!.catalog).toMatchObject({
|
|
115
|
-
scope_key: scope.scopeKey,
|
|
116
|
-
channel_key: channelKey,
|
|
117
|
-
generation: 1,
|
|
118
|
-
payload: compiled.canonicalPayload,
|
|
119
|
-
catalog_hash: compiled.catalogHash,
|
|
120
|
-
is_tombstone: false,
|
|
121
|
-
updated_at_ms: 10,
|
|
122
|
-
});
|
|
123
|
-
await expect(
|
|
124
|
-
reads.getReleaseCatalog({
|
|
125
|
-
strategy: "APP_VERSION",
|
|
126
|
-
platform: "ios",
|
|
127
|
-
channelKey,
|
|
128
|
-
appVersion: "1.0.0",
|
|
129
|
-
}),
|
|
130
|
-
).resolves.toMatchObject({
|
|
131
|
-
generation: 1,
|
|
132
|
-
releases: [{ releaseId: release.id, bundleId: bundle.id }],
|
|
133
|
-
});
|
|
134
|
-
await expect(reads.getBundle(bundle.id)).resolves.toMatchObject({
|
|
135
|
-
patches: [patch],
|
|
136
|
-
});
|
|
137
|
-
await expect(reads.countBundles("ios")).resolves.toBe(2);
|
|
138
|
-
await expect(reads.findBaseBundleIds(baseKey, NEWEST, 3)).resolves.toEqual([
|
|
139
|
-
bundle.id,
|
|
140
|
-
]);
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
it("updates and deletes a release with the next catalog generation each", async () => {
|
|
144
|
-
const { db, reads } = await setup();
|
|
145
|
-
const bundle = createBundleRowFixture("511");
|
|
146
|
-
const [deployed] = await changeReleases(db, [deploy(bundle)]);
|
|
147
|
-
const id = deployed!.release!.id;
|
|
148
|
-
|
|
149
|
-
const [disabled] = await changeReleases(db, [
|
|
150
|
-
{
|
|
151
|
-
scope,
|
|
152
|
-
change: { operation: "update", id, update: { enabled: false } },
|
|
153
|
-
updatedAtMs: 20,
|
|
154
|
-
},
|
|
155
|
-
]);
|
|
156
|
-
expect(disabled!.release).toMatchObject({ revision: 2, enabled: false });
|
|
157
|
-
expect(disabled!.catalog).toMatchObject({
|
|
158
|
-
generation: 2,
|
|
159
|
-
is_tombstone: true,
|
|
160
|
-
catalog_id: deployed!.catalog.catalog_id,
|
|
161
|
-
});
|
|
162
|
-
await expect(reads.findBaseBundleIds(baseKey, NEWEST, 3)).resolves.toEqual(
|
|
163
|
-
[],
|
|
164
|
-
);
|
|
165
|
-
|
|
166
|
-
const [deleted] = await changeReleases(db, [
|
|
167
|
-
{ scope, change: { operation: "delete", id }, updatedAtMs: 30 },
|
|
168
|
-
]);
|
|
169
|
-
expect(deleted).toMatchObject({
|
|
170
|
-
release: null,
|
|
171
|
-
catalog: { generation: 3 },
|
|
172
|
-
});
|
|
173
|
-
await expect(reads.getRelease(id)).resolves.toBeNull();
|
|
174
|
-
});
|
|
175
|
-
|
|
176
|
-
it("orders ids after the scope's latest release and refuses one that does not sort after it", async () => {
|
|
177
|
-
const { db } = await setup();
|
|
178
|
-
const first = createBundleRowFixture("521");
|
|
179
|
-
const second = createBundleRowFixture("522");
|
|
180
|
-
const [one] = await changeReleases(db, [deploy(first)]);
|
|
181
|
-
const [two] = await changeReleases(db, [deploy(second)]);
|
|
182
|
-
expect(two!.release!.id > one!.release!.id).toBe(true);
|
|
183
|
-
|
|
184
|
-
await expect(
|
|
185
|
-
changeReleases(db, [
|
|
186
|
-
{
|
|
187
|
-
scope,
|
|
188
|
-
change: {
|
|
189
|
-
operation: "insert",
|
|
190
|
-
row: { ...releaseOf(first), id: one!.release!.id },
|
|
191
|
-
},
|
|
192
|
-
updatedAtMs: 40,
|
|
193
|
-
},
|
|
194
|
-
]),
|
|
195
|
-
).rejects.toMatchObject({ code: "NON_MONOTONIC_RELEASE_ID" });
|
|
196
|
-
});
|
|
197
|
-
|
|
198
|
-
it("refuses a release outside its scope and a scope whose catalog history is missing", async () => {
|
|
199
|
-
const { adapter, schema, db } = await setup();
|
|
200
|
-
await expect(
|
|
201
|
-
changeReleases(db, [
|
|
202
|
-
{
|
|
203
|
-
scope,
|
|
204
|
-
change: { operation: "delete", id: NEWEST },
|
|
205
|
-
updatedAtMs: 50,
|
|
206
|
-
},
|
|
207
|
-
]),
|
|
208
|
-
).rejects.toMatchObject({ code: "RELEASE_NOT_FOUND" });
|
|
209
|
-
|
|
210
|
-
await changeReleases(db, [deploy(createBundleRowFixture("531"))]);
|
|
211
|
-
// A restore that lost the catalog row: a write under the engine, which
|
|
212
|
-
// keeps a catalog while its scope has releases.
|
|
213
|
-
const table = schema.models.get("release_catalogs")!.table;
|
|
214
|
-
const [row] = await adapter.get(table, [[scope.scopeKey]]);
|
|
215
|
-
await adapter.write([
|
|
216
|
-
{
|
|
217
|
-
type: "delete",
|
|
218
|
-
table,
|
|
219
|
-
key: [scope.scopeKey],
|
|
220
|
-
guard: { v: Number(row!._v) },
|
|
221
|
-
previous: row!,
|
|
222
|
-
},
|
|
223
|
-
]);
|
|
224
|
-
await expect(
|
|
225
|
-
changeReleases(db, [deploy(createBundleRowFixture("532"))]),
|
|
226
|
-
).rejects.toMatchObject({ code: "CATALOG_IDENTITY_MISSING" });
|
|
227
|
-
await expect(rebuildCatalog(db, scope, 60)).rejects.toMatchObject({
|
|
228
|
-
code: "CATALOG_IDENTITY_MISSING",
|
|
229
|
-
});
|
|
230
|
-
});
|
|
231
|
-
|
|
232
|
-
it("serializes concurrent deploys in one scope through its catalog row", async () => {
|
|
233
|
-
const { db, reads } = await setup();
|
|
234
|
-
const bundles = Array.from({ length: 8 }, (_, n) =>
|
|
235
|
-
createBundleRowFixture(String(541 + n)),
|
|
236
|
-
);
|
|
237
|
-
const results = await Promise.all(
|
|
238
|
-
bundles.map((bundle) => changeReleases(db, [deploy(bundle)])),
|
|
239
|
-
);
|
|
240
|
-
const generations = results.map(([result]) => result!.catalog.generation);
|
|
241
|
-
expect(generations.toSorted((a, b) => a - b)).toEqual([
|
|
242
|
-
1, 2, 3, 4, 5, 6, 7, 8,
|
|
243
|
-
]);
|
|
244
|
-
const byGeneration = results
|
|
245
|
-
.map(([result]) => result!)
|
|
246
|
-
.sort((a, b) => a.catalog.generation - b.catalog.generation);
|
|
247
|
-
const ids = byGeneration.map(({ release }) => release!.id);
|
|
248
|
-
expect(ids).toEqual(ids.toSorted());
|
|
249
|
-
await expect(
|
|
250
|
-
reads.getReleaseCatalogRow(scope.scopeKey),
|
|
251
|
-
).resolves.toMatchObject({ generation: 8 });
|
|
252
|
-
await expect(
|
|
253
|
-
reads.listReleases({
|
|
254
|
-
filter: { kind: "scope", scopeKey: scope.scopeKey },
|
|
255
|
-
limit: 10,
|
|
256
|
-
}),
|
|
257
|
-
).resolves.toHaveLength(8);
|
|
258
|
-
});
|
|
259
|
-
|
|
260
|
-
it("reads only the scope's enabled releases and its latest id, all of them used", async () => {
|
|
261
|
-
const { engine, db } = await setup();
|
|
262
|
-
const bundles = Array.from({ length: 5 }, (_, n) =>
|
|
263
|
-
createBundleRowFixture(String(551 + n)),
|
|
264
|
-
);
|
|
265
|
-
const deployed: string[] = [];
|
|
266
|
-
for (const bundle of bundles) {
|
|
267
|
-
const [result] = await changeReleases(db, [deploy(bundle)]);
|
|
268
|
-
deployed.push(result!.release!.id);
|
|
269
|
-
}
|
|
270
|
-
for (const id of deployed.slice(0, 2)) {
|
|
271
|
-
await changeReleases(db, [
|
|
272
|
-
{
|
|
273
|
-
scope,
|
|
274
|
-
change: { operation: "update", id, update: { enabled: false } },
|
|
275
|
-
updatedAtMs: 70,
|
|
276
|
-
},
|
|
277
|
-
]);
|
|
278
|
-
}
|
|
279
|
-
const measured = await engine.measureReads(() =>
|
|
280
|
-
changeReleases(db, [deploy(createBundleRowFixture("556"))]),
|
|
281
|
-
);
|
|
282
|
-
// three enabled releases for the compile, one row for the latest id
|
|
283
|
-
expect(measured.adapter.rows).toBe(4);
|
|
284
|
-
expect(measured.adapter.queries).toBe(2);
|
|
285
|
-
});
|
|
286
|
-
|
|
287
|
-
it("rebuilds a catalog only when its releases changed underneath it", async () => {
|
|
288
|
-
const { db } = await setup();
|
|
289
|
-
const [deployed] = await changeReleases(db, [
|
|
290
|
-
deploy(createBundleRowFixture("561")),
|
|
291
|
-
]);
|
|
292
|
-
await expect(rebuildCatalog(db, scope, 80)).resolves.toMatchObject({
|
|
293
|
-
changed: false,
|
|
294
|
-
catalog: { generation: 1 },
|
|
295
|
-
});
|
|
296
|
-
// The release changes underneath the catalog, as only a raw write does.
|
|
297
|
-
await db.transaction(async (tx) => {
|
|
298
|
-
const stored = await tx.findOne("releases", {
|
|
299
|
-
id: deployed!.release!.id,
|
|
300
|
-
});
|
|
301
|
-
tx.update("releases", stored!, { message: "hotfix", revision: 2 });
|
|
302
|
-
});
|
|
303
|
-
await expect(rebuildCatalog(db, scope, 90)).resolves.toMatchObject({
|
|
304
|
-
changed: true,
|
|
305
|
-
catalog: { generation: 2, updated_at_ms: 90 },
|
|
306
|
-
});
|
|
307
|
-
});
|
|
308
|
-
});
|
package/src/core/releases.ts
DELETED
|
@@ -1,345 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
createReleaseCatalogScopeKey,
|
|
3
|
-
encodeChannelKey,
|
|
4
|
-
} from "@hot-updater/core";
|
|
5
|
-
import {
|
|
6
|
-
compileReleaseCatalog,
|
|
7
|
-
createUUIDv7,
|
|
8
|
-
createUUIDv7After,
|
|
9
|
-
isUUIDv7,
|
|
10
|
-
releaseRowToRelease,
|
|
11
|
-
ReleaseCatalogMutationError,
|
|
12
|
-
type BundlePatchRow,
|
|
13
|
-
type BundleRow,
|
|
14
|
-
type ReleaseCatalogCompilation,
|
|
15
|
-
type ReleaseCatalogRow,
|
|
16
|
-
type ReleaseCatalogScope,
|
|
17
|
-
type ReleaseRow,
|
|
18
|
-
type ReleaseRowUpdate,
|
|
19
|
-
} from "@hot-updater/plugin-core";
|
|
20
|
-
|
|
21
|
-
import { toCatalogRow, toReleaseRow, type CoreDatabase } from "./reads";
|
|
22
|
-
import { insertBundle, type CoreTransaction } from "./writes";
|
|
23
|
-
|
|
24
|
-
const PAGE = 500;
|
|
25
|
-
|
|
26
|
-
/** One change to one release, applied with its scope's catalog. */
|
|
27
|
-
export type ReleaseChange =
|
|
28
|
-
/** `id` is assigned after the scope's latest release unless given. */
|
|
29
|
-
| {
|
|
30
|
-
readonly operation: "insert";
|
|
31
|
-
readonly row: Omit<ReleaseRow, "id"> & { readonly id?: string };
|
|
32
|
-
}
|
|
33
|
-
| {
|
|
34
|
-
readonly operation: "update";
|
|
35
|
-
readonly id: string;
|
|
36
|
-
readonly update: Omit<ReleaseRowUpdate, "revision" | "scope_key">;
|
|
37
|
-
}
|
|
38
|
-
| { readonly operation: "delete"; readonly id: string };
|
|
39
|
-
|
|
40
|
-
export interface ReleaseChangeInput {
|
|
41
|
-
readonly scope: ReleaseCatalogScope;
|
|
42
|
-
readonly change: ReleaseChange;
|
|
43
|
-
/** A deploy's new bundle and its patches, written first. */
|
|
44
|
-
readonly bundle?: {
|
|
45
|
-
readonly row: BundleRow;
|
|
46
|
-
readonly patches: readonly BundlePatchRow[];
|
|
47
|
-
};
|
|
48
|
-
readonly updatedAtMs: number;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export interface ReleaseChangeResult {
|
|
52
|
-
readonly catalog: ReleaseCatalogRow;
|
|
53
|
-
readonly release: ReleaseRow | null;
|
|
54
|
-
readonly diagnostics: ReleaseCatalogCompilation["diagnostics"];
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
const fail = (
|
|
58
|
-
code: ConstructorParameters<typeof ReleaseCatalogMutationError>[0],
|
|
59
|
-
message: string,
|
|
60
|
-
): never => {
|
|
61
|
-
throw new ReleaseCatalogMutationError(code, message);
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
const checkScope = (scope: ReleaseCatalogScope): void => {
|
|
65
|
-
const channelKey = encodeChannelKey(scope.channelName);
|
|
66
|
-
const expected =
|
|
67
|
-
scope.strategy === "APP_VERSION"
|
|
68
|
-
? createReleaseCatalogScopeKey({
|
|
69
|
-
channelKey,
|
|
70
|
-
platform: scope.platform,
|
|
71
|
-
strategy: "APP_VERSION",
|
|
72
|
-
})
|
|
73
|
-
: createReleaseCatalogScopeKey({
|
|
74
|
-
channelKey,
|
|
75
|
-
fingerprintHash: scope.fingerprintHash ?? "",
|
|
76
|
-
platform: scope.platform,
|
|
77
|
-
strategy: "FINGERPRINT",
|
|
78
|
-
});
|
|
79
|
-
if (
|
|
80
|
-
(scope.strategy === "FINGERPRINT") !== (scope.fingerprintHash !== null) ||
|
|
81
|
-
scope.scopeKey !== expected
|
|
82
|
-
) {
|
|
83
|
-
fail("INVALID_SCOPE", "Release catalog scope metadata is inconsistent");
|
|
84
|
-
}
|
|
85
|
-
};
|
|
86
|
-
|
|
87
|
-
/** A scope's enabled releases, all of them, under the catalog's guard. */
|
|
88
|
-
const enabledReleases = async (
|
|
89
|
-
tx: CoreTransaction,
|
|
90
|
-
scopeKey: string,
|
|
91
|
-
): Promise<ReleaseRow[]> => {
|
|
92
|
-
const rows: ReleaseRow[] = [];
|
|
93
|
-
let cursor: string | undefined;
|
|
94
|
-
do {
|
|
95
|
-
const page = await tx.findMany("releases", {
|
|
96
|
-
index: "byScopeEnabled",
|
|
97
|
-
where: { scope_key: scopeKey, enabled: true },
|
|
98
|
-
limit: PAGE,
|
|
99
|
-
...(cursor === undefined ? {} : { cursor }),
|
|
100
|
-
});
|
|
101
|
-
rows.push(...page.rows.map(toReleaseRow));
|
|
102
|
-
cursor = page.next;
|
|
103
|
-
} while (cursor !== undefined);
|
|
104
|
-
return rows;
|
|
105
|
-
};
|
|
106
|
-
|
|
107
|
-
/** The scope's newest release id: `byScope` descending, limit 1. */
|
|
108
|
-
const latestReleaseId = async (tx: CoreTransaction, scopeKey: string) => {
|
|
109
|
-
const { rows } = await tx.findMany("releases", {
|
|
110
|
-
index: "byScope",
|
|
111
|
-
where: { scope_key: scopeKey },
|
|
112
|
-
order: "desc",
|
|
113
|
-
limit: 1,
|
|
114
|
-
});
|
|
115
|
-
return rows[0]?.id ?? null;
|
|
116
|
-
};
|
|
117
|
-
|
|
118
|
-
/** Compiles `enabled` and writes it as the scope's next catalog generation. */
|
|
119
|
-
const writeCatalog = async (
|
|
120
|
-
tx: CoreTransaction,
|
|
121
|
-
scope: ReleaseCatalogScope,
|
|
122
|
-
stored: Awaited<ReturnType<typeof readCatalog>>,
|
|
123
|
-
enabled: readonly ReleaseRow[],
|
|
124
|
-
updatedAtMs: number,
|
|
125
|
-
) => {
|
|
126
|
-
const compilation = await compileReleaseCatalog({
|
|
127
|
-
strategy: scope.strategy,
|
|
128
|
-
releases: enabled.map(releaseRowToRelease),
|
|
129
|
-
});
|
|
130
|
-
const generation = (stored.generation ?? 0) + 1;
|
|
131
|
-
if (!Number.isSafeInteger(generation)) {
|
|
132
|
-
fail(
|
|
133
|
-
"CATALOG_GENERATION_EXHAUSTED",
|
|
134
|
-
`Catalog "${scope.scopeKey}" exhausted its generation counter`,
|
|
135
|
-
);
|
|
136
|
-
}
|
|
137
|
-
const catalog: ReleaseCatalogRow = {
|
|
138
|
-
scope_key: scope.scopeKey,
|
|
139
|
-
catalog_id: stored.catalog?.catalog_id ?? createUUIDv7(),
|
|
140
|
-
strategy: scope.strategy,
|
|
141
|
-
channel_id: scope.channelId,
|
|
142
|
-
channel_key: encodeChannelKey(scope.channelName),
|
|
143
|
-
platform: scope.platform,
|
|
144
|
-
fingerprint_hash: scope.fingerprintHash,
|
|
145
|
-
generation,
|
|
146
|
-
payload: compilation.canonicalPayload,
|
|
147
|
-
catalog_hash: compilation.catalogHash,
|
|
148
|
-
byte_size: compilation.byteSize,
|
|
149
|
-
is_tombstone: compilation.payload.releaseDescriptors.length === 0,
|
|
150
|
-
updated_at_ms: updatedAtMs,
|
|
151
|
-
};
|
|
152
|
-
const { scope_key: _scopeKey, ...set } = catalog;
|
|
153
|
-
if (stored.row === null) tx.create("release_catalogs", catalog);
|
|
154
|
-
else tx.update("release_catalogs", stored.row, set);
|
|
155
|
-
return { catalog, compilation };
|
|
156
|
-
};
|
|
157
|
-
|
|
158
|
-
/** The scope's catalog row, and its compiled catalog and generation if it has one. */
|
|
159
|
-
export const readCatalog = async (tx: CoreTransaction, scopeKey: string) => {
|
|
160
|
-
const row = await tx.findOne("release_catalogs", { scope_key: scopeKey });
|
|
161
|
-
return {
|
|
162
|
-
row,
|
|
163
|
-
generation: row?.generation ?? null,
|
|
164
|
-
catalog: row === null ? null : toCatalogRow(row),
|
|
165
|
-
};
|
|
166
|
-
};
|
|
167
|
-
|
|
168
|
-
/** A scope with releases and no compiled catalog lost its history. */
|
|
169
|
-
const assertHistory = (
|
|
170
|
-
stored: Awaited<ReturnType<typeof readCatalog>>,
|
|
171
|
-
hasReleases: boolean,
|
|
172
|
-
) => {
|
|
173
|
-
if (stored.catalog === null && hasReleases) {
|
|
174
|
-
fail(
|
|
175
|
-
"CATALOG_IDENTITY_MISSING",
|
|
176
|
-
"Catalog history is missing. Restore its catalog row from backup before rebuilding or deploying.",
|
|
177
|
-
);
|
|
178
|
-
}
|
|
179
|
-
};
|
|
180
|
-
|
|
181
|
-
/** One release change and its scope's next catalog, inside `tx`. */
|
|
182
|
-
export const changeRelease = async (
|
|
183
|
-
tx: CoreTransaction,
|
|
184
|
-
{ scope, change, bundle, updatedAtMs }: ReleaseChangeInput,
|
|
185
|
-
): Promise<ReleaseChangeResult> => {
|
|
186
|
-
checkScope(scope);
|
|
187
|
-
const stored = await readCatalog(tx, scope.scopeKey);
|
|
188
|
-
const enabled = await enabledReleases(tx, scope.scopeKey);
|
|
189
|
-
if (bundle !== undefined) {
|
|
190
|
-
insertBundle(tx, bundle.row);
|
|
191
|
-
for (const patch of bundle.patches) tx.create("bundle_patches", patch);
|
|
192
|
-
}
|
|
193
|
-
let before: ReleaseRow | null = null;
|
|
194
|
-
let release: ReleaseRow | null;
|
|
195
|
-
if (change.operation === "insert") {
|
|
196
|
-
const latest = await latestReleaseId(tx, scope.scopeKey);
|
|
197
|
-
assertHistory(stored, latest !== null);
|
|
198
|
-
const floor = [
|
|
199
|
-
latest,
|
|
200
|
-
bundle && isUUIDv7(bundle.row.id) ? bundle.row.id : null,
|
|
201
|
-
]
|
|
202
|
-
.filter((id): id is string => id !== null)
|
|
203
|
-
.sort()
|
|
204
|
-
.at(-1);
|
|
205
|
-
const id = change.row.id ?? createUUIDv7After(floor ?? null);
|
|
206
|
-
if (latest !== null && id <= latest) {
|
|
207
|
-
fail(
|
|
208
|
-
"NON_MONOTONIC_RELEASE_ID",
|
|
209
|
-
`Release "${id}" must sort after "${latest}"`,
|
|
210
|
-
);
|
|
211
|
-
}
|
|
212
|
-
release = { ...change.row, id };
|
|
213
|
-
if (
|
|
214
|
-
release.scope_key !== scope.scopeKey ||
|
|
215
|
-
release.channel_id !== scope.channelId ||
|
|
216
|
-
release.platform !== scope.platform ||
|
|
217
|
-
release.strategy !== scope.strategy ||
|
|
218
|
-
release.fingerprint_hash !== scope.fingerprintHash ||
|
|
219
|
-
release.revision !== 1
|
|
220
|
-
) {
|
|
221
|
-
fail(
|
|
222
|
-
"INVALID_SCOPE",
|
|
223
|
-
"Inserted Release does not match its catalog scope",
|
|
224
|
-
);
|
|
225
|
-
}
|
|
226
|
-
tx.create("releases", release);
|
|
227
|
-
} else {
|
|
228
|
-
const row = await tx.findOne("releases", { id: change.id });
|
|
229
|
-
if (row === null || row.scope_key !== scope.scopeKey) {
|
|
230
|
-
return fail(
|
|
231
|
-
"RELEASE_NOT_FOUND",
|
|
232
|
-
`Release "${change.id}" was not found in scope "${scope.scopeKey}"`,
|
|
233
|
-
);
|
|
234
|
-
}
|
|
235
|
-
assertHistory(stored, true);
|
|
236
|
-
before = toReleaseRow(row);
|
|
237
|
-
if (change.operation === "delete") {
|
|
238
|
-
await tx.delete("releases", row);
|
|
239
|
-
release = null;
|
|
240
|
-
} else {
|
|
241
|
-
const set = { ...change.update, revision: before.revision + 1 };
|
|
242
|
-
tx.update("releases", row, set);
|
|
243
|
-
release = { ...before, ...set };
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
const changedId = before?.id ?? release?.id;
|
|
247
|
-
const next = [
|
|
248
|
-
...enabled.filter(({ id }) => id !== changedId),
|
|
249
|
-
...(release?.enabled ? [release] : []),
|
|
250
|
-
].sort((left, right) => (left.id < right.id ? -1 : 1));
|
|
251
|
-
const { catalog, compilation } = await writeCatalog(
|
|
252
|
-
tx,
|
|
253
|
-
scope,
|
|
254
|
-
stored,
|
|
255
|
-
next,
|
|
256
|
-
updatedAtMs,
|
|
257
|
-
);
|
|
258
|
-
return { catalog, release, diagnostics: compilation.diagnostics };
|
|
259
|
-
};
|
|
260
|
-
|
|
261
|
-
/**
|
|
262
|
-
* Release changes rooted at their catalogs: each reads its scope's catalog
|
|
263
|
-
* and enabled releases, applies the change, and writes the next catalog
|
|
264
|
-
* generation, all in one transaction. A concurrent change in a scope bumps
|
|
265
|
-
* its catalog row, so this transaction reruns instead of publishing a stale
|
|
266
|
-
* catalog.
|
|
267
|
-
*/
|
|
268
|
-
export const changeReleases = (
|
|
269
|
-
db: CoreDatabase,
|
|
270
|
-
inputs: readonly ReleaseChangeInput[],
|
|
271
|
-
): Promise<ReleaseChangeResult[]> => {
|
|
272
|
-
const scopes = new Set(inputs.map(({ scope }) => scope.scopeKey));
|
|
273
|
-
if (scopes.size !== inputs.length) {
|
|
274
|
-
fail("INVALID_SCOPE", "A batch cannot change one catalog scope twice");
|
|
275
|
-
}
|
|
276
|
-
return db.transaction(async (tx) => {
|
|
277
|
-
const results: ReleaseChangeResult[] = [];
|
|
278
|
-
for (const input of inputs) results.push(await changeRelease(tx, input));
|
|
279
|
-
return results;
|
|
280
|
-
});
|
|
281
|
-
};
|
|
282
|
-
|
|
283
|
-
/** Recompiles a scope's catalog from its enabled releases inside `tx`; an unchanged catalog is not rewritten. */
|
|
284
|
-
export const rebuildScope = async (
|
|
285
|
-
tx: CoreTransaction,
|
|
286
|
-
scope: ReleaseCatalogScope,
|
|
287
|
-
updatedAtMs: number,
|
|
288
|
-
): Promise<{
|
|
289
|
-
readonly catalog: ReleaseCatalogRow;
|
|
290
|
-
readonly current: ReleaseCatalogRow | null;
|
|
291
|
-
readonly changed: boolean;
|
|
292
|
-
readonly diagnostics: ReleaseCatalogCompilation["diagnostics"];
|
|
293
|
-
}> => {
|
|
294
|
-
checkScope(scope);
|
|
295
|
-
const stored = await readCatalog(tx, scope.scopeKey);
|
|
296
|
-
assertHistory(stored, (await latestReleaseId(tx, scope.scopeKey)) !== null);
|
|
297
|
-
const enabled = await enabledReleases(tx, scope.scopeKey);
|
|
298
|
-
const compilation = await compileReleaseCatalog({
|
|
299
|
-
strategy: scope.strategy,
|
|
300
|
-
releases: enabled.map(releaseRowToRelease),
|
|
301
|
-
});
|
|
302
|
-
const current = stored.catalog;
|
|
303
|
-
if (
|
|
304
|
-
current !== null &&
|
|
305
|
-
current.strategy === scope.strategy &&
|
|
306
|
-
current.channel_id === scope.channelId &&
|
|
307
|
-
current.channel_key === encodeChannelKey(scope.channelName) &&
|
|
308
|
-
current.platform === scope.platform &&
|
|
309
|
-
current.fingerprint_hash === scope.fingerprintHash &&
|
|
310
|
-
current.catalog_hash === compilation.catalogHash
|
|
311
|
-
) {
|
|
312
|
-
return {
|
|
313
|
-
catalog: current,
|
|
314
|
-
current,
|
|
315
|
-
changed: false,
|
|
316
|
-
diagnostics: compilation.diagnostics,
|
|
317
|
-
};
|
|
318
|
-
}
|
|
319
|
-
const written = await writeCatalog(tx, scope, stored, enabled, updatedAtMs);
|
|
320
|
-
return {
|
|
321
|
-
catalog: written.catalog,
|
|
322
|
-
current,
|
|
323
|
-
changed: true,
|
|
324
|
-
diagnostics: written.compilation.diagnostics,
|
|
325
|
-
};
|
|
326
|
-
};
|
|
327
|
-
|
|
328
|
-
/** Recompiles a scope's catalog from its enabled releases; an unchanged catalog is not rewritten. */
|
|
329
|
-
export const rebuildCatalog = (
|
|
330
|
-
db: CoreDatabase,
|
|
331
|
-
scope: ReleaseCatalogScope,
|
|
332
|
-
updatedAtMs: number,
|
|
333
|
-
): Promise<{
|
|
334
|
-
readonly catalog: ReleaseCatalogRow;
|
|
335
|
-
readonly changed: boolean;
|
|
336
|
-
readonly diagnostics: ReleaseCatalogCompilation["diagnostics"];
|
|
337
|
-
}> =>
|
|
338
|
-
db.transaction(async (tx) => {
|
|
339
|
-
const { current: _current, ...rebuilt } = await rebuildScope(
|
|
340
|
-
tx,
|
|
341
|
-
scope,
|
|
342
|
-
updatedAtMs,
|
|
343
|
-
);
|
|
344
|
-
return rebuilt;
|
|
345
|
-
});
|