@malloy-publisher/server 0.0.235 → 0.0.237
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/dist/app/api-doc.yaml +83 -27
- package/dist/app/assets/{EnvironmentPage-BsAnavYN.js → EnvironmentPage-DaP6CpgK.js} +1 -1
- package/dist/app/assets/{HomePage-CADE138j.js → HomePage-C9yNw3iu.js} +1 -1
- package/dist/app/assets/{LightMode-Cfh7KzN8.js → LightMode-Be4-G-dX.js} +1 -1
- package/dist/app/assets/{MainPage-CO3pRlnV.js → MainPage-J_rU2SgI.js} +2 -2
- package/dist/app/assets/{MaterializationsPage-p9YjkRXZ.js → MaterializationsPage-DHgPI4MO.js} +1 -1
- package/dist/app/assets/ModelPage-BzXfjTu5.js +1 -0
- package/dist/app/assets/{PackagePage-e4kN75YR.js → PackagePage-ByoSTLJ4.js} +1 -1
- package/dist/app/assets/RouteError-CrSeKN2r.js +1 -0
- package/dist/app/assets/{ThemeEditorPage-CciagFTq.js → ThemeEditorPage-Btxnmhtk.js} +1 -1
- package/dist/app/assets/{WorkbookPage-DNWmkCXa.js → WorkbookPage-D6JLPnWO.js} +1 -1
- package/dist/app/assets/{core-Rj_4rRnA.es-BZyvITuO.js → core-BSRgt1mG.es-Bc_D2Lq4.js} +1 -1
- package/dist/app/assets/{index-CH2AcDzc.js → index-BRijWj6K.js} +15 -15
- package/dist/app/assets/{index-DQa463gC.js → index-BX4D94xw.js} +1 -1
- package/dist/app/assets/{index-VBbcc8s6.js → index-Cvy0xtb7.js} +1 -1
- package/dist/app/assets/{index-DQpV7MyA.js → index-DMAhIJNC.js} +1 -1
- package/dist/app/index.html +1 -1
- package/dist/package_load_worker.mjs +59 -20
- package/dist/server.mjs +1342 -616
- package/package.json +8 -2
- package/.eslintrc.json +0 -44
- package/.prettierignore +0 -1
- package/.prettierrc +0 -4
- package/build.ts +0 -97
- package/dist/app/assets/ModelPage-C1OSTv-x.js +0 -1
- package/dist/app/assets/RouteError-CzbfOkng.js +0 -1
- package/eslint.config.mjs +0 -76
- package/k6-tests/README.md +0 -144
- package/k6-tests/bun.lock +0 -797
- package/k6-tests/load-test/load-test-crud-connections.ts +0 -263
- package/k6-tests/load-test/load-test-crud-packages.ts +0 -461
- package/k6-tests/load-test/load-test-crud-projects.ts +0 -160
- package/k6-tests/load-test/load-test-crud.ts +0 -142
- package/k6-tests/load-test/load-test.ts +0 -784
- package/k6-tests/package.json +0 -27
- package/k6-tests/scripts/run-with-otel.sh +0 -50
- package/k6-tests/smoke-test/smoke-test.ts +0 -158
- package/k6-tests/tsconfig.json +0 -29
- package/k6-tests/utils/client_factory.ts +0 -128
- package/k6-tests/utils/common.ts +0 -489
- package/k6-tests/utils/logger.ts +0 -62
- package/k6-tests/utils/types.d.ts +0 -35
- package/malloy_mcp.dxt +0 -0
- package/publisher.config.example.bigquery.json +0 -33
- package/publisher.config.example.duckdb.json +0 -23
- package/publisher.config.json +0 -23
- package/scripts/bake-duckdb-extensions.js +0 -110
- package/src/config.spec.ts +0 -1535
- package/src/config.theme.spec.ts +0 -178
- package/src/config.ts +0 -1142
- package/src/constants.ts +0 -105
- package/src/controller/compile.controller.ts +0 -40
- package/src/controller/connection.controller.spec.ts +0 -849
- package/src/controller/connection.controller.ts +0 -901
- package/src/controller/database.controller.ts +0 -24
- package/src/controller/materialization.controller.spec.ts +0 -293
- package/src/controller/materialization.controller.ts +0 -319
- package/src/controller/model.controller.ts +0 -164
- package/src/controller/package.controller.spec.ts +0 -273
- package/src/controller/package.controller.ts +0 -306
- package/src/controller/query.controller.ts +0 -152
- package/src/controller/theme.controller.ts +0 -83
- package/src/controller/watch-mode.controller.ts +0 -243
- package/src/data_styles.ts +0 -71
- package/src/default-publisher.config.json +0 -23
- package/src/ducklake_version.spec.ts +0 -163
- package/src/ducklake_version.ts +0 -153
- package/src/errors.spec.ts +0 -119
- package/src/errors.ts +0 -237
- package/src/filter_deprecation.spec.ts +0 -64
- package/src/filter_deprecation.ts +0 -42
- package/src/health.spec.ts +0 -123
- package/src/health.ts +0 -233
- package/src/heap_check.spec.ts +0 -144
- package/src/heap_check.ts +0 -144
- package/src/instrumentation.ts +0 -214
- package/src/json_utils.spec.ts +0 -51
- package/src/json_utils.ts +0 -33
- package/src/logger.spec.ts +0 -210
- package/src/logger.ts +0 -251
- package/src/malloy_pin_prereqs.spec.ts +0 -25
- package/src/materialization_metrics.spec.ts +0 -169
- package/src/materialization_metrics.ts +0 -346
- package/src/mcp/error_messages.spec.ts +0 -35
- package/src/mcp/error_messages.ts +0 -183
- package/src/mcp/handler_utils.spec.ts +0 -108
- package/src/mcp/handler_utils.ts +0 -251
- package/src/mcp/mcp_constants.ts +0 -6
- package/src/mcp/query_envelope.spec.ts +0 -229
- package/src/mcp/query_envelope.ts +0 -240
- package/src/mcp/server.protocol.spec.ts +0 -250
- package/src/mcp/server.ts +0 -87
- package/src/mcp/skills/build_skills_bundle.spec.ts +0 -51
- package/src/mcp/skills/build_skills_bundle.ts +0 -176
- package/src/mcp/skills/skills_bundle.json +0 -1
- package/src/mcp/skills/skills_bundle.spec.ts +0 -171
- package/src/mcp/tool_response.spec.ts +0 -108
- package/src/mcp/tool_response.ts +0 -138
- package/src/mcp/tools/compile_tool.spec.ts +0 -315
- package/src/mcp/tools/compile_tool.ts +0 -208
- package/src/mcp/tools/docs_search/build_docs_index.ts +0 -132
- package/src/mcp/tools/docs_search/malloy_docs_index.json +0 -1
- package/src/mcp/tools/docs_search_tool.spec.ts +0 -32
- package/src/mcp/tools/docs_search_tool.ts +0 -128
- package/src/mcp/tools/embedding_index.spec.ts +0 -1236
- package/src/mcp/tools/embedding_index.ts +0 -808
- package/src/mcp/tools/execute_query_tool.spec.ts +0 -294
- package/src/mcp/tools/execute_query_tool.ts +0 -316
- package/src/mcp/tools/get_context_eval.ts +0 -275
- package/src/mcp/tools/get_context_tool.spec.ts +0 -592
- package/src/mcp/tools/get_context_tool.ts +0 -585
- package/src/mcp/tools/reload_package_tool.spec.ts +0 -232
- package/src/mcp/tools/reload_package_tool.ts +0 -132
- package/src/mcp_config.spec.ts +0 -919
- package/src/mcp_config.ts +0 -425
- package/src/oom_guards.integration.spec.ts +0 -269
- package/src/package_load/package_load_pool.spec.ts +0 -252
- package/src/package_load/package_load_pool.ts +0 -931
- package/src/package_load/package_load_worker.ts +0 -1034
- package/src/package_load/protocol.ts +0 -364
- package/src/package_load/rpc_wait_accountant.spec.ts +0 -109
- package/src/package_load/rpc_wait_accountant.ts +0 -76
- package/src/package_load_metrics.spec.ts +0 -114
- package/src/package_load_metrics.ts +0 -127
- package/src/path_safety.spec.ts +0 -158
- package/src/path_safety.ts +0 -146
- package/src/pg_helpers.spec.ts +0 -223
- package/src/pg_helpers.ts +0 -52
- package/src/query_cap_metrics.spec.ts +0 -89
- package/src/query_cap_metrics.ts +0 -116
- package/src/query_concurrency.spec.ts +0 -247
- package/src/query_concurrency.ts +0 -237
- package/src/query_metadata_metrics.ts +0 -49
- package/src/query_param_utils.ts +0 -29
- package/src/query_timeout.spec.ts +0 -224
- package/src/query_timeout.ts +0 -179
- package/src/runtime/publisher.js +0 -328
- package/src/server-old.ts +0 -988
- package/src/server.ts +0 -2059
- package/src/service/annotations.spec.ts +0 -118
- package/src/service/annotations.ts +0 -91
- package/src/service/authorize.spec.ts +0 -154
- package/src/service/authorize.ts +0 -498
- package/src/service/authorize_integration.spec.ts +0 -2041
- package/src/service/build_plan.spec.ts +0 -685
- package/src/service/build_plan.ts +0 -797
- package/src/service/compile_authorize.spec.ts +0 -85
- package/src/service/compile_fragment_techniques.spec.ts +0 -156
- package/src/service/connection.spec.ts +0 -2360
- package/src/service/connection.ts +0 -2187
- package/src/service/connection_config.spec.ts +0 -734
- package/src/service/connection_config.ts +0 -899
- package/src/service/connection_federation.spec.ts +0 -184
- package/src/service/connection_fingerprint.spec.ts +0 -102
- package/src/service/connection_service.spec.ts +0 -711
- package/src/service/connection_service.ts +0 -291
- package/src/service/cron_evaluator.spec.ts +0 -79
- package/src/service/cron_evaluator.ts +0 -105
- package/src/service/db_utils.spec.ts +0 -1085
- package/src/service/db_utils.ts +0 -1502
- package/src/service/duckdb_instance_isolation.spec.ts +0 -137
- package/src/service/ducklake_lazy_attach.spec.ts +0 -110
- package/src/service/embedding_provider.spec.ts +0 -329
- package/src/service/embedding_provider.ts +0 -236
- package/src/service/environment.ts +0 -2191
- package/src/service/environment_admission.spec.ts +0 -344
- package/src/service/environment_compile.spec.ts +0 -197
- package/src/service/environment_store.spec.ts +0 -2274
- package/src/service/environment_store.ts +0 -2434
- package/src/service/environment_store_anchoring.spec.ts +0 -107
- package/src/service/environment_store_clone.spec.ts +0 -350
- package/src/service/explore_visibility.spec.ts +0 -434
- package/src/service/exports_probe.spec.ts +0 -107
- package/src/service/extension_fetch_policy.spec.ts +0 -256
- package/src/service/filter.spec.ts +0 -458
- package/src/service/filter.ts +0 -341
- package/src/service/filter_bypass.spec.ts +0 -418
- package/src/service/filter_integration.spec.ts +0 -1004
- package/src/service/freshness.spec.ts +0 -183
- package/src/service/freshness.ts +0 -112
- package/src/service/gcs_s3_utils.ts +0 -427
- package/src/service/given.ts +0 -105
- package/src/service/givens_integration.spec.ts +0 -219
- package/src/service/manifest_loader.spec.ts +0 -189
- package/src/service/manifest_loader.ts +0 -156
- package/src/service/materialization_build_session.spec.ts +0 -435
- package/src/service/materialization_build_session.ts +0 -681
- package/src/service/materialization_config_validation.spec.ts +0 -99
- package/src/service/materialization_config_validation.ts +0 -120
- package/src/service/materialization_eligibility.spec.ts +0 -158
- package/src/service/materialization_eligibility.ts +0 -305
- package/src/service/materialization_schedule_surface.spec.ts +0 -256
- package/src/service/materialization_scheduler.spec.ts +0 -289
- package/src/service/materialization_scheduler.ts +0 -304
- package/src/service/materialization_serve_transform.spec.ts +0 -1003
- package/src/service/materialization_serve_transform.ts +0 -779
- package/src/service/materialization_service.spec.ts +0 -2373
- package/src/service/materialization_service.ts +0 -2342
- package/src/service/materialization_test_fixtures.ts +0 -249
- package/src/service/model.spec.ts +0 -1157
- package/src/service/model.ts +0 -3370
- package/src/service/model_limits.spec.ts +0 -209
- package/src/service/model_limits.ts +0 -131
- package/src/service/model_storage_serve.spec.ts +0 -193
- package/src/service/model_storage_serve_joins.spec.ts +0 -193
- package/src/service/package.spec.ts +0 -612
- package/src/service/package.ts +0 -1799
- package/src/service/package_manifest.spec.ts +0 -230
- package/src/service/package_manifest.ts +0 -241
- package/src/service/package_memory_governor.spec.ts +0 -173
- package/src/service/package_memory_governor.ts +0 -233
- package/src/service/package_quote_bound_tables.spec.ts +0 -171
- package/src/service/package_race.spec.ts +0 -208
- package/src/service/package_reload_safety.spec.ts +0 -193
- package/src/service/package_rollback.spec.ts +0 -190
- package/src/service/package_worker_path.spec.ts +0 -645
- package/src/service/path_injection.spec.ts +0 -39
- package/src/service/persist_annotation_validation.spec.ts +0 -89
- package/src/service/persist_annotation_validation.ts +0 -59
- package/src/service/persistence_policy.spec.ts +0 -374
- package/src/service/proxy.spec.ts +0 -414
- package/src/service/proxy.ts +0 -248
- package/src/service/query_boundary.spec.ts +0 -470
- package/src/service/query_metadata.spec.ts +0 -408
- package/src/service/query_metadata.ts +0 -492
- package/src/service/query_metadata_identity.spec.ts +0 -149
- package/src/service/query_text.spec.ts +0 -79
- package/src/service/query_text.ts +0 -43
- package/src/service/quoting.spec.ts +0 -135
- package/src/service/quoting.ts +0 -78
- package/src/service/resolve_environment.ts +0 -15
- package/src/service/restricted_mode.spec.ts +0 -299
- package/src/service/source_extraction.ts +0 -225
- package/src/service/theme_store.ts +0 -199
- package/src/storage/DatabaseInterface.ts +0 -198
- package/src/storage/StorageManager.ts +0 -113
- package/src/storage/duckdb/ConnectionRepository.ts +0 -143
- package/src/storage/duckdb/DuckDBConnection.ts +0 -123
- package/src/storage/duckdb/DuckDBRepository.ts +0 -208
- package/src/storage/duckdb/EnvironmentRepository.ts +0 -148
- package/src/storage/duckdb/MaterializationRepository.spec.ts +0 -191
- package/src/storage/duckdb/MaterializationRepository.ts +0 -336
- package/src/storage/duckdb/PackageRepository.ts +0 -135
- package/src/storage/duckdb/schema.ts +0 -229
- package/src/stream_helpers.spec.ts +0 -280
- package/src/stream_helpers.ts +0 -162
- package/src/telemetry.ts +0 -20
- package/src/test_helpers/metrics_harness.ts +0 -166
- package/src/theme_key_parity.spec.ts +0 -57
- package/src/utils.ts +0 -29
- package/tests/fixtures/authorize-compile/model.malloy +0 -9
- package/tests/fixtures/authorize-compile/publisher.json +0 -4
- package/tests/fixtures/html-pages-nopublic/model.malloy +0 -1
- package/tests/fixtures/html-pages-nopublic/publisher.json +0 -5
- package/tests/fixtures/html-pages-test/data.csv +0 -3
- package/tests/fixtures/html-pages-test/public/assets/app.css +0 -3
- package/tests/fixtures/html-pages-test/public/barehtml.html +0 -4
- package/tests/fixtures/html-pages-test/public/bodymeta.html +0 -8
- package/tests/fixtures/html-pages-test/public/data.json +0 -1
- package/tests/fixtures/html-pages-test/public/fitcomment.html +0 -11
- package/tests/fixtures/html-pages-test/public/index.html +0 -9
- package/tests/fixtures/html-pages-test/public/nohead.html +0 -8
- package/tests/fixtures/html-pages-test/public/notfit.html +0 -13
- package/tests/fixtures/html-pages-test/public/slides.html +0 -12
- package/tests/fixtures/html-pages-test/public/sub/page2.html +0 -9
- package/tests/fixtures/html-pages-test/public/unterminated.html +0 -10
- package/tests/fixtures/html-pages-test/publisher.json +0 -5
- package/tests/fixtures/html-pages-test/report.malloy +0 -1
- package/tests/fixtures/persist-multi-level/data/orders.csv +0 -5
- package/tests/fixtures/persist-multi-level/multi_level.malloy +0 -18
- package/tests/fixtures/persist-multi-level/publisher.json +0 -5
- package/tests/fixtures/persist-schedule-test/data/orders.csv +0 -5
- package/tests/fixtures/persist-schedule-test/persist_schedule_test.malloy +0 -11
- package/tests/fixtures/persist-schedule-test/publisher.json +0 -7
- package/tests/fixtures/persist-schedule-warn-test/data/orders.csv +0 -5
- package/tests/fixtures/persist-schedule-warn-test/persist_warn_test.malloy +0 -11
- package/tests/fixtures/persist-schedule-warn-test/publisher.json +0 -6
- package/tests/fixtures/persist-test/data/orders.csv +0 -5
- package/tests/fixtures/persist-test/persist_test.malloy +0 -11
- package/tests/fixtures/persist-test/publisher.json +0 -5
- package/tests/fixtures/publisher.config.json +0 -15
- package/tests/fixtures/query-givens/data/orders.csv +0 -7
- package/tests/fixtures/query-givens/model.malloy +0 -34
- package/tests/fixtures/query-givens/publisher.json +0 -5
- package/tests/fixtures/xlsx/database.xlsx +0 -0
- package/tests/harness/mcp_test_setup.ts +0 -332
- package/tests/harness/rest_e2e.ts +0 -68
- package/tests/integration/authorize/compile_authorize_http.integration.spec.ts +0 -92
- package/tests/integration/concurrent_package/concurrent_package.integration.spec.ts +0 -280
- package/tests/integration/duckdb_storage/duckdb_storage.integration.spec.ts +0 -138
- package/tests/integration/first_boot/readiness_line.integration.spec.ts +0 -177
- package/tests/integration/html_pages/html_pages.integration.spec.ts +0 -440
- package/tests/integration/legacy_routes/legacy_routes.integration.spec.ts +0 -259
- package/tests/integration/materialization/environment_list.integration.spec.ts +0 -133
- package/tests/integration/materialization/freshness_gate.integration.spec.ts +0 -292
- package/tests/integration/materialization/manifest_binding.integration.spec.ts +0 -430
- package/tests/integration/materialization/materialization_lifecycle.integration.spec.ts +0 -441
- package/tests/integration/materialization/orchestrated_rebind.integration.spec.ts +0 -150
- package/tests/integration/materialization/reference_manifest.integration.spec.ts +0 -251
- package/tests/integration/materialization/schedule_edit.integration.spec.ts +0 -126
- package/tests/integration/materialization/scheduler.integration.spec.ts +0 -200
- package/tests/integration/materialization/scheduler_recovery.integration.spec.ts +0 -172
- package/tests/integration/materialization/scheduler_transitions.integration.spec.ts +0 -256
- package/tests/integration/materialization/scheduler_wiring.integration.spec.ts +0 -143
- package/tests/integration/mcp/mcp_execute_query_tool.integration.spec.ts +0 -438
- package/tests/integration/mcp/mcp_get_context_semantic.integration.spec.ts +0 -235
- package/tests/integration/mcp/mcp_transport.integration.spec.ts +0 -98
- package/tests/integration/query_givens/query_givens.integration.spec.ts +0 -146
- package/tests/integration/query_givens/query_givens_authorize.integration.spec.ts +0 -121
- package/tests/integration/sdk_givens/sdk_givens.integration.spec.ts +0 -110
- package/tests/integration/watch-mode/watch_mode.integration.spec.ts +0 -421
- package/tests/unit/controller/theme.controller.spec.ts +0 -141
- package/tests/unit/duckdb/attached_databases.test.ts +0 -1243
- package/tests/unit/duckdb/duckdb_connection.test.ts +0 -181
- package/tests/unit/duckdb/legacy_schema_migration.test.ts +0 -197
- package/tests/unit/duckdb/repositories.test.ts +0 -208
- package/tests/unit/ducklake/ducklake.test.ts +0 -952
- package/tests/unit/service/theme_store.spec.ts +0 -139
- package/tsconfig.json +0 -32
package/src/logger.ts
DELETED
|
@@ -1,251 +0,0 @@
|
|
|
1
|
-
import { AxiosError } from "axios";
|
|
2
|
-
import { RequestHandler } from "express";
|
|
3
|
-
import winston from "winston";
|
|
4
|
-
|
|
5
|
-
const isTelemetryEnabled = Boolean(process.env.OTEL_EXPORTER_OTLP_ENDPOINT);
|
|
6
|
-
|
|
7
|
-
// Determine log level from environment variable
|
|
8
|
-
// Valid levels: error, warn, info, verbose, debug, silly
|
|
9
|
-
// Default: 'debug'
|
|
10
|
-
const VALID_LOG_LEVELS = ["error", "warn", "info", "verbose", "debug", "silly"];
|
|
11
|
-
const getLogLevel = (): string => {
|
|
12
|
-
if (process.env.LOG_LEVEL) {
|
|
13
|
-
const logLevel = process.env.LOG_LEVEL.toLowerCase();
|
|
14
|
-
if (VALID_LOG_LEVELS.includes(logLevel)) {
|
|
15
|
-
return logLevel;
|
|
16
|
-
} else {
|
|
17
|
-
console.error(
|
|
18
|
-
`Invalid log level: ${process.env.LOG_LEVEL}. Valid log levels are: ${VALID_LOG_LEVELS.join(", ")}. Defaulting to "debug".`,
|
|
19
|
-
);
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
return "debug";
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
export const logger = winston.createLogger({
|
|
26
|
-
level: getLogLevel(),
|
|
27
|
-
format: isTelemetryEnabled
|
|
28
|
-
? winston.format.combine(
|
|
29
|
-
winston.format.uncolorize(),
|
|
30
|
-
winston.format.timestamp(),
|
|
31
|
-
winston.format.errors({ stack: true }),
|
|
32
|
-
winston.format.json(),
|
|
33
|
-
)
|
|
34
|
-
: winston.format.combine(
|
|
35
|
-
winston.format.colorize(),
|
|
36
|
-
winston.format.simple(),
|
|
37
|
-
),
|
|
38
|
-
transports: [new winston.transports.Console()],
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
//-
|
|
42
|
-
/**
|
|
43
|
-
* Extracts the trace ID from a W3C traceparent header.
|
|
44
|
-
* Format: version-trace-id-parent-id-trace-flags
|
|
45
|
-
* Example: 00-81f2264f363f1b5596c84ab29e6be171-83ef39df12ab6bab-01
|
|
46
|
-
*
|
|
47
|
-
* @param traceparent The traceparent header value
|
|
48
|
-
* @returns The trace ID (32 hex characters) or undefined if invalid
|
|
49
|
-
*/
|
|
50
|
-
function extractTraceIdFromTraceparent(
|
|
51
|
-
traceparent: string | undefined,
|
|
52
|
-
): string | undefined {
|
|
53
|
-
if (!traceparent) {
|
|
54
|
-
return undefined;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// format of traceparent can either be: version-traceId-parentId-traceFlags or traceId
|
|
58
|
-
const parts = traceparent.split("-");
|
|
59
|
-
const traceId =
|
|
60
|
-
parts.length >= 2 ? parts[1] : parts.length == 1 ? parts[0] : undefined;
|
|
61
|
-
// Validate that the traceId is 32 hex characters
|
|
62
|
-
if (traceId && traceId.length === 32 && /^[0-9a-fA-F]{32}$/.test(traceId)) {
|
|
63
|
-
return traceId;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
return undefined;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
const DISABLE_RESPONSE_LOGGING =
|
|
70
|
-
process.env.DISABLE_RESPONSE_LOGGING === "true" ||
|
|
71
|
-
process.env.DISABLE_RESPONSE_LOGGING === "1";
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Format duration in milliseconds to a human-readable string with unit
|
|
75
|
-
* @param durationMs Duration in milliseconds
|
|
76
|
-
* @returns Formatted string with 2 decimal places and unit (s or ms)
|
|
77
|
-
*/
|
|
78
|
-
export function formatDuration(durationMs: number): string {
|
|
79
|
-
// If duration is >= 1000ms, show in seconds, otherwise show in milliseconds
|
|
80
|
-
if (durationMs >= 1000) {
|
|
81
|
-
const seconds = durationMs / 1000;
|
|
82
|
-
return `${seconds.toFixed(2)}s`;
|
|
83
|
-
}
|
|
84
|
-
return `${durationMs.toFixed(2)}ms`;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// Connection endpoints carry provider credentials in their request/response
|
|
88
|
-
// bodies (BigQuery serviceAccountKeyJson, Snowflake privateKey/password, Postgres
|
|
89
|
-
// password/connectionString, S3 secretAccessKey/sessionToken, Azure clientSecret/
|
|
90
|
-
// sasUrl, Databricks token, ...), and axios error logs can carry credential HTTP
|
|
91
|
-
// headers (Authorization, Cookie). Those values are masked by key name before
|
|
92
|
-
// they reach a log transport. Matching is case-insensitive so header casing
|
|
93
|
-
// (Authorization vs authorization) does not slip through.
|
|
94
|
-
export const SENSITIVE_KEY_NAMES = [
|
|
95
|
-
// connection config credentials
|
|
96
|
-
"password",
|
|
97
|
-
"connectionString",
|
|
98
|
-
"serviceAccountKeyJson",
|
|
99
|
-
"privateKey",
|
|
100
|
-
"privateKeyPass",
|
|
101
|
-
"secret",
|
|
102
|
-
"secretAccessKey",
|
|
103
|
-
"sessionToken",
|
|
104
|
-
"sasUrl",
|
|
105
|
-
"clientSecret",
|
|
106
|
-
"oauthClientSecret",
|
|
107
|
-
"peakaKey",
|
|
108
|
-
"token",
|
|
109
|
-
"accessToken",
|
|
110
|
-
"apiKey",
|
|
111
|
-
"api_key",
|
|
112
|
-
// credential-bearing HTTP headers
|
|
113
|
-
"authorization",
|
|
114
|
-
"proxy-authorization",
|
|
115
|
-
"cookie",
|
|
116
|
-
"set-cookie",
|
|
117
|
-
"x-api-key",
|
|
118
|
-
];
|
|
119
|
-
const SENSITIVE_KEYS: ReadonlySet<string> = new Set(
|
|
120
|
-
SENSITIVE_KEY_NAMES.map((name) => name.toLowerCase()),
|
|
121
|
-
);
|
|
122
|
-
|
|
123
|
-
const REDACTED = "[REDACTED]";
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
* Deep-copy `value`, replacing any property whose key names a credential
|
|
127
|
-
* (SENSITIVE_KEYS) with a placeholder. The match is by key name (case-
|
|
128
|
-
* insensitive) and recurses through nested objects and arrays, since
|
|
129
|
-
* connections arrive nested under `connections[]`. Primitives and Dates pass
|
|
130
|
-
* through unchanged and the input is never mutated; used to keep secrets out of
|
|
131
|
-
* the request/response and axios-error logs.
|
|
132
|
-
*/
|
|
133
|
-
export function redactSensitive(
|
|
134
|
-
value: unknown,
|
|
135
|
-
seen: WeakSet<object> = new WeakSet(),
|
|
136
|
-
): unknown {
|
|
137
|
-
if (value === null || typeof value !== "object" || value instanceof Date) {
|
|
138
|
-
return value;
|
|
139
|
-
}
|
|
140
|
-
if (seen.has(value)) {
|
|
141
|
-
return "[Circular]";
|
|
142
|
-
}
|
|
143
|
-
seen.add(value);
|
|
144
|
-
if (Array.isArray(value)) {
|
|
145
|
-
return value.map((item) => redactSensitive(item, seen));
|
|
146
|
-
}
|
|
147
|
-
const result: Record<string, unknown> = {};
|
|
148
|
-
for (const [key, val] of Object.entries(value as Record<string, unknown>)) {
|
|
149
|
-
result[key] = SENSITIVE_KEYS.has(key.toLowerCase())
|
|
150
|
-
? REDACTED
|
|
151
|
-
: redactSensitive(val, seen);
|
|
152
|
-
}
|
|
153
|
-
return result;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
export const loggerMiddleware: RequestHandler = (req, res, next) => {
|
|
157
|
-
const startTime = performance.now();
|
|
158
|
-
const resJson = res.json;
|
|
159
|
-
res.json = (body: unknown) => {
|
|
160
|
-
res.locals.body = body;
|
|
161
|
-
return resJson.call(res, body);
|
|
162
|
-
};
|
|
163
|
-
res.on("finish", () => {
|
|
164
|
-
const endTime = performance.now();
|
|
165
|
-
const durationMs = endTime - startTime;
|
|
166
|
-
|
|
167
|
-
// Extract trace ID from traceparent header if present
|
|
168
|
-
const traceparent = req.headers["traceparent"] as string | undefined;
|
|
169
|
-
const traceId = extractTraceIdFromTraceparent(traceparent);
|
|
170
|
-
|
|
171
|
-
const logMetadata: Record<string, unknown> = {
|
|
172
|
-
statusCode: res.statusCode,
|
|
173
|
-
duration: formatDuration(durationMs),
|
|
174
|
-
payload: redactSensitive(req.body),
|
|
175
|
-
params: req.params,
|
|
176
|
-
query: req.query,
|
|
177
|
-
};
|
|
178
|
-
|
|
179
|
-
// Only include response body if response logging is enabled
|
|
180
|
-
if (!DISABLE_RESPONSE_LOGGING) {
|
|
181
|
-
logMetadata.response = redactSensitive(res.locals.body);
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
// Add traceId to log metadata if present
|
|
185
|
-
if (traceId) {
|
|
186
|
-
logMetadata.traceId = traceId;
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
// Skip logging for metrics and health endpoints to reduce log noise
|
|
190
|
-
if (
|
|
191
|
-
req.url !== "/metrics" &&
|
|
192
|
-
req.url !== "/health" &&
|
|
193
|
-
req.url !== "/health/liveness" &&
|
|
194
|
-
req.url !== "/health/readiness"
|
|
195
|
-
) {
|
|
196
|
-
logger.info(`${req.method} ${req.url}`, logMetadata);
|
|
197
|
-
}
|
|
198
|
-
});
|
|
199
|
-
next();
|
|
200
|
-
};
|
|
201
|
-
|
|
202
|
-
/**
|
|
203
|
-
* Build the message + metadata logged for an AxiosError, with secrets removed.
|
|
204
|
-
* A failing upstream call can echo a connection config in `response.data` or
|
|
205
|
-
* return credential headers, and the raw `error.request` / `error` objects hold
|
|
206
|
-
* the outgoing Authorization header. Response fields are redacted and the raw
|
|
207
|
-
* request object is reduced to a few safe descriptors, so credentials never
|
|
208
|
-
* reach the log. Split out from `logAxiosError` so it can be unit tested.
|
|
209
|
-
*/
|
|
210
|
-
export function buildAxiosErrorLog(error: AxiosError): {
|
|
211
|
-
message: string;
|
|
212
|
-
meta: Record<string, unknown>;
|
|
213
|
-
} {
|
|
214
|
-
if (error.response) {
|
|
215
|
-
// The request was made and the server responded with a status code
|
|
216
|
-
// that falls out of the range of 2xx.
|
|
217
|
-
return {
|
|
218
|
-
message: "Axios server-side error",
|
|
219
|
-
meta: {
|
|
220
|
-
url: error.response.config.url,
|
|
221
|
-
status: error.response.status,
|
|
222
|
-
headers: redactSensitive(error.response.headers),
|
|
223
|
-
data: redactSensitive(error.response.data),
|
|
224
|
-
},
|
|
225
|
-
};
|
|
226
|
-
}
|
|
227
|
-
if (error.request) {
|
|
228
|
-
// The request was made but no response was received. `error.request` is
|
|
229
|
-
// the raw ClientRequest/XHR and carries the outgoing headers (including
|
|
230
|
-
// Authorization), so log only safe descriptors from the config.
|
|
231
|
-
return {
|
|
232
|
-
message: "Axios client-side error",
|
|
233
|
-
meta: {
|
|
234
|
-
method: error.config?.method,
|
|
235
|
-
url: error.config?.url,
|
|
236
|
-
code: error.code,
|
|
237
|
-
},
|
|
238
|
-
};
|
|
239
|
-
}
|
|
240
|
-
// Something happened setting up the request. The AxiosError still holds
|
|
241
|
-
// `config.headers`, so log only the message.
|
|
242
|
-
return {
|
|
243
|
-
message: "Axios unknown error",
|
|
244
|
-
meta: { message: error.message },
|
|
245
|
-
};
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
export const logAxiosError = (error: AxiosError) => {
|
|
249
|
-
const { message, meta } = buildAxiosErrorLog(error);
|
|
250
|
-
logger.error(message, meta);
|
|
251
|
-
};
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from "bun:test";
|
|
2
|
-
import type { VirtualMap } from "@malloydata/malloy";
|
|
3
|
-
|
|
4
|
-
// Prerequisite guard for the DuckLake materialization tier's build path.
|
|
5
|
-
//
|
|
6
|
-
// The tier resolves persist/virtual sources by handing the Malloy compile a
|
|
7
|
-
// `virtualMap` (connectionName → virtualName → tablePath). This asserts the
|
|
8
|
-
// pinned `@malloydata/malloy` still exports that public `VirtualMap` type, so a
|
|
9
|
-
// pin bump that drops or renames it fails CI typecheck here — turning a
|
|
10
|
-
// point-in-time manual confirm into a durable guard. Confirmed present in the
|
|
11
|
-
// shipped pin (^0.0.422): `VirtualMap = Map<string, Map<string, string>>` is
|
|
12
|
-
// exported from the package root and rides `PrepareResultOptions.virtualMap`.
|
|
13
|
-
describe("malloy pin prerequisites (DuckLake tier)", () => {
|
|
14
|
-
it("exposes the VirtualMap substitution type in the pinned malloy", () => {
|
|
15
|
-
// Compile-time guard: this type reference fails typecheck if `VirtualMap`
|
|
16
|
-
// is removed/renamed in a future pin. The runtime assertions below double
|
|
17
|
-
// as a shape check on the nested Map<string, Map<string, string>>.
|
|
18
|
-
const virtualMap: VirtualMap = new Map([
|
|
19
|
-
["main_pg", new Map([["orders", "catalog.public.orders"]])],
|
|
20
|
-
]);
|
|
21
|
-
expect(virtualMap.get("main_pg")?.get("orders")).toBe(
|
|
22
|
-
"catalog.public.orders",
|
|
23
|
-
);
|
|
24
|
-
});
|
|
25
|
-
});
|
|
@@ -1,169 +0,0 @@
|
|
|
1
|
-
import { afterEach, beforeEach, describe, expect, it } from "bun:test";
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
recordChainedStorageBuild,
|
|
5
|
-
recordConnectionDigestSkipped,
|
|
6
|
-
recordDropTables,
|
|
7
|
-
recordEligibilityRefused,
|
|
8
|
-
recordMaterializationRun,
|
|
9
|
-
recordServeShapeTierDrop,
|
|
10
|
-
recordServeShapeTypeFallback,
|
|
11
|
-
recordSourcesOutcome,
|
|
12
|
-
recordStorageBuildFailure,
|
|
13
|
-
recordStorageServeRouting,
|
|
14
|
-
resetMaterializationTelemetryForTesting,
|
|
15
|
-
} from "./materialization_metrics";
|
|
16
|
-
import {
|
|
17
|
-
startMetricsHarness,
|
|
18
|
-
type MetricsHarness,
|
|
19
|
-
} from "./test_helpers/metrics_harness";
|
|
20
|
-
|
|
21
|
-
describe("materialization_metrics", () => {
|
|
22
|
-
let harness: MetricsHarness;
|
|
23
|
-
|
|
24
|
-
beforeEach(async () => {
|
|
25
|
-
harness = await startMetricsHarness();
|
|
26
|
-
// Drop cached instruments so they re-bind to this test's provider.
|
|
27
|
-
resetMaterializationTelemetryForTesting();
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
afterEach(async () => {
|
|
31
|
-
resetMaterializationTelemetryForTesting();
|
|
32
|
-
await harness.shutdown();
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
it("counts runs labeled by mode and outcome", async () => {
|
|
36
|
-
recordMaterializationRun("auto", "success", 10);
|
|
37
|
-
recordMaterializationRun("auto", "success", 20);
|
|
38
|
-
recordMaterializationRun("orchestrated", "failed", 5);
|
|
39
|
-
|
|
40
|
-
expect(
|
|
41
|
-
await harness.collectCounter("publisher_materialization_runs_total", {
|
|
42
|
-
mode: "auto",
|
|
43
|
-
outcome: "success",
|
|
44
|
-
}),
|
|
45
|
-
).toBe(2);
|
|
46
|
-
expect(
|
|
47
|
-
await harness.collectCounter("publisher_materialization_runs_total", {
|
|
48
|
-
mode: "orchestrated",
|
|
49
|
-
outcome: "failed",
|
|
50
|
-
}),
|
|
51
|
-
).toBe(1);
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
it("adds the source count labeled by outcome, ignoring non-positive counts", async () => {
|
|
55
|
-
recordSourcesOutcome("built", 3);
|
|
56
|
-
recordSourcesOutcome("reused", 2);
|
|
57
|
-
recordSourcesOutcome("built", 0); // guarded: no emission
|
|
58
|
-
|
|
59
|
-
expect(
|
|
60
|
-
await harness.collectCounter(
|
|
61
|
-
"publisher_materialization_sources_total",
|
|
62
|
-
{ outcome: "built" },
|
|
63
|
-
),
|
|
64
|
-
).toBe(3);
|
|
65
|
-
expect(
|
|
66
|
-
await harness.collectCounter(
|
|
67
|
-
"publisher_materialization_sources_total",
|
|
68
|
-
{ outcome: "reused" },
|
|
69
|
-
),
|
|
70
|
-
).toBe(2);
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
it("counts drop-table outcomes (labeled by engine) and connection-digest skips", async () => {
|
|
74
|
-
recordDropTables("success", "storage");
|
|
75
|
-
recordDropTables("failure", "in_warehouse");
|
|
76
|
-
recordConnectionDigestSkipped();
|
|
77
|
-
|
|
78
|
-
expect(
|
|
79
|
-
await harness.collectCounter(
|
|
80
|
-
"publisher_materialization_drop_tables_total",
|
|
81
|
-
{ outcome: "failure", engine: "in_warehouse" },
|
|
82
|
-
),
|
|
83
|
-
).toBe(1);
|
|
84
|
-
expect(
|
|
85
|
-
await harness.collectCounter(
|
|
86
|
-
"publisher_materialization_drop_tables_total",
|
|
87
|
-
{ outcome: "success", engine: "storage" },
|
|
88
|
-
),
|
|
89
|
-
).toBe(1);
|
|
90
|
-
expect(
|
|
91
|
-
await harness.collectCounter(
|
|
92
|
-
"publisher_materialization_connection_digest_skipped_total",
|
|
93
|
-
),
|
|
94
|
-
).toBe(1);
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
it("counts storage= serve-routing decisions labeled by outcome", async () => {
|
|
98
|
-
recordStorageServeRouting("storage");
|
|
99
|
-
recordStorageServeRouting("storage");
|
|
100
|
-
recordStorageServeRouting("live_fallback");
|
|
101
|
-
|
|
102
|
-
expect(
|
|
103
|
-
await harness.collectCounter("publisher_storage_serve_routing_total", {
|
|
104
|
-
outcome: "storage",
|
|
105
|
-
}),
|
|
106
|
-
).toBe(2);
|
|
107
|
-
expect(
|
|
108
|
-
await harness.collectCounter("publisher_storage_serve_routing_total", {
|
|
109
|
-
outcome: "live_fallback",
|
|
110
|
-
}),
|
|
111
|
-
).toBe(1);
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
it("counts chained storage builds labeled by outcome", async () => {
|
|
115
|
-
recordChainedStorageBuild("parent_reuse");
|
|
116
|
-
recordChainedStorageBuild("parent_reuse");
|
|
117
|
-
recordChainedStorageBuild("inline_fallback");
|
|
118
|
-
recordChainedStorageBuild("strict_refused");
|
|
119
|
-
|
|
120
|
-
expect(
|
|
121
|
-
await harness.collectCounter("publisher_storage_chained_build_total", {
|
|
122
|
-
outcome: "parent_reuse",
|
|
123
|
-
}),
|
|
124
|
-
).toBe(2);
|
|
125
|
-
expect(
|
|
126
|
-
await harness.collectCounter("publisher_storage_chained_build_total", {
|
|
127
|
-
outcome: "inline_fallback",
|
|
128
|
-
}),
|
|
129
|
-
).toBe(1);
|
|
130
|
-
expect(
|
|
131
|
-
await harness.collectCounter("publisher_storage_chained_build_total", {
|
|
132
|
-
outcome: "strict_refused",
|
|
133
|
-
}),
|
|
134
|
-
).toBe(1);
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
it("counts storage build failures, eligibility refusals, tier drops, and type fallbacks", async () => {
|
|
138
|
-
recordStorageBuildFailure("lake");
|
|
139
|
-
recordEligibilityRefused("given");
|
|
140
|
-
recordEligibilityRefused("free_parameter");
|
|
141
|
-
recordServeShapeTierDrop(0);
|
|
142
|
-
recordServeShapeTypeFallback("array");
|
|
143
|
-
|
|
144
|
-
expect(
|
|
145
|
-
await harness.collectCounter(
|
|
146
|
-
"publisher_storage_build_failures_total",
|
|
147
|
-
{ destination: "lake" },
|
|
148
|
-
),
|
|
149
|
-
).toBe(1);
|
|
150
|
-
expect(
|
|
151
|
-
await harness.collectCounter(
|
|
152
|
-
"publisher_materialization_eligibility_refused_total",
|
|
153
|
-
{ reason: "given" },
|
|
154
|
-
),
|
|
155
|
-
).toBe(1);
|
|
156
|
-
expect(
|
|
157
|
-
await harness.collectCounter(
|
|
158
|
-
"publisher_storage_serve_shape_tier_drop_total",
|
|
159
|
-
{ tier: "0" },
|
|
160
|
-
),
|
|
161
|
-
).toBe(1);
|
|
162
|
-
expect(
|
|
163
|
-
await harness.collectCounter(
|
|
164
|
-
"publisher_storage_serve_shape_type_fallback_total",
|
|
165
|
-
{ kind: "array" },
|
|
166
|
-
),
|
|
167
|
-
).toBe(1);
|
|
168
|
-
});
|
|
169
|
-
});
|