@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,606 @@
|
|
|
1
|
+
import { ANSI_STYLE, POSTGRES_STYLE } from '../adapters/adapter.js';
|
|
2
|
+
import { findTable } from '../shared/schema.js';
|
|
3
|
+
import { parseQuery, explain } from '../shared/query.js';
|
|
4
|
+
import { PathError, explainView, parseViewQuery } from '../shared/view.js';
|
|
5
|
+
import { textToView, viewToTextWithSchema } from '../shared/viewtext.js';
|
|
6
|
+
import { breakdownToText, sectionFromText, textToBreakdown } from '../shared/breakdowntext.js';
|
|
7
|
+
import { explainBreakdown } from '../shared/breakdown.js';
|
|
8
|
+
import { readRecords, readCount, readCounts, readView, readViewCount, readBreakdown, ResourceReadError, DEFAULT_COUNT_LIMIT, } from './resourceReadOperations.js';
|
|
9
|
+
import { clampLimit, clampOffset, COUNT_EACH_MAX } from '../shared/reads.js';
|
|
10
|
+
import { readPageStep } from '../shared/keysetPage.js';
|
|
11
|
+
import { recordsPaging, settlePage, viewPaging } from './keysetReadHttp.js';
|
|
12
|
+
/**
|
|
13
|
+
* A view's count as a plain count, when it is one: every condition names a
|
|
14
|
+
* column of the base itself — no path through a reference, no rollup, no
|
|
15
|
+
* label — so the view's joins and projection cannot change how many rows
|
|
16
|
+
* there are. Null otherwise, and for a condition compared with another column
|
|
17
|
+
* (`on_hand <= reorder_at`): only the view's compiler resolves the right-hand
|
|
18
|
+
* column against the reader's catalog, so a structured count refuses one, and
|
|
19
|
+
* the tab is counted as its list reads it, through the view.
|
|
20
|
+
*/
|
|
21
|
+
function plainCount(schema, view) {
|
|
22
|
+
const base = findTable(schema, view.base);
|
|
23
|
+
if (!base)
|
|
24
|
+
return null;
|
|
25
|
+
const own = (path) => path === undefined || (!path.includes('.') && !view.computed?.[path] && base.columns.some((column) => column.name === path));
|
|
26
|
+
const groups = view.filter?.groups ?? [];
|
|
27
|
+
if (!groups.every((group) => group.every((condition) => own(condition.path) && condition.other === undefined)))
|
|
28
|
+
return null;
|
|
29
|
+
return groups.length
|
|
30
|
+
? {
|
|
31
|
+
filter: {
|
|
32
|
+
groups: groups.map((group) => group.map((condition) => ({
|
|
33
|
+
column: condition.path,
|
|
34
|
+
op: condition.op,
|
|
35
|
+
...(condition.value === undefined ? {} : { value: condition.value }),
|
|
36
|
+
...(condition.collation === undefined ? {} : { collation: condition.collation }),
|
|
37
|
+
}))),
|
|
38
|
+
},
|
|
39
|
+
}
|
|
40
|
+
: {};
|
|
41
|
+
}
|
|
42
|
+
/* What a batched list's page may say: what `/api/run` reads of a first page. */
|
|
43
|
+
const RUN_FIELDS = ['q', 'limit', 'offset', 'count', 'exactCount', 'countLimit'];
|
|
44
|
+
/** A dashboard is at most a few dozen sections; a batch past this is not one. */
|
|
45
|
+
export const BREAKDOWN_BATCH = 48;
|
|
46
|
+
/* How many of a batch's breakdowns read at once: the PostgreSQL read pool's
|
|
47
|
+
default size (--read-pool), so a batch never queues behind itself. */
|
|
48
|
+
const BREAKDOWN_CONCURRENCY = 4;
|
|
49
|
+
/** The furthest a list is paged by offset over HTTP: past it the rows skipped cost more than the page. */
|
|
50
|
+
export const MAX_PAGE_OFFSET = 10_000;
|
|
51
|
+
/** The routes a list, a view or a breakdown is paged through. */
|
|
52
|
+
const PAGED = new Set(['/api/query', '/api/run', '/api/view/run', '/api/breakdown']);
|
|
53
|
+
/**
|
|
54
|
+
* Parse and shape the five resource-read routes using an already-authorized
|
|
55
|
+
* adapter. This owns no source acquisition, response stream or HTTP error class:
|
|
56
|
+
* escaping service validation errors retain their identity for the host to map.
|
|
57
|
+
*/
|
|
58
|
+
export async function dispatchResourceReadHttp(path, body, adapter, schema, options) {
|
|
59
|
+
/* A union's reads are its branches', each through this same reader (unionReads.ts). */
|
|
60
|
+
const app = options.app;
|
|
61
|
+
if (app)
|
|
62
|
+
adapter = app.reader(adapter, schema);
|
|
63
|
+
const sendData = (_route, value) => reply(200, app ? app.reply({ ...value }) : { ...value });
|
|
64
|
+
/* The person is looked up once, and only for text that compares with them. */
|
|
65
|
+
/* An App's weeks start where its locale says, never where a request does. */
|
|
66
|
+
const weekOf = (def) => (options.weekStart === undefined ? def : { ...def, weekStart: options.weekStart });
|
|
67
|
+
/* With the memberships the text reads (`me.group_member.group_id`), through this request's own reader. */
|
|
68
|
+
const personFor = async (...texts) => options.me && app ? app.person(options.me, texts, schema, adapter) : {};
|
|
69
|
+
/* A page is found by skipping every row before it, so the database walks
|
|
70
|
+
them all: page 80,000 of a sorted list was fifteen seconds on SQLite,
|
|
71
|
+
with the server's one handle held the whole time, and two seconds on
|
|
72
|
+
PostgreSQL. Nobody reads that far by paging; they narrow the list. An
|
|
73
|
+
export reads its own way (exportRoute.ts), and the App API by cursor. */
|
|
74
|
+
/* The query bar's list pages by key (keysetReadHttp.ts): a step after a
|
|
75
|
+
row, before one or from the end costs what the first page does, and the
|
|
76
|
+
offset it carries only names the page. A step the order cannot take —
|
|
77
|
+
no key, a sort through a reference — is an offset again, and meets the
|
|
78
|
+
ceiling below. */
|
|
79
|
+
const step = path === '/api/run' ? readPageStep(body) : undefined;
|
|
80
|
+
if (step === 'invalid')
|
|
81
|
+
return refusal(400, ['A page starts "after" a row, "before" one, or at the "end": one of the three.']);
|
|
82
|
+
const tooDeep = () => clampOffset(body.offset) > MAX_PAGE_OFFSET
|
|
83
|
+
? reply(200, {
|
|
84
|
+
errors: [
|
|
85
|
+
{
|
|
86
|
+
message: `That page starts past the first ${MAX_PAGE_OFFSET.toLocaleString('en-US')} rows, ` +
|
|
87
|
+
'which is further than a list is paged. Narrow the filter, or sort the other way to reach the end.',
|
|
88
|
+
},
|
|
89
|
+
],
|
|
90
|
+
})
|
|
91
|
+
: undefined;
|
|
92
|
+
if (PAGED.has(path) && !step) {
|
|
93
|
+
const refused = tooDeep();
|
|
94
|
+
if (refused)
|
|
95
|
+
return refused;
|
|
96
|
+
}
|
|
97
|
+
if (path === '/api/query') {
|
|
98
|
+
const { result, order } = await readRecords(adapter, schema, {
|
|
99
|
+
table: String(body.table ?? ''),
|
|
100
|
+
filter: body.filter,
|
|
101
|
+
columns: Array.isArray(body.columns) ? body.columns : undefined,
|
|
102
|
+
orderBy: body.orderBy,
|
|
103
|
+
limit: body.limit,
|
|
104
|
+
offset: body.offset,
|
|
105
|
+
});
|
|
106
|
+
return sendData(path, { ...result, order });
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Parse-and-run, for the query bar.
|
|
110
|
+
*
|
|
111
|
+
* The language lives on the server and only on the server. The client could
|
|
112
|
+
* parse it too, but then there would be two implementations to keep in step
|
|
113
|
+
* and a build step to ship the shared one to the browser. Sending the text
|
|
114
|
+
* and getting back rows, the compiled SQL and any errors costs one round
|
|
115
|
+
* trip and keeps the client a static file.
|
|
116
|
+
*/
|
|
117
|
+
if (path === '/api/run') {
|
|
118
|
+
/* `count: 'none'` is for a caller that never shows a total — a dashboard
|
|
119
|
+
tile, a palette search, a lookup, the cards and the calendar — and so
|
|
120
|
+
never pays for one. Anything else unreadable is refused rather than
|
|
121
|
+
read as the default, as /api/view/run refuses it. */
|
|
122
|
+
if (body.count !== undefined && body.count !== 'none' && body.count !== 'exact' && body.count !== 'estimate') {
|
|
123
|
+
return refusal(400, ['count must be "none", "exact" or "estimate".']);
|
|
124
|
+
}
|
|
125
|
+
const text = String(body.q ?? '');
|
|
126
|
+
const person = await personFor(text);
|
|
127
|
+
const parsed = parseQuery(text, { schema, now: options.now(), ...person });
|
|
128
|
+
/* A view is a superset of a query, so the bar can take one.
|
|
129
|
+
`invoice customer_id.name contains Harbour` is not a legal single-table
|
|
130
|
+
query — `customer_id.name` is not a column on invoice — but it is a
|
|
131
|
+
perfectly good view, and refusing it because of which endpoint the text
|
|
132
|
+
arrived at would be an implementation detail leaking into the language.
|
|
133
|
+
|
|
134
|
+
The fall-through is deliberately one-way and last. Anything that parses
|
|
135
|
+
cleanly as a query still runs as a query, so no text that works today
|
|
136
|
+
can change meaning; only text that would otherwise have been an error
|
|
137
|
+
gets a second reading. */
|
|
138
|
+
if ((!parsed.query || parsed.errors.length) && adapter.runView) {
|
|
139
|
+
const asView = textToView(schema, text, { id: 'bar', name: '', now: options.now(), ...person });
|
|
140
|
+
if (asView.view && !asView.errors.length) {
|
|
141
|
+
const base = findTable(schema, asView.view.base);
|
|
142
|
+
/* A union pages by offset: its rows have no one key order across branches (unionReads.ts). */
|
|
143
|
+
const paging = base && !base.union ? viewPaging(schema, base, asView.view, step) : undefined;
|
|
144
|
+
if (step && !paging?.continuation) {
|
|
145
|
+
const refused = tooDeep();
|
|
146
|
+
if (refused)
|
|
147
|
+
return refused;
|
|
148
|
+
}
|
|
149
|
+
const most = options.rowsMost?.(asView.view.base);
|
|
150
|
+
const bounded = most === undefined ? body : { ...body, limit: Math.min(clampLimit(body.limit ?? asView.view.limit), most) };
|
|
151
|
+
return runViewForBar(adapter, schema, asView.view, bounded, app, body.count === 'none' ? 'none' : 'exact', paging);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
if (!parsed.query)
|
|
155
|
+
return reply(200, { errors: parsed.errors });
|
|
156
|
+
// Errors that would change which rows come back must not be papered over
|
|
157
|
+
// with a partial result — a filter clause that failed to compile would
|
|
158
|
+
// otherwise silently return more rows than asked for.
|
|
159
|
+
if (parsed.errors.length) {
|
|
160
|
+
return sendData(path, { errors: parsed.errors, explain: explain(parsed.query) });
|
|
161
|
+
}
|
|
162
|
+
let q = parsed.query;
|
|
163
|
+
/* An explicit `columns` overrides the query's own `show` clause, matching
|
|
164
|
+
/api/query. Without it the two endpoints disagreed: one honoured the
|
|
165
|
+
field and the other ignored it silently, which is the worst of the
|
|
166
|
+
three options — a caller asking for three columns got all of them and
|
|
167
|
+
no indication why. */
|
|
168
|
+
if (Array.isArray(body.columns) && body.columns.length) {
|
|
169
|
+
const known = new Set(findTable(schema, q.table)?.columns.map((c) => c.name) ?? []);
|
|
170
|
+
const requested = body.columns.filter((c) => known.has(c));
|
|
171
|
+
const unknown = body.columns.filter((c) => !known.has(c));
|
|
172
|
+
if (unknown.length) {
|
|
173
|
+
return refusal(400, [`No column called "${unknown[0]}" on ${q.table}.`]);
|
|
174
|
+
}
|
|
175
|
+
// A copy: a parse is kept and shared (shared/query.ts), never changed.
|
|
176
|
+
q = { ...q, columns: requested };
|
|
177
|
+
}
|
|
178
|
+
/* An API reports no totals (adapters/http), and counting one would walk
|
|
179
|
+
every page of someone else's rate budget: its lists page by whether a
|
|
180
|
+
full page came back, as a view without a count does. */
|
|
181
|
+
const exact = body.exactCount === true || body.count === 'exact';
|
|
182
|
+
const countMode = schema.dialect === 'http' || body.count === 'none' ? 'none' : exact ? 'exact' : 'estimate';
|
|
183
|
+
/* A filtered total is counted to DEFAULT_COUNT_LIMIT unless the request
|
|
184
|
+
asks for the exact number or names its own bound: past it the list says
|
|
185
|
+
"10,000+" and offers to count exactly. Unfiltered, the catalog's
|
|
186
|
+
estimate or a plain count answers as before. */
|
|
187
|
+
const countLimit = body.countLimit ?? (!exact && q.filter?.groups?.length ? DEFAULT_COUNT_LIMIT : undefined);
|
|
188
|
+
const own = findTable(schema, q.table);
|
|
189
|
+
const most = options.rowsMost?.(own?.id ?? q.table);
|
|
190
|
+
const bounded = (limit) => (most === undefined ? limit : Math.min(clampLimit(limit), most));
|
|
191
|
+
const paging = own && !own.union ? recordsPaging(own, schema.dialect, q.orderBy, q.columns, q.filter, step) : undefined;
|
|
192
|
+
if (step && !paging?.continuation) {
|
|
193
|
+
const refused = tooDeep();
|
|
194
|
+
if (refused)
|
|
195
|
+
return refused;
|
|
196
|
+
}
|
|
197
|
+
const { result, total, order, request: { limit, offset }, } = await readRecords(adapter, schema, { ...q, ...(paging?.columns ? { columns: paging.columns } : {}), limit: bounded(body.limit ?? q.limit), offset: body.offset }, countMode, countLimit, paging?.continuation);
|
|
198
|
+
const settled = paging ? settlePage(paging.order, paging.extra, result) : undefined;
|
|
199
|
+
return sendData(path, {
|
|
200
|
+
table: q.table,
|
|
201
|
+
...result,
|
|
202
|
+
...(settled ? { rows: settled.rows, columns: settled.columns, ...(settled.bounds ? { bounds: settled.bounds } : {}) } : {}),
|
|
203
|
+
...(paging?.continuation ? { keyset: true } : {}),
|
|
204
|
+
...(total ? { total: total.count, exactTotal: total.exact } : {}),
|
|
205
|
+
// Only when a bounded count stopped: `total` is then the bound, and more match.
|
|
206
|
+
...(total?.capped ? { cappedTotal: true } : {}),
|
|
207
|
+
limit,
|
|
208
|
+
offset,
|
|
209
|
+
order,
|
|
210
|
+
explain: explain(q),
|
|
211
|
+
errors: [],
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Several counts in one request: a list's tab badges.
|
|
216
|
+
*
|
|
217
|
+
* Each item is a question in the language, as a tab writes it. Every one
|
|
218
|
+
* that reads a table with a plain filter is counted in one statement where
|
|
219
|
+
* the reader can (readCounts: one conditional aggregate per tab over a
|
|
220
|
+
* small table, one bounded count per tab over a large one), through this
|
|
221
|
+
* request's own reader — the same grants, the same row scope. A tab that
|
|
222
|
+
* needs a view (a path through a reference) is counted as a view. Each is
|
|
223
|
+
* bounded as a list's total is, and a question that does not parse fails
|
|
224
|
+
* alone, in its item.
|
|
225
|
+
*/
|
|
226
|
+
if (path === '/api/counts') {
|
|
227
|
+
const items = body.items;
|
|
228
|
+
if (!Array.isArray(items) || !items.length || items.length > COUNT_EACH_MAX || items.some((item) => typeof item !== 'string')) {
|
|
229
|
+
return refusal(400, [`A count batch is a list of 1 to ${COUNT_EACH_MAX} questions.`]);
|
|
230
|
+
}
|
|
231
|
+
const person = await personFor(...items);
|
|
232
|
+
const results = Array.from({ length: items.length });
|
|
233
|
+
const plain = [];
|
|
234
|
+
const views = [];
|
|
235
|
+
for (const [at, text] of items.entries()) {
|
|
236
|
+
const parsed = parseQuery(text, { schema, now: options.now(), ...person });
|
|
237
|
+
if (parsed.query && !parsed.errors.length) {
|
|
238
|
+
plain.push({ at, table: parsed.query.table, filter: parsed.query.filter });
|
|
239
|
+
continue;
|
|
240
|
+
}
|
|
241
|
+
const asView = adapter.runView ? textToView(schema, text, { id: 'bar', name: '', now: options.now(), ...person }) : undefined;
|
|
242
|
+
/* A list's tab asks its count in the list's own words, `show` paths
|
|
243
|
+
and all, which only a view reads; but a count reads only the
|
|
244
|
+
conditions. Conditions on the base's own columns are a plain count,
|
|
245
|
+
which is counted with the other tabs in one statement (countEach),
|
|
246
|
+
where a view is a statement of its own. */
|
|
247
|
+
const counted = asView?.view && !asView.errors.length ? plainCount(schema, asView.view) : null;
|
|
248
|
+
if (counted) {
|
|
249
|
+
plain.push({ at, table: asView.view.base, ...(counted.filter ? { filter: counted.filter } : {}) });
|
|
250
|
+
continue;
|
|
251
|
+
}
|
|
252
|
+
if (asView?.view && !asView.errors.length) {
|
|
253
|
+
/* A view's own statement, begun now and settled beside the plain
|
|
254
|
+
batch below: their waits overlap instead of adding. */
|
|
255
|
+
const view = asView.view;
|
|
256
|
+
views.push(readViewCount(adapter, schema, view, body.countLimit).then((counted) => {
|
|
257
|
+
results[at] = { total: counted.count, exactTotal: true, ...(counted.capped ? { cappedTotal: true } : {}) };
|
|
258
|
+
}));
|
|
259
|
+
continue;
|
|
260
|
+
}
|
|
261
|
+
results[at] = { errors: parsed.errors.length ? parsed.errors : [{ message: 'That question does not read as a count.' }] };
|
|
262
|
+
}
|
|
263
|
+
const batch = plain.length
|
|
264
|
+
? readCounts(adapter, schema, plain, body.countLimit).then((counts) => {
|
|
265
|
+
plain.forEach(({ at }, i) => {
|
|
266
|
+
results[at] = {
|
|
267
|
+
total: counts[i].count,
|
|
268
|
+
exactTotal: counts[i].exact,
|
|
269
|
+
...(counts[i].capped ? { cappedTotal: true } : {}),
|
|
270
|
+
};
|
|
271
|
+
});
|
|
272
|
+
})
|
|
273
|
+
: undefined;
|
|
274
|
+
/* Settled whole, so a failure leaves no read running behind the reply. */
|
|
275
|
+
const settled = await Promise.allSettled(batch ? [...views, batch] : views);
|
|
276
|
+
const failed = settled.find((result) => result.status === 'rejected');
|
|
277
|
+
if (failed)
|
|
278
|
+
throw failed.reason;
|
|
279
|
+
return reply(200, { results });
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Several breakdowns in one request: a dashboard's cards, and its lists.
|
|
283
|
+
*
|
|
284
|
+
* A metric asks for its number, its compare window's number and its spark,
|
|
285
|
+
* and every chart and table asks once more, so an eight-card home was about
|
|
286
|
+
* thirty requests queued on one active connection and six browser sockets.
|
|
287
|
+
* Each item is answered by the single-breakdown route below, through this
|
|
288
|
+
* request's own adapter, so it reads exactly what that route would have —
|
|
289
|
+
* the same grant, the same row scope, the same errors — and a failing item
|
|
290
|
+
* fails alone. They run a few at a time: a PostgreSQL connection
|
|
291
|
+
* reads through a pool of several, so a filter rail's facets and a
|
|
292
|
+
* dashboard's cards cost the slowest of them rather than their sum; SQLite
|
|
293
|
+
* reads in process, where running them together costs nothing more. The
|
|
294
|
+
* answers keep the request's order.
|
|
295
|
+
*/
|
|
296
|
+
if (path === '/api/breakdowns') {
|
|
297
|
+
const items = body.items;
|
|
298
|
+
if (!Array.isArray(items) ||
|
|
299
|
+
!items.length ||
|
|
300
|
+
items.length > BREAKDOWN_BATCH ||
|
|
301
|
+
items.some((item) => !item || typeof item !== 'object' || Array.isArray(item))) {
|
|
302
|
+
return refusal(400, [`A breakdown batch is a list of 1 to ${BREAKDOWN_BATCH} breakdowns.`]);
|
|
303
|
+
}
|
|
304
|
+
/* A dashboard's lists ride with its numbers: an item that is `run` is a
|
|
305
|
+
list's first page, answered as `/api/run` answers it. Only the page's
|
|
306
|
+
own fields are passed on, so a batch cannot ask anything the single
|
|
307
|
+
route would not. */
|
|
308
|
+
const run = (item) => item.run && typeof item.run === 'object' && !Array.isArray(item.run) ? item.run : undefined;
|
|
309
|
+
if (items.some((item) => 'run' in item && !run(item))) {
|
|
310
|
+
return refusal(400, ['A batched list is `run: { q, limit, offset, count, exactCount, countLimit }`.']);
|
|
311
|
+
}
|
|
312
|
+
const results = Array.from({ length: items.length });
|
|
313
|
+
const queue = items.map((item, at) => ({ item, at }));
|
|
314
|
+
const one = async () => {
|
|
315
|
+
for (let next = queue.shift(); next; next = queue.shift()) {
|
|
316
|
+
const page = run(next.item);
|
|
317
|
+
const { def, text, limit, offset } = next.item;
|
|
318
|
+
try {
|
|
319
|
+
results[next.at] = (await (page
|
|
320
|
+
? dispatchResourceReadHttp('/api/run', Object.fromEntries(RUN_FIELDS.filter((field) => page[field] !== undefined).map((field) => [field, page[field]])), adapter, schema, options)
|
|
321
|
+
: dispatchResourceReadHttp('/api/breakdown', { def, text, limit, offset }, adapter, schema, options)));
|
|
322
|
+
}
|
|
323
|
+
catch (error) {
|
|
324
|
+
/* A request's own refusal (a ResourceReadError: the provider's are
|
|
325
|
+
stripped of the class before they get here) is said in its item.
|
|
326
|
+
Anything else is the host's to map and, in an App, to keep private,
|
|
327
|
+
so it fails the whole request; the client then asks each alone.
|
|
328
|
+
The rest of the batch is not started: its answer is not sent. */
|
|
329
|
+
if (!(error instanceof ResourceReadError)) {
|
|
330
|
+
queue.length = 0;
|
|
331
|
+
throw error;
|
|
332
|
+
}
|
|
333
|
+
results[next.at] = reply(error.status, { error: error.message });
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
};
|
|
337
|
+
await Promise.all(Array.from({ length: Math.min(BREAKDOWN_CONCURRENCY, queue.length) }, one));
|
|
338
|
+
return reply(200, { results });
|
|
339
|
+
}
|
|
340
|
+
/**
|
|
341
|
+
* Run a breakdown: counts and sums, grouped by something.
|
|
342
|
+
*
|
|
343
|
+
* Text in, groups out. The language lives on the server and only on the
|
|
344
|
+
* server — the same rule the query bar and the view composer follow — so
|
|
345
|
+
* the client sends the line somebody typed and gets back the rows, what the
|
|
346
|
+
* columns are, and how many groups there are in total.
|
|
347
|
+
*
|
|
348
|
+
* Errors are a 200 with `errors`, not a 4xx: a half-typed breakdown is the
|
|
349
|
+
* normal state of an input box, and an HTTP error code for it would have
|
|
350
|
+
* the client rendering "request failed" over a message that says which
|
|
351
|
+
* column was misspelled.
|
|
352
|
+
*/
|
|
353
|
+
if (path === '/api/breakdown') {
|
|
354
|
+
if (!adapter.runBreakdown) {
|
|
355
|
+
return reply(501, { error: `${schema.dialect} connections cannot group in this build.` });
|
|
356
|
+
}
|
|
357
|
+
/* The structured entry, for page sections: their root filters walk
|
|
358
|
+
dotted paths the text grammar cannot write, so they arrive as the
|
|
359
|
+
BreakdownDef the planner built rather than as text. One that does
|
|
360
|
+
not compile is answered in the language's own error vocabulary —
|
|
361
|
+
the def may also be hand-made, and a hand is a thing that slips. */
|
|
362
|
+
if (body.def && typeof body.def === 'object') {
|
|
363
|
+
const given = weekOf(body.def);
|
|
364
|
+
try {
|
|
365
|
+
const { breakdown: def, result, names, total, offset, } = await readBreakdown(adapter, schema, given, { limit: body.limit, offset: body.offset });
|
|
366
|
+
return sendData(path, {
|
|
367
|
+
breakdown: def,
|
|
368
|
+
columns: result.columns,
|
|
369
|
+
resolved: result.resolved,
|
|
370
|
+
rows: result.rows,
|
|
371
|
+
...(names ? { names } : {}),
|
|
372
|
+
total,
|
|
373
|
+
offset,
|
|
374
|
+
ms: result.ms,
|
|
375
|
+
sql: result.sql,
|
|
376
|
+
});
|
|
377
|
+
}
|
|
378
|
+
catch (err) {
|
|
379
|
+
// ResourceReadError and the host's former HttpError conversion both
|
|
380
|
+
// receive appError's generic read projection here. Do not promote this
|
|
381
|
+
// structured-entry catch into a new public validation exemption.
|
|
382
|
+
return reply(200, { errors: [app ? app.error(err) : { message: err.message }] });
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
const text = String(body.text ?? '');
|
|
386
|
+
const parsed = textToBreakdown(schema, text, { now: options.now(), ...(await personFor(text)) });
|
|
387
|
+
if (!parsed.breakdown)
|
|
388
|
+
return reply(200, { errors: parsed.errors });
|
|
389
|
+
/* Handed on as the structure it parsed to, without its text. An App's
|
|
390
|
+
access layer re-reads any text it is given (text is authoritative
|
|
391
|
+
until materialized), and it has no request clock: it read "next 7
|
|
392
|
+
days" on the wall clock in the server's zone, so the filter rail's
|
|
393
|
+
counts asked about another week than its list did. Without the text,
|
|
394
|
+
the def is checked as a structured one, the way `body.def` is above. */
|
|
395
|
+
const { text: _text, ...materialized } = weekOf(parsed.breakdown);
|
|
396
|
+
const { breakdown: def, result, names, total, offset, } = await readBreakdown(adapter, schema, materialized, { limit: body.limit, offset: body.offset });
|
|
397
|
+
return sendData(path, {
|
|
398
|
+
breakdown: def,
|
|
399
|
+
text: breakdownToText(schema, def),
|
|
400
|
+
/* The workbench-to-config bridge: the same line, already shaped as
|
|
401
|
+
a dashboard section for the copy button in the breakdown head. */
|
|
402
|
+
section: sectionFromText(schema, text),
|
|
403
|
+
columns: result.columns,
|
|
404
|
+
resolved: result.resolved,
|
|
405
|
+
rows: result.rows,
|
|
406
|
+
/* Each reference key's groups by the name of the record they are, as a grid names it. */
|
|
407
|
+
...(names ? { names } : {}),
|
|
408
|
+
total,
|
|
409
|
+
offset,
|
|
410
|
+
ms: result.ms,
|
|
411
|
+
sql: result.sql,
|
|
412
|
+
/* The same statement with its values written in, for the SQL pane.
|
|
413
|
+
`sql` above keeps the parameterised form, which is what actually ran
|
|
414
|
+
and what anything machine-readable should be reading. */
|
|
415
|
+
explain: explainBreakdown(schema, def, styleFor(schema), offset),
|
|
416
|
+
});
|
|
417
|
+
}
|
|
418
|
+
/**
|
|
419
|
+
* Run a multi-table view: the composer's whole back end.
|
|
420
|
+
* The optional query box overrides the supplied definition, but parse errors
|
|
421
|
+
* must never be papered over with a partial result and a broader filter.
|
|
422
|
+
*/
|
|
423
|
+
if (path === '/api/view/run') {
|
|
424
|
+
/* Views historically count exactly. Opting out is deliberately explicit:
|
|
425
|
+
* malformed input must refuse rather than quietly skip a caller's count. */
|
|
426
|
+
const countMode = body.count === undefined ? 'exact' : body.count;
|
|
427
|
+
if (countMode !== 'none' && countMode !== 'exact') {
|
|
428
|
+
return refusal(400, ['count must be "none" or "exact".']);
|
|
429
|
+
}
|
|
430
|
+
if (!adapter.runView) {
|
|
431
|
+
return reply(501, { error: `${schema.dialect} connections cannot run views in this build.` });
|
|
432
|
+
}
|
|
433
|
+
let view = normaliseView(body.view);
|
|
434
|
+
let merged = view;
|
|
435
|
+
const person = await personFor(body.text, body.query);
|
|
436
|
+
const errors = [];
|
|
437
|
+
if (!view.base && typeof body.text !== 'string') {
|
|
438
|
+
return refusal(400, ['A view needs a base table.']);
|
|
439
|
+
}
|
|
440
|
+
/* A view may arrive as text instead of a structure — `work_order show
|
|
441
|
+
reference, customer_id.name as customer count …`. It is the same
|
|
442
|
+
language and the same parser; only the shape of what the client sent
|
|
443
|
+
differs, so it is normalised here and everything below is unchanged. */
|
|
444
|
+
if (typeof body.text === 'string' && body.text.trim()) {
|
|
445
|
+
const parsed = textToView(schema, body.text, { id: view.id, name: view.name, now: options.now(), ...person });
|
|
446
|
+
if (parsed.errors.length || !parsed.view)
|
|
447
|
+
return reply(200, { errors: parsed.errors });
|
|
448
|
+
view = parsed.view;
|
|
449
|
+
merged = parsed.view;
|
|
450
|
+
}
|
|
451
|
+
if (typeof body.query === 'string' && body.query.trim()) {
|
|
452
|
+
const parsed = parseViewQuery(schema, view.base, body.query, options.now(), person);
|
|
453
|
+
errors.push(...parsed.errors);
|
|
454
|
+
merged = {
|
|
455
|
+
...view,
|
|
456
|
+
filter: parsed.filter.groups.length ? parsed.filter : view.filter,
|
|
457
|
+
/* A `show` clause in the box overrides the checklist, matching how
|
|
458
|
+
`/api/run` lets an explicit column list win. Silently honouring one
|
|
459
|
+
and ignoring the other is the worst of the three options. */
|
|
460
|
+
columns: parsed.columns.length ? parsed.columns.map((p) => ({ path: p })) : view.columns,
|
|
461
|
+
orderBy: parsed.orderBy.length ? parsed.orderBy : view.orderBy,
|
|
462
|
+
limit: parsed.limit ?? view.limit,
|
|
463
|
+
};
|
|
464
|
+
}
|
|
465
|
+
if (errors.length)
|
|
466
|
+
return reply(200, { errors });
|
|
467
|
+
try {
|
|
468
|
+
const { view: validated, result, total, more, limit, offset, } = await readView(adapter, schema, merged, { limit: body.limit, offset: body.offset }, countMode);
|
|
469
|
+
return sendData(path, {
|
|
470
|
+
view: validated,
|
|
471
|
+
text: viewToTextWithSchema(schema, merged),
|
|
472
|
+
total,
|
|
473
|
+
columns: result.columns,
|
|
474
|
+
resolved: result.resolved,
|
|
475
|
+
joins: result.joins,
|
|
476
|
+
rows: result.rows,
|
|
477
|
+
ms: result.ms,
|
|
478
|
+
sql: result.sql,
|
|
479
|
+
explain: explainView(schema, { ...merged, limit }, styleFor(schema)),
|
|
480
|
+
more,
|
|
481
|
+
limit,
|
|
482
|
+
offset,
|
|
483
|
+
errors: [],
|
|
484
|
+
});
|
|
485
|
+
}
|
|
486
|
+
catch (err) {
|
|
487
|
+
if (err instanceof PathError) {
|
|
488
|
+
return refusal(400, [err.message]);
|
|
489
|
+
}
|
|
490
|
+
throw err;
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
/* `countLimit`, here and on /api/run, bounds the count (countLimitOf): at
|
|
494
|
+
most that many rows are counted, and past it the answer is the bound with
|
|
495
|
+
`capped`. Absent, the count is the one these routes always gave. */
|
|
496
|
+
if (path === '/api/count') {
|
|
497
|
+
const result = await readCount(adapter, schema, {
|
|
498
|
+
table: String(body.table ?? ''),
|
|
499
|
+
filter: body.filter,
|
|
500
|
+
exact: body.exactCount === true,
|
|
501
|
+
countLimit: body.countLimit,
|
|
502
|
+
});
|
|
503
|
+
return reply(200, {
|
|
504
|
+
count: result.count,
|
|
505
|
+
exact: result.exact,
|
|
506
|
+
...(result.capped ? { capped: true } : {}),
|
|
507
|
+
});
|
|
508
|
+
}
|
|
509
|
+
return undefined;
|
|
510
|
+
}
|
|
511
|
+
function reply(status, body) {
|
|
512
|
+
return { status, body };
|
|
513
|
+
}
|
|
514
|
+
function refusal(status, messages) {
|
|
515
|
+
return reply(status, { error: messages[0], errors: messages.map((message) => ({ message })) });
|
|
516
|
+
}
|
|
517
|
+
/**
|
|
518
|
+
* Run a view for the query bar, answering in the shape the grid expects.
|
|
519
|
+
*
|
|
520
|
+
* Same keys as `/api/run`'s ordinary answer — `table`, `columns`, `rows`,
|
|
521
|
+
* `total`, `explain` — so the renderer needs no branch. What it gains is
|
|
522
|
+
* `resolved`, which says what each output column actually is; a client that
|
|
523
|
+
* ignores it renders path-named columns as plain text, which is a degradation
|
|
524
|
+
* rather than a break.
|
|
525
|
+
*/
|
|
526
|
+
async function runViewForBar(adapter, schema, view, body, app, countMode = 'exact', paging) {
|
|
527
|
+
try {
|
|
528
|
+
const { view: validated, result, total, limit, offset, } = await readView(adapter, schema, paging?.view ?? view, { limit: body.limit, offset: body.offset }, countMode, undefined, paging?.continuation);
|
|
529
|
+
/* A row's value for an order path is under the column that path compiled to. */
|
|
530
|
+
const named = (path) => result.resolved?.find((column) => column.path === path)?.name ?? path;
|
|
531
|
+
const settled = paging ? settlePage(paging.order, paging.extra, result, named) : undefined;
|
|
532
|
+
const dropped = new Set(paging?.extra ?? []);
|
|
533
|
+
const value = {
|
|
534
|
+
table: view.base,
|
|
535
|
+
view: validated,
|
|
536
|
+
text: viewToTextWithSchema(schema, view),
|
|
537
|
+
columns: settled?.columns ?? result.columns,
|
|
538
|
+
resolved: dropped.size ? result.resolved?.filter((column) => !dropped.has(column.path)) : result.resolved,
|
|
539
|
+
joins: result.joins,
|
|
540
|
+
rows: settled?.rows ?? result.rows,
|
|
541
|
+
...(settled?.bounds ? { bounds: settled.bounds } : {}),
|
|
542
|
+
...(paging?.continuation ? { keyset: true } : {}),
|
|
543
|
+
ms: result.ms,
|
|
544
|
+
total,
|
|
545
|
+
limit,
|
|
546
|
+
offset,
|
|
547
|
+
explain: explainView(schema, { ...view, limit }, styleFor(schema)),
|
|
548
|
+
errors: [],
|
|
549
|
+
};
|
|
550
|
+
return reply(200, app ? app.reply(value) : value);
|
|
551
|
+
}
|
|
552
|
+
catch (err) {
|
|
553
|
+
if (err instanceof PathError)
|
|
554
|
+
return refusal(400, [err.message]);
|
|
555
|
+
throw err;
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
/**
|
|
559
|
+
* Which dialect writes the SQL shown in the explain panel.
|
|
560
|
+
*
|
|
561
|
+
* The adapter picks its own style when it runs the statement; this is the
|
|
562
|
+
* copy the user reads, and it has to agree with what actually ran or the
|
|
563
|
+
* panel is teaching the wrong thing.
|
|
564
|
+
*/
|
|
565
|
+
export function styleFor(schema) {
|
|
566
|
+
if (schema.dialect === 'postgres')
|
|
567
|
+
return POSTGRES_STYLE;
|
|
568
|
+
return ANSI_STYLE;
|
|
569
|
+
}
|
|
570
|
+
/**
|
|
571
|
+
* Coerce a JSON body into a `ViewDef`.
|
|
572
|
+
*
|
|
573
|
+
* Shape only. Whether the paths mean anything is `compileView`'s job, and it
|
|
574
|
+
* refuses what it cannot resolve — so this does not need to know the schema,
|
|
575
|
+
* and there is no second, weaker validator to disagree with the first.
|
|
576
|
+
*/
|
|
577
|
+
export function normaliseView(raw) {
|
|
578
|
+
const v = (raw ?? {});
|
|
579
|
+
const columns = Array.isArray(v.columns) ? v.columns : [];
|
|
580
|
+
const orderBy = Array.isArray(v.orderBy) ? v.orderBy : [];
|
|
581
|
+
return {
|
|
582
|
+
id: String(v.id ?? ''),
|
|
583
|
+
name: String(v.name ?? ''),
|
|
584
|
+
base: String(v.base ?? '').trim(),
|
|
585
|
+
columns: columns
|
|
586
|
+
.map((c) => typeof c === 'string'
|
|
587
|
+
? { path: c }
|
|
588
|
+
: { path: String(c?.path ?? ''), alias: c?.alias })
|
|
589
|
+
.filter((c) => c.path),
|
|
590
|
+
aggregates: Array.isArray(v.aggregates) ? v.aggregates : undefined,
|
|
591
|
+
filter: (v.filter ?? undefined),
|
|
592
|
+
orderBy: orderBy
|
|
593
|
+
.map((o) => {
|
|
594
|
+
const entry = o;
|
|
595
|
+
return {
|
|
596
|
+
path: String(entry?.path ?? ''),
|
|
597
|
+
direction: entry?.direction === 'desc' ? 'desc' : 'asc',
|
|
598
|
+
/* A similar list's closest-first order. Only a number passes here,
|
|
599
|
+
and the compiler refuses one that is not finite and safe. */
|
|
600
|
+
...(typeof entry?.near === 'number' ? { near: entry.near } : {}),
|
|
601
|
+
};
|
|
602
|
+
})
|
|
603
|
+
.filter((o) => o.path),
|
|
604
|
+
limit: typeof v.limit === 'number' ? v.limit : undefined,
|
|
605
|
+
};
|
|
606
|
+
}
|