@mistriwork/engine 0.0.0-stage → 1.0.0-rc.10
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 +21 -0
- package/README.md +17 -2
- package/dist/adapters/adapter.d.ts +693 -0
- package/dist/adapters/adapter.js +444 -0
- package/dist/adapters/cache/cacheStore.d.ts +75 -0
- package/dist/adapters/cache/cacheStore.js +160 -0
- package/dist/adapters/cache/resp.d.ts +52 -0
- package/dist/adapters/cache/resp.js +237 -0
- package/dist/adapters/commands/canonicalJson.d.ts +19 -0
- package/dist/adapters/commands/canonicalJson.js +154 -0
- package/dist/adapters/connect.d.ts +29 -0
- package/dist/adapters/connect.js +40 -0
- package/dist/adapters/connectionBudget.d.ts +101 -0
- package/dist/adapters/connectionBudget.js +128 -0
- package/dist/adapters/dbLatency.d.ts +35 -0
- package/dist/adapters/dbLatency.js +79 -0
- package/dist/adapters/epochCache.d.ts +50 -0
- package/dist/adapters/epochCache.js +85 -0
- package/dist/adapters/http/egress.d.ts +48 -0
- package/dist/adapters/http/egress.js +175 -0
- package/dist/adapters/http/httpAdapter.d.ts +71 -0
- package/dist/adapters/http/httpAdapter.js +512 -0
- package/dist/adapters/http/httpDescription.d.ts +32 -0
- package/dist/adapters/http/httpDescription.js +246 -0
- package/dist/adapters/http/openapi.d.ts +98 -0
- package/dist/adapters/http/openapi.js +487 -0
- package/dist/adapters/layoutRefusal.d.ts +24 -0
- package/dist/adapters/layoutRefusal.js +35 -0
- package/dist/adapters/net/networkPolicy.d.ts +44 -0
- package/dist/adapters/net/networkPolicy.js +123 -0
- package/dist/adapters/net/untrustedDatabase.d.ts +18 -0
- package/dist/adapters/net/untrustedDatabase.js +120 -0
- package/dist/adapters/poolAdmission.d.ts +43 -0
- package/dist/adapters/poolAdmission.js +184 -0
- package/dist/adapters/poolMetrics.d.ts +121 -0
- package/dist/adapters/poolMetrics.js +185 -0
- package/dist/adapters/postgres.d.ts +436 -0
- package/dist/adapters/postgres.js +1890 -0
- package/dist/adapters/postgresCatalog.d.ts +96 -0
- package/dist/adapters/postgresCatalog.js +387 -0
- package/dist/adapters/postgresCatalogDigest.d.ts +30 -0
- package/dist/adapters/postgresCatalogDigest.js +87 -0
- package/dist/adapters/postgresCatalogRows.d.ts +62 -0
- package/dist/adapters/postgresCatalogRows.js +37 -0
- package/dist/adapters/postgresDates.d.ts +1 -0
- package/dist/adapters/postgresDates.js +39 -0
- package/dist/adapters/postgresMaintenance.d.ts +33 -0
- package/dist/adapters/postgresMaintenance.js +179 -0
- package/dist/adapters/postgresPool.d.ts +255 -0
- package/dist/adapters/postgresPool.js +838 -0
- package/dist/adapters/postgresPooler.d.ts +28 -0
- package/dist/adapters/postgresPooler.js +267 -0
- package/dist/adapters/postgresReadCatalog.d.ts +31 -0
- package/dist/adapters/postgresReadCatalog.js +226 -0
- package/dist/adapters/postgresReadSnapshot.d.ts +46 -0
- package/dist/adapters/postgresReadSnapshot.js +133 -0
- package/dist/adapters/postgresSchemaEpoch.d.ts +24 -0
- package/dist/adapters/postgresSchemaEpoch.js +149 -0
- package/dist/adapters/postgresTransactionHandle.d.ts +173 -0
- package/dist/adapters/postgresTransactionHandle.js +524 -0
- package/dist/adapters/postgresValues.d.ts +30 -0
- package/dist/adapters/postgresValues.js +75 -0
- package/dist/adapters/replicas.d.ts +70 -0
- package/dist/adapters/replicas.js +208 -0
- package/dist/adapters/reservedSql.d.ts +38 -0
- package/dist/adapters/reservedSql.js +264 -0
- package/dist/adapters/rolePrivileges.d.ts +17 -0
- package/dist/adapters/rolePrivileges.js +22 -0
- package/dist/adapters/scoped/keyRows.d.ts +65 -0
- package/dist/adapters/scoped/keyRows.js +173 -0
- package/dist/adapters/scoped/postgresScopeCatalog.d.ts +16 -0
- package/dist/adapters/scoped/postgresScopeCatalog.js +117 -0
- package/dist/adapters/scoped/scopedCommandOperations.d.ts +5 -0
- package/dist/adapters/scoped/scopedCommandOperations.js +48 -0
- package/dist/adapters/scoped/scopedReads.d.ts +20 -0
- package/dist/adapters/scoped/scopedReads.js +174 -0
- package/dist/adapters/scoped/scopedTransaction.d.ts +89 -0
- package/dist/adapters/scoped/scopedTransaction.js +303 -0
- package/dist/adapters/scoped/sqliteScopeCatalog.d.ts +16 -0
- package/dist/adapters/scoped/sqliteScopeCatalog.js +241 -0
- package/dist/adapters/scoped/updateGuard.d.ts +3 -0
- package/dist/adapters/scoped/updateGuard.js +40 -0
- package/dist/adapters/serverSettings.d.ts +45 -0
- package/dist/adapters/serverSettings.js +46 -0
- package/dist/adapters/sqlite.d.ts +262 -0
- package/dist/adapters/sqlite.js +1434 -0
- package/dist/adapters/sqliteCostlyReads.d.ts +33 -0
- package/dist/adapters/sqliteCostlyReads.js +49 -0
- package/dist/adapters/sqliteDecimals.d.ts +22 -0
- package/dist/adapters/sqliteDecimals.js +57 -0
- package/dist/adapters/sqliteHandles.d.ts +43 -0
- package/dist/adapters/sqliteHandles.js +143 -0
- package/dist/adapters/sqliteStatementProcess.d.ts +29 -0
- package/dist/adapters/sqliteStatementProcess.js +131 -0
- package/dist/adapters/statementControl.d.ts +34 -0
- package/dist/adapters/statementControl.js +90 -0
- package/dist/adapters/storeHost.d.ts +130 -0
- package/dist/adapters/storeHost.js +13 -0
- package/dist/adapters/telemetry/drivers.d.ts +21 -0
- package/dist/adapters/telemetry/drivers.js +321 -0
- package/dist/adapters/telemetry/metrics.d.ts +63 -0
- package/dist/adapters/telemetry/metrics.js +122 -0
- package/dist/adapters/telemetry/otlp.d.ts +12 -0
- package/dist/adapters/telemetry/otlp.js +320 -0
- package/dist/adapters/telemetry/otlpEncode.d.ts +48 -0
- package/dist/adapters/telemetry/otlpEncode.js +366 -0
- package/dist/adapters/telemetry/otlpEnv.d.ts +1 -0
- package/dist/adapters/telemetry/otlpEnv.js +12 -0
- package/dist/adapters/telemetry/serverTiming.d.ts +83 -0
- package/dist/adapters/telemetry/serverTiming.js +503 -0
- package/dist/adapters/telemetry/start.d.ts +10 -0
- package/dist/adapters/telemetry/start.js +25 -0
- package/dist/adapters/telemetry/statement.d.ts +16 -0
- package/dist/adapters/telemetry/statement.js +134 -0
- package/dist/adapters/telemetry/trace.d.ts +127 -0
- package/dist/adapters/telemetry/trace.js +295 -0
- package/dist/adapters/writeAhead.d.ts +27 -0
- package/dist/adapters/writeAhead.js +46 -0
- package/dist/adapters/writeAttribution.d.ts +18 -0
- package/dist/adapters/writeAttribution.js +23 -0
- package/dist/adapters/writeCapture.d.ts +73 -0
- package/dist/adapters/writeCapture.js +20 -0
- package/dist/adapters/writeLanes.d.ts +94 -0
- package/dist/adapters/writeLanes.js +232 -0
- package/dist/engine.d.ts +15 -0
- package/dist/engine.js +13 -0
- package/dist/server/auth/credentials.d.ts +61 -0
- package/dist/server/auth/credentials.js +260 -0
- package/dist/server/cacheService.d.ts +50 -0
- package/dist/server/cacheService.js +110 -0
- package/dist/server/cli/args.d.ts +176 -0
- package/dist/server/cli/args.js +342 -0
- package/dist/server/cli/bin.d.ts +5 -0
- package/dist/server/cli/bin.js +66 -0
- package/dist/server/cli/browser.d.ts +15 -0
- package/dist/server/cli/browser.js +37 -0
- package/dist/server/cli/config.d.ts +50 -0
- package/dist/server/cli/config.js +206 -0
- package/dist/server/cli/startup.d.ts +36 -0
- package/dist/server/cli/startup.js +128 -0
- package/dist/server/cli/startupOptions.d.ts +63 -0
- package/dist/server/cli/startupOptions.js +143 -0
- package/dist/server/cli/subcommand.d.ts +28 -0
- package/dist/server/cli/subcommand.js +32 -0
- package/dist/server/cli/usage.d.ts +13 -0
- package/dist/server/cli/usage.js +31 -0
- package/dist/server/clientHttp.d.ts +184 -0
- package/dist/server/clientHttp.js +700 -0
- package/dist/server/clientSurface.d.ts +128 -0
- package/dist/server/clientSurface.js +182 -0
- package/dist/server/columnGrants.d.ts +103 -0
- package/dist/server/columnGrants.js +730 -0
- package/dist/server/compileCache.d.ts +1 -0
- package/dist/server/compileCache.js +30 -0
- package/dist/server/config/locations.d.ts +1 -0
- package/dist/server/config/locations.js +15 -0
- package/dist/server/configPaths.d.ts +7 -0
- package/dist/server/configPaths.js +34 -0
- package/dist/server/configSections.d.ts +64 -0
- package/dist/server/configSections.js +72 -0
- package/dist/server/connectionRedaction.d.ts +30 -0
- package/dist/server/connectionRedaction.js +77 -0
- package/dist/server/connections.d.ts +353 -0
- package/dist/server/connections.js +978 -0
- package/dist/server/constraints.d.ts +82 -0
- package/dist/server/constraints.js +169 -0
- package/dist/server/demo.d.ts +9 -0
- package/dist/server/demo.js +554 -0
- package/dist/server/devclient.d.ts +108 -0
- package/dist/server/devclient.js +361 -0
- package/dist/server/evidence.d.ts +55 -0
- package/dist/server/evidence.js +323 -0
- package/dist/server/hiddenColumns.d.ts +32 -0
- package/dist/server/hiddenColumns.js +238 -0
- package/dist/server/http/baselineHeaders.d.ts +24 -0
- package/dist/server/http/baselineHeaders.js +12 -0
- package/dist/server/http/captured.d.ts +35 -0
- package/dist/server/http/captured.js +73 -0
- package/dist/server/http/clock.d.ts +1 -0
- package/dist/server/http/clock.js +14 -0
- package/dist/server/http/connectionSource.d.ts +4 -0
- package/dist/server/http/connectionSource.js +48 -0
- package/dist/server/http/context.d.ts +189 -0
- package/dist/server/http/context.js +11 -0
- package/dist/server/http/crawlerText.d.ts +15 -0
- package/dist/server/http/crawlerText.js +32 -0
- package/dist/server/http/dataRoutes.d.ts +88 -0
- package/dist/server/http/dataRoutes.js +137 -0
- package/dist/server/http/door.d.ts +57 -0
- package/dist/server/http/door.js +39 -0
- package/dist/server/http/exportRoute.d.ts +15 -0
- package/dist/server/http/exportRoute.js +320 -0
- package/dist/server/http/firstPaint.d.ts +108 -0
- package/dist/server/http/firstPaint.js +262 -0
- package/dist/server/http/httpOperationRoutes.d.ts +11 -0
- package/dist/server/http/httpOperationRoutes.js +50 -0
- package/dist/server/http/pageReads.d.ts +20 -0
- package/dist/server/http/pageReads.js +205 -0
- package/dist/server/http/pageRoutes.d.ts +39 -0
- package/dist/server/http/pageRoutes.js +291 -0
- package/dist/server/http/probes.d.ts +22 -0
- package/dist/server/http/probes.js +27 -0
- package/dist/server/http/rateLimit.d.ts +131 -0
- package/dist/server/http/rateLimit.js +351 -0
- package/dist/server/http/readRoutes.d.ts +9 -0
- package/dist/server/http/readRoutes.js +131 -0
- package/dist/server/http/readRouting.d.ts +20 -0
- package/dist/server/http/readRouting.js +80 -0
- package/dist/server/http/recordCompose.d.ts +67 -0
- package/dist/server/http/recordCompose.js +167 -0
- package/dist/server/http/recordWrites.d.ts +89 -0
- package/dist/server/http/recordWrites.js +298 -0
- package/dist/server/http/refusalReport.d.ts +38 -0
- package/dist/server/http/refusalReport.js +63 -0
- package/dist/server/http/reply.d.ts +130 -0
- package/dist/server/http/reply.js +394 -0
- package/dist/server/http/requestOrigin.d.ts +11 -0
- package/dist/server/http/requestOrigin.js +8 -0
- package/dist/server/http/router.d.ts +45 -0
- package/dist/server/http/router.js +22 -0
- package/dist/server/http/serverCore.d.ts +68 -0
- package/dist/server/http/serverCore.js +177 -0
- package/dist/server/http/traceRequest.d.ts +30 -0
- package/dist/server/http/traceRequest.js +224 -0
- package/dist/server/http/trust.d.ts +261 -0
- package/dist/server/http/trust.js +472 -0
- package/dist/server/http/writeRefusal.d.ts +33 -0
- package/dist/server/http/writeRefusal.js +24 -0
- package/dist/server/httpConnection.d.ts +49 -0
- package/dist/server/httpConnection.js +170 -0
- package/dist/server/impact.d.ts +55 -0
- package/dist/server/impact.js +47 -0
- package/dist/server/journal.d.ts +134 -0
- package/dist/server/journal.js +398 -0
- package/dist/server/keysetReadHttp.d.ts +52 -0
- package/dist/server/keysetReadHttp.js +85 -0
- package/dist/server/layouts.d.ts +49 -0
- package/dist/server/layouts.js +192 -0
- package/dist/server/migrate/cli.d.ts +55 -0
- package/dist/server/migrate/cli.js +517 -0
- package/dist/server/migrate/database.d.ts +37 -0
- package/dist/server/migrate/database.js +247 -0
- package/dist/server/migrate/desired.d.ts +76 -0
- package/dist/server/migrate/desired.js +292 -0
- package/dist/server/migrate/files.d.ts +34 -0
- package/dist/server/migrate/files.js +141 -0
- package/dist/server/migrate/flyway.d.ts +7 -0
- package/dist/server/migrate/flyway.js +69 -0
- package/dist/server/migrate/history.d.ts +70 -0
- package/dist/server/migrate/history.js +211 -0
- package/dist/server/migrate/runner.d.ts +100 -0
- package/dist/server/migrate/runner.js +409 -0
- package/dist/server/migrate/snapshot.d.ts +30 -0
- package/dist/server/migrate/snapshot.js +239 -0
- package/dist/server/migrate/target.d.ts +33 -0
- package/dist/server/migrate/target.js +82 -0
- package/dist/server/openapiDraft.d.ts +25 -0
- package/dist/server/openapiDraft.js +171 -0
- package/dist/server/operations/diagnostics.d.ts +101 -0
- package/dist/server/operations/diagnostics.js +284 -0
- package/dist/server/operations/requestMetrics.d.ts +33 -0
- package/dist/server/operations/requestMetrics.js +94 -0
- package/dist/server/packageVersion.d.ts +1 -0
- package/dist/server/packageVersion.js +11 -0
- package/dist/server/poolConfig.d.ts +34 -0
- package/dist/server/poolConfig.js +114 -0
- package/dist/server/product.d.ts +20 -0
- package/dist/server/product.js +12 -0
- package/dist/server/recordHistoryOperations.d.ts +39 -0
- package/dist/server/recordHistoryOperations.js +43 -0
- package/dist/server/recordWriteOperations.d.ts +111 -0
- package/dist/server/recordWriteOperations.js +329 -0
- package/dist/server/resourceReadHttp.d.ts +81 -0
- package/dist/server/resourceReadHttp.js +606 -0
- package/dist/server/resourceReadOperations.d.ts +147 -0
- package/dist/server/resourceReadOperations.js +452 -0
- package/dist/server/scaffoldMachine.d.ts +54 -0
- package/dist/server/scaffoldMachine.js +184 -0
- package/dist/server/seed/cli.d.ts +20 -0
- package/dist/server/seed/cli.js +164 -0
- package/dist/server/seed/lexicon.d.ts +26 -0
- package/dist/server/seed/lexicon.js +585 -0
- package/dist/server/seed/seed.d.ts +70 -0
- package/dist/server/seed/seed.js +779 -0
- package/dist/server/seed/words.d.ts +21 -0
- package/dist/server/seed/words.js +164 -0
- package/dist/server/serverRequests.d.ts +6 -0
- package/dist/server/serverRequests.js +33 -0
- package/dist/server/serverTimeouts.d.ts +33 -0
- package/dist/server/serverTimeouts.js +32 -0
- package/dist/server/shapeonly.d.ts +32 -0
- package/dist/server/shapeonly.js +110 -0
- package/dist/server/startupWarnings.d.ts +32 -0
- package/dist/server/startupWarnings.js +92 -0
- package/dist/shared/addressParams.d.ts +28 -0
- package/dist/shared/addressParams.js +47 -0
- package/dist/shared/appCards.d.ts +123 -0
- package/dist/shared/appCards.js +385 -0
- package/dist/shared/appComponents.d.ts +177 -0
- package/dist/shared/appComponents.js +422 -0
- package/dist/shared/appDocuments.d.ts +43 -0
- package/dist/shared/appDocuments.js +131 -0
- package/dist/shared/appEmbeds.d.ts +21 -0
- package/dist/shared/appEmbeds.js +24 -0
- package/dist/shared/appIcons.d.ts +28 -0
- package/dist/shared/appIcons.js +223 -0
- package/dist/shared/appLinks.d.ts +17 -0
- package/dist/shared/appLinks.js +124 -0
- package/dist/shared/appListColumns.d.ts +3 -0
- package/dist/shared/appListColumns.js +66 -0
- package/dist/shared/appLocale.d.ts +36 -0
- package/dist/shared/appLocale.js +86 -0
- package/dist/shared/appMessages.d.ts +44 -0
- package/dist/shared/appMessages.js +78 -0
- package/dist/shared/appNoun.d.ts +21 -0
- package/dist/shared/appNoun.js +32 -0
- package/dist/shared/autoBucket.d.ts +98 -0
- package/dist/shared/autoBucket.js +305 -0
- package/dist/shared/autoValues.d.ts +25 -0
- package/dist/shared/autoValues.js +25 -0
- package/dist/shared/breakdown.d.ts +228 -0
- package/dist/shared/breakdown.js +557 -0
- package/dist/shared/breakdowntext.d.ts +41 -0
- package/dist/shared/breakdowntext.js +400 -0
- package/dist/shared/builtInThemes.d.ts +2 -0
- package/dist/shared/builtInThemes.js +771 -0
- package/dist/shared/chartSeparation.d.ts +11 -0
- package/dist/shared/chartSeparation.js +58 -0
- package/dist/shared/clauses.d.ts +22 -0
- package/dist/shared/clauses.js +97 -0
- package/dist/shared/columnCaption.d.ts +16 -0
- package/dist/shared/columnCaption.js +90 -0
- package/dist/shared/commandFieldPath.d.ts +2 -0
- package/dist/shared/commandFieldPath.js +7 -0
- package/dist/shared/commandWire.d.ts +26 -0
- package/dist/shared/commandWire.js +41 -0
- package/dist/shared/computed.d.ts +161 -0
- package/dist/shared/computed.js +378 -0
- package/dist/shared/computedParse.d.ts +13 -0
- package/dist/shared/computedParse.js +278 -0
- package/dist/shared/computedValue.d.ts +47 -0
- package/dist/shared/computedValue.js +191 -0
- package/dist/shared/connection.d.ts +30 -0
- package/dist/shared/connection.js +1 -0
- package/dist/shared/csv.d.ts +20 -0
- package/dist/shared/csv.js +63 -0
- package/dist/shared/dashLayout.d.ts +30 -0
- package/dist/shared/dashLayout.js +132 -0
- package/dist/shared/dashboardAsks.d.ts +93 -0
- package/dist/shared/dashboardAsks.js +129 -0
- package/dist/shared/dashboardTrend.d.ts +20 -0
- package/dist/shared/dashboardTrend.js +50 -0
- package/dist/shared/declaredReferences.d.ts +50 -0
- package/dist/shared/declaredReferences.js +202 -0
- package/dist/shared/definedFields.d.ts +63 -0
- package/dist/shared/definedFields.js +103 -0
- package/dist/shared/definedValues.d.ts +63 -0
- package/dist/shared/definedValues.js +184 -0
- package/dist/shared/displayDefaults.d.ts +135 -0
- package/dist/shared/displayDefaults.js +529 -0
- package/dist/shared/dueDate.d.ts +6 -0
- package/dist/shared/dueDate.js +6 -0
- package/dist/shared/duration.d.ts +4 -0
- package/dist/shared/duration.js +23 -0
- package/dist/shared/fileBounds.d.ts +9 -0
- package/dist/shared/fileBounds.js +9 -0
- package/dist/shared/filter.d.ts +217 -0
- package/dist/shared/filter.js +305 -0
- package/dist/shared/firstPaint.d.ts +24 -0
- package/dist/shared/firstPaint.js +33 -0
- package/dist/shared/form.d.ts +21 -0
- package/dist/shared/form.js +25 -0
- package/dist/shared/formValues.d.ts +104 -0
- package/dist/shared/formValues.js +352 -0
- package/dist/shared/funnel.d.ts +45 -0
- package/dist/shared/funnel.js +108 -0
- package/dist/shared/httpOperations.d.ts +48 -0
- package/dist/shared/httpOperations.js +9 -0
- package/dist/shared/iconGlyphs.d.ts +4 -0
- package/dist/shared/iconGlyphs.js +151 -0
- package/dist/shared/iconWeights.d.ts +3 -0
- package/dist/shared/iconWeights.js +162 -0
- package/dist/shared/imageWidths.d.ts +32 -0
- package/dist/shared/imageWidths.js +38 -0
- package/dist/shared/keysetPage.d.ts +64 -0
- package/dist/shared/keysetPage.js +161 -0
- package/dist/shared/like.d.ts +20 -0
- package/dist/shared/like.js +29 -0
- package/dist/shared/listEmpty.d.ts +12 -0
- package/dist/shared/listEmpty.js +36 -0
- package/dist/shared/listFilters.d.ts +28 -0
- package/dist/shared/listFilters.js +84 -0
- package/dist/shared/listPresentations.d.ts +199 -0
- package/dist/shared/listPresentations.js +7 -0
- package/dist/shared/listQuestion.d.ts +52 -0
- package/dist/shared/listQuestion.js +137 -0
- package/dist/shared/lookPalettes.d.ts +62 -0
- package/dist/shared/lookPalettes.js +306 -0
- package/dist/shared/maskQuoted.d.ts +24 -0
- package/dist/shared/maskQuoted.js +48 -0
- package/dist/shared/mentionLabel.d.ts +19 -0
- package/dist/shared/mentionLabel.js +38 -0
- package/dist/shared/mentionLookup.d.ts +17 -0
- package/dist/shared/mentionLookup.js +64 -0
- package/dist/shared/menuCounts.d.ts +16 -0
- package/dist/shared/menuCounts.js +74 -0
- package/dist/shared/model.d.ts +79 -0
- package/dist/shared/model.js +153 -0
- package/dist/shared/money.d.ts +44 -0
- package/dist/shared/money.js +81 -0
- package/dist/shared/moneyEntry.d.ts +7 -0
- package/dist/shared/moneyEntry.js +27 -0
- package/dist/shared/mount.d.ts +118 -0
- package/dist/shared/mount.js +248 -0
- package/dist/shared/niceTicks.d.ts +26 -0
- package/dist/shared/niceTicks.js +50 -0
- package/dist/shared/order.d.ts +59 -0
- package/dist/shared/order.js +133 -0
- package/dist/shared/page.d.ts +135 -0
- package/dist/shared/page.js +1187 -0
- package/dist/shared/pageAnatomy.d.ts +99 -0
- package/dist/shared/pageAnatomy.js +370 -0
- package/dist/shared/pageConfig.d.ts +25 -0
- package/dist/shared/pageConfig.js +1308 -0
- package/dist/shared/pageEmptyActions.d.ts +12 -0
- package/dist/shared/pageEmptyActions.js +20 -0
- package/dist/shared/pageLayouts.d.ts +72 -0
- package/dist/shared/pageLayouts.js +205 -0
- package/dist/shared/pageModel.d.ts +785 -0
- package/dist/shared/pageModel.js +121 -0
- package/dist/shared/pagePaths.d.ts +180 -0
- package/dist/shared/pagePaths.js +869 -0
- package/dist/shared/pagePlans.d.ts +52 -0
- package/dist/shared/pagePlans.js +108 -0
- package/dist/shared/pageRoutes.d.ts +9 -0
- package/dist/shared/pageRoutes.js +9 -0
- package/dist/shared/query.d.ts +166 -0
- package/dist/shared/query.js +1302 -0
- package/dist/shared/queryDates.d.ts +12 -0
- package/dist/shared/queryDates.js +101 -0
- package/dist/shared/queryOperands.d.ts +99 -0
- package/dist/shared/queryOperands.js +131 -0
- package/dist/shared/reads.d.ts +103 -0
- package/dist/shared/reads.js +154 -0
- package/dist/shared/recordLabel.d.ts +51 -0
- package/dist/shared/recordLabel.js +123 -0
- package/dist/shared/recordReadKeys.d.ts +30 -0
- package/dist/shared/recordReadKeys.js +51 -0
- package/dist/shared/recordReads.d.ts +268 -0
- package/dist/shared/recordReads.js +368 -0
- package/dist/shared/recordview.d.ts +198 -0
- package/dist/shared/recordview.js +356 -0
- package/dist/shared/referenceModel.d.ts +58 -0
- package/dist/shared/referenceModel.js +194 -0
- package/dist/shared/refusal.d.ts +64 -0
- package/dist/shared/refusal.js +144 -0
- package/dist/shared/relatedCreate.d.ts +30 -0
- package/dist/shared/relatedCreate.js +162 -0
- package/dist/shared/resourceHttp.d.ts +464 -0
- package/dist/shared/resourceHttp.js +1 -0
- package/dist/shared/richText.d.ts +85 -0
- package/dist/shared/richText.js +305 -0
- package/dist/shared/rollups.d.ts +143 -0
- package/dist/shared/rollups.js +64 -0
- package/dist/shared/rowScope.d.ts +72 -0
- package/dist/shared/rowScope.js +376 -0
- package/dist/shared/runtimeTables.d.ts +44 -0
- package/dist/shared/runtimeTables.js +79 -0
- package/dist/shared/schema.d.ts +523 -0
- package/dist/shared/schema.js +627 -0
- package/dist/shared/schematext.d.ts +38 -0
- package/dist/shared/schematext.js +101 -0
- package/dist/shared/scopeCatalog.d.ts +29 -0
- package/dist/shared/scopeCatalog.js +468 -0
- package/dist/shared/servedApp.d.ts +681 -0
- package/dist/shared/servedApp.js +45 -0
- package/dist/shared/sessionLease.d.ts +34 -0
- package/dist/shared/sessionLease.js +3 -0
- package/dist/shared/shape.d.ts +55 -0
- package/dist/shared/shape.js +168 -0
- package/dist/shared/slug.d.ts +1 -0
- package/dist/shared/slug.js +12 -0
- package/dist/shared/sortText.d.ts +14 -0
- package/dist/shared/sortText.js +26 -0
- package/dist/shared/sqlRelation.d.ts +4 -0
- package/dist/shared/sqlRelation.js +8 -0
- package/dist/shared/sqlsaved.d.ts +44 -0
- package/dist/shared/sqlsaved.js +63 -0
- package/dist/shared/stitchedPaths.d.ts +27 -0
- package/dist/shared/stitchedPaths.js +38 -0
- package/dist/shared/structuredFilter.d.ts +22 -0
- package/dist/shared/structuredFilter.js +1 -0
- package/dist/shared/subtitlePath.d.ts +20 -0
- package/dist/shared/subtitlePath.js +24 -0
- package/dist/shared/suggest.d.ts +18 -0
- package/dist/shared/suggest.js +59 -0
- package/dist/shared/tableSizing.d.ts +4 -0
- package/dist/shared/tableSizing.js +9 -0
- package/dist/shared/tagLists.d.ts +57 -0
- package/dist/shared/tagLists.js +34 -0
- package/dist/shared/textRules.d.ts +54 -0
- package/dist/shared/textRules.js +133 -0
- package/dist/shared/theme.d.ts +94 -0
- package/dist/shared/theme.js +800 -0
- package/dist/shared/themeColor.d.ts +34 -0
- package/dist/shared/themeColor.js +109 -0
- package/dist/shared/themeFaces.d.ts +30 -0
- package/dist/shared/themeFaces.js +42 -0
- package/dist/shared/themeInk.d.ts +20 -0
- package/dist/shared/themeInk.js +52 -0
- package/dist/shared/themeLooks.d.ts +9 -0
- package/dist/shared/themeLooks.js +572 -0
- package/dist/shared/themeParts.d.ts +26 -0
- package/dist/shared/themeParts.js +71 -0
- package/dist/shared/themePartsCheck.d.ts +21 -0
- package/dist/shared/themePartsCheck.js +91 -0
- package/dist/shared/themePresets.d.ts +85 -0
- package/dist/shared/themePresets.js +139 -0
- package/dist/shared/themeRecipeWords.d.ts +156 -0
- package/dist/shared/themeRecipeWords.js +156 -0
- package/dist/shared/themeRecipes.d.ts +213 -0
- package/dist/shared/themeRecipes.js +234 -0
- package/dist/shared/themeResolve.d.ts +55 -0
- package/dist/shared/themeResolve.js +52 -0
- package/dist/shared/themeTokens.d.ts +107 -0
- package/dist/shared/themeTokens.js +116 -0
- package/dist/shared/themeType.d.ts +38 -0
- package/dist/shared/themeType.js +205 -0
- package/dist/shared/unitWord.d.ts +4 -0
- package/dist/shared/unitWord.js +37 -0
- package/dist/shared/view.d.ts +195 -0
- package/dist/shared/view.js +987 -0
- package/dist/shared/viewLabels.d.ts +47 -0
- package/dist/shared/viewLabels.js +459 -0
- package/dist/shared/viewPaths.d.ts +248 -0
- package/dist/shared/viewPaths.js +294 -0
- package/dist/shared/viewtext.d.ts +57 -0
- package/dist/shared/viewtext.js +282 -0
- package/dist/shared/vocabulary.d.ts +71 -0
- package/dist/shared/vocabulary.js +249 -0
- package/dist/shared/weekStart.d.ts +7 -0
- package/dist/shared/weekStart.js +36 -0
- package/mark.svg +1 -0
- package/package.json +261 -4
- package/schema/model.d.ts +298 -0
- package/schema/theme.d.ts +587 -0
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How many connections this process can hold against each PostgreSQL
|
|
3
|
+
* database, and whether the server would let it.
|
|
4
|
+
*
|
|
5
|
+
* Every pool is sized for the process it lives in and knows nothing of the
|
|
6
|
+
* others: the read and write pools (`--read-pool`, `--write-pool`), the
|
|
7
|
+
* background writer, a LISTEN connection, the auth store's pool. A second
|
|
8
|
+
* replica multiplies all of them, and the server's limit (the role's, or
|
|
9
|
+
* `max_connections`) is the first anyone hears of the product — as a 53300
|
|
10
|
+
* under load. So each holder says what it may open when it is made
|
|
11
|
+
* (`holdConnections`), the totals are read by database, and a start compares
|
|
12
|
+
* them with what the server says it allows (`adviseConnectionLimits`).
|
|
13
|
+
* `mistri check --deploy` does the same sum before anything runs
|
|
14
|
+
* (`processConnections`), for as many replicas as the operator names.
|
|
15
|
+
*
|
|
16
|
+
* Counted: pools at their `max`, whether or not they have opened yet — a
|
|
17
|
+
* ceiling, not a reading. Not counted: the short-lived client that cancels a
|
|
18
|
+
* statement (pg_cancel_backend) and the one-shot clients of migrations and
|
|
19
|
+
* maintenance, which run beside a stopped or starting server.
|
|
20
|
+
*/
|
|
21
|
+
/** The connections a manager of PostgreSQL pools may hold: its readers, its writers and the one background writer. */
|
|
22
|
+
export const managerConnections = (readers, writers) => readers + writers + 1;
|
|
23
|
+
/**
|
|
24
|
+
* What a short-lived store manager asks for (a retention prune's, a command line's): one reader and one writer.
|
|
25
|
+
*/
|
|
26
|
+
export const SMALL_STORE_POOL = Object.freeze({ readers: 1, writers: 1 });
|
|
27
|
+
/**
|
|
28
|
+
* The one manager the server's own stores share on a database (postgresPool.ts sharedPgConnections): the jobs host
|
|
29
|
+
* with its workflow and event-delivery stores, the effects host, the mail outbox, the integrations store, the
|
|
30
|
+
* decisions, assistant and API event stores. Two readers and two writers, whatever the App's pools, sized for their
|
|
31
|
+
* short statements and kept apart from the pools a person's reads and saves use, where a burst of job claims could
|
|
32
|
+
* otherwise queue ahead of a save. Not all of them are background: the assistant store, a tenant's decision
|
|
33
|
+
* suggestions and the API event feed answer a person, and share the two readers and two writers with job claims
|
|
34
|
+
* and completions, the mail outbox and the integrations. That is deliberate (no connection is added for them) and
|
|
35
|
+
* bounded by the pool's own queue, which answers busy. A job's own command and every delivery run as background
|
|
36
|
+
* work, on the one background writer, whose line is bounded the same way (postgresPool.ts). `mistri check --deploy`
|
|
37
|
+
* counts the same size (servedHosts.ts), so they cannot drift.
|
|
38
|
+
*/
|
|
39
|
+
export const RUNTIME_STORE_POOL = Object.freeze({ readers: 2, writers: 2 });
|
|
40
|
+
/** `host:port/database` of a connection string, without its credentials: what two URLs share when they name one database. */
|
|
41
|
+
export function databaseOf(url) {
|
|
42
|
+
try {
|
|
43
|
+
const parsed = new URL(url);
|
|
44
|
+
return `${parsed.hostname}:${parsed.port || '5432'}${parsed.pathname.replace(/\/+$/, '') || '/'}`;
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
return url;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
const holds = new Set();
|
|
51
|
+
/**
|
|
52
|
+
* Record that this process may now hold up to `count` connections to `url`'s database. Returns the release, called
|
|
53
|
+
* when the holder closes; calling it twice is harmless.
|
|
54
|
+
*/
|
|
55
|
+
export function holdConnections(url, count, ask) {
|
|
56
|
+
const hold = { database: databaseOf(url), count, ...(ask ? { ask } : {}) };
|
|
57
|
+
holds.add(hold);
|
|
58
|
+
return () => void holds.delete(hold);
|
|
59
|
+
}
|
|
60
|
+
/** Up to how many connections this process holds now, by database. */
|
|
61
|
+
export function heldConnections() {
|
|
62
|
+
const totals = new Map();
|
|
63
|
+
for (const hold of holds)
|
|
64
|
+
totals.set(hold.database, (totals.get(hold.database) ?? 0) + hold.count);
|
|
65
|
+
return totals;
|
|
66
|
+
}
|
|
67
|
+
/** The connections one process may hold on the primary: its manager, plus the LISTEN connection. */
|
|
68
|
+
export const primaryConnections = (shape) => managerConnections(shape.readers, shape.writers) + (shape.listen === false ? 0 : 1);
|
|
69
|
+
/** One database's line for `mistri check --deploy`: "3 processes × 41 connections = 123". */
|
|
70
|
+
export function sayBudget(budget) {
|
|
71
|
+
const times = `${budget.processes} process${budget.processes === 1 ? '' : 'es'} × ${budget.perProcess} connections = ${budget.total}`;
|
|
72
|
+
const limit = budget.limit === undefined ? '' : ` (limit ${budget.limit})`;
|
|
73
|
+
const cpus = budget.cpus === undefined ? '' : ` (at ${budget.cpus} cpus; pass --cpus for the deployment's)`;
|
|
74
|
+
const parts = budget.parts?.length ? `; a process: ${budget.parts.map((part) => `${part.host} ${part.connections}`).join(' + ')}` : '';
|
|
75
|
+
return `${budget.database}: ${times}${limit}${cpus}${parts}`;
|
|
76
|
+
}
|
|
77
|
+
/** The smaller of the limits that apply to this role, or undefined when neither is set. */
|
|
78
|
+
export function effectiveLimit(roleLimit, usable) {
|
|
79
|
+
const limits = [roleLimit, usable].filter((limit) => limit !== undefined && limit >= 0);
|
|
80
|
+
return limits.length ? Math.min(...limits) : undefined;
|
|
81
|
+
}
|
|
82
|
+
const LIMITS = `SELECT r.rolconnlimit AS role_limit,
|
|
83
|
+
current_setting('max_connections')::int - current_setting('superuser_reserved_connections')::int AS usable
|
|
84
|
+
FROM pg_roles r WHERE r.rolname = current_user`;
|
|
85
|
+
/**
|
|
86
|
+
* One line a database whose holders may open more connections than its server allows this role, naming both
|
|
87
|
+
* numbers and the flags that lower them. Never refuses and never throws: one round trip per database, started
|
|
88
|
+
* after the first connection is open, whose failure (a pooler that answers no catalog, a role that may not read
|
|
89
|
+
* it) is silent.
|
|
90
|
+
*/
|
|
91
|
+
export async function adviseConnectionLimits(say) {
|
|
92
|
+
const totals = heldConnections();
|
|
93
|
+
const asked = new Set();
|
|
94
|
+
for (const hold of [...holds]) {
|
|
95
|
+
if (!hold.ask || asked.has(hold.database) || !totals.has(hold.database))
|
|
96
|
+
continue;
|
|
97
|
+
asked.add(hold.database);
|
|
98
|
+
try {
|
|
99
|
+
const line = await limitAdvice(hold.database, totals.get(hold.database), await hold.ask());
|
|
100
|
+
if (line)
|
|
101
|
+
say(line);
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
/* The advice is a courtesy: a start never depends on it. */
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
/** The warning for one database given a connection to ask, or undefined when it fits. Exported for tests. */
|
|
109
|
+
export async function limitAdvice(database, held, connection) {
|
|
110
|
+
const row = (await connection.query(LIMITS)).rows[0];
|
|
111
|
+
if (!row)
|
|
112
|
+
return undefined;
|
|
113
|
+
const whole = (value) => {
|
|
114
|
+
const number = Number(value);
|
|
115
|
+
return value === null || value === undefined || !Number.isInteger(number) ? undefined : number;
|
|
116
|
+
};
|
|
117
|
+
const roleLimit = whole(row.role_limit);
|
|
118
|
+
const usable = whole(row.usable);
|
|
119
|
+
const limit = effectiveLimit(roleLimit, usable);
|
|
120
|
+
if (limit === undefined || held <= limit)
|
|
121
|
+
return undefined;
|
|
122
|
+
const source = roleLimit !== undefined && roleLimit >= 0 && roleLimit <= (usable ?? Infinity)
|
|
123
|
+
? `the role's limit`
|
|
124
|
+
: `the server's max_connections less its reserved ones`;
|
|
125
|
+
return (`this process may open ${held} connections to ${database}, and ${source} allows ${limit}. ` +
|
|
126
|
+
`Lower --read-pool and --write-pool (or a connection's "pool"), and MISTRI_AUTH_POOL for the sign-in store, or raise the limit; ` +
|
|
127
|
+
`with several replicas the sum of all of them counts.`);
|
|
128
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A remote database's distance, felt on a laptop: `--db-latency <ms>` (or
|
|
3
|
+
* `MISTRI_DEV_DB_LATENCY`) makes every round trip wait that long before it is
|
|
4
|
+
* sent, so an App that asks the database eleven questions in a row feels it in
|
|
5
|
+
* development, where the database is a millisecond away, rather than in
|
|
6
|
+
* production, where it is twenty.
|
|
7
|
+
*
|
|
8
|
+
* A round trip is a flight: on PostgreSQL the message a client writes to its
|
|
9
|
+
* socket, so a pipelined batch leaves in one write and pays once, the way a
|
|
10
|
+
* remote database charges. On SQLite it is the statement call, which has no
|
|
11
|
+
* network to be pipelined on.
|
|
12
|
+
*
|
|
13
|
+
* Development only. Production would pay the wait for nothing, so it is
|
|
14
|
+
* refused there (NODE_ENV=production), and by the serve of a build
|
|
15
|
+
* (`refuseForBuild`): a build is what is deployed.
|
|
16
|
+
*/
|
|
17
|
+
/** The wait before each flight, in milliseconds; 0 is none. */
|
|
18
|
+
export declare const dbLatency: () => number;
|
|
19
|
+
/** Set the wait: read once at start by `configureDbLatency`; tests set it directly. */
|
|
20
|
+
export declare function setDbLatency(value: number): void;
|
|
21
|
+
/**
|
|
22
|
+
* The wait the flag or the environment asks for, validated and set. The flag wins over the variable. Throws a
|
|
23
|
+
* message fit for the terminal when the value is not a number of milliseconds, or the process is a production one.
|
|
24
|
+
*/
|
|
25
|
+
export declare function configureDbLatency(flag: string | undefined, env?: NodeJS.ProcessEnv): number;
|
|
26
|
+
/** A build is what is deployed: the wait is refused with it, and cleared. */
|
|
27
|
+
export declare function refuseForBuild(): void;
|
|
28
|
+
/** Wait one round trip, for an engine with no network of its own (SQLite's statement call). Nothing when off. */
|
|
29
|
+
export declare function roundTrip(): Promise<void>;
|
|
30
|
+
/**
|
|
31
|
+
* Hold each message `client` writes to its socket for the wait before it leaves. Timers of one duration fire in
|
|
32
|
+
* the order they were set, so the messages still leave in order; two written in the same tick leave together, which
|
|
33
|
+
* is what a pipeline is. A no-op when the wait is off, for a client without a socket, and for one already held.
|
|
34
|
+
*/
|
|
35
|
+
export declare function delayFlights(client: object): void;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A remote database's distance, felt on a laptop: `--db-latency <ms>` (or
|
|
3
|
+
* `MISTRI_DEV_DB_LATENCY`) makes every round trip wait that long before it is
|
|
4
|
+
* sent, so an App that asks the database eleven questions in a row feels it in
|
|
5
|
+
* development, where the database is a millisecond away, rather than in
|
|
6
|
+
* production, where it is twenty.
|
|
7
|
+
*
|
|
8
|
+
* A round trip is a flight: on PostgreSQL the message a client writes to its
|
|
9
|
+
* socket, so a pipelined batch leaves in one write and pays once, the way a
|
|
10
|
+
* remote database charges. On SQLite it is the statement call, which has no
|
|
11
|
+
* network to be pipelined on.
|
|
12
|
+
*
|
|
13
|
+
* Development only. Production would pay the wait for nothing, so it is
|
|
14
|
+
* refused there (NODE_ENV=production), and by the serve of a build
|
|
15
|
+
* (`refuseForBuild`): a build is what is deployed.
|
|
16
|
+
*/
|
|
17
|
+
let ms = 0;
|
|
18
|
+
/** The wait before each flight, in milliseconds; 0 is none. */
|
|
19
|
+
export const dbLatency = () => ms;
|
|
20
|
+
/** Set the wait: read once at start by `configureDbLatency`; tests set it directly. */
|
|
21
|
+
export function setDbLatency(value) {
|
|
22
|
+
ms = value;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* The wait the flag or the environment asks for, validated and set. The flag wins over the variable. Throws a
|
|
26
|
+
* message fit for the terminal when the value is not a number of milliseconds, or the process is a production one.
|
|
27
|
+
*/
|
|
28
|
+
export function configureDbLatency(flag, env = process.env) {
|
|
29
|
+
const given = flag ?? env.MISTRI_DEV_DB_LATENCY;
|
|
30
|
+
if (given === undefined || (flag === undefined && given.trim() === ''))
|
|
31
|
+
return ms;
|
|
32
|
+
const source = flag !== undefined ? '--db-latency' : 'MISTRI_DEV_DB_LATENCY';
|
|
33
|
+
if (!/^\d{1,4}(\.\d+)?$/.test(given.trim()) || Number(given) > 5000)
|
|
34
|
+
throw new Error(`${source} takes the milliseconds each database round trip should wait, like 20 (0 to 5000); it got "${given}".`);
|
|
35
|
+
if (env.NODE_ENV === 'production')
|
|
36
|
+
throw new Error(`${source} slows every database round trip on purpose to feel a remote database in development, and NODE_ENV is production.`);
|
|
37
|
+
ms = Number(given);
|
|
38
|
+
return ms;
|
|
39
|
+
}
|
|
40
|
+
/** A build is what is deployed: the wait is refused with it, and cleared. */
|
|
41
|
+
export function refuseForBuild() {
|
|
42
|
+
if (ms === 0)
|
|
43
|
+
return;
|
|
44
|
+
ms = 0;
|
|
45
|
+
throw new Error('--db-latency (or MISTRI_DEV_DB_LATENCY) is for development and is refused when serving a build, which is what is deployed.');
|
|
46
|
+
}
|
|
47
|
+
/** Wait one round trip, for an engine with no network of its own (SQLite's statement call). Nothing when off. */
|
|
48
|
+
export async function roundTrip() {
|
|
49
|
+
if (ms > 0)
|
|
50
|
+
await new Promise((done) => setTimeout(done, ms));
|
|
51
|
+
}
|
|
52
|
+
const delayed = new WeakSet();
|
|
53
|
+
/**
|
|
54
|
+
* Hold each message `client` writes to its socket for the wait before it leaves. Timers of one duration fire in
|
|
55
|
+
* the order they were set, so the messages still leave in order; two written in the same tick leave together, which
|
|
56
|
+
* is what a pipeline is. A no-op when the wait is off, for a client without a socket, and for one already held.
|
|
57
|
+
*/
|
|
58
|
+
export function delayFlights(client) {
|
|
59
|
+
if (ms <= 0 || delayed.has(client))
|
|
60
|
+
return;
|
|
61
|
+
const stream = client.connection?.stream;
|
|
62
|
+
if (!stream?.write)
|
|
63
|
+
return;
|
|
64
|
+
delayed.add(client);
|
|
65
|
+
const write = stream.write.bind(stream);
|
|
66
|
+
stream.write = (chunk, ...rest) => {
|
|
67
|
+
if (ms <= 0)
|
|
68
|
+
return write(chunk, ...rest);
|
|
69
|
+
setTimeout(() => {
|
|
70
|
+
try {
|
|
71
|
+
write(chunk, ...rest);
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
// The socket went away while the message waited: the client hears it close.
|
|
75
|
+
}
|
|
76
|
+
}, ms);
|
|
77
|
+
return true;
|
|
78
|
+
};
|
|
79
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A cache that is never wrong, because it is never trusted on its own.
|
|
3
|
+
*
|
|
4
|
+
* Every entry is kept under the version of the thing it was derived from —
|
|
5
|
+
* the catalog's epoch (postgresSchemaEpoch.ts, SQLite's `schema_version`),
|
|
6
|
+
* an App's version, a role set — and is served only to a caller that holds
|
|
7
|
+
* the current version, read cheaply inside the transaction that will use the
|
|
8
|
+
* entry. An entry under any other version is a miss, never an answer: a
|
|
9
|
+
* stale cache is only a slower one. So nothing here expires by time, and
|
|
10
|
+
* nothing needs invalidating; a new version simply stops matching.
|
|
11
|
+
*
|
|
12
|
+
* The version is read BEFORE what is derived from it, never after: a change
|
|
13
|
+
* committing between the two leaves an entry filed under a version no later
|
|
14
|
+
* read can match, so it is derived again rather than trusted on a version it
|
|
15
|
+
* postdates.
|
|
16
|
+
*
|
|
17
|
+
* Generic on purpose: the catalog caches here, the command metadata in the
|
|
18
|
+
* journal and the plans compiled per (App, roles, epoch) all keep their
|
|
19
|
+
* entries through one of these, and so can a composed read that wants to.
|
|
20
|
+
*/
|
|
21
|
+
export declare class EpochCache<V> {
|
|
22
|
+
private readonly max;
|
|
23
|
+
private readonly entries;
|
|
24
|
+
private counts;
|
|
25
|
+
/** At most `max` keys; the least recently set goes first. Bounded, because a key can carry a caller's role set. */
|
|
26
|
+
constructor(max?: number);
|
|
27
|
+
/** The value kept for `key` under exactly `version`; anything else is a miss. */
|
|
28
|
+
get(version: string | undefined, key: string): V | undefined;
|
|
29
|
+
/** What is kept for `key`, whatever its version: for work that must happen before the version is read (a lock). Never an answer. */
|
|
30
|
+
peek(key: string): {
|
|
31
|
+
version: string;
|
|
32
|
+
value: V;
|
|
33
|
+
} | undefined;
|
|
34
|
+
/** Keep `value` under `version`, the one read before `value` was derived. Returns the value. */
|
|
35
|
+
set<T extends V>(version: string | undefined, key: string, value: T): T;
|
|
36
|
+
/** Read through: the kept value under `version`, or `derive()` kept under it. */
|
|
37
|
+
through<T extends V>(version: string | undefined, key: string, derive: () => Promise<T>): Promise<T>;
|
|
38
|
+
/** Synchronous read through, for SQLite. */
|
|
39
|
+
throughSync<T extends V>(version: string | undefined, key: string, derive: () => T): T;
|
|
40
|
+
clear(): void;
|
|
41
|
+
/** Drop what is kept for `key`, whatever its version. */
|
|
42
|
+
forget(key: string): void;
|
|
43
|
+
get size(): number;
|
|
44
|
+
/** Hits and misses since the process started, for the operator and the budget tests. */
|
|
45
|
+
stats(): Readonly<{
|
|
46
|
+
hits: number;
|
|
47
|
+
misses: number;
|
|
48
|
+
size: number;
|
|
49
|
+
}>;
|
|
50
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A cache that is never wrong, because it is never trusted on its own.
|
|
3
|
+
*
|
|
4
|
+
* Every entry is kept under the version of the thing it was derived from —
|
|
5
|
+
* the catalog's epoch (postgresSchemaEpoch.ts, SQLite's `schema_version`),
|
|
6
|
+
* an App's version, a role set — and is served only to a caller that holds
|
|
7
|
+
* the current version, read cheaply inside the transaction that will use the
|
|
8
|
+
* entry. An entry under any other version is a miss, never an answer: a
|
|
9
|
+
* stale cache is only a slower one. So nothing here expires by time, and
|
|
10
|
+
* nothing needs invalidating; a new version simply stops matching.
|
|
11
|
+
*
|
|
12
|
+
* The version is read BEFORE what is derived from it, never after: a change
|
|
13
|
+
* committing between the two leaves an entry filed under a version no later
|
|
14
|
+
* read can match, so it is derived again rather than trusted on a version it
|
|
15
|
+
* postdates.
|
|
16
|
+
*
|
|
17
|
+
* Generic on purpose: the catalog caches here, the command metadata in the
|
|
18
|
+
* journal and the plans compiled per (App, roles, epoch) all keep their
|
|
19
|
+
* entries through one of these, and so can a composed read that wants to.
|
|
20
|
+
*/
|
|
21
|
+
export class EpochCache {
|
|
22
|
+
max;
|
|
23
|
+
entries = new Map();
|
|
24
|
+
counts = { hits: 0, misses: 0 };
|
|
25
|
+
/** At most `max` keys; the least recently set goes first. Bounded, because a key can carry a caller's role set. */
|
|
26
|
+
constructor(max = 512) {
|
|
27
|
+
this.max = max;
|
|
28
|
+
}
|
|
29
|
+
/** The value kept for `key` under exactly `version`; anything else is a miss. */
|
|
30
|
+
get(version, key) {
|
|
31
|
+
if (version === undefined) {
|
|
32
|
+
this.counts.misses++;
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
const entry = this.entries.get(key);
|
|
36
|
+
if (entry?.version === version) {
|
|
37
|
+
this.counts.hits++;
|
|
38
|
+
return entry.value;
|
|
39
|
+
}
|
|
40
|
+
this.counts.misses++;
|
|
41
|
+
return undefined;
|
|
42
|
+
}
|
|
43
|
+
/** What is kept for `key`, whatever its version: for work that must happen before the version is read (a lock). Never an answer. */
|
|
44
|
+
peek(key) {
|
|
45
|
+
return this.entries.get(key);
|
|
46
|
+
}
|
|
47
|
+
/** Keep `value` under `version`, the one read before `value` was derived. Returns the value. */
|
|
48
|
+
set(version, key, value) {
|
|
49
|
+
if (version === undefined)
|
|
50
|
+
return value;
|
|
51
|
+
this.entries.delete(key);
|
|
52
|
+
this.entries.set(key, { version, value });
|
|
53
|
+
while (this.entries.size > this.max)
|
|
54
|
+
this.entries.delete(this.entries.keys().next().value);
|
|
55
|
+
return value;
|
|
56
|
+
}
|
|
57
|
+
/** Read through: the kept value under `version`, or `derive()` kept under it. */
|
|
58
|
+
async through(version, key, derive) {
|
|
59
|
+
const kept = this.get(version, key);
|
|
60
|
+
if (kept !== undefined)
|
|
61
|
+
return kept;
|
|
62
|
+
return this.set(version, key, await derive());
|
|
63
|
+
}
|
|
64
|
+
/** Synchronous read through, for SQLite. */
|
|
65
|
+
throughSync(version, key, derive) {
|
|
66
|
+
const kept = this.get(version, key);
|
|
67
|
+
if (kept !== undefined)
|
|
68
|
+
return kept;
|
|
69
|
+
return this.set(version, key, derive());
|
|
70
|
+
}
|
|
71
|
+
clear() {
|
|
72
|
+
this.entries.clear();
|
|
73
|
+
}
|
|
74
|
+
/** Drop what is kept for `key`, whatever its version. */
|
|
75
|
+
forget(key) {
|
|
76
|
+
this.entries.delete(key);
|
|
77
|
+
}
|
|
78
|
+
get size() {
|
|
79
|
+
return this.entries.size;
|
|
80
|
+
}
|
|
81
|
+
/** Hits and misses since the process started, for the operator and the budget tests. */
|
|
82
|
+
stats() {
|
|
83
|
+
return { ...this.counts, size: this.entries.size };
|
|
84
|
+
}
|
|
85
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { type NetworkPolicy, type Resolver } from '../net/networkPolicy.js';
|
|
2
|
+
export type { Resolver } from '../net/networkPolicy.js';
|
|
3
|
+
export interface EgressPolicy extends NetworkPolicy {
|
|
4
|
+
/** Plain `http:`; for an API on a trusted network or a test, never the default. */
|
|
5
|
+
insecure: boolean;
|
|
6
|
+
connectTimeoutMs: number;
|
|
7
|
+
/** The whole request, from the first byte sent to the last one read. */
|
|
8
|
+
timeoutMs: number;
|
|
9
|
+
maxBytes: number;
|
|
10
|
+
resolver?: Resolver;
|
|
11
|
+
}
|
|
12
|
+
export declare const DEFAULT_POLICY: EgressPolicy;
|
|
13
|
+
/** Why a request failed, as a reason the App's error mapping can rely on; the message is for the operator. */
|
|
14
|
+
export declare class HttpSourceError extends Error {
|
|
15
|
+
readonly reason: 'refused' | 'timeout' | 'redirect' | 'too_large' | 'not_json' | 'status' | 'shape' | 'network';
|
|
16
|
+
readonly status?: number | undefined;
|
|
17
|
+
constructor(reason: 'refused' | 'timeout' | 'redirect' | 'too_large' | 'not_json' | 'status' | 'shape' | 'network', message: string, status?: number | undefined);
|
|
18
|
+
}
|
|
19
|
+
export interface EgressReply {
|
|
20
|
+
status: number;
|
|
21
|
+
json: unknown;
|
|
22
|
+
}
|
|
23
|
+
interface EgressRequest {
|
|
24
|
+
method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
|
|
25
|
+
headers: Record<string, string>;
|
|
26
|
+
/** Sent as JSON. A service's own client builds it; never anything a browser sent verbatim. */
|
|
27
|
+
body?: unknown;
|
|
28
|
+
/** Sent as it is, with its own media type, in place of a JSON body: a warehouse's NDJSON. */
|
|
29
|
+
text?: {
|
|
30
|
+
readonly type: string;
|
|
31
|
+
readonly body: string;
|
|
32
|
+
};
|
|
33
|
+
/** The answer's body is never read, whatever its status: the reply is the status alone. A webhook's POST. */
|
|
34
|
+
discard?: true;
|
|
35
|
+
/** What the call is, for its span: a webhook, an HTTP source, a search service. */
|
|
36
|
+
kind?: 'webhook' | 'http' | 'search' | 'analytics';
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* One GET. A 2xx answers its parsed JSON; any other status answers the status
|
|
40
|
+
* alone — its body is never read into anything a caller could forward.
|
|
41
|
+
*/
|
|
42
|
+
export declare function send(url: URL, headers: Record<string, string>, policy: EgressPolicy): Promise<EgressReply>;
|
|
43
|
+
/**
|
|
44
|
+
* One request of any method, under the same rules as a GET: a JSON body out,
|
|
45
|
+
* a JSON body back from a 2xx and nothing read from anything else. For the
|
|
46
|
+
* services a config names (search), which write as well as read.
|
|
47
|
+
*/
|
|
48
|
+
export declare function request(url: URL, asked: EgressRequest, policy: EgressPolicy): Promise<EgressReply>;
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The one place a request to an API leaves the process.
|
|
3
|
+
*
|
|
4
|
+
* Every HTTP connection's traffic goes through `request`, so the rules that
|
|
5
|
+
* make it safe to point tablewalk at someone else's server live here once:
|
|
6
|
+
*
|
|
7
|
+
* - the address a name resolves to is checked, and that exact address is
|
|
8
|
+
* the one connected to (the shared network policy, networkPolicy.ts);
|
|
9
|
+
* - a redirect is refused, not followed — following one is how a trusted
|
|
10
|
+
* name hands the request to an address nobody checked;
|
|
11
|
+
* - a response is JSON, arrives within a deadline, and is read under a byte
|
|
12
|
+
* cap — and a webhook's (`discard`) is not read at all: its status is the
|
|
13
|
+
* whole reply, and its body is drained unread;
|
|
14
|
+
* - a failure is an `HttpSourceError` carrying a reason, never the response
|
|
15
|
+
* body, a header or the credential.
|
|
16
|
+
*
|
|
17
|
+
* Private networks are reachable by default: internal APIs are the common
|
|
18
|
+
* case, and an HTTP connection only ever comes from the operator's config,
|
|
19
|
+
* never from a browser. Cloud metadata and link-local addresses are not,
|
|
20
|
+
* unless the connection says so, because they hand out credentials to
|
|
21
|
+
* whoever asks.
|
|
22
|
+
*/
|
|
23
|
+
import { errorCode, inSpan, injectTrace, tracing } from '../telemetry/trace.js';
|
|
24
|
+
import { request as httpRequest } from 'node:http';
|
|
25
|
+
import { request as httpsRequest } from 'node:https';
|
|
26
|
+
import { checkedLookup, refusedLiteral } from '../net/networkPolicy.js';
|
|
27
|
+
export const DEFAULT_POLICY = Object.freeze({
|
|
28
|
+
allowPrivate: true,
|
|
29
|
+
allowLinkLocal: false,
|
|
30
|
+
insecure: false,
|
|
31
|
+
connectTimeoutMs: 5_000,
|
|
32
|
+
timeoutMs: 15_000,
|
|
33
|
+
maxBytes: 5 * 1024 * 1024,
|
|
34
|
+
});
|
|
35
|
+
/** Why a request failed, as a reason the App's error mapping can rely on; the message is for the operator. */
|
|
36
|
+
export class HttpSourceError extends Error {
|
|
37
|
+
reason;
|
|
38
|
+
status;
|
|
39
|
+
constructor(reason, message, status) {
|
|
40
|
+
super(message);
|
|
41
|
+
this.reason = reason;
|
|
42
|
+
this.status = status;
|
|
43
|
+
this.name = 'HttpSourceError';
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
const refused = (host, addresses) => new HttpSourceError('refused', `${host} resolves only to addresses this connection may not reach (${addresses.join(', ')}).`);
|
|
47
|
+
/* JSON with its big integers kept: a number past 2^53 comes back as the digits
|
|
48
|
+
it arrived with, which every display path keeps whole, rather than as the
|
|
49
|
+
nearest double. The reviver's third argument is the value's source text. */
|
|
50
|
+
function parseJson(text) {
|
|
51
|
+
const reviver = (_key, value, context) => typeof value === 'number' && !Number.isSafeInteger(value) && context?.source && /^-?\d+$/.test(context.source) ? context.source : value;
|
|
52
|
+
return JSON.parse(text, reviver);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* One GET. A 2xx answers its parsed JSON; any other status answers the status
|
|
56
|
+
* alone — its body is never read into anything a caller could forward.
|
|
57
|
+
*/
|
|
58
|
+
export function send(url, headers, policy) {
|
|
59
|
+
return request(url, { method: 'GET', headers }, policy);
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* One request of any method, under the same rules as a GET: a JSON body out,
|
|
63
|
+
* a JSON body back from a 2xx and nothing read from anything else. For the
|
|
64
|
+
* services a config names (search), which write as well as read.
|
|
65
|
+
*/
|
|
66
|
+
export function request(url, asked, policy) {
|
|
67
|
+
if (!tracing())
|
|
68
|
+
return requestUntraced(url, asked, policy);
|
|
69
|
+
/* An outbound call's span: its method, host and status travel, and the
|
|
70
|
+
caller's trace goes with it as `traceparent`. The URL's path and query,
|
|
71
|
+
the headers and the bodies stay local (adapters/telemetry/trace.ts). */
|
|
72
|
+
return inSpan(asked.method, {
|
|
73
|
+
kind: 'client',
|
|
74
|
+
attributes: {
|
|
75
|
+
'http.request.method': asked.method,
|
|
76
|
+
'server.address': url.hostname,
|
|
77
|
+
'server.port': url.port ? Number(url.port) : url.protocol === 'https:' ? 443 : 80,
|
|
78
|
+
'mistri.outbound.kind': asked.kind ?? 'http',
|
|
79
|
+
},
|
|
80
|
+
}, async (span) => {
|
|
81
|
+
span.detail(() => ({
|
|
82
|
+
request: {
|
|
83
|
+
method: asked.method,
|
|
84
|
+
url: url.href,
|
|
85
|
+
headers: asked.headers,
|
|
86
|
+
...(asked.text !== undefined ? { body: asked.text.body } : asked.body !== undefined ? { body: JSON.stringify(asked.body) } : {}),
|
|
87
|
+
},
|
|
88
|
+
}));
|
|
89
|
+
const reply = await requestUntraced(url, { ...asked, headers: injectTrace(asked.headers) }, policy);
|
|
90
|
+
span.setAttribute('http.response.status_code', reply.status);
|
|
91
|
+
if (reply.status >= 400)
|
|
92
|
+
span.fail(String(reply.status));
|
|
93
|
+
span.detail(() => ({
|
|
94
|
+
response: { status: reply.status, ...(reply.json !== undefined ? { body: JSON.stringify(reply.json).slice(0, 64 * 1024) } : {}) },
|
|
95
|
+
}));
|
|
96
|
+
return reply;
|
|
97
|
+
}, (error) => (error instanceof HttpSourceError ? error.reason : errorCode(error)));
|
|
98
|
+
}
|
|
99
|
+
function requestUntraced(url, asked, policy) {
|
|
100
|
+
const host = url.host;
|
|
101
|
+
if (url.protocol !== 'https:' && !(url.protocol === 'http:' && policy.insecure)) {
|
|
102
|
+
return Promise.reject(new HttpSourceError('refused', `${url.protocol}// is not allowed; use https, or set "insecure": true for an API on a trusted network.`));
|
|
103
|
+
}
|
|
104
|
+
if (url.username || url.password) {
|
|
105
|
+
return Promise.reject(new HttpSourceError('refused', 'A credential belongs in the connection\'s "auth", not in its URL.'));
|
|
106
|
+
}
|
|
107
|
+
// An address written into the URL is never looked up, so it is checked here, before any socket opens.
|
|
108
|
+
const literal = refusedLiteral(url.hostname, policy);
|
|
109
|
+
if (literal)
|
|
110
|
+
return Promise.reject(refused(host, [literal]));
|
|
111
|
+
const payload = asked.text !== undefined
|
|
112
|
+
? Buffer.from(asked.text.body, 'utf8')
|
|
113
|
+
: asked.body === undefined
|
|
114
|
+
? undefined
|
|
115
|
+
: Buffer.from(JSON.stringify(asked.body), 'utf8');
|
|
116
|
+
const headers = payload
|
|
117
|
+
? { ...asked.headers, 'content-type': asked.text?.type ?? 'application/json', 'content-length': String(payload.byteLength) }
|
|
118
|
+
: asked.headers;
|
|
119
|
+
return new Promise((resolve, reject) => {
|
|
120
|
+
let settled = false;
|
|
121
|
+
const finish = (error, reply) => {
|
|
122
|
+
if (settled)
|
|
123
|
+
return;
|
|
124
|
+
settled = true;
|
|
125
|
+
clearTimeout(deadline);
|
|
126
|
+
if (error) {
|
|
127
|
+
outgoing.destroy();
|
|
128
|
+
reject(error);
|
|
129
|
+
}
|
|
130
|
+
else
|
|
131
|
+
resolve(reply);
|
|
132
|
+
};
|
|
133
|
+
const deadline = setTimeout(() => finish(new HttpSourceError('timeout', `${host} did not answer within ${policy.timeoutMs / 1000} s.`)), policy.timeoutMs);
|
|
134
|
+
const open = url.protocol === 'https:' ? httpsRequest : httpRequest;
|
|
135
|
+
const outgoing = open(url, {
|
|
136
|
+
method: asked.method,
|
|
137
|
+
headers,
|
|
138
|
+
lookup: checkedLookup(policy, refused),
|
|
139
|
+
timeout: policy.connectTimeoutMs,
|
|
140
|
+
}, (response) => {
|
|
141
|
+
const status = response.statusCode ?? 0;
|
|
142
|
+
if (status >= 300 && status < 400) {
|
|
143
|
+
return finish(new HttpSourceError('redirect', `${host} redirected (${status}); redirects are not followed. Point the connection at the final address.`, status));
|
|
144
|
+
}
|
|
145
|
+
if (asked.discard || status < 200 || status > 299) {
|
|
146
|
+
response.resume();
|
|
147
|
+
return finish(null, { status, json: undefined });
|
|
148
|
+
}
|
|
149
|
+
const type = String(response.headers['content-type'] ?? '');
|
|
150
|
+
if (!/^application\/([\w.+-]*\+)?json\b/i.test(type)) {
|
|
151
|
+
return finish(new HttpSourceError('not_json', `${host} answered ${type || 'without a content type'}, not JSON.`));
|
|
152
|
+
}
|
|
153
|
+
const chunks = [];
|
|
154
|
+
let size = 0;
|
|
155
|
+
response.on('data', (chunk) => {
|
|
156
|
+
size += chunk.length;
|
|
157
|
+
if (size > policy.maxBytes)
|
|
158
|
+
return finish(new HttpSourceError('too_large', `${host} answered more than ${Math.round(policy.maxBytes / 1024 / 1024)} MB.`));
|
|
159
|
+
chunks.push(chunk);
|
|
160
|
+
});
|
|
161
|
+
response.on('end', () => {
|
|
162
|
+
try {
|
|
163
|
+
finish(null, { status, json: parseJson(Buffer.concat(chunks).toString('utf8')) });
|
|
164
|
+
}
|
|
165
|
+
catch {
|
|
166
|
+
finish(new HttpSourceError('not_json', `${host} answered text that is not JSON.`));
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
response.on('error', () => finish(new HttpSourceError('network', `${host} closed the connection mid-answer.`)));
|
|
170
|
+
});
|
|
171
|
+
outgoing.on('timeout', () => finish(new HttpSourceError('timeout', `${host} did not accept a connection within ${policy.connectTimeoutMs / 1000} s.`)));
|
|
172
|
+
outgoing.on('error', (error) => finish(error instanceof HttpSourceError ? error : new HttpSourceError('network', `${host}: ${error.code ?? 'the connection failed'}.`)));
|
|
173
|
+
outgoing.end(payload);
|
|
174
|
+
});
|
|
175
|
+
}
|