@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,291 @@
|
|
|
1
|
+
import { pageAbouts } from '../../shared/pageModel.js';
|
|
2
|
+
import { resolveOf, validatePage } from '../../shared/page.js';
|
|
3
|
+
import { planPageSections } from '../../shared/pagePlans.js';
|
|
4
|
+
import { filtersPath, filtersSection, writeLayout } from '../layouts.js';
|
|
5
|
+
import { readRecords, readCounts } from '../resourceReadOperations.js';
|
|
6
|
+
import { AppAccessDenied } from '../columnGrants.js';
|
|
7
|
+
import { inBatches } from '../impact.js';
|
|
8
|
+
import { referencesTo, findTable, labelColumn, primaryKey } from '../../shared/schema.js';
|
|
9
|
+
import { httpRead, send } from './reply.js';
|
|
10
|
+
export async function pageRoutes(post, hooks) {
|
|
11
|
+
const { res, path, body, adapter, schema, registry, connection, configPages, access, principal, rowPolicy, appNow } = post;
|
|
12
|
+
const rules = hooks.rules;
|
|
13
|
+
/**
|
|
14
|
+
* The saved list filters for one list (`list`: an App list view's key,
|
|
15
|
+
* not a table — two views over one table keep their own): a list of
|
|
16
|
+
* {name, query}, written whole — the client owns ordering and dedupe, and reads the current list
|
|
17
|
+
* before it writes — or null to remove the entry. The same store
|
|
18
|
+
* discipline as saved pages, for the same reason: a filter that lives in
|
|
19
|
+
* one browser dies with the browser. In a signed-in App the write lands in
|
|
20
|
+
* the verified account's own section (layouts.ts); the body cannot name
|
|
21
|
+
* another, and a request with no account that may keep one is refused.
|
|
22
|
+
*/
|
|
23
|
+
if (path === '/api/filters/save') {
|
|
24
|
+
const section = filtersSection(connection, { signIn: Boolean(rules?.signsIn(post)), account: principal, rowPolicy });
|
|
25
|
+
if (section === null) {
|
|
26
|
+
send(res, 403, { error: 'Saved views are kept per account here, and this request has none that may keep them.' });
|
|
27
|
+
return true;
|
|
28
|
+
}
|
|
29
|
+
const list = String(body.list ?? '');
|
|
30
|
+
if (!list) {
|
|
31
|
+
send(res, 400, { error: 'Saved filters belong to a list.' });
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
const filters = body.filters;
|
|
35
|
+
if (filters !== null && !Array.isArray(filters)) {
|
|
36
|
+
send(res, 400, { error: 'Filters must be a list, or null to remove them.' });
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
/* Shape-checked per entry, refused not coerced: the store round-trips
|
|
40
|
+
whatever it is handed, so junk accepted here is junk served to every
|
|
41
|
+
browser from now on. */
|
|
42
|
+
if (Array.isArray(filters)) {
|
|
43
|
+
for (const f of filters) {
|
|
44
|
+
const shaped = f &&
|
|
45
|
+
typeof f === 'object' &&
|
|
46
|
+
typeof f.name === 'string' &&
|
|
47
|
+
typeof f.query === 'string';
|
|
48
|
+
if (!shaped) {
|
|
49
|
+
send(res, 400, { error: 'Each saved filter must be { name, query }, both strings.' });
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
try {
|
|
55
|
+
// An array is as opaque to the store as a layout object; it only
|
|
56
|
+
// round-trips what the client wrote.
|
|
57
|
+
await writeLayout(section, list, filters ?? null, filtersPath());
|
|
58
|
+
}
|
|
59
|
+
catch (err) {
|
|
60
|
+
/* Unlike layouts, filters keep no localStorage mirror — a failed write
|
|
61
|
+
means the filter is saved nowhere, and the message must say so. */
|
|
62
|
+
send(res, 500, rules
|
|
63
|
+
? { error: 'The filter could not be saved. Try again shortly.', code: 'definition_save_failed' }
|
|
64
|
+
: { error: `The filter was not saved — the filters file could not be written: ${err.message}` });
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
send(res, 200, { ok: true });
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* What each section of a page needs to run, for one root record.
|
|
72
|
+
*
|
|
73
|
+
* One call for the whole page rather than one per section, and it returns
|
|
74
|
+
* *plans* rather than results: the client runs each view itself, so a count
|
|
75
|
+
* over a large child table does not hold up the record's own name. Waiting
|
|
76
|
+
* for all of them would make the slowest section the speed of the page.
|
|
77
|
+
*
|
|
78
|
+
* The views are built here because building them is path resolution against
|
|
79
|
+
* a schema, and a second copy of those rules in the browser is the drift
|
|
80
|
+
* this codebase has paid for in every feature that tried it.
|
|
81
|
+
*
|
|
82
|
+
* A section that cannot be built comes back with its reason, in place. One
|
|
83
|
+
* bad path must not cost the other five sections — a page is most useful on
|
|
84
|
+
* exactly the day something is misconfigured.
|
|
85
|
+
*/
|
|
86
|
+
if (path === '/api/pages/plan') {
|
|
87
|
+
const key = (body.key ?? {});
|
|
88
|
+
const name = registry.list().find((c) => c.id === connection)?.name;
|
|
89
|
+
/* A page arrives either as a name or as itself.
|
|
90
|
+
|
|
91
|
+
Pages come from three places: the config file, the schema, and the
|
|
92
|
+
builder — and the third lives in the browser's own storage, which the
|
|
93
|
+
server has never seen. Planning by id alone meant a page someone had
|
|
94
|
+
just built could be listed, opened and titled, and then rendered as
|
|
95
|
+
"there is no page called that", because the only part that needed the
|
|
96
|
+
schema was the part that had never heard of it.
|
|
97
|
+
|
|
98
|
+
Handing the definition over is safe for the same reason a filter is: it
|
|
99
|
+
is structured, it is validated against this connection before anything
|
|
100
|
+
runs, and every value in it ends up bound rather than written into
|
|
101
|
+
SQL. */
|
|
102
|
+
const asked = body.page;
|
|
103
|
+
const found = typeof asked === 'object' && asked !== null
|
|
104
|
+
? asked
|
|
105
|
+
: String(asked ?? '').startsWith('suggested:')
|
|
106
|
+
? hooks.suggested(post, String(asked).slice('suggested:'.length))
|
|
107
|
+
: configPages.find((p) => p.id === String(asked ?? '') && (!p.connection || p.connection === connection || p.connection === name));
|
|
108
|
+
if (!found) {
|
|
109
|
+
send(res, 404, { error: `There is no page called "${String(asked ?? '')}".` });
|
|
110
|
+
return true;
|
|
111
|
+
}
|
|
112
|
+
if (access && !access.readable.has(found.base))
|
|
113
|
+
throw new AppAccessDenied();
|
|
114
|
+
if (access?.fields && rules && !rules.readsPage(schema, found))
|
|
115
|
+
throw new AppAccessDenied();
|
|
116
|
+
if (typeof found.base !== 'string' || !Array.isArray(found.sections)) {
|
|
117
|
+
send(res, 400, { error: 'That is not a page: it needs a "base" table and a list of sections.' });
|
|
118
|
+
return true;
|
|
119
|
+
}
|
|
120
|
+
const page = validatePage(schema, found);
|
|
121
|
+
if (page.error) {
|
|
122
|
+
send(res, 400, { error: page.error });
|
|
123
|
+
return true;
|
|
124
|
+
}
|
|
125
|
+
const base = findTable(schema, page.base);
|
|
126
|
+
const missing = primaryKey(base).filter((c) => key[c] === undefined);
|
|
127
|
+
if (missing.length) {
|
|
128
|
+
send(res, 400, {
|
|
129
|
+
error: `This page is about one ${base.name}, and the key is missing ${missing.join(', ')}.`,
|
|
130
|
+
});
|
|
131
|
+
return true;
|
|
132
|
+
}
|
|
133
|
+
if (rowPolicy && rules)
|
|
134
|
+
await rules.requireRecord(adapter, schema, page.base, key);
|
|
135
|
+
/* Sections about a record the root points at need that record's key,
|
|
136
|
+
which only the root row knows. One read, of just the reference
|
|
137
|
+
columns, shared by every such section — and a reference that is null
|
|
138
|
+
resolves to `null`, which the section renders as its empty state
|
|
139
|
+
rather than as a filter that can never match. */
|
|
140
|
+
const ofs = pageAbouts(page);
|
|
141
|
+
const ofKeys = {};
|
|
142
|
+
if (ofs.length) {
|
|
143
|
+
const resolvedOfs = ofs.map((of) => ({ of, ...resolveOf(schema, page.base, of) })).filter((r) => r.fk);
|
|
144
|
+
const wanted = [...new Set(resolvedOfs.flatMap((r) => r.fk.from.columns))];
|
|
145
|
+
if (wanted.length) {
|
|
146
|
+
const row = (await httpRead(() => readRecords(adapter, schema, {
|
|
147
|
+
table: page.base,
|
|
148
|
+
filter: { groups: [primaryKey(base).map((c) => ({ column: c, op: '=', value: key[c] }))] },
|
|
149
|
+
columns: wanted,
|
|
150
|
+
limit: 1,
|
|
151
|
+
offset: 0,
|
|
152
|
+
}))).result.rows[0];
|
|
153
|
+
for (const r of resolvedOfs) {
|
|
154
|
+
const values = r.fk.from.columns.map((c) => row?.[c]);
|
|
155
|
+
ofKeys[r.of] = values.every((v) => v !== null && v !== undefined)
|
|
156
|
+
? Object.fromEntries(r.fk.to.columns.map((c, i) => [c, values[i]]))
|
|
157
|
+
: null;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
/* A matched list shares the record's own values, so they are read here,
|
|
162
|
+
on the server, from the record's row — never taken from the request.
|
|
163
|
+
Read through the same scoped adapter, so a value the reader may not
|
|
164
|
+
read is refused like any other read of it. */
|
|
165
|
+
const likeColumns = [
|
|
166
|
+
...new Set(page.sections.flatMap((s) => (s.kind === 'list' && s.similar ? [...s.similar.same, ...Object.keys(s.similar.near ?? {})] : []))),
|
|
167
|
+
];
|
|
168
|
+
let rootValues;
|
|
169
|
+
if (likeColumns.length) {
|
|
170
|
+
rootValues = ((await httpRead(() => readRecords(adapter, schema, {
|
|
171
|
+
table: page.base,
|
|
172
|
+
filter: { groups: [primaryKey(base).map((c) => ({ column: c, op: '=', value: key[c] }))] },
|
|
173
|
+
columns: likeColumns,
|
|
174
|
+
limit: 1,
|
|
175
|
+
offset: 0,
|
|
176
|
+
}))).result.rows[0] ?? {});
|
|
177
|
+
}
|
|
178
|
+
// Capture once after root lookup: every section uses the same App date.
|
|
179
|
+
const plans = planPageSections(schema, page, key, ofKeys, appNow(), rootValues);
|
|
180
|
+
send(res, 200, { page, plans });
|
|
181
|
+
return true;
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* The endpoint the whole tool exists for: given one row, how many rows in
|
|
185
|
+
* every other table point at it, and what would you click to see them.
|
|
186
|
+
*
|
|
187
|
+
* Counting is done server-side and in parallel because a row in a
|
|
188
|
+
* well-normalised schema can be referenced from a dozen places, and a dozen
|
|
189
|
+
* sequential round trips is the difference between instant and sluggish.
|
|
190
|
+
*/
|
|
191
|
+
if (path === '/api/references') {
|
|
192
|
+
const tableId = String(body.table ?? '');
|
|
193
|
+
const key = (body.key ?? {});
|
|
194
|
+
const table = findTable(schema, tableId);
|
|
195
|
+
if (!table) {
|
|
196
|
+
send(res, 404, { error: `Unknown table "${tableId}"` });
|
|
197
|
+
return true;
|
|
198
|
+
}
|
|
199
|
+
const incoming = referencesTo(schema, tableId);
|
|
200
|
+
/* A declared reference may point at a column that is not this row's key
|
|
201
|
+
(a code, a slug): its value is the row's, so the row is read for it,
|
|
202
|
+
in the one read a row policy makes to admit the record anyway. */
|
|
203
|
+
const unkeyed = [...new Set(incoming.flatMap((fk) => fk.to.columns))].filter((column) => !Object.hasOwn(key, column));
|
|
204
|
+
let row = key;
|
|
205
|
+
if (rowPolicy && rules)
|
|
206
|
+
row = { ...(await rules.readRecord(adapter, schema, tableId, key, unkeyed)), ...key };
|
|
207
|
+
else if (unkeyed.length && Object.keys(key).length) {
|
|
208
|
+
const { result } = await readRecords(adapter, schema, {
|
|
209
|
+
table: table.id,
|
|
210
|
+
columns: unkeyed,
|
|
211
|
+
limit: 1,
|
|
212
|
+
offset: 0,
|
|
213
|
+
filter: { groups: [Object.entries(key).map(([column, value]) => ({ column, op: '=', value }))] },
|
|
214
|
+
});
|
|
215
|
+
row = { ...result.rows[0], ...key };
|
|
216
|
+
}
|
|
217
|
+
/* Every reference counted in one statement where the reader can say it
|
|
218
|
+
in one (readCounts), each bounded: past DEFAULT_COUNT_LIMIT the answer
|
|
219
|
+
is the bound and `capped`, and the panel says "10,000+". These were a
|
|
220
|
+
filtered, unbounded COUNT(*) apiece, four at a time — on a hub table
|
|
221
|
+
with a dozen incoming keys, a dozen scans against the connection
|
|
222
|
+
serving the page they are for, most of them over unindexed columns. */
|
|
223
|
+
const described = incoming
|
|
224
|
+
.map((fk) => {
|
|
225
|
+
/* Every column of the key has to match, which is what makes this
|
|
226
|
+
correct for composite keys and not just single-column ones. */
|
|
227
|
+
const conditions = fk.to.columns.map((toCol, i) => ({
|
|
228
|
+
column: fk.from.columns[i] ?? fk.from.columns[0],
|
|
229
|
+
op: '=',
|
|
230
|
+
value: row[toCol],
|
|
231
|
+
}));
|
|
232
|
+
const usable = conditions.every((c) => c.value !== undefined && c.value !== null);
|
|
233
|
+
const filter = { groups: [conditions] };
|
|
234
|
+
return usable
|
|
235
|
+
? {
|
|
236
|
+
fk,
|
|
237
|
+
filter,
|
|
238
|
+
base: {
|
|
239
|
+
table: fk.from.table,
|
|
240
|
+
columns: fk.from.columns,
|
|
241
|
+
// The matching key columns on this row's side, so the client can
|
|
242
|
+
// pair them by position rather than guessing from key order.
|
|
243
|
+
toColumns: fk.to.columns,
|
|
244
|
+
constraint: fk.name,
|
|
245
|
+
filter,
|
|
246
|
+
label: labelColumn(findTable(schema, fk.from.table)),
|
|
247
|
+
},
|
|
248
|
+
}
|
|
249
|
+
: null;
|
|
250
|
+
})
|
|
251
|
+
.filter((item) => item !== null);
|
|
252
|
+
/* A source that reports no totals (an API) is not asked for one: the
|
|
253
|
+
reference is listed without a count, and the panel's own read of its
|
|
254
|
+
rows says what is there. Asking would only ever be refused. */
|
|
255
|
+
const countable = described.filter((item) => findTable(schema, item.fk.from.table)?.countable !== false);
|
|
256
|
+
const failed = (err) => {
|
|
257
|
+
const said = rules?.said(err);
|
|
258
|
+
return { count: -1, error: said ? said.message : err.message, ...(said ? { code: said.code } : {}) };
|
|
259
|
+
};
|
|
260
|
+
const counts = new Map();
|
|
261
|
+
try {
|
|
262
|
+
const answered = countable.length
|
|
263
|
+
? await readCounts(adapter, schema, countable.map((item) => ({ table: item.fk.from.table, filter: item.filter })))
|
|
264
|
+
: [];
|
|
265
|
+
countable.forEach((item, i) => counts.set(item.fk.name, { count: answered[i].count, ...(answered[i].capped ? { capped: true } : {}) }));
|
|
266
|
+
}
|
|
267
|
+
catch {
|
|
268
|
+
/* One unreadable table (permissions, a dropped view) should not blank
|
|
269
|
+
the whole panel: asked again one at a time, each failure stays in
|
|
270
|
+
its own row. A small window, as before, so the record itself can
|
|
271
|
+
still be answered on the same connection. */
|
|
272
|
+
await inBatches(countable, 4, async (item) => {
|
|
273
|
+
try {
|
|
274
|
+
const [one] = await readCounts(adapter, schema, [{ table: item.fk.from.table, filter: item.filter }]);
|
|
275
|
+
counts.set(item.fk.name, { count: one.count, ...(one.capped ? { capped: true } : {}) });
|
|
276
|
+
}
|
|
277
|
+
catch (err) {
|
|
278
|
+
counts.set(item.fk.name, failed(err));
|
|
279
|
+
}
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
const results = described.map((item) => ({ ...item.base, ...counts.get(item.fk.name) }));
|
|
283
|
+
send(res, 200, {
|
|
284
|
+
table: tableId,
|
|
285
|
+
primaryKey: primaryKey(table),
|
|
286
|
+
references: results,
|
|
287
|
+
});
|
|
288
|
+
return true;
|
|
289
|
+
}
|
|
290
|
+
return false;
|
|
291
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `/healthz` and `/readyz`, for an orchestrator.
|
|
3
|
+
*
|
|
4
|
+
* `/healthz` is liveness: the process answers HTTP. `/readyz` is readiness:
|
|
5
|
+
* it should be sent traffic now — false while it starts, while a row policy
|
|
6
|
+
* restarts after a save, and from the moment it begins shutting down, so a
|
|
7
|
+
* load balancer stops sending before the listener closes. Both are answered
|
|
8
|
+
* before any gate or App, carry nothing but their word, are never cached and
|
|
9
|
+
* are not traced (a heartbeat every few seconds is not a trace).
|
|
10
|
+
*
|
|
11
|
+
* Both answer `{ deploy, build }` beside the status (`mistri deploy` verifies a
|
|
12
|
+
* roll by them): `deploy` is MISTRI_DEPLOY_ID, which the platform's Worker sets
|
|
13
|
+
* in the container's environment on each deploy, and `build` is the id of the
|
|
14
|
+
* build being served. Both are random or a hash, so safe to expose.
|
|
15
|
+
*
|
|
16
|
+
* The operator reads with more in them (`/api/operations/readiness`) are
|
|
17
|
+
* signed-in and granted; these are not, and so say nothing else.
|
|
18
|
+
*/
|
|
19
|
+
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
20
|
+
/** Where `/readyz` reads the served build's id from; the App framework registers it when it serves a build. */
|
|
21
|
+
export declare function setBuildIdSource(source: () => string | null): void;
|
|
22
|
+
export declare function probe(req: IncomingMessage, res: ServerResponse, path: string, ready?: () => boolean): boolean;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
let buildSource = () => null;
|
|
2
|
+
/** Where `/readyz` reads the served build's id from; the App framework registers it when it serves a build. */
|
|
3
|
+
export function setBuildIdSource(source) {
|
|
4
|
+
buildSource = source;
|
|
5
|
+
}
|
|
6
|
+
export function probe(req, res, path, ready) {
|
|
7
|
+
if (path !== '/healthz' && path !== '/readyz')
|
|
8
|
+
return false;
|
|
9
|
+
if (req.method !== 'GET' && req.method !== 'HEAD') {
|
|
10
|
+
res.writeHead(405, { allow: 'GET, HEAD', 'cache-control': 'no-store' }).end();
|
|
11
|
+
return true;
|
|
12
|
+
}
|
|
13
|
+
let ok = true;
|
|
14
|
+
if (path === '/readyz') {
|
|
15
|
+
try {
|
|
16
|
+
ok = ready?.() ?? true;
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
ok = false;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
res.writeHead(ok ? 200 : 503, { 'content-type': 'application/json; charset=utf-8', 'cache-control': 'no-store' });
|
|
23
|
+
res.end(req.method === 'HEAD'
|
|
24
|
+
? undefined
|
|
25
|
+
: JSON.stringify({ status: ok ? 'ok' : 'unavailable', deploy: process.env.MISTRI_DEPLOY_ID || null, build: buildSource() }));
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A fixed-window limiter per client, for the one surface a signed-out person
|
|
3
|
+
* may write to: a public form. In memory by default, so a restart forgets
|
|
4
|
+
* and a second process does not share; when the config names a cache
|
|
5
|
+
* (`"kind": "cache"`), the same windows are counted there instead, so every
|
|
6
|
+
* instance of a deployment spends one budget (`SharedWindowLimiter`). The
|
|
7
|
+
* limits are deployment-owned defaults and not configurable. The address is
|
|
8
|
+
* the one `forwardedClient` resolves: a forwarded header only when the socket
|
|
9
|
+
* peer is a trusted proxy — on this machine, or named by `--trust-proxy` —
|
|
10
|
+
* else the peer itself, so a proxy on another host that nobody named still
|
|
11
|
+
* collapses its clients to one address, which the docs say.
|
|
12
|
+
*
|
|
13
|
+
* Bounded, because the clients are whoever the network sends. The review
|
|
14
|
+
* that asked for this measured the first version: past its cap it scanned
|
|
15
|
+
* every tracked address on each new one and dropped only the fully expired,
|
|
16
|
+
* which under the one-hour window was none — 40,000 addresses held the event
|
|
17
|
+
* loop for 21 seconds, and every address in one IPv6 /64 had its own budget.
|
|
18
|
+
* Now: a hard cap on tracked clients, a Map kept in least-recently-seen
|
|
19
|
+
* order (a touch re-inserts, the front is the stalest) so expiry is a sweep
|
|
20
|
+
* from the front that stops at the first live entry — O(1) amortised, no
|
|
21
|
+
* scan and no timer — and an IPv6 client is its /64.
|
|
22
|
+
*/
|
|
23
|
+
import type { IncomingMessage } from 'node:http';
|
|
24
|
+
import { type CacheStore } from '../../adapters/cache/cacheStore.js';
|
|
25
|
+
import { type ProxyRange } from './trust.js';
|
|
26
|
+
interface RateWindow {
|
|
27
|
+
limit: number;
|
|
28
|
+
ms: number;
|
|
29
|
+
}
|
|
30
|
+
/** `scope` says whose budget ran out: this client's, or the one every client shares. */
|
|
31
|
+
type RateDecision = {
|
|
32
|
+
ok: true;
|
|
33
|
+
remaining: number;
|
|
34
|
+
} | {
|
|
35
|
+
ok: false;
|
|
36
|
+
retryAfterSeconds: number;
|
|
37
|
+
scope: 'client' | 'all';
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Which budgets a take spends: the client's and the shared ceiling together (`'both'`, the default), or one of
|
|
41
|
+
* them. A door that proves its caller (a ticket, a human check) spends the client's first and the ceiling only
|
|
42
|
+
* once the proof passes, so a flood that cannot prove anything spends its own addresses' budgets, never the one
|
|
43
|
+
* every visitor shares.
|
|
44
|
+
*/
|
|
45
|
+
export type RatePart = 'both' | 'client' | 'all';
|
|
46
|
+
/** A limiter that decides now (in memory) or once the shared cache has counted. */
|
|
47
|
+
interface WindowLimiter {
|
|
48
|
+
take(address: string, part?: RatePart): RateDecision | Promise<RateDecision>;
|
|
49
|
+
/** Forget this process's own counts; tests and a policy reload use it. A shared cache's windows expire on their own. */
|
|
50
|
+
reset(): void;
|
|
51
|
+
}
|
|
52
|
+
interface LimiterOptions {
|
|
53
|
+
/** The most clients tracked at once. */
|
|
54
|
+
maxClients?: number;
|
|
55
|
+
/**
|
|
56
|
+
* A new client, when every slot holds a budget still in force: `refuse` it
|
|
57
|
+
* until the stalest slot expires, or `evict` the stalest and admit it.
|
|
58
|
+
*/
|
|
59
|
+
whenFull?: 'refuse' | 'evict';
|
|
60
|
+
/** Windows over every client together: what rotating addresses cannot exceed. */
|
|
61
|
+
total?: readonly RateWindow[];
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* The key a client's budget is kept under. IPv4 as it is; an IPv4-mapped
|
|
65
|
+
* IPv6 address (`::ffff:192.0.2.1`, how a dual-stack socket reports an IPv4
|
|
66
|
+
* peer) as that IPv4 address; any other IPv6 address as its /64, the
|
|
67
|
+
* smallest network one subscriber is routinely given — one host can
|
|
68
|
+
* otherwise draw a fresh budget from each of its 2^64 addresses. Anything
|
|
69
|
+
* that is not an address (`unknown`) is its own key.
|
|
70
|
+
*/
|
|
71
|
+
export declare function limitKey(address: string): string;
|
|
72
|
+
export declare class FixedWindowLimiter implements WindowLimiter {
|
|
73
|
+
private readonly windows;
|
|
74
|
+
private readonly now;
|
|
75
|
+
private readonly hits;
|
|
76
|
+
private readonly longest;
|
|
77
|
+
private readonly maxClients;
|
|
78
|
+
private readonly whenFull;
|
|
79
|
+
private readonly totalWindows;
|
|
80
|
+
private total;
|
|
81
|
+
constructor(windows: readonly RateWindow[], now?: () => number, options?: LimiterOptions);
|
|
82
|
+
/** Count one request for the client, or say how long it waits. */
|
|
83
|
+
take(address: string, part?: RatePart): RateDecision;
|
|
84
|
+
private takeShared;
|
|
85
|
+
/** How many clients are tracked; tests read it. */
|
|
86
|
+
get size(): number;
|
|
87
|
+
/** Forget every client and the shared count; tests and a policy reload use it. */
|
|
88
|
+
reset(): void;
|
|
89
|
+
private expire;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* The same windows, counted in the deployment's cache so every instance
|
|
93
|
+
* spends one budget. Each window is a key per client (and one for everyone)
|
|
94
|
+
* counted by the cache's atomic windowed count, which starts the window on
|
|
95
|
+
* the first request; a refused request is counted too, which only keeps an
|
|
96
|
+
* exceeded window exceeded until it ends on its own. There is no cap on
|
|
97
|
+
* tracked clients to keep: every key expires with its window.
|
|
98
|
+
*
|
|
99
|
+
* When the cache cannot count, the process's own limiter decides — the
|
|
100
|
+
* budget degrades to one instance's, never to none.
|
|
101
|
+
*/
|
|
102
|
+
export declare class SharedWindowLimiter implements WindowLimiter {
|
|
103
|
+
private readonly name;
|
|
104
|
+
private readonly windows;
|
|
105
|
+
private readonly cache;
|
|
106
|
+
private readonly fallback;
|
|
107
|
+
private readonly totalWindows?;
|
|
108
|
+
constructor(name: string, windows: readonly RateWindow[], cache: CacheStore, fallback: FixedWindowLimiter, totalWindows?: readonly RateWindow[] | undefined);
|
|
109
|
+
take(address: string, part?: RatePart): Promise<RateDecision>;
|
|
110
|
+
reset(): void;
|
|
111
|
+
private count;
|
|
112
|
+
}
|
|
113
|
+
/** The client a limit counts against; a forwarded header only from a trusted peer (loopback, or `--trust-proxy`). */
|
|
114
|
+
export declare function clientAddress(req: Pick<IncomingMessage, 'socket' | 'headers'>, trusted?: readonly ProxyRange[]): string;
|
|
115
|
+
export declare const PUBLIC_FORM_SUBMIT_WINDOWS: readonly RateWindow[];
|
|
116
|
+
export declare const PUBLIC_FORM_SUBMIT_TOTAL: readonly RateWindow[];
|
|
117
|
+
export declare const PUBLIC_FORM_READ_WINDOWS: readonly RateWindow[];
|
|
118
|
+
export declare const INVITATION_CLAIM_WINDOWS: readonly RateWindow[];
|
|
119
|
+
export declare const INVITATION_CLAIM_TOTAL: readonly RateWindow[];
|
|
120
|
+
export declare function publicFormLimiter(kind: 'submit' | 'read' | 'start' | 'status' | 'link' | 'code' | 'check'): FixedWindowLimiter | SharedWindowLimiter;
|
|
121
|
+
/** The invitation claims' own budget (tenantInvitationHttp.ts), never the forms'. */
|
|
122
|
+
export declare function invitationClaimLimiter(): FixedWindowLimiter | SharedWindowLimiter;
|
|
123
|
+
/**
|
|
124
|
+
* Count the public forms' windows in the deployment's cache, under the
|
|
125
|
+
* deployment's namespace (`tw:<app>:form:`), or — with no cache, or the
|
|
126
|
+
* process's own — in this process, as before.
|
|
127
|
+
*/
|
|
128
|
+
export declare function configurePublicFormLimits(cache: CacheStore | undefined, namespace: string): void;
|
|
129
|
+
/** Forgets the forms' budgets and the claims'; tests and a policy reload use it. */
|
|
130
|
+
export declare function resetPublicFormLimits(): void;
|
|
131
|
+
export {};
|