@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
|
@@ -1,291 +0,0 @@
|
|
|
1
|
-
import { components } from "../api";
|
|
2
|
-
import { ConnectionNotFoundError, FrozenConfigError } from "../errors";
|
|
3
|
-
import { logger } from "../logger";
|
|
4
|
-
import { buildEnvironmentMalloyConfig } from "./connection";
|
|
5
|
-
import { EnvironmentStore } from "./environment_store";
|
|
6
|
-
|
|
7
|
-
type ApiConnection = components["schemas"]["Connection"];
|
|
8
|
-
type ReleaseCallback = () => Promise<void>;
|
|
9
|
-
type ConnectionUpdateEnvironment = {
|
|
10
|
-
runConnectionUpdateExclusive?: <T>(fn: () => Promise<T>) => Promise<T>;
|
|
11
|
-
updateConnections?: (
|
|
12
|
-
nextMalloyConfig: ReturnType<typeof buildEnvironmentMalloyConfig>,
|
|
13
|
-
apiConnections?: ApiConnection[],
|
|
14
|
-
afterPreviousRelease?: ReleaseCallback,
|
|
15
|
-
) => void;
|
|
16
|
-
deleteConnection?: (connectionName: string) => Promise<void>;
|
|
17
|
-
deleteDuckDBConnection?: (connectionName: string) => Promise<void>;
|
|
18
|
-
deleteDuckLakeConnection?: (connectionName: string) => Promise<void>;
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
async function runEnvironmentConnectionUpdate<T>(
|
|
22
|
-
environment: ConnectionUpdateEnvironment,
|
|
23
|
-
fn: () => Promise<T>,
|
|
24
|
-
): Promise<T> {
|
|
25
|
-
if (environment.runConnectionUpdateExclusive) {
|
|
26
|
-
return environment.runConnectionUpdateExclusive(fn);
|
|
27
|
-
}
|
|
28
|
-
return fn();
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
function updateEnvironmentConnections(
|
|
32
|
-
environment: ConnectionUpdateEnvironment,
|
|
33
|
-
nextMalloyConfig: ReturnType<typeof buildEnvironmentMalloyConfig>,
|
|
34
|
-
afterPreviousRelease?: ReleaseCallback,
|
|
35
|
-
): void {
|
|
36
|
-
environment.updateConnections?.(
|
|
37
|
-
nextMalloyConfig,
|
|
38
|
-
nextMalloyConfig.apiConnections,
|
|
39
|
-
afterPreviousRelease,
|
|
40
|
-
);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
function buildDeletedConnectionCleanup(
|
|
44
|
-
environment: ConnectionUpdateEnvironment,
|
|
45
|
-
deletedConnection: ApiConnection,
|
|
46
|
-
connectionName: string,
|
|
47
|
-
): ReleaseCallback | undefined {
|
|
48
|
-
if (
|
|
49
|
-
deletedConnection.type === "duckdb" &&
|
|
50
|
-
typeof environment.deleteDuckDBConnection === "function"
|
|
51
|
-
) {
|
|
52
|
-
return () => environment.deleteDuckDBConnection!(connectionName);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
if (
|
|
56
|
-
deletedConnection.type === "ducklake" &&
|
|
57
|
-
typeof environment.deleteDuckLakeConnection === "function"
|
|
58
|
-
) {
|
|
59
|
-
return () => environment.deleteDuckLakeConnection!(connectionName);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
return undefined;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
export class ConnectionService {
|
|
66
|
-
private environmentStore: EnvironmentStore;
|
|
67
|
-
|
|
68
|
-
constructor(environmentStore: EnvironmentStore) {
|
|
69
|
-
this.environmentStore = environmentStore;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
public async getConnection(environmentName: string, connectionName: string) {
|
|
73
|
-
await this.environmentStore.finishedInitialization;
|
|
74
|
-
|
|
75
|
-
const repository = this.environmentStore.storageManager.getRepository();
|
|
76
|
-
const dbEnvironment =
|
|
77
|
-
await repository.getEnvironmentByName(environmentName);
|
|
78
|
-
|
|
79
|
-
if (!dbEnvironment) {
|
|
80
|
-
throw new Error(
|
|
81
|
-
`Environment "${environmentName}" not found in database`,
|
|
82
|
-
);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
const dbConnection = await repository.getConnectionByName(
|
|
86
|
-
dbEnvironment.id,
|
|
87
|
-
connectionName,
|
|
88
|
-
);
|
|
89
|
-
|
|
90
|
-
if (!dbConnection) {
|
|
91
|
-
throw new ConnectionNotFoundError(
|
|
92
|
-
`Connection "${connectionName}" not found in environment "${environmentName}"`,
|
|
93
|
-
);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
return { dbEnvironment, dbConnection, repository };
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
public async addConnection(
|
|
100
|
-
environmentName: string,
|
|
101
|
-
connectionName: string,
|
|
102
|
-
connection: ApiConnection,
|
|
103
|
-
): Promise<void> {
|
|
104
|
-
await this.environmentStore.finishedInitialization;
|
|
105
|
-
|
|
106
|
-
if (this.environmentStore.publisherConfigIsFrozen) {
|
|
107
|
-
throw new FrozenConfigError();
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
logger.info(
|
|
111
|
-
`Adding connection "${connectionName}" to environment "${environmentName}"`,
|
|
112
|
-
);
|
|
113
|
-
|
|
114
|
-
// Get database environment record and repository
|
|
115
|
-
const repository = this.environmentStore.storageManager.getRepository();
|
|
116
|
-
const dbEnvironment =
|
|
117
|
-
await repository.getEnvironmentByName(environmentName);
|
|
118
|
-
|
|
119
|
-
if (!dbEnvironment) {
|
|
120
|
-
throw new Error(
|
|
121
|
-
`Environment "${environmentName}" not found in database`,
|
|
122
|
-
);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
// Check if connection already exists in database
|
|
126
|
-
const existingDbConn = await repository.getConnectionByName(
|
|
127
|
-
dbEnvironment.id,
|
|
128
|
-
connectionName!,
|
|
129
|
-
);
|
|
130
|
-
|
|
131
|
-
if (existingDbConn) {
|
|
132
|
-
throw new Error(
|
|
133
|
-
`Connection "${connectionName}" already exists in environment "${environmentName}".`,
|
|
134
|
-
);
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
// Update in-memory connections
|
|
138
|
-
const environment = await this.environmentStore.getEnvironment(
|
|
139
|
-
environmentName,
|
|
140
|
-
false,
|
|
141
|
-
);
|
|
142
|
-
await runEnvironmentConnectionUpdate(environment, async () => {
|
|
143
|
-
const existingConnections = environment.listApiConnections();
|
|
144
|
-
const nextMalloyConfig = buildEnvironmentMalloyConfig(
|
|
145
|
-
[...existingConnections, connection],
|
|
146
|
-
environment.metadata.location || "",
|
|
147
|
-
);
|
|
148
|
-
|
|
149
|
-
await this.environmentStore.addConnection(
|
|
150
|
-
connection,
|
|
151
|
-
dbEnvironment.id,
|
|
152
|
-
repository,
|
|
153
|
-
);
|
|
154
|
-
|
|
155
|
-
updateEnvironmentConnections(environment, nextMalloyConfig);
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
logger.info(
|
|
159
|
-
`Successfully added connection "${connection.name}" to environment "${environmentName}"`,
|
|
160
|
-
);
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
public async updateConnection(
|
|
164
|
-
environmentName: string,
|
|
165
|
-
connectionName: string,
|
|
166
|
-
connection: Partial<ApiConnection>,
|
|
167
|
-
): Promise<void> {
|
|
168
|
-
await this.environmentStore.finishedInitialization;
|
|
169
|
-
|
|
170
|
-
if (this.environmentStore.publisherConfigIsFrozen) {
|
|
171
|
-
throw new FrozenConfigError();
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
logger.info(
|
|
175
|
-
`Updating connection "${connectionName}" in environment "${environmentName}"`,
|
|
176
|
-
);
|
|
177
|
-
|
|
178
|
-
const { dbEnvironment, dbConnection, repository } =
|
|
179
|
-
await this.getConnection(environmentName, connectionName);
|
|
180
|
-
|
|
181
|
-
// Update in-memory connections
|
|
182
|
-
const environment = await this.environmentStore.getEnvironment(
|
|
183
|
-
environmentName,
|
|
184
|
-
false,
|
|
185
|
-
);
|
|
186
|
-
await runEnvironmentConnectionUpdate(environment, async () => {
|
|
187
|
-
const existingConnections = environment.listApiConnections();
|
|
188
|
-
|
|
189
|
-
const updatedConnection = {
|
|
190
|
-
...dbConnection.config,
|
|
191
|
-
...connection,
|
|
192
|
-
name: connectionName,
|
|
193
|
-
};
|
|
194
|
-
|
|
195
|
-
const updatedConnections = existingConnections.map(
|
|
196
|
-
(conn: ApiConnection) =>
|
|
197
|
-
conn.name === connectionName ? updatedConnection : conn,
|
|
198
|
-
);
|
|
199
|
-
|
|
200
|
-
// Pass isUpdateConnectionRequest=true so the DuckLake wrapper
|
|
201
|
-
// re-attaches against the updated catalog/storage settings instead
|
|
202
|
-
// of trusting the prior generation's persisted attach state.
|
|
203
|
-
const nextMalloyConfig = buildEnvironmentMalloyConfig(
|
|
204
|
-
updatedConnections,
|
|
205
|
-
environment.metadata.location || "",
|
|
206
|
-
true,
|
|
207
|
-
);
|
|
208
|
-
|
|
209
|
-
await this.environmentStore.updateConnection(
|
|
210
|
-
updatedConnection,
|
|
211
|
-
dbEnvironment.id,
|
|
212
|
-
repository,
|
|
213
|
-
);
|
|
214
|
-
|
|
215
|
-
updateEnvironmentConnections(environment, nextMalloyConfig);
|
|
216
|
-
});
|
|
217
|
-
|
|
218
|
-
logger.info(
|
|
219
|
-
`Successfully updated connection "${connectionName}" in environment "${environmentName}"`,
|
|
220
|
-
);
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
public async deleteConnection(
|
|
224
|
-
environmentName: string,
|
|
225
|
-
connectionName: string,
|
|
226
|
-
): Promise<void> {
|
|
227
|
-
await this.environmentStore.finishedInitialization;
|
|
228
|
-
|
|
229
|
-
if (this.environmentStore.publisherConfigIsFrozen) {
|
|
230
|
-
throw new FrozenConfigError();
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
logger.info(
|
|
234
|
-
`Deleting connection "${connectionName}" from environment "${environmentName}"`,
|
|
235
|
-
);
|
|
236
|
-
|
|
237
|
-
const { dbConnection, repository } = await this.getConnection(
|
|
238
|
-
environmentName,
|
|
239
|
-
connectionName,
|
|
240
|
-
);
|
|
241
|
-
|
|
242
|
-
// Update in-memory connections
|
|
243
|
-
const environment = await this.environmentStore.getEnvironment(
|
|
244
|
-
environmentName,
|
|
245
|
-
false,
|
|
246
|
-
);
|
|
247
|
-
await runEnvironmentConnectionUpdate(environment, async () => {
|
|
248
|
-
if (typeof environment.listApiConnections !== "function") {
|
|
249
|
-
if (typeof environment.deleteConnection === "function") {
|
|
250
|
-
await environment.deleteConnection(connectionName);
|
|
251
|
-
}
|
|
252
|
-
await repository.deleteConnection(dbConnection.id);
|
|
253
|
-
return;
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
const deletedConnection =
|
|
257
|
-
"getApiConnection" in environment &&
|
|
258
|
-
typeof environment.getApiConnection === "function"
|
|
259
|
-
? environment.getApiConnection(connectionName)
|
|
260
|
-
: dbConnection.config;
|
|
261
|
-
const updatedConnections = environment
|
|
262
|
-
.listApiConnections()
|
|
263
|
-
.filter(
|
|
264
|
-
(connection: ApiConnection) =>
|
|
265
|
-
connection.name !== connectionName,
|
|
266
|
-
);
|
|
267
|
-
const nextMalloyConfig = buildEnvironmentMalloyConfig(
|
|
268
|
-
updatedConnections,
|
|
269
|
-
environment.metadata.location || "",
|
|
270
|
-
);
|
|
271
|
-
const deleteConnectionFilesAfterRelease =
|
|
272
|
-
buildDeletedConnectionCleanup(
|
|
273
|
-
environment,
|
|
274
|
-
deletedConnection,
|
|
275
|
-
connectionName,
|
|
276
|
-
);
|
|
277
|
-
|
|
278
|
-
await repository.deleteConnection(dbConnection.id);
|
|
279
|
-
|
|
280
|
-
updateEnvironmentConnections(
|
|
281
|
-
environment,
|
|
282
|
-
nextMalloyConfig,
|
|
283
|
-
deleteConnectionFilesAfterRelease,
|
|
284
|
-
);
|
|
285
|
-
});
|
|
286
|
-
|
|
287
|
-
logger.info(
|
|
288
|
-
`Successfully deleted connection "${connectionName}" from environment "${environmentName}"`,
|
|
289
|
-
);
|
|
290
|
-
}
|
|
291
|
-
}
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from "bun:test";
|
|
2
|
-
import { CronEvaluator } from "./cron_evaluator";
|
|
3
|
-
|
|
4
|
-
describe("CronEvaluator", () => {
|
|
5
|
-
const cron = new CronEvaluator();
|
|
6
|
-
|
|
7
|
-
describe("isValid", () => {
|
|
8
|
-
it("accepts 5-field UNIX crons", () => {
|
|
9
|
-
expect(cron.isValid("0 6 * * *")).toBe(true);
|
|
10
|
-
expect(cron.isValid("*/15 * * * *")).toBe(true);
|
|
11
|
-
expect(cron.isValid("0 0 1 1 *")).toBe(true);
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
it("rejects a 6-field (seconds) cron — the contract is 5-field", () => {
|
|
15
|
-
expect(cron.isValid("0 0 6 * * *")).toBe(false);
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
it("rejects garbage and empty input", () => {
|
|
19
|
-
expect(cron.isValid("not a cron")).toBe(false);
|
|
20
|
-
expect(cron.isValid("")).toBe(false);
|
|
21
|
-
expect(cron.isValid("* * *")).toBe(false);
|
|
22
|
-
// Out-of-range field.
|
|
23
|
-
expect(cron.isValid("99 * * * *")).toBe(false);
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
it("rejects cron-parser / Quartz extensions the UNIX parser lacks", () => {
|
|
27
|
-
// These parse under cron-parser but the control plane's cron-utils
|
|
28
|
-
// UNIX parser rejects them — pinning the grammar keeps a cron from
|
|
29
|
-
// validating locally yet silently never arming in production.
|
|
30
|
-
expect(cron.isValid("0 6 L * *")).toBe(false); // last day of month
|
|
31
|
-
expect(cron.isValid("0 6 15W * *")).toBe(false); // nearest weekday
|
|
32
|
-
expect(cron.isValid("0 6 * * 1#2")).toBe(false); // 2nd Monday
|
|
33
|
-
expect(cron.isValid("0 0 ? * *")).toBe(false); // Quartz no-specific
|
|
34
|
-
expect(cron.isValid("0 6 LW * *")).toBe(false); // last weekday
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
it("accepts UNIX month/day names (not mistaken for extensions)", () => {
|
|
38
|
-
expect(cron.isValid("0 6 * JUL *")).toBe(true); // JUL contains 'L'
|
|
39
|
-
expect(cron.isValid("0 6 * * WED")).toBe(true); // WED contains 'W'
|
|
40
|
-
expect(cron.isValid("0 6 * * THU")).toBe(true); // THU contains 'H'
|
|
41
|
-
expect(cron.isValid("0 6 * * MON-FRI")).toBe(true);
|
|
42
|
-
});
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
describe("nextAfter (UTC, strictly after)", () => {
|
|
46
|
-
it("returns the next daily fire", () => {
|
|
47
|
-
const from = new Date("2026-07-13T00:00:00Z");
|
|
48
|
-
expect(cron.nextAfter("0 6 * * *", from).toISOString()).toBe(
|
|
49
|
-
"2026-07-13T06:00:00.000Z",
|
|
50
|
-
);
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
it("rolls to the next day when the fire time has passed", () => {
|
|
54
|
-
const from = new Date("2026-07-13T07:00:00Z");
|
|
55
|
-
expect(cron.nextAfter("0 6 * * *", from).toISOString()).toBe(
|
|
56
|
-
"2026-07-14T06:00:00.000Z",
|
|
57
|
-
);
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
it("advances strictly past a `from` that lands exactly on a fire", () => {
|
|
61
|
-
const from = new Date("2026-07-13T06:00:00Z");
|
|
62
|
-
// Strictly after: the 06:00 instant itself is excluded.
|
|
63
|
-
expect(cron.nextAfter("0 6 * * *", from).toISOString()).toBe(
|
|
64
|
-
"2026-07-14T06:00:00.000Z",
|
|
65
|
-
);
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
it("steps every 15 minutes", () => {
|
|
69
|
-
const from = new Date("2026-07-13T09:07:00Z");
|
|
70
|
-
expect(cron.nextAfter("*/15 * * * *", from).toISOString()).toBe(
|
|
71
|
-
"2026-07-13T09:15:00.000Z",
|
|
72
|
-
);
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
it("throws on an invalid cron (callers guard with isValid)", () => {
|
|
76
|
-
expect(() => cron.nextAfter("nope", new Date())).toThrow();
|
|
77
|
-
});
|
|
78
|
-
});
|
|
79
|
-
});
|
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Evaluate a 5-field UNIX cron expression, in UTC, for the standalone
|
|
3
|
-
* materialization scheduler. Mirrors the control plane's `CronEvaluator`
|
|
4
|
-
* semantics (5-field, UTC, "strictly after") so a given `materialization.schedule`
|
|
5
|
-
* fires at the same instants whether the publisher runs standalone or the control
|
|
6
|
-
* plane drives it.
|
|
7
|
-
*
|
|
8
|
-
* Thin wrapper over `cron-parser` that pins three policies:
|
|
9
|
-
* - **exactly 5 fields** — `cron-parser` also accepts an optional leading
|
|
10
|
-
* seconds field (6 fields); the manifest contract is 5-field UNIX cron, so a
|
|
11
|
-
* 6-field expression is rejected rather than silently reinterpreted.
|
|
12
|
-
* - **plain UNIX grammar** — `cron-parser` accepts extensions (`L` last,
|
|
13
|
-
* `W` nearest-weekday, `#` nth-weekday, `?` Quartz no-specific) that the
|
|
14
|
-
* control plane's `cron-utils` UNIX parser rejects. Without this pin, an
|
|
15
|
-
* expression like `0 6 L * *` would validate and fire locally but, after
|
|
16
|
-
* publish, silently never arm in production. Month/day names (JAN, MON-FRI)
|
|
17
|
-
* are still allowed.
|
|
18
|
-
* - **UTC** — schedules are absolute, never tied to the server's local zone.
|
|
19
|
-
*/
|
|
20
|
-
import { CronExpressionParser } from "cron-parser";
|
|
21
|
-
|
|
22
|
-
/** Valid 3-letter month and day-of-week names in UNIX cron. */
|
|
23
|
-
const UNIX_CRON_NAMES = new Set([
|
|
24
|
-
"JAN",
|
|
25
|
-
"FEB",
|
|
26
|
-
"MAR",
|
|
27
|
-
"APR",
|
|
28
|
-
"MAY",
|
|
29
|
-
"JUN",
|
|
30
|
-
"JUL",
|
|
31
|
-
"AUG",
|
|
32
|
-
"SEP",
|
|
33
|
-
"OCT",
|
|
34
|
-
"NOV",
|
|
35
|
-
"DEC",
|
|
36
|
-
"SUN",
|
|
37
|
-
"MON",
|
|
38
|
-
"TUE",
|
|
39
|
-
"WED",
|
|
40
|
-
"THU",
|
|
41
|
-
"FRI",
|
|
42
|
-
"SAT",
|
|
43
|
-
]);
|
|
44
|
-
|
|
45
|
-
export class CronEvaluator {
|
|
46
|
-
/** True when `expr` is a syntactically valid 5-field UNIX cron. */
|
|
47
|
-
isValid(expr: string): boolean {
|
|
48
|
-
if (!this.hasFiveFields(expr) || !this.isPlainUnixGrammar(expr)) {
|
|
49
|
-
return false;
|
|
50
|
-
}
|
|
51
|
-
try {
|
|
52
|
-
CronExpressionParser.parse(expr, { tz: "UTC" });
|
|
53
|
-
return true;
|
|
54
|
-
} catch {
|
|
55
|
-
return false;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* The next fire instant strictly after `from` (UTC). Throws when `expr` is
|
|
61
|
-
* not a valid 5-field cron — callers guard with {@link isValid} (the
|
|
62
|
-
* scheduler skips + logs an invalid cron rather than letting it throw in the
|
|
63
|
-
* tick).
|
|
64
|
-
*/
|
|
65
|
-
nextAfter(expr: string, from: Date): Date {
|
|
66
|
-
if (!this.hasFiveFields(expr) || !this.isPlainUnixGrammar(expr)) {
|
|
67
|
-
throw new Error(
|
|
68
|
-
`Expected a 5-field UNIX cron, got: ${JSON.stringify(expr)}`,
|
|
69
|
-
);
|
|
70
|
-
}
|
|
71
|
-
return CronExpressionParser.parse(expr, {
|
|
72
|
-
currentDate: from,
|
|
73
|
-
tz: "UTC",
|
|
74
|
-
})
|
|
75
|
-
.next()
|
|
76
|
-
.toDate();
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/** Whitespace-split field count is exactly 5. */
|
|
80
|
-
private hasFiveFields(expr: string): boolean {
|
|
81
|
-
return typeof expr === "string" && expr.trim().split(/\s+/).length === 5;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
* Reject cron-parser / Quartz extensions absent from plain UNIX cron: `#`
|
|
86
|
-
* and `?` (never part of a name), and any alphabetic token that is not a
|
|
87
|
-
* UNIX month/day name — which catches `L`, `W`, `LW`, `L-3`, `15W`, etc.
|
|
88
|
-
* while still allowing named fields like `JUL` or `MON-FRI`.
|
|
89
|
-
*/
|
|
90
|
-
private isPlainUnixGrammar(expr: string): boolean {
|
|
91
|
-
for (const field of expr.trim().split(/\s+/)) {
|
|
92
|
-
if (/[#?]/.test(field)) return false;
|
|
93
|
-
for (const token of field.split(/[,\-/]/)) {
|
|
94
|
-
if (token === "" || token === "*") continue;
|
|
95
|
-
if (
|
|
96
|
-
/[A-Za-z]/.test(token) &&
|
|
97
|
-
!UNIX_CRON_NAMES.has(token.toUpperCase())
|
|
98
|
-
) {
|
|
99
|
-
return false;
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
return true;
|
|
104
|
-
}
|
|
105
|
-
}
|