@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,323 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Evidence: capturing what a caller handed in as frozen plain data, and
|
|
3
|
+
* failing closed when it cannot be trusted.
|
|
4
|
+
*
|
|
5
|
+
* It lived in `src/server/tenant/` because tenancy is where it was first
|
|
6
|
+
* needed, and 27 modules outside tenancy ended up importing tenancy for it —
|
|
7
|
+
* `auth/`, `app/`, `cli/`, `commands/` and every non-tenant `api/` file — which
|
|
8
|
+
* made a folder boundary unreadable: almost every arrow into tenant/ was this
|
|
9
|
+
* one file. Nothing in it is tenant-specific. It stays under `src/server/`
|
|
10
|
+
* rather than `src/shared/` because it reads `node:util/types` and the
|
|
11
|
+
* adapters' outcome error, neither of which the client may carry.
|
|
12
|
+
*
|
|
13
|
+
* The names are unchanged, tenant spelling and all: they are what the refusal
|
|
14
|
+
* path reads as, and renaming them would have made one mechanical move into a
|
|
15
|
+
* diff nobody could review.
|
|
16
|
+
*/
|
|
17
|
+
import { isProxy, isUint8Array } from 'node:util/types';
|
|
18
|
+
import { TransactionOutcomeUnknown } from '../adapters/adapter.js';
|
|
19
|
+
import { PoolBusy } from '../adapters/poolMetrics.js';
|
|
20
|
+
import { Refusal, recordRefusalCause, refusalCause } from '../shared/refusal.js';
|
|
21
|
+
import { isCapturedScopeCatalog } from '../shared/scopeCatalog.js';
|
|
22
|
+
import { keepBreakdownsAgainst } from '../shared/breakdown.js';
|
|
23
|
+
import { isRowScopeSnapshot } from '../shared/rowScope.js';
|
|
24
|
+
import { carryServerRequest } from './serverRequests.js';
|
|
25
|
+
/** Private admission errors reveal neither membership existence nor provider data. */
|
|
26
|
+
export class TenantContextError extends Error {
|
|
27
|
+
code = 'tenant_context_unavailable';
|
|
28
|
+
constructor() {
|
|
29
|
+
super('The tenant context could not be verified.');
|
|
30
|
+
this.name = 'TenantContextError';
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/* The recorded reason behind every opaque refusal lives with the refusal
|
|
34
|
+
class itself (shared/refusal.ts), so an adapter's scope check records one
|
|
35
|
+
the same way a tenant denial does. */
|
|
36
|
+
export { recordRefusalCause, refusalCause, refusalHeadline, refusalReasons, refusalReasonsBelow } from '../shared/refusal.js';
|
|
37
|
+
export const denyTenant = (cause) => {
|
|
38
|
+
throw recordRefusalCause(new TenantContextError(), cause);
|
|
39
|
+
};
|
|
40
|
+
/** The database could not answer, so authority was never decided: not a
|
|
41
|
+
* refusal. Still a TenantContextError — every consumer that denies on one
|
|
42
|
+
* still denies — and carries no `cause`, so no driver text travels with it
|
|
43
|
+
* (the driver's error is recorded for the operator, as any refusal's is).
|
|
44
|
+
* Only an owner that answers a caller tells the two apart (503, not 403). */
|
|
45
|
+
export class TenantUnavailableError extends TenantContextError {
|
|
46
|
+
code = 'tenant_temporarily_unavailable';
|
|
47
|
+
}
|
|
48
|
+
const NETWORK = new Set(['ECONNREFUSED', 'ECONNRESET', 'EPIPE', 'ETIMEDOUT', 'EHOSTUNREACH', 'ENETUNREACH', 'ENOTFOUND', 'EAI_AGAIN']);
|
|
49
|
+
/* Recognized positively. Every refusal in the tenant path is a
|
|
50
|
+
TenantContextError, and anything unrecognized denies, so a new failure
|
|
51
|
+
shape can only ever be answered as a refusal, never as a fault that hides
|
|
52
|
+
one. */
|
|
53
|
+
export function databaseFault(error) {
|
|
54
|
+
if (error instanceof TenantUnavailableError)
|
|
55
|
+
return true;
|
|
56
|
+
if (error instanceof TenantContextError || !(error instanceof Error))
|
|
57
|
+
return false;
|
|
58
|
+
if (error instanceof TransactionOutcomeUnknown)
|
|
59
|
+
return true;
|
|
60
|
+
/* A pool that would not lend a connection in time (poolMetrics.ts): nothing
|
|
61
|
+
was leased, so nothing was asked. Under load this is the commonest fault
|
|
62
|
+
there is, and answered as a denial it told a person their tenant context
|
|
63
|
+
was gone because the server was busy (a field report: 403s on reads at
|
|
64
|
+
twelve users on half a core). */
|
|
65
|
+
if (error instanceof PoolBusy)
|
|
66
|
+
return true;
|
|
67
|
+
// A check refused because the engine could not answer (the SQLite catalog
|
|
68
|
+
// scan): the cause, one level deep and itself a raw driver error, decides.
|
|
69
|
+
if (error instanceof Refusal)
|
|
70
|
+
return !(error.cause instanceof Refusal) && databaseFault(error.cause);
|
|
71
|
+
const { code, severity } = error;
|
|
72
|
+
// node:sqlite: busy, locked, I/O, a missing or unreadable file.
|
|
73
|
+
if (code === 'ERR_SQLITE_ERROR')
|
|
74
|
+
return true;
|
|
75
|
+
if (typeof code === 'string' && NETWORK.has(code))
|
|
76
|
+
return true;
|
|
77
|
+
/* An integrity rule the database enforced (class 23: a key already taken, a
|
|
78
|
+
reference to nothing, a required value, a check) is the database answering,
|
|
79
|
+
and refusing: permanent for that write, and never a reason to try again.
|
|
80
|
+
Counted as unanswered, a duplicate key was told "try again" with a
|
|
81
|
+
Retry-After (a live load test). Every write route answers it as the refusal
|
|
82
|
+
it is (constraints.ts writeRefusalStatus). A data exception (class 22) stays
|
|
83
|
+
below on purpose: on a tenant read it is a filter value its column cannot
|
|
84
|
+
hold, and a denial there would end the person's context; a write route
|
|
85
|
+
recognizes it before asking this (tenantWriteFault.ts). */
|
|
86
|
+
if (typeof severity === 'string' && typeof code === 'string' && code.startsWith('23'))
|
|
87
|
+
return false;
|
|
88
|
+
// pg's DatabaseError: a server-reported SQLSTATE (a terminated backend, a
|
|
89
|
+
// database refusing connections, a cancelled or timed-out statement).
|
|
90
|
+
if (typeof severity === 'string' && typeof code === 'string' && /^[0-9A-Z]{5}$/.test(code))
|
|
91
|
+
return true;
|
|
92
|
+
// pg's own connection errors, and this pool's, carry no code.
|
|
93
|
+
return /^(?:Connection terminated|Client has encountered a connection error|Client was closed|timeout exceeded when trying to connect|Observed PostgreSQL checkout is unavailable|Postgres connection manager is closed)/.test(error.message);
|
|
94
|
+
}
|
|
95
|
+
/** The request's own fault, said to the caller as that, not as the context's
|
|
96
|
+
* denial: no record this context reads has the key (`not_found`, the same for
|
|
97
|
+
* one that is missing and one that is another tenant's), or a read that cannot
|
|
98
|
+
* be answered as asked (`invalid_read`). The context read and decided
|
|
99
|
+
* nothing to its detriment, and revalidates before this is let out
|
|
100
|
+
* (tenantReadRuntime.ts), so the session that asked keeps going. It carries
|
|
101
|
+
* no data: its words are fixed here. */
|
|
102
|
+
export class TenantRequestFault extends Error {
|
|
103
|
+
status;
|
|
104
|
+
code;
|
|
105
|
+
constructor(status, code) {
|
|
106
|
+
super(code === 'not_found' ? 'No such record.' : 'This read cannot be answered.');
|
|
107
|
+
this.status = status;
|
|
108
|
+
this.code = code;
|
|
109
|
+
this.name = 'TenantRequestFault';
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Whether the database not answering is what failed, under however many
|
|
114
|
+
* refusals and failures it was recorded: a tenant write's failure is
|
|
115
|
+
* value-free on purpose and keeps what failed beneath it, and a read that
|
|
116
|
+
* waited on that write (an inbox's mail) refuses with it as its cause. Read
|
|
117
|
+
* positively, as `databaseFault` is, and a denial anywhere on the way down
|
|
118
|
+
* stays a denial: it decided something, whatever lies beneath it.
|
|
119
|
+
*/
|
|
120
|
+
export function databaseUnanswered(error) {
|
|
121
|
+
let at = error;
|
|
122
|
+
for (let depth = 0; at !== null && typeof at === 'object' && depth < 16; depth++) {
|
|
123
|
+
if (databaseFault(at))
|
|
124
|
+
return true;
|
|
125
|
+
if (at instanceof TenantContextError)
|
|
126
|
+
return false;
|
|
127
|
+
at = refusalCause(at) ?? (at instanceof Error ? at.cause : undefined);
|
|
128
|
+
}
|
|
129
|
+
return false;
|
|
130
|
+
}
|
|
131
|
+
/** Deny, unless the cause is the database failing to answer: then the tenant
|
|
132
|
+
* context is unavailable. Fails closed either way. */
|
|
133
|
+
export const denyTenantFor = (cause) => {
|
|
134
|
+
throw recordRefusalCause(databaseUnanswered(cause) ? new TenantUnavailableError() : new TenantContextError(), cause);
|
|
135
|
+
};
|
|
136
|
+
const capturedData = new WeakMap();
|
|
137
|
+
/* A scope catalog (shared/scopeCatalog.ts) is detached, validated and deeply
|
|
138
|
+
frozen plain data too; its cost is measured once, without copying it. So is
|
|
139
|
+
a row scope snapshotRowScope made (shared/rowScope.ts): a tenant read hands
|
|
140
|
+
its request's scope through several captures, and each copied it whole. */
|
|
141
|
+
const catalogCosts = new WeakMap();
|
|
142
|
+
function catalogCost(value) {
|
|
143
|
+
let cost = catalogCosts.get(value);
|
|
144
|
+
if (cost)
|
|
145
|
+
return cost;
|
|
146
|
+
cost = { nodes: 0, characters: 0, depth: 0 };
|
|
147
|
+
const walk = (node, depth) => {
|
|
148
|
+
cost.nodes++;
|
|
149
|
+
if (depth > cost.depth)
|
|
150
|
+
cost.depth = depth;
|
|
151
|
+
if (typeof node === 'string')
|
|
152
|
+
cost.characters += node.length;
|
|
153
|
+
else if (node && typeof node === 'object')
|
|
154
|
+
for (const key of Object.keys(node)) {
|
|
155
|
+
if (!Array.isArray(node))
|
|
156
|
+
cost.characters += key.length;
|
|
157
|
+
walk(node[key], depth + 1);
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
walk(value, 0);
|
|
161
|
+
catalogCosts.set(value, cost);
|
|
162
|
+
return cost;
|
|
163
|
+
}
|
|
164
|
+
/* A caller's value frozen all the way down — every object and array in it frozen as given, plain data with no
|
|
165
|
+
accessor (a copy refuses one) and no proxy — is one nothing can change either: freezing cannot be undone, and a
|
|
166
|
+
frozen object's values cannot be swapped. A policy's row scope is such a constant (`Object.freeze({ lead: true,
|
|
167
|
+
… })`), handed back on every request and copied afresh by each, so every request's scope was new data and nothing
|
|
168
|
+
keyed by it was ever found again (tenantReadScope.ts). Its capture is kept with it, and reused as a captured value
|
|
169
|
+
is: same object, same cost charged. */
|
|
170
|
+
const frozenCaptures = new WeakMap();
|
|
171
|
+
/** Test-only: how many objects and arrays captures have copied, as opposed to reused. */
|
|
172
|
+
export const captureCounters = { copied: 0 };
|
|
173
|
+
/** Whether a value is one captureTenantData froze all the way down, or a
|
|
174
|
+
* captured scope catalog: data that cannot change for as long as it lives, so
|
|
175
|
+
* an answer derived from it alone may be kept with it (a WeakMap keyed by it)
|
|
176
|
+
* and is gone when it is. A reload captures new values and starts afresh. */
|
|
177
|
+
export function isCapturedTenantData(value) {
|
|
178
|
+
return value !== null && typeof value === 'object' && (capturedData.has(value) || isCapturedScopeCatalog(value));
|
|
179
|
+
}
|
|
180
|
+
/* A breakdown compiled against such a catalog is kept with it (breakdown.ts compileBreakdown): a served tenant
|
|
181
|
+
catalog is one, and an enter compiles each of its breakdowns against it for the access check and the SQL pane. */
|
|
182
|
+
keepBreakdownsAgainst(isCapturedTenantData);
|
|
183
|
+
/** Server evidence is data, never getters, proxies, thenables or inherited grants. */
|
|
184
|
+
export function captureTenantData(input) {
|
|
185
|
+
/* A capture handed back whole is itself, within every bound by having been
|
|
186
|
+
made within them: answered before the walk's state is set up, since a
|
|
187
|
+
request hands the same evidence through dozens of these. */
|
|
188
|
+
if (input !== null && typeof input === 'object' && capturedData.has(input))
|
|
189
|
+
return carryServerRequest(input, input);
|
|
190
|
+
let nodes = 0, characters = 0, reach = 0, bytes = 0,
|
|
191
|
+
/* Objects copied that were not frozen as given: a subtree with none is the caller's constant. */
|
|
192
|
+
thawed = 0;
|
|
193
|
+
const reuse = (value, depth) => {
|
|
194
|
+
const cost = capturedData.get(value) ??
|
|
195
|
+
(isCapturedScopeCatalog(value) || isRowScopeSnapshot(value) ? catalogCost(value) : undefined);
|
|
196
|
+
if (!cost)
|
|
197
|
+
return undefined;
|
|
198
|
+
// Exactly the counts a fresh copy of this value would have added.
|
|
199
|
+
if ((nodes += cost.nodes) > 262_144 || depth + cost.depth > 24 || (characters += cost.characters) > 16_777_216)
|
|
200
|
+
return denyTenant();
|
|
201
|
+
if (depth + cost.depth > reach)
|
|
202
|
+
reach = depth + cost.depth;
|
|
203
|
+
return value;
|
|
204
|
+
};
|
|
205
|
+
const copy = (value, depth = 0) => {
|
|
206
|
+
if (value !== null && typeof value === 'object' && !isProxy(value)) {
|
|
207
|
+
const kept = reuse(frozenCaptures.get(value) ?? value, depth);
|
|
208
|
+
if (kept !== undefined)
|
|
209
|
+
return kept;
|
|
210
|
+
}
|
|
211
|
+
if (++nodes > 262_144 || depth > 24)
|
|
212
|
+
return denyTenant();
|
|
213
|
+
if (depth > reach)
|
|
214
|
+
reach = depth;
|
|
215
|
+
if (value === undefined || value === null || typeof value === 'boolean')
|
|
216
|
+
return value;
|
|
217
|
+
if (typeof value === 'number')
|
|
218
|
+
return Number.isFinite(value) ? value : denyTenant();
|
|
219
|
+
if (typeof value === 'string') {
|
|
220
|
+
if ((characters += value.length) > 16_777_216)
|
|
221
|
+
return denyTenant();
|
|
222
|
+
return value;
|
|
223
|
+
}
|
|
224
|
+
if (typeof value !== 'object' || isProxy(value))
|
|
225
|
+
return denyTenant();
|
|
226
|
+
/* A file's bytes (a file resource's content column, read or written): a
|
|
227
|
+
genuine byte array, copied, so nothing the caller still holds changes
|
|
228
|
+
what was captured. Counted against the same budget as text. */
|
|
229
|
+
if (isUint8Array(value)) {
|
|
230
|
+
const copied = Buffer.from(value);
|
|
231
|
+
bytes++;
|
|
232
|
+
if ((characters += copied.byteLength) > 16_777_216)
|
|
233
|
+
return denyTenant();
|
|
234
|
+
return copied;
|
|
235
|
+
}
|
|
236
|
+
const array = Array.isArray(value), prototype = Object.getPrototypeOf(value);
|
|
237
|
+
if (array ? prototype !== Array.prototype : prototype !== null && prototype !== Object.prototype)
|
|
238
|
+
return denyTenant();
|
|
239
|
+
const keys = Reflect.ownKeys(value);
|
|
240
|
+
if (keys.length > 65_537)
|
|
241
|
+
return denyTenant();
|
|
242
|
+
captureCounters.copied++;
|
|
243
|
+
const before = { nodes: nodes - 1, characters, reach, bytes, thawed };
|
|
244
|
+
// Counted after `before`: the value itself must have been frozen too, not only what it holds.
|
|
245
|
+
if (!Object.isFrozen(value))
|
|
246
|
+
thawed++;
|
|
247
|
+
reach = depth;
|
|
248
|
+
let result;
|
|
249
|
+
if (array) {
|
|
250
|
+
const length = Object.getOwnPropertyDescriptor(value, 'length')?.value;
|
|
251
|
+
if (!Number.isInteger(length) || length > 65_536 || keys.length !== length + 1)
|
|
252
|
+
return denyTenant();
|
|
253
|
+
result = Object.freeze(Array.from({ length }, (_, index) => {
|
|
254
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, String(index));
|
|
255
|
+
if (!descriptor?.enumerable || !('value' in descriptor))
|
|
256
|
+
return denyTenant();
|
|
257
|
+
return copy(descriptor.value, depth + 1);
|
|
258
|
+
}));
|
|
259
|
+
}
|
|
260
|
+
else {
|
|
261
|
+
const record = Object.create(null);
|
|
262
|
+
for (const key of keys) {
|
|
263
|
+
if (typeof key !== 'string' || (characters += key.length) > 16_777_216)
|
|
264
|
+
return denyTenant();
|
|
265
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
266
|
+
if (!descriptor?.enumerable || !('value' in descriptor))
|
|
267
|
+
return denyTenant();
|
|
268
|
+
record[key] = copy(descriptor.value, depth + 1);
|
|
269
|
+
}
|
|
270
|
+
result = Object.freeze(record);
|
|
271
|
+
}
|
|
272
|
+
if (bytes === before.bytes) {
|
|
273
|
+
capturedData.set(result, {
|
|
274
|
+
nodes: nodes - before.nodes,
|
|
275
|
+
characters: characters - before.characters,
|
|
276
|
+
depth: reach - depth,
|
|
277
|
+
});
|
|
278
|
+
if (thawed === before.thawed)
|
|
279
|
+
frozenCaptures.set(value, result);
|
|
280
|
+
}
|
|
281
|
+
reach = Math.max(reach, before.reach);
|
|
282
|
+
return result;
|
|
283
|
+
};
|
|
284
|
+
try {
|
|
285
|
+
// A request the server built for a file's own columns stays the server's through the copy (serverRequests.ts).
|
|
286
|
+
return carryServerRequest(input, copy(input));
|
|
287
|
+
}
|
|
288
|
+
catch {
|
|
289
|
+
return denyTenant();
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
export function tenantRecord(value, fields) {
|
|
293
|
+
if (!value || typeof value !== 'object' || Array.isArray(value) || (fields && Object.keys(value).some((key) => !fields.includes(key))))
|
|
294
|
+
denyTenant();
|
|
295
|
+
}
|
|
296
|
+
export function tenantIdentifier(value, maximum = 256) {
|
|
297
|
+
if (typeof value !== 'string' || !value.length || value.length > maximum || value !== value.trim() || /\p{Cc}/u.test(value))
|
|
298
|
+
denyTenant();
|
|
299
|
+
}
|
|
300
|
+
/** Trusted callbacks are captured without invoking configuration accessors. */
|
|
301
|
+
export function tenantOptions(input, fields) {
|
|
302
|
+
if (!input || typeof input !== 'object' || isProxy(input) || Array.isArray(input))
|
|
303
|
+
return denyTenant();
|
|
304
|
+
const prototype = Object.getPrototypeOf(input);
|
|
305
|
+
if (prototype !== null && prototype !== Object.prototype)
|
|
306
|
+
return denyTenant();
|
|
307
|
+
const result = Object.create(null);
|
|
308
|
+
const keys = Reflect.ownKeys(input);
|
|
309
|
+
/* The refusal names the key it did not expect: a loader that grows a key
|
|
310
|
+
(an App's pageFiles did) otherwise stops every tenant start with only
|
|
311
|
+
"the tenant context could not be verified". Recorded for the operator's
|
|
312
|
+
reader alone, and cut short, since the key is the caller's text. */
|
|
313
|
+
const unknown = keys.find((key) => typeof key !== 'string' || !fields.includes(key));
|
|
314
|
+
if (unknown !== undefined)
|
|
315
|
+
return denyTenant(`"${String(unknown).slice(0, 64)}" is not a key this takes; it takes ${fields.join(', ')}.`);
|
|
316
|
+
for (const key of keys) {
|
|
317
|
+
const descriptor = Object.getOwnPropertyDescriptor(input, key);
|
|
318
|
+
if (!descriptor?.enumerable || !('value' in descriptor))
|
|
319
|
+
return denyTenant();
|
|
320
|
+
result[key] = descriptor.value;
|
|
321
|
+
}
|
|
322
|
+
return result;
|
|
323
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A connection that never hands out some of its columns.
|
|
3
|
+
*
|
|
4
|
+
* `"hidden": { "account": ["password_hash"], "*": ["*_token"] }` in
|
|
5
|
+
* tablewalk.json keeps those columns from everything served over the
|
|
6
|
+
* connection: the Workbench, MCP, and every App on it. It is enforced where
|
|
7
|
+
* `"rows": false` is (shapeonly.ts), by wrapping the adapter before the
|
|
8
|
+
* registry stores it, so a feature added later inherits the boundary instead
|
|
9
|
+
* of having to remember it.
|
|
10
|
+
*
|
|
11
|
+
* The checks are the App grants' own (resourceChecks in columnGrants.ts):
|
|
12
|
+
* the catalog is served without the columns, so a query, a view, a filter or
|
|
13
|
+
* a sort that names one is refused as naming a column that is not there, and
|
|
14
|
+
* a read that names no columns gets the visible ones, never `SELECT *`.
|
|
15
|
+
* Raw SQL is refused outright: a statement cannot be column-redacted
|
|
16
|
+
* honestly. The strongest form of this boundary is still the database's own:
|
|
17
|
+
* a role without SELECT on those columns, which no tablewalk bug can undo.
|
|
18
|
+
*/
|
|
19
|
+
import { type Adapter } from '../adapters/adapter.js';
|
|
20
|
+
import { type DatabaseSchema } from '../shared/schema.js';
|
|
21
|
+
/** Table (id, bare name or "*") → column names, `*` a wildcard within a name. As written in tablewalk.json. */
|
|
22
|
+
export type HiddenColumnRules = Readonly<Record<string, readonly string[]>>;
|
|
23
|
+
/** The rules as the config file must spell them, refused with the file's own words otherwise. */
|
|
24
|
+
export declare function parseHiddenColumns(raw: unknown, where: string): HiddenColumnRules;
|
|
25
|
+
/** The catalog as served: the columns gone, and every edge, index and list naming one. */
|
|
26
|
+
export declare function withoutHiddenColumns(schema: DatabaseSchema, rules: HiddenColumnRules, name: string): DatabaseSchema;
|
|
27
|
+
/**
|
|
28
|
+
* The same adapter with the rules' columns cut from every answer and refused
|
|
29
|
+
* in every question. Methods are copied, not proxied, so an optional one the
|
|
30
|
+
* adapter lacks stays absent (shapeonly.ts says why).
|
|
31
|
+
*/
|
|
32
|
+
export declare function hideColumns(adapter: Adapter, name: string, rules: HiddenColumnRules, introspected: DatabaseSchema): Adapter;
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A connection that never hands out some of its columns.
|
|
3
|
+
*
|
|
4
|
+
* `"hidden": { "account": ["password_hash"], "*": ["*_token"] }` in
|
|
5
|
+
* tablewalk.json keeps those columns from everything served over the
|
|
6
|
+
* connection: the Workbench, MCP, and every App on it. It is enforced where
|
|
7
|
+
* `"rows": false` is (shapeonly.ts), by wrapping the adapter before the
|
|
8
|
+
* registry stores it, so a feature added later inherits the boundary instead
|
|
9
|
+
* of having to remember it.
|
|
10
|
+
*
|
|
11
|
+
* The checks are the App grants' own (resourceChecks in columnGrants.ts):
|
|
12
|
+
* the catalog is served without the columns, so a query, a view, a filter or
|
|
13
|
+
* a sort that names one is refused as naming a column that is not there, and
|
|
14
|
+
* a read that names no columns gets the visible ones, never `SELECT *`.
|
|
15
|
+
* Raw SQL is refused outright: a statement cannot be column-redacted
|
|
16
|
+
* honestly. The strongest form of this boundary is still the database's own:
|
|
17
|
+
* a role without SELECT on those columns, which no tablewalk bug can undo.
|
|
18
|
+
*/
|
|
19
|
+
import { Refusal } from '../adapters/adapter.js';
|
|
20
|
+
import { CONNECTION_HIDDEN } from '../shared/schema.js';
|
|
21
|
+
import { AppAccessDenied, accessibleSchema, authorizeColumnWrites, resourceChecks } from './columnGrants.js';
|
|
22
|
+
import { lendWriteView } from '../adapters/storeHost.js';
|
|
23
|
+
import { configFileName } from './product.js';
|
|
24
|
+
/** The rules as the config file must spell them, refused with the file's own words otherwise. */
|
|
25
|
+
export function parseHiddenColumns(raw, where) {
|
|
26
|
+
const shape = `"hidden" must be an object of table → column names, like { "account": ["password_hash"], "*": ["*_token"] }`;
|
|
27
|
+
if (!raw || typeof raw !== 'object' || Array.isArray(raw) || !Object.keys(raw).length)
|
|
28
|
+
throw new Error(`${where}: ${shape}.`);
|
|
29
|
+
for (const [table, columns] of Object.entries(raw)) {
|
|
30
|
+
if (!table.trim() ||
|
|
31
|
+
!Array.isArray(columns) ||
|
|
32
|
+
!columns.length ||
|
|
33
|
+
columns.some((column) => typeof column !== 'string' || !column.trim() || /^\*+$/.test(column.trim()))) {
|
|
34
|
+
throw new Error(`${where}: "hidden" for "${table}" is not a list of column names (a "*" matches within a name, never a whole table). ${shape}.`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return raw;
|
|
38
|
+
}
|
|
39
|
+
const matcher = (pattern) => new RegExp(`^${pattern
|
|
40
|
+
.trim()
|
|
41
|
+
.split('*')
|
|
42
|
+
.map((part) => part.replace(/[.+?^${}()|[\]\\]/g, '\\$&'))
|
|
43
|
+
.join('.*')}$`, 'i');
|
|
44
|
+
/** Each table's cut columns under the rules, by table id; a primary key is refused, since every link to a record carries it. */
|
|
45
|
+
function hiddenByTable(schema, rules, name) {
|
|
46
|
+
const patterns = Object.entries(rules).map(([table, columns]) => ({ table, columns: columns.map(matcher) }));
|
|
47
|
+
const cuts = new Map();
|
|
48
|
+
for (const table of schema.tables) {
|
|
49
|
+
const applying = patterns.filter((rule) => rule.table === '*' || rule.table === table.id || rule.table === table.name);
|
|
50
|
+
const cut = table.columns.filter((column) => applying.some((rule) => rule.columns.some((pattern) => pattern.test(column.name))));
|
|
51
|
+
const key = cut.find((column) => column.primaryKey);
|
|
52
|
+
if (key) {
|
|
53
|
+
throw new Error(`"${name}" has "hidden" covering ${table.id}.${key.name}, part of a primary key: every link to a record carries it. ` +
|
|
54
|
+
`Narrow the pattern in your ${configFileName()}.`);
|
|
55
|
+
}
|
|
56
|
+
if (cut.length)
|
|
57
|
+
cuts.set(table.id, new Set(cut.map((column) => column.name)));
|
|
58
|
+
}
|
|
59
|
+
return cuts;
|
|
60
|
+
}
|
|
61
|
+
/** Every table read and written as the connection allows, minus the cut columns, as one grant. */
|
|
62
|
+
function grantOf(schema, cuts) {
|
|
63
|
+
const all = new Set(schema.tables.map((table) => table.id));
|
|
64
|
+
return {
|
|
65
|
+
readable: all,
|
|
66
|
+
writable: all,
|
|
67
|
+
fields: new Map([...cuts].map(([id, cut]) => {
|
|
68
|
+
const visible = schema.tables
|
|
69
|
+
.find((table) => table.id === id)
|
|
70
|
+
.columns.map((column) => column.name)
|
|
71
|
+
.filter((column) => !cut.has(column));
|
|
72
|
+
return [id, { read: new Set(visible), write: new Set(visible) }];
|
|
73
|
+
})),
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
/** The catalog as served: the columns gone, and every edge, index and list naming one. */
|
|
77
|
+
export function withoutHiddenColumns(schema, rules, name) {
|
|
78
|
+
const cuts = hiddenByTable(schema, rules, name);
|
|
79
|
+
if (!cuts.size)
|
|
80
|
+
return schema;
|
|
81
|
+
const pruned = accessibleSchema(schema, grantOf(schema, cuts));
|
|
82
|
+
const keep = (id, columns) => columns?.filter((column) => !cuts.get(id)?.has(column));
|
|
83
|
+
return {
|
|
84
|
+
...pruned,
|
|
85
|
+
tables: pruned.tables.map((table) => {
|
|
86
|
+
// accessibleSchema narrows `deletable` where a field map exists; a connection's deletes stay its own to judge.
|
|
87
|
+
const original = schema.tables.find((item) => item.id === table.id);
|
|
88
|
+
const { deletable: _deletable, ...rest } = table;
|
|
89
|
+
// Likewise each column's `writable`: the grant says nothing about writes here.
|
|
90
|
+
const columns = table.columns.map((column) => {
|
|
91
|
+
const { writable: _writable, ...said } = column;
|
|
92
|
+
const was = original.columns.find((item) => item.name === column.name);
|
|
93
|
+
return was.writable !== undefined ? { ...said, writable: was.writable } : said;
|
|
94
|
+
});
|
|
95
|
+
const cut = cuts.get(table.id);
|
|
96
|
+
return {
|
|
97
|
+
...rest,
|
|
98
|
+
columns,
|
|
99
|
+
...(cut ? { [CONNECTION_HIDDEN]: [...cut] } : {}),
|
|
100
|
+
...(original.deletable !== undefined ? { deletable: original.deletable } : {}),
|
|
101
|
+
...(table.filterable ? { filterable: keep(table.id, table.filterable) } : {}),
|
|
102
|
+
...(table.sortable ? { sortable: keep(table.id, table.sortable) } : {}),
|
|
103
|
+
};
|
|
104
|
+
}),
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* The same adapter with the rules' columns cut from every answer and refused
|
|
109
|
+
* in every question. Methods are copied, not proxied, so an optional one the
|
|
110
|
+
* adapter lacks stays absent (shapeonly.ts says why).
|
|
111
|
+
*/
|
|
112
|
+
export function hideColumns(adapter, name, rules, introspected) {
|
|
113
|
+
const refused = (what) => new Refusal(`"${name}" hides columns ("hidden" in your ${configFileName()}): ${what}. ` +
|
|
114
|
+
'The hidden columns are not in its catalog, so nothing can ask for them.');
|
|
115
|
+
let full = introspected;
|
|
116
|
+
let cuts = hiddenByTable(full, rules, name);
|
|
117
|
+
let checks = resourceChecks(full, grantOf(full, cuts));
|
|
118
|
+
const refresh = (schema) => {
|
|
119
|
+
full = schema;
|
|
120
|
+
cuts = hiddenByTable(full, rules, name);
|
|
121
|
+
checks = resourceChecks(full, grantOf(full, cuts));
|
|
122
|
+
};
|
|
123
|
+
/* A grant's refusal is deliberately opaque to an App's reader; here the
|
|
124
|
+
person asking owns the config, so it says which boundary answered. */
|
|
125
|
+
const checked = (check) => {
|
|
126
|
+
try {
|
|
127
|
+
return check();
|
|
128
|
+
}
|
|
129
|
+
catch (error) {
|
|
130
|
+
if (error instanceof AppAccessDenied)
|
|
131
|
+
throw refused('this request names a hidden column, or would return one');
|
|
132
|
+
throw error;
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
const from = (key) => {
|
|
136
|
+
const method = adapter[key];
|
|
137
|
+
return typeof method === 'function' ? method.bind(adapter) : undefined;
|
|
138
|
+
};
|
|
139
|
+
const authorized = (tx) => {
|
|
140
|
+
const inner = authorizeColumnWrites(full, grantOf(full, cuts), tx);
|
|
141
|
+
const guard = (run) => (...args) => {
|
|
142
|
+
try {
|
|
143
|
+
return run(...args).catch((error) => {
|
|
144
|
+
throw error instanceof AppAccessDenied ? refused('this write names a hidden column, or would return or remove one') : error;
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
catch (error) {
|
|
148
|
+
return Promise.reject(error instanceof AppAccessDenied ? refused('this write names a hidden column, or would return or remove one') : error);
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
return {
|
|
152
|
+
...(inner.lockRecord ? { lockRecord: guard(inner.lockRecord) } : {}),
|
|
153
|
+
query: guard(inner.query),
|
|
154
|
+
count: guard(inner.count),
|
|
155
|
+
insert: guard(inner.insert),
|
|
156
|
+
update: guard(inner.update),
|
|
157
|
+
remove: guard(inner.remove),
|
|
158
|
+
...(inner.tell ? { tell: guard(inner.tell) } : {}),
|
|
159
|
+
};
|
|
160
|
+
};
|
|
161
|
+
const reads = (bound) => ({
|
|
162
|
+
query: (request) => bound.query(checked(() => checks.queryFor(request))),
|
|
163
|
+
count: (table, filter, limit) => bound.count(table, checked(() => checks.filterFor(table, filter)), limit),
|
|
164
|
+
runView: (view, offset) => bound.runView(checked(() => checks.viewFor(view)), offset),
|
|
165
|
+
countView: (view, limit) => bound.countView(checked(() => checks.viewFor(view)), limit),
|
|
166
|
+
runBreakdown: (def, offset) => bound.runBreakdown(checked(() => checks.breakdownFor(def)), offset),
|
|
167
|
+
countBreakdown: (def, limit) => bound.countBreakdown(checked(() => checks.breakdownFor(def)), limit),
|
|
168
|
+
});
|
|
169
|
+
const wrapped = Object.create(Object.getPrototypeOf(adapter));
|
|
170
|
+
Object.assign(wrapped, adapter);
|
|
171
|
+
wrapped.close = from('close');
|
|
172
|
+
wrapped.introspect = async () => {
|
|
173
|
+
refresh(await adapter.introspect());
|
|
174
|
+
return withoutHiddenColumns(full, rules, name);
|
|
175
|
+
};
|
|
176
|
+
if (adapter.poolStats)
|
|
177
|
+
wrapped.poolStats = from('poolStats');
|
|
178
|
+
if (adapter.privileges)
|
|
179
|
+
wrapped.privileges = from('privileges');
|
|
180
|
+
if (adapter.estimateCount)
|
|
181
|
+
wrapped.estimateCount = from('estimateCount');
|
|
182
|
+
wrapped.query = async (request) => adapter.query(checked(() => checks.queryFor(request)));
|
|
183
|
+
wrapped.count = async (table, filter, limit) => adapter.count(table, checked(() => checks.filterFor(table, filter)), limit);
|
|
184
|
+
if (adapter.countEach)
|
|
185
|
+
wrapped.countEach = async (items, limit) => adapter.countEach(checked(() => items.map((item) => ({ table: item.table, filter: checks.filterFor(item.table, item.filter) }))), limit);
|
|
186
|
+
if (adapter.runView)
|
|
187
|
+
wrapped.runView = async (view, offset) => adapter.runView(checked(() => checks.viewFor(view)), offset);
|
|
188
|
+
if (adapter.countView)
|
|
189
|
+
wrapped.countView = async (view, limit) => adapter.countView(checked(() => checks.viewFor(view)), limit);
|
|
190
|
+
if (adapter.runBreakdown)
|
|
191
|
+
wrapped.runBreakdown = async (def, offset) => adapter.runBreakdown(checked(() => checks.breakdownFor(def)), offset);
|
|
192
|
+
if (adapter.countBreakdown)
|
|
193
|
+
wrapped.countBreakdown = async (def, limit) => adapter.countBreakdown(checked(() => checks.breakdownFor(def)), limit);
|
|
194
|
+
if (adapter.scopeReads)
|
|
195
|
+
wrapped.scopeReads = async (scope) => reads(await adapter.scopeReads(scope));
|
|
196
|
+
/* Raw SQL can name any column, in any spelling, through any function: no
|
|
197
|
+
honest redaction exists for it. EXPLAIN is refused with it, since a plan
|
|
198
|
+
can be asked to run the statement. */
|
|
199
|
+
if (adapter.runSql)
|
|
200
|
+
wrapped.runSql = async () => {
|
|
201
|
+
throw refused('raw SQL is refused, because a statement can name any column. Remove "hidden" to run SQL here, or connect as a database role without SELECT on those columns');
|
|
202
|
+
};
|
|
203
|
+
if (adapter.explainSql)
|
|
204
|
+
wrapped.explainSql = async () => {
|
|
205
|
+
throw refused('explaining raw SQL is refused with running it');
|
|
206
|
+
};
|
|
207
|
+
// A table's DDL spells out every column, the hidden ones too.
|
|
208
|
+
if (adapter.ddl)
|
|
209
|
+
wrapped.ddl = async (table) => (cuts.has(table) ? undefined : adapter.ddl(table));
|
|
210
|
+
/* Profile keeps its numbers for the columns that are served. */
|
|
211
|
+
if (adapter.profile)
|
|
212
|
+
wrapped.profile = async (table, limits) => {
|
|
213
|
+
const result = await adapter.profile(table, limits);
|
|
214
|
+
const cut = cuts.get(table);
|
|
215
|
+
return cut ? { ...result, columns: result.columns.filter((column) => !cut.has(column.column)) } : result;
|
|
216
|
+
};
|
|
217
|
+
/* Writes are judged by the same grant: a hidden column is never written,
|
|
218
|
+
and an insert's stored row comes back without it. A delete removes every
|
|
219
|
+
column, the hidden ones too, and journals them for Undo, so it is
|
|
220
|
+
refused on a table with hidden columns. */
|
|
221
|
+
if (adapter.insert)
|
|
222
|
+
wrapped.insert = (request) => authorized(adapter).insert(request);
|
|
223
|
+
if (adapter.update)
|
|
224
|
+
wrapped.update = (request) => authorized(adapter).update(request);
|
|
225
|
+
if (adapter.remove)
|
|
226
|
+
wrapped.remove = (request) => authorized(adapter).remove(request);
|
|
227
|
+
if (adapter.transaction)
|
|
228
|
+
wrapped.transaction = (run) => adapter.transaction((tx) => run(authorized(tx)));
|
|
229
|
+
if (adapter.scopeTransaction)
|
|
230
|
+
wrapped.scopeTransaction = (scope, run) => adapter.scopeTransaction(scope, (tx, catalog) => run(authorized(tx), withoutHiddenColumns(catalog, rules, name)));
|
|
231
|
+
/* The command journal runs its work under the same grant and catalog. */
|
|
232
|
+
lendWriteView(wrapped, {
|
|
233
|
+
over: adapter,
|
|
234
|
+
records: (records) => authorized(records),
|
|
235
|
+
catalog: (catalog) => withoutHiddenColumns(catalog, rules, name),
|
|
236
|
+
});
|
|
237
|
+
return wrapped;
|
|
238
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The headers every answer carries, set before anything is routed so a reply
|
|
3
|
+
* that names its own (a mail link's `no-referrer`) still wins: `writeHead`'s
|
|
4
|
+
* headers override what `setHeader` put first.
|
|
5
|
+
*
|
|
6
|
+
* - `Referrer-Policy: strict-origin-when-cross-origin`: an address under a
|
|
7
|
+
* record (`/compass/leads/127?search=…`) leaves this origin as the origin
|
|
8
|
+
* alone, and never over plain http.
|
|
9
|
+
* - `Permissions-Policy`: no page here uses a camera, a microphone, a
|
|
10
|
+
* location or a payment sheet, so none is granted — to a component, or to
|
|
11
|
+
* whatever frames or is framed.
|
|
12
|
+
* - `Strict-Transport-Security`, only on an answer that arrived over https
|
|
13
|
+
* (trust.ts `arrivedOverHttps`): the socket's own TLS, an https public
|
|
14
|
+
* address, or a proxy this server trusts saying it forwarded https. A
|
|
15
|
+
* plain-http server (a laptop, a loopback dev server) never pins its name
|
|
16
|
+
* to https.
|
|
17
|
+
*/
|
|
18
|
+
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
19
|
+
import { type ProxyRange } from './trust.js';
|
|
20
|
+
export declare const REFERRER_POLICY = "strict-origin-when-cross-origin";
|
|
21
|
+
export declare const PERMISSIONS_POLICY: string;
|
|
22
|
+
/** A year, and the names under this one: the time browsers ask of a name kept on https. */
|
|
23
|
+
export declare const STRICT_TRANSPORT = "max-age=31536000; includeSubDomains";
|
|
24
|
+
export declare function setBaselineHeaders(req: Pick<IncomingMessage, 'headers' | 'socket'>, res: ServerResponse, trustedProxies?: readonly ProxyRange[]): void;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { arrivedOverHttps } from './trust.js';
|
|
2
|
+
export const REFERRER_POLICY = 'strict-origin-when-cross-origin';
|
|
3
|
+
export const PERMISSIONS_POLICY = 'camera=(), microphone=(), geolocation=(), payment=(), usb=(), serial=(), bluetooth=(), hid=(), midi=(), ' +
|
|
4
|
+
'magnetometer=(), gyroscope=(), accelerometer=(), display-capture=(), browsing-topics=()';
|
|
5
|
+
/** A year, and the names under this one: the time browsers ask of a name kept on https. */
|
|
6
|
+
export const STRICT_TRANSPORT = 'max-age=31536000; includeSubDomains';
|
|
7
|
+
export function setBaselineHeaders(req, res, trustedProxies = []) {
|
|
8
|
+
res.setHeader('referrer-policy', REFERRER_POLICY);
|
|
9
|
+
res.setHeader('permissions-policy', PERMISSIONS_POLICY);
|
|
10
|
+
if (arrivedOverHttps(req, trustedProxies))
|
|
11
|
+
res.setHeader('strict-transport-security', STRICT_TRANSPORT);
|
|
12
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A reply held in memory: what a route sends when it answers a request made
|
|
3
|
+
* inside another (recordCompose.ts). The route is the same code an HTTP
|
|
4
|
+
* request reaches — the same grants, row scope and hidden columns — and
|
|
5
|
+
* writes through `send` as ever; only the bytes stop here instead of on a
|
|
6
|
+
* socket. Just enough of ServerResponse for the reply helpers (reply.ts) and
|
|
7
|
+
* the routes that set a header on the way.
|
|
8
|
+
*/
|
|
9
|
+
import { EventEmitter } from 'node:events';
|
|
10
|
+
import type { OutgoingHttpHeaders, ServerResponse } from 'node:http';
|
|
11
|
+
export declare class CapturedReply extends EventEmitter {
|
|
12
|
+
statusCode: number;
|
|
13
|
+
headersSent: boolean;
|
|
14
|
+
writableEnded: boolean;
|
|
15
|
+
destroyed: boolean;
|
|
16
|
+
/** No request: nothing is compressed, and the whole reply is one JSON body. */
|
|
17
|
+
readonly req: undefined;
|
|
18
|
+
private readonly headers;
|
|
19
|
+
private chunks;
|
|
20
|
+
setHeader(name: string, value: number | string | readonly string[]): this;
|
|
21
|
+
getHeader(name: string): string | number | readonly string[] | undefined;
|
|
22
|
+
hasHeader(name: string): boolean;
|
|
23
|
+
removeHeader(name: string): void;
|
|
24
|
+
writeHead(status: number, headers?: OutgoingHttpHeaders): this;
|
|
25
|
+
write(chunk: Buffer | string): boolean;
|
|
26
|
+
end(chunk?: Buffer | string): this;
|
|
27
|
+
destroy(): this;
|
|
28
|
+
/** As the route answered: its status and its JSON, or undefined when it sent nothing. */
|
|
29
|
+
answer(): {
|
|
30
|
+
status: number;
|
|
31
|
+
body: unknown;
|
|
32
|
+
} | undefined;
|
|
33
|
+
/** Typed as the response the routes take. */
|
|
34
|
+
asResponse(): ServerResponse;
|
|
35
|
+
}
|