@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,479 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
canonicalJson,
|
|
3
|
-
compareUtf8,
|
|
4
|
-
type DatabaseAdapter,
|
|
5
|
-
DatabaseAdapterContractError,
|
|
6
|
-
type DatabaseKey,
|
|
7
|
-
type DatabaseKeyValue,
|
|
8
|
-
DATABASE_VERSION_COLUMN as V,
|
|
9
|
-
expiresAt,
|
|
10
|
-
findPhysicalIndex,
|
|
11
|
-
indexEntries,
|
|
12
|
-
indexOrderColumns,
|
|
13
|
-
indexOrderTuple,
|
|
14
|
-
matchesQuery,
|
|
15
|
-
type PhysicalIndex,
|
|
16
|
-
type PhysicalTable,
|
|
17
|
-
type QueryBound,
|
|
18
|
-
type QueryRequest,
|
|
19
|
-
rowKey,
|
|
20
|
-
type StoredRow,
|
|
21
|
-
type WriteOp,
|
|
22
|
-
type WriteResult,
|
|
23
|
-
} from "@hot-updater/plugin-core/internal";
|
|
24
|
-
|
|
25
|
-
/** An item's address: a partition, and a sort key within it. */
|
|
26
|
-
export interface KvKey {
|
|
27
|
-
readonly pk: string;
|
|
28
|
-
readonly sk: string;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/** What an op requires of its item before the write: that it exists or not, or that its `_v` is `v`. */
|
|
32
|
-
export type KvCondition = { readonly exists: boolean } | { readonly v: number };
|
|
33
|
-
|
|
34
|
-
export type KvOp = {
|
|
35
|
-
readonly key: KvKey;
|
|
36
|
-
readonly condition?: KvCondition;
|
|
37
|
-
/**
|
|
38
|
-
* When a put's or a created item expires, in epoch milliseconds, which
|
|
39
|
-
* the store maps to its native TTL. Every item of a row of a table with
|
|
40
|
-
* retention carries it, index copies included.
|
|
41
|
-
*/
|
|
42
|
-
readonly expiresAt?: number;
|
|
43
|
-
} & (
|
|
44
|
-
| { readonly type: "put"; readonly value: StoredRow }
|
|
45
|
-
| { readonly type: "delete" }
|
|
46
|
-
| { readonly type: "check" }
|
|
47
|
-
/** Adds to numeric attributes, creating the item from `init` when it is missing. */
|
|
48
|
-
| {
|
|
49
|
-
readonly type: "add";
|
|
50
|
-
readonly by: Readonly<Record<string, number>>;
|
|
51
|
-
readonly init?: StoredRow;
|
|
52
|
-
}
|
|
53
|
-
);
|
|
54
|
-
|
|
55
|
-
/** Sort keys from `gte` up to `lt` in one partition, resuming past `after`. */
|
|
56
|
-
export interface KvRange {
|
|
57
|
-
readonly pk: string;
|
|
58
|
-
readonly gte?: string;
|
|
59
|
-
readonly lt?: string;
|
|
60
|
-
/**
|
|
61
|
-
* `lt` as an inclusive bound, with `lt`: every key the helper writes is
|
|
62
|
-
* below `lt` exactly when it is at most `lte`. A store whose two-sided
|
|
63
|
-
* range is inclusive (DynamoDB's `BETWEEN`) uses it to read nothing past
|
|
64
|
-
* the range.
|
|
65
|
-
*/
|
|
66
|
-
readonly lte?: string;
|
|
67
|
-
readonly order: "asc" | "desc";
|
|
68
|
-
readonly limit: number;
|
|
69
|
-
readonly after?: string;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
export interface KvItem {
|
|
73
|
-
readonly sk: string;
|
|
74
|
-
readonly value: StoredRow;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* A key-value backend (DynamoDB, Firestore): strongly consistent point
|
|
79
|
-
* reads, one partition's sort-key range per page, and atomic writes whose
|
|
80
|
-
* conditions all see the state before the write. Sort keys compare as UTF-8.
|
|
81
|
-
*/
|
|
82
|
-
export interface KeyValueStore {
|
|
83
|
-
readonly id: string;
|
|
84
|
-
/**
|
|
85
|
-
* The most items, and bytes, one atomic write takes; `itemBytes` caps each
|
|
86
|
-
* item, and `keyBytes` the partition and sort keys the store indexes whole.
|
|
87
|
-
*/
|
|
88
|
-
readonly limits: {
|
|
89
|
-
readonly items: number;
|
|
90
|
-
readonly bytes: number;
|
|
91
|
-
readonly itemBytes?: number;
|
|
92
|
-
readonly keyBytes?: { readonly pk: number; readonly sk: number };
|
|
93
|
-
};
|
|
94
|
-
get(keys: readonly KvKey[]): Promise<readonly (StoredRow | null)[]>;
|
|
95
|
-
/** One native page; `more` when the range may go on past it. An empty page ends the range. */
|
|
96
|
-
query(
|
|
97
|
-
range: KvRange,
|
|
98
|
-
): Promise<{ readonly items: readonly KvItem[]; readonly more: boolean }>;
|
|
99
|
-
/** Applies every op or none; `failedOp` names an op whose condition failed. */
|
|
100
|
-
write(ops: readonly KvOp[]): Promise<WriteResult>;
|
|
101
|
-
/** Deletes items with no condition and not atomically, a batch at a time. */
|
|
102
|
-
deleteConsumed?(keys: readonly KvKey[]): Promise<void>;
|
|
103
|
-
/** Prepares the store, such as its one table, for `db migrate`. */
|
|
104
|
-
readonly migrations?: { apply(): Promise<void> };
|
|
105
|
-
dispose?(): Promise<void>;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
const SEPARATOR = "\u0001";
|
|
109
|
-
|
|
110
|
-
/** Order-preserving text for key values; each value ends in the lowest code point any encoding uses. */
|
|
111
|
-
export const encodeKvKey = (values: readonly DatabaseKeyValue[]): string =>
|
|
112
|
-
values
|
|
113
|
-
.map((value) => {
|
|
114
|
-
if (typeof value === "boolean") return `${Number(value)}${SEPARATOR}`;
|
|
115
|
-
if (typeof value === "number") {
|
|
116
|
-
// IEEE 754 bits sort as hex once positives flip the sign bit and negatives every bit.
|
|
117
|
-
const view = new DataView(new ArrayBuffer(8));
|
|
118
|
-
view.setFloat64(0, value === 0 ? 0 : value);
|
|
119
|
-
const mask = view.getUint32(0) >>> 31 ? [~0, ~0] : [1 << 31, 0];
|
|
120
|
-
const words = [0, 4].map((at, word) =>
|
|
121
|
-
((view.getUint32(at) ^ mask[word]!) >>> 0)
|
|
122
|
-
.toString(16)
|
|
123
|
-
.padStart(8, "0"),
|
|
124
|
-
);
|
|
125
|
-
return `${words.join("")}${SEPARATOR}`;
|
|
126
|
-
}
|
|
127
|
-
let text = "";
|
|
128
|
-
// U+0000–U+0002 become two code units above the separator, in order.
|
|
129
|
-
for (const char of value) {
|
|
130
|
-
text +=
|
|
131
|
-
char < "\u0003"
|
|
132
|
-
? `\u0002${String.fromCharCode(char.charCodeAt(0) + 1)}`
|
|
133
|
-
: char;
|
|
134
|
-
}
|
|
135
|
-
return `${text}${SEPARATOR}`;
|
|
136
|
-
})
|
|
137
|
-
.join("");
|
|
138
|
-
|
|
139
|
-
/** The first sort key after every key that starts with `prefix`. */
|
|
140
|
-
const pastPrefix = (prefix: string) => `${prefix.slice(0, -1)}\u0002`;
|
|
141
|
-
|
|
142
|
-
/** A unique item's sort key, and an index item's when its order is empty. */
|
|
143
|
-
const ONLY = "#";
|
|
144
|
-
|
|
145
|
-
interface Layout {
|
|
146
|
-
readonly table: PhysicalTable;
|
|
147
|
-
readonly rows: string;
|
|
148
|
-
/** The columns index copies hold: all but `_v` and counters (columns with a default). */
|
|
149
|
-
readonly copied: readonly string[];
|
|
150
|
-
readonly counters: readonly string[];
|
|
151
|
-
/** Indexes with items of their own: unique ones, and those not in key order. */
|
|
152
|
-
readonly indexed: readonly PhysicalIndex[];
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
/** An index whose eq and order columns are the key, in order, reads the row items. */
|
|
156
|
-
const inKeyOrder = (table: PhysicalTable, index: PhysicalIndex) => {
|
|
157
|
-
const columns = [...index.eq, ...indexOrderColumns(table, index)];
|
|
158
|
-
return (
|
|
159
|
-
!index.unique &&
|
|
160
|
-
columns.length === table.key.length &&
|
|
161
|
-
columns.every((column, position) => column === table.key[position])
|
|
162
|
-
);
|
|
163
|
-
};
|
|
164
|
-
|
|
165
|
-
const same = (left: StoredRow, right: StoredRow, columns: readonly string[]) =>
|
|
166
|
-
columns.every(
|
|
167
|
-
(name) => canonicalJson(left[name]) === canonicalJson(right[name]),
|
|
168
|
-
);
|
|
169
|
-
|
|
170
|
-
type Planned = { readonly op: KvOp; readonly origin: number };
|
|
171
|
-
|
|
172
|
-
export interface KvAdapterOptions {
|
|
173
|
-
readonly store: KeyValueStore;
|
|
174
|
-
readonly tablePrefix?: string;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
/**
|
|
178
|
-
* The storage adapter over a key-value store. A row is one item at
|
|
179
|
-
* `pk = <table>`, `sk = enc(key)`; each index not in key order adds an item
|
|
180
|
-
* per entry at `pk = <table>#<index>#enc(eq)`, `sk = enc(order)`, and each
|
|
181
|
-
* unique entry one item at `sk = "#"`, written only where no other row holds
|
|
182
|
-
* it. Index items hold a copy of the row without `_v` or counters, so an
|
|
183
|
-
* increment, which changes only those, never makes them stale.
|
|
184
|
-
*/
|
|
185
|
-
export const createKvAdapter = ({
|
|
186
|
-
store,
|
|
187
|
-
tablePrefix = "",
|
|
188
|
-
}: KvAdapterOptions): DatabaseAdapter => {
|
|
189
|
-
const layouts = new WeakMap<PhysicalTable, Layout>();
|
|
190
|
-
const layoutOf = (table: PhysicalTable): Layout => {
|
|
191
|
-
const known = layouts.get(table);
|
|
192
|
-
if (known) return known;
|
|
193
|
-
const counters = table.columns
|
|
194
|
-
.filter((column) => column.default !== undefined && column.name !== V)
|
|
195
|
-
.map((column) => column.name);
|
|
196
|
-
const layout = {
|
|
197
|
-
table,
|
|
198
|
-
rows: tablePrefix + table.name,
|
|
199
|
-
copied: table.columns
|
|
200
|
-
.map((column) => column.name)
|
|
201
|
-
.filter((name) => name !== V && !counters.includes(name)),
|
|
202
|
-
counters,
|
|
203
|
-
indexed: table.indexes.filter((index) => !inKeyOrder(table, index)),
|
|
204
|
-
};
|
|
205
|
-
layouts.set(table, layout);
|
|
206
|
-
return layout;
|
|
207
|
-
};
|
|
208
|
-
const rowItem = (layout: Layout, key: DatabaseKey): KvKey => ({
|
|
209
|
-
pk: layout.rows,
|
|
210
|
-
sk: encodeKvKey(key),
|
|
211
|
-
});
|
|
212
|
-
const partition = (layout: Layout, index: PhysicalIndex, eq: DatabaseKey) =>
|
|
213
|
-
`${layout.rows}#${index.name}#${encodeKvKey(eq)}`;
|
|
214
|
-
const copyOf = (layout: Layout, row: StoredRow): StoredRow =>
|
|
215
|
-
Object.fromEntries(layout.copied.map((name) => [name, row[name] ?? null]));
|
|
216
|
-
/** The expiry every item of `row` carries, for a table with retention. */
|
|
217
|
-
const stamp = (table: PhysicalTable, row: StoredRow | undefined) => {
|
|
218
|
-
const at = row && expiresAt(table, row);
|
|
219
|
-
return at === undefined ? {} : { expiresAt: at };
|
|
220
|
-
};
|
|
221
|
-
|
|
222
|
-
/** Every index and unique item a row has, by address. */
|
|
223
|
-
const itemsOf = (layout: Layout, row: StoredRow | null) => {
|
|
224
|
-
const items = new Map<string, { key: KvKey; unique: boolean }>();
|
|
225
|
-
for (const index of row === null ? [] : layout.indexed) {
|
|
226
|
-
for (const eq of indexEntries(layout.table, index, row!)) {
|
|
227
|
-
const pk = partition(layout, index, eq);
|
|
228
|
-
const sk = index.unique
|
|
229
|
-
? ONLY
|
|
230
|
-
: encodeKvKey(indexOrderTuple(layout.table, index, row!)) || ONLY;
|
|
231
|
-
items.set(JSON.stringify([pk, sk]), {
|
|
232
|
-
key: { pk, sk },
|
|
233
|
-
unique: index.unique === true,
|
|
234
|
-
});
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
return items;
|
|
238
|
-
};
|
|
239
|
-
|
|
240
|
-
/** Moves a row's index items from `before` to `after`; a unique entry is taken only where no row holds it. */
|
|
241
|
-
const indexOps = (
|
|
242
|
-
layout: Layout,
|
|
243
|
-
before: StoredRow | null,
|
|
244
|
-
after: StoredRow | null,
|
|
245
|
-
): KvOp[] => {
|
|
246
|
-
const old = itemsOf(layout, before);
|
|
247
|
-
const next = itemsOf(layout, after);
|
|
248
|
-
const ops: KvOp[] = [...old]
|
|
249
|
-
.filter(([id]) => !next.has(id))
|
|
250
|
-
.map(([, item]) => ({ type: "delete", key: item.key }));
|
|
251
|
-
const copy = after && copyOf(layout, after);
|
|
252
|
-
const unchanged =
|
|
253
|
-
before !== null && copy !== null && same(before, copy, layout.copied);
|
|
254
|
-
for (const [id, item] of next) {
|
|
255
|
-
if (old.has(id) && unchanged) continue;
|
|
256
|
-
const taken = item.unique && !old.has(id);
|
|
257
|
-
ops.push({
|
|
258
|
-
type: "put",
|
|
259
|
-
key: item.key,
|
|
260
|
-
value: copy!,
|
|
261
|
-
condition: taken ? { exists: false } : undefined,
|
|
262
|
-
...stamp(layout.table, after!),
|
|
263
|
-
});
|
|
264
|
-
}
|
|
265
|
-
return ops;
|
|
266
|
-
};
|
|
267
|
-
|
|
268
|
-
/** The item ops of one adapter op: its row item first, then its index items. */
|
|
269
|
-
const plan = (op: WriteOp): KvOp[] => {
|
|
270
|
-
const layout = layoutOf(op.table);
|
|
271
|
-
const key = rowItem(
|
|
272
|
-
layout,
|
|
273
|
-
op.type === "insert" ? rowKey(op.table, op.row) : op.key,
|
|
274
|
-
);
|
|
275
|
-
const guard = op.type === "insert" ? { exists: false } : op.guard;
|
|
276
|
-
const condition = guard && ("v" in guard ? { v: guard.v } : guard);
|
|
277
|
-
switch (op.type) {
|
|
278
|
-
case "check":
|
|
279
|
-
return [{ type: "check", key, condition }];
|
|
280
|
-
case "increment":
|
|
281
|
-
if (
|
|
282
|
-
layout.indexed.length > 0 &&
|
|
283
|
-
(op.init !== undefined ||
|
|
284
|
-
Object.keys(op.by).some((name) => layout.copied.includes(name)))
|
|
285
|
-
) {
|
|
286
|
-
throw new DatabaseAdapterContractError(
|
|
287
|
-
`${op.table.name} has index copies: an increment may change only counters of an existing row.`,
|
|
288
|
-
);
|
|
289
|
-
}
|
|
290
|
-
return [
|
|
291
|
-
{
|
|
292
|
-
type: "add",
|
|
293
|
-
key,
|
|
294
|
-
by: { ...op.by, [V]: 1 },
|
|
295
|
-
init: op.init,
|
|
296
|
-
condition: condition ?? (op.init ? undefined : { exists: true }),
|
|
297
|
-
...stamp(op.table, op.init),
|
|
298
|
-
},
|
|
299
|
-
];
|
|
300
|
-
case "delete":
|
|
301
|
-
return [
|
|
302
|
-
{ type: "delete", key, condition },
|
|
303
|
-
...indexOps(layout, op.previous, null),
|
|
304
|
-
];
|
|
305
|
-
default: {
|
|
306
|
-
const before = op.type === "insert" ? null : op.previous;
|
|
307
|
-
const row =
|
|
308
|
-
op.type === "insert"
|
|
309
|
-
? op.row
|
|
310
|
-
: { ...op.previous, ...op.set, [V]: op.guard.v + 1 };
|
|
311
|
-
return [
|
|
312
|
-
{ type: "put", key, value: row, condition, ...stamp(op.table, row) },
|
|
313
|
-
...indexOps(layout, before, row),
|
|
314
|
-
];
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
};
|
|
318
|
-
|
|
319
|
-
/**
|
|
320
|
-
* One op per item. Only unique items of two rows can meet: one op frees
|
|
321
|
-
* the value and another takes it. That becomes one unconditional put, as
|
|
322
|
-
* the freeing op's guard already holds the value's owner. Two rows taking
|
|
323
|
-
* one value fail at the later op.
|
|
324
|
-
*/
|
|
325
|
-
const compile = (ops: readonly WriteOp[]) => {
|
|
326
|
-
const items = new Map<string, Planned>();
|
|
327
|
-
for (const [origin, op] of ops.entries()) {
|
|
328
|
-
for (const kv of plan(op)) {
|
|
329
|
-
const id = JSON.stringify([kv.key.pk, kv.key.sk]);
|
|
330
|
-
const earlier = items.get(id);
|
|
331
|
-
const put = [earlier, { op: kv, origin }].find(
|
|
332
|
-
(planned) => planned?.op.type === "put",
|
|
333
|
-
);
|
|
334
|
-
if (earlier === undefined) {
|
|
335
|
-
items.set(id, { op: kv, origin });
|
|
336
|
-
} else if (
|
|
337
|
-
put?.op.type === "put" &&
|
|
338
|
-
[earlier.op, kv].some(({ type }) => type === "delete")
|
|
339
|
-
) {
|
|
340
|
-
items.set(id, { op: { ...put.op, condition: undefined }, origin });
|
|
341
|
-
} else {
|
|
342
|
-
return { failedOp: origin };
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
return { items: [...items.values()] };
|
|
347
|
-
};
|
|
348
|
-
|
|
349
|
-
const encoder = new TextEncoder();
|
|
350
|
-
const sizeOf = ({ op }: Planned) =>
|
|
351
|
-
encoder.encode(
|
|
352
|
-
op.key.pk +
|
|
353
|
-
op.key.sk +
|
|
354
|
-
JSON.stringify(
|
|
355
|
-
op.type === "put" ? op.value : op.type === "add" ? op.init : null,
|
|
356
|
-
),
|
|
357
|
-
).length;
|
|
358
|
-
|
|
359
|
-
/** Fills counters from the rows; a row that still equals its copy is returned whole, `_v` included. */
|
|
360
|
-
const complete = async (layout: Layout, copies: readonly StoredRow[]) => {
|
|
361
|
-
if (layout.counters.length === 0 || copies.length === 0) return copies;
|
|
362
|
-
const rows = await store.get(
|
|
363
|
-
copies.map((copy) => rowItem(layout, rowKey(layout.table, copy))),
|
|
364
|
-
);
|
|
365
|
-
return copies.map((copy, at) => {
|
|
366
|
-
const row = rows[at];
|
|
367
|
-
if (row && same(row, copy, layout.copied)) return row;
|
|
368
|
-
const counters = layout.counters.map((name) => [name, row?.[name] ?? 0]);
|
|
369
|
-
return { ...copy, ...Object.fromEntries(counters) };
|
|
370
|
-
});
|
|
371
|
-
};
|
|
372
|
-
|
|
373
|
-
/**
|
|
374
|
-
* A request's sort keys within its partition, from `gte` up to `lt`; null
|
|
375
|
-
* when none can match. Every encoding ends in the separator, so the keys
|
|
376
|
-
* that start with a prefix end right before `pastPrefix` of it.
|
|
377
|
-
*/
|
|
378
|
-
const rangeOf = (prefix: string, request: QueryRequest) => {
|
|
379
|
-
const edge = (bound: QueryBound | undefined, lower: boolean) => {
|
|
380
|
-
if (bound === undefined) {
|
|
381
|
-
return prefix === "" ? undefined : lower ? prefix : pastPrefix(prefix);
|
|
382
|
-
}
|
|
383
|
-
const text = prefix + encodeKvKey(bound.values);
|
|
384
|
-
if (text === "") return bound.inclusive ? undefined : null;
|
|
385
|
-
return lower === bound.inclusive ? text : pastPrefix(text);
|
|
386
|
-
};
|
|
387
|
-
const gte = edge(request.lower, true);
|
|
388
|
-
const lt = edge(request.upper, false);
|
|
389
|
-
if (gte === null || lt === null) return null;
|
|
390
|
-
// Bounds that cross leave nothing, and DynamoDB refuses them.
|
|
391
|
-
if (gte !== undefined && lt !== undefined && compareUtf8(gte, lt) >= 0) {
|
|
392
|
-
return null;
|
|
393
|
-
}
|
|
394
|
-
if (lt === undefined) return { gte, lt };
|
|
395
|
-
// No key holds U+0000, so none sorts between an `lt` without its final
|
|
396
|
-
// separator and `lt`; and no key ends in U+0002, so an `lt` from
|
|
397
|
-
// `pastPrefix` is never a key itself.
|
|
398
|
-
return { gte, lt, lte: lt.endsWith(SEPARATOR) ? lt.slice(0, -1) : lt };
|
|
399
|
-
};
|
|
400
|
-
|
|
401
|
-
return {
|
|
402
|
-
id: store.id,
|
|
403
|
-
fits(ops) {
|
|
404
|
-
const { items } = compile(ops);
|
|
405
|
-
// A write in which two rows take one unique value fails at its op, not here.
|
|
406
|
-
if (items === undefined) return true;
|
|
407
|
-
const { items: most, bytes, itemBytes = bytes, keyBytes } = store.limits;
|
|
408
|
-
const sizes = items.map(sizeOf);
|
|
409
|
-
const length = (text: string) => encoder.encode(text).length;
|
|
410
|
-
return (
|
|
411
|
-
items.length <= most &&
|
|
412
|
-
sizes.reduce((sum, size) => sum + size, 0) <= bytes &&
|
|
413
|
-
sizes.every((size) => size <= itemBytes) &&
|
|
414
|
-
(keyBytes === undefined ||
|
|
415
|
-
items.every(
|
|
416
|
-
({ op }) =>
|
|
417
|
-
length(op.key.pk) <= keyBytes.pk &&
|
|
418
|
-
length(op.key.sk) <= keyBytes.sk,
|
|
419
|
-
))
|
|
420
|
-
);
|
|
421
|
-
},
|
|
422
|
-
get: (table, keys) =>
|
|
423
|
-
store.get(keys.map((key) => rowItem(layoutOf(table), key))),
|
|
424
|
-
async query(table, request) {
|
|
425
|
-
const layout = layoutOf(table);
|
|
426
|
-
const index = findPhysicalIndex(table, request.index);
|
|
427
|
-
if (index.unique) {
|
|
428
|
-
const key = { pk: partition(layout, index, request.eq), sk: ONLY };
|
|
429
|
-
const [copy] = await store.get([key]);
|
|
430
|
-
const found = copy && matchesQuery(table, index, request, copy);
|
|
431
|
-
return complete(layout, found ? [copy] : []);
|
|
432
|
-
}
|
|
433
|
-
const own = inKeyOrder(table, index);
|
|
434
|
-
const range = rangeOf(own ? encodeKvKey(request.eq) : "", request);
|
|
435
|
-
if (range === null) return [];
|
|
436
|
-
const pk = own ? layout.rows : partition(layout, index, request.eq);
|
|
437
|
-
const rows: StoredRow[] = [];
|
|
438
|
-
let after: string | undefined;
|
|
439
|
-
// Native pages are capped (DynamoDB: 1 MB), so read on until the limit or the range's end.
|
|
440
|
-
while (rows.length < request.limit) {
|
|
441
|
-
const { items, more } = await store.query({
|
|
442
|
-
pk,
|
|
443
|
-
...range,
|
|
444
|
-
order: request.order,
|
|
445
|
-
limit: request.limit - rows.length,
|
|
446
|
-
after,
|
|
447
|
-
});
|
|
448
|
-
rows.push(...items.map((item) => item.value));
|
|
449
|
-
if (!more || items.length === 0) break;
|
|
450
|
-
after = items.at(-1)!.sk;
|
|
451
|
-
}
|
|
452
|
-
return own ? rows : complete(layout, rows);
|
|
453
|
-
},
|
|
454
|
-
async write(ops) {
|
|
455
|
-
const { items, failedOp } = compile(ops);
|
|
456
|
-
if (items === undefined) return { ok: false, failedOp };
|
|
457
|
-
const result = await store.write(items.map(({ op }) => op));
|
|
458
|
-
return !result.ok && "failedOp" in result
|
|
459
|
-
? { ok: false, failedOp: items[result.failedOp]!.origin }
|
|
460
|
-
: result;
|
|
461
|
-
},
|
|
462
|
-
...(store.deleteConsumed === undefined
|
|
463
|
-
? {}
|
|
464
|
-
: {
|
|
465
|
-
deleteConsumed: (table, rows) => {
|
|
466
|
-
const layout = layoutOf(table);
|
|
467
|
-
return store.deleteConsumed!(
|
|
468
|
-
rows.flatMap((row) => [
|
|
469
|
-
rowItem(layout, rowKey(table, row)),
|
|
470
|
-
...[...itemsOf(layout, row).values()].map(({ key }) => key),
|
|
471
|
-
]),
|
|
472
|
-
);
|
|
473
|
-
},
|
|
474
|
-
}),
|
|
475
|
-
// Tables need no items of their own; the store prepares itself, if at all.
|
|
476
|
-
migrations: { apply: async () => store.migrations?.apply() },
|
|
477
|
-
...(store.dispose === undefined ? {} : { dispose: () => store.dispose!() }),
|
|
478
|
-
};
|
|
479
|
-
};
|
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
compareUtf8,
|
|
3
|
-
DATABASE_VERSION_COLUMN,
|
|
4
|
-
type StoredRow,
|
|
5
|
-
} from "@hot-updater/plugin-core/internal";
|
|
6
|
-
|
|
7
|
-
import type { KeyValueStore, KvCondition, KvKey } from "./kvAdapter";
|
|
8
|
-
|
|
9
|
-
export interface MemoryKeyValueStoreOptions {
|
|
10
|
-
/** Test-only: the most items one `query` page returns. */
|
|
11
|
-
readonly nativePageSize?: number;
|
|
12
|
-
readonly limits?: KeyValueStore["limits"];
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* An in-memory key-value store that behaves like DynamoDB where the adapter
|
|
17
|
-
* can tell: a write checks every condition against the state before it,
|
|
18
|
-
* refuses two ops on one item, and applies all ops or none.
|
|
19
|
-
*/
|
|
20
|
-
export const createMemoryKeyValueStore = (
|
|
21
|
-
options: MemoryKeyValueStoreOptions = {},
|
|
22
|
-
): KeyValueStore & {
|
|
23
|
-
readonly items: () => number;
|
|
24
|
-
/** Each item's expiry, as a store's native TTL would hold it, by `[pk, sk]` JSON. */
|
|
25
|
-
readonly expiries: () => ReadonlyMap<string, number>;
|
|
26
|
-
} => {
|
|
27
|
-
let partitions = new Map<string, Map<string, StoredRow>>();
|
|
28
|
-
let expiries = new Map<string, number>();
|
|
29
|
-
const read = (key: KvKey) => partitions.get(key.pk)?.get(key.sk) ?? null;
|
|
30
|
-
const holds = (key: KvKey, condition: KvCondition | undefined) => {
|
|
31
|
-
if (condition === undefined) return true;
|
|
32
|
-
const item = read(key);
|
|
33
|
-
return "v" in condition
|
|
34
|
-
? item !== null && item[DATABASE_VERSION_COLUMN] === condition.v
|
|
35
|
-
: (item !== null) === condition.exists;
|
|
36
|
-
};
|
|
37
|
-
return {
|
|
38
|
-
id: "memory-kv",
|
|
39
|
-
limits: options.limits ?? { items: 100, bytes: 4_000_000 },
|
|
40
|
-
items: () =>
|
|
41
|
-
[...partitions.values()].reduce((sum, items) => sum + items.size, 0),
|
|
42
|
-
expiries: () => expiries,
|
|
43
|
-
async get(keys) {
|
|
44
|
-
return keys.map((key) => structuredClone(read(key)));
|
|
45
|
-
},
|
|
46
|
-
async query({ pk, gte, lt, order, limit, after }) {
|
|
47
|
-
const direction = order === "asc" ? 1 : -1;
|
|
48
|
-
const matching = [...(partitions.get(pk) ?? new Map<string, StoredRow>())]
|
|
49
|
-
.filter(
|
|
50
|
-
([sk]) =>
|
|
51
|
-
(gte === undefined || compareUtf8(sk, gte) >= 0) &&
|
|
52
|
-
(lt === undefined || compareUtf8(sk, lt) < 0) &&
|
|
53
|
-
(after === undefined || direction * compareUtf8(sk, after) > 0),
|
|
54
|
-
)
|
|
55
|
-
.sort(([left], [right]) => direction * compareUtf8(left, right));
|
|
56
|
-
const size = Math.min(limit, options.nativePageSize ?? limit);
|
|
57
|
-
return {
|
|
58
|
-
items: matching
|
|
59
|
-
.slice(0, size)
|
|
60
|
-
.map(([sk, value]) => ({ sk, value: structuredClone(value) })),
|
|
61
|
-
more: matching.length > size,
|
|
62
|
-
};
|
|
63
|
-
},
|
|
64
|
-
async write(ops) {
|
|
65
|
-
const ids = new Set(ops.map(({ key }) => JSON.stringify(key)));
|
|
66
|
-
if (ids.size !== ops.length) {
|
|
67
|
-
throw new Error("A write may touch each item once.");
|
|
68
|
-
}
|
|
69
|
-
const failed = ops.findIndex((op) => !holds(op.key, op.condition));
|
|
70
|
-
if (failed !== -1) return { ok: false, failedOp: failed };
|
|
71
|
-
const next = new Map(partitions);
|
|
72
|
-
const stamped = new Map(expiries);
|
|
73
|
-
for (const op of ops) {
|
|
74
|
-
if (op.type === "check") continue;
|
|
75
|
-
const items = new Map(next.get(op.key.pk));
|
|
76
|
-
next.set(op.key.pk, items);
|
|
77
|
-
const id = JSON.stringify([op.key.pk, op.key.sk]);
|
|
78
|
-
if (op.type === "delete") {
|
|
79
|
-
items.delete(op.key.sk);
|
|
80
|
-
stamped.delete(id);
|
|
81
|
-
} else if (op.type === "put") {
|
|
82
|
-
items.set(op.key.sk, structuredClone(op.value));
|
|
83
|
-
// A put replaces the whole item, and any expiry it had.
|
|
84
|
-
if (op.expiresAt === undefined) stamped.delete(id);
|
|
85
|
-
else stamped.set(id, op.expiresAt);
|
|
86
|
-
} else {
|
|
87
|
-
if (!items.has(op.key.sk) && op.expiresAt !== undefined) {
|
|
88
|
-
stamped.set(id, op.expiresAt);
|
|
89
|
-
}
|
|
90
|
-
const item: Record<string, unknown> = structuredClone(
|
|
91
|
-
items.get(op.key.sk) ?? op.init ?? {},
|
|
92
|
-
);
|
|
93
|
-
for (const [name, delta] of Object.entries(op.by)) {
|
|
94
|
-
item[name] = Number(item[name] ?? 0) + delta;
|
|
95
|
-
}
|
|
96
|
-
items.set(op.key.sk, item as StoredRow);
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
partitions = next;
|
|
100
|
-
expiries = stamped;
|
|
101
|
-
return { ok: true };
|
|
102
|
-
},
|
|
103
|
-
async deleteConsumed(keys) {
|
|
104
|
-
const next = new Map(partitions);
|
|
105
|
-
for (const { pk, sk } of keys) {
|
|
106
|
-
const items = new Map(next.get(pk));
|
|
107
|
-
items.delete(sk);
|
|
108
|
-
next.set(pk, items);
|
|
109
|
-
expiries.delete(JSON.stringify([pk, sk]));
|
|
110
|
-
}
|
|
111
|
-
partitions = next;
|
|
112
|
-
},
|
|
113
|
-
async dispose() {
|
|
114
|
-
partitions = new Map();
|
|
115
|
-
expiries = new Map();
|
|
116
|
-
},
|
|
117
|
-
};
|
|
118
|
-
};
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { createMemoryAdapter } from "@hot-updater/plugin-core/internal";
|
|
2
|
-
import { setupReadBudgetTestSuite } from "@hot-updater/test-utils";
|
|
3
|
-
|
|
4
|
-
import { readBudgetServer } from "../readBudgets.testFixtures";
|
|
5
|
-
|
|
6
|
-
/** The reference adapter, with the native page size the suite sets. */
|
|
7
|
-
setupReadBudgetTestSuite({
|
|
8
|
-
name: "memory",
|
|
9
|
-
server: readBudgetServer,
|
|
10
|
-
createAdapter: async ({ nativePageSize }) => ({
|
|
11
|
-
adapter: createMemoryAdapter({ nativePageSize }),
|
|
12
|
-
}),
|
|
13
|
-
});
|