@malloy-publisher/server 0.0.196-dev → 0.0.197-dev

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.
Files changed (99) hide show
  1. package/dist/app/api-doc.yaml +213 -214
  2. package/dist/app/assets/EnvironmentPage-1j6QDWAy.js +1 -0
  3. package/dist/app/assets/HomePage-DMop21VG.js +1 -0
  4. package/dist/app/assets/MainPage-BbE8ETz1.js +2 -0
  5. package/dist/app/assets/ModelPage-D2jvfe3t.js +1 -0
  6. package/dist/app/assets/PackagePage-BbnhGoD3.js +1 -0
  7. package/dist/app/assets/{RouteError-DefbDO7F.js → RouteError-D3LGEZ3i.js} +1 -1
  8. package/dist/app/assets/WorkbookPage-DttVIj4u.js +1 -0
  9. package/dist/app/assets/{core-BrfQApxh.es-DnvCX4oH.js → core-w79IMXAG.es-Bd0UlzOL.js} +1 -1
  10. package/dist/app/assets/{index-Bu0ub036.js → index-5K9YjIxF.js} +117 -117
  11. package/dist/app/assets/{index-CkzK3JIl.js → index-C513UodQ.js} +1 -1
  12. package/dist/app/assets/{index-CoA6HIGS.js → index-DIgzgp69.js} +1 -1
  13. package/dist/app/assets/{index.umd-B6Ms2PpL.js → index.umd-BMeMPq_9.js} +1 -1
  14. package/dist/app/index.html +1 -1
  15. package/dist/server.mjs +1328 -1304
  16. package/package.json +1 -1
  17. package/publisher.config.json +2 -2
  18. package/src/config.spec.ts +74 -66
  19. package/src/config.ts +50 -47
  20. package/src/controller/compile.controller.ts +10 -7
  21. package/src/controller/connection.controller.ts +79 -58
  22. package/src/controller/database.controller.ts +10 -7
  23. package/src/controller/manifest.controller.ts +23 -14
  24. package/src/controller/materialization.controller.ts +14 -14
  25. package/src/controller/model.controller.ts +35 -20
  26. package/src/controller/package.controller.ts +83 -49
  27. package/src/controller/query.controller.ts +11 -8
  28. package/src/controller/watch-mode.controller.ts +35 -29
  29. package/src/errors.ts +2 -2
  30. package/src/mcp/error_messages.ts +2 -2
  31. package/src/mcp/handler_utils.ts +23 -20
  32. package/src/mcp/mcp_constants.ts +1 -1
  33. package/src/mcp/prompts/handlers.ts +3 -3
  34. package/src/mcp/prompts/prompt_service.ts +5 -5
  35. package/src/mcp/prompts/utils.ts +12 -12
  36. package/src/mcp/resource_metadata.ts +3 -3
  37. package/src/mcp/resources/environment_resource.ts +187 -0
  38. package/src/mcp/resources/model_resource.ts +19 -17
  39. package/src/mcp/resources/notebook_resource.ts +13 -13
  40. package/src/mcp/resources/package_resource.ts +30 -27
  41. package/src/mcp/resources/query_resource.ts +15 -10
  42. package/src/mcp/resources/source_resource.ts +10 -10
  43. package/src/mcp/resources/view_resource.ts +11 -11
  44. package/src/mcp/server.ts +16 -14
  45. package/src/mcp/tools/discovery_tools.ts +67 -49
  46. package/src/mcp/tools/execute_query_tool.ts +14 -14
  47. package/src/server.ts +175 -159
  48. package/src/service/connection.spec.ts +158 -133
  49. package/src/service/connection.ts +42 -39
  50. package/src/service/connection_config.spec.ts +13 -11
  51. package/src/service/connection_config.ts +28 -19
  52. package/src/service/connection_service.spec.ts +63 -43
  53. package/src/service/connection_service.ts +106 -89
  54. package/src/service/{project.ts → environment.ts} +92 -77
  55. package/src/service/{project_compile.spec.ts → environment_compile.spec.ts} +1 -1
  56. package/src/service/{project_store.spec.ts → environment_store.spec.ts} +99 -85
  57. package/src/service/{project_store.ts → environment_store.ts} +368 -326
  58. package/src/service/manifest_service.spec.ts +15 -15
  59. package/src/service/manifest_service.ts +26 -21
  60. package/src/service/materialization_service.spec.ts +93 -59
  61. package/src/service/materialization_service.ts +71 -62
  62. package/src/service/materialized_table_gc.spec.ts +15 -15
  63. package/src/service/materialized_table_gc.ts +3 -3
  64. package/src/service/model.ts +2 -2
  65. package/src/service/package.spec.ts +2 -2
  66. package/src/service/package.ts +23 -21
  67. package/src/service/resolve_environment.ts +15 -0
  68. package/src/storage/DatabaseInterface.ts +34 -25
  69. package/src/storage/StorageManager.mock.ts +3 -3
  70. package/src/storage/StorageManager.ts +24 -23
  71. package/src/storage/duckdb/ConnectionRepository.ts +13 -11
  72. package/src/storage/duckdb/DuckDBConnection.ts +1 -1
  73. package/src/storage/duckdb/DuckDBManifestStore.ts +6 -6
  74. package/src/storage/duckdb/DuckDBRepository.ts +47 -47
  75. package/src/storage/duckdb/{ProjectRepository.ts → EnvironmentRepository.ts} +35 -35
  76. package/src/storage/duckdb/ManifestRepository.ts +21 -20
  77. package/src/storage/duckdb/MaterializationRepository.ts +31 -28
  78. package/src/storage/duckdb/PackageRepository.ts +11 -11
  79. package/src/storage/duckdb/manifest_store.spec.ts +2 -2
  80. package/src/storage/duckdb/schema.ts +20 -20
  81. package/src/storage/ducklake/DuckLakeManifestStore.ts +14 -14
  82. package/tests/fixtures/publisher.config.json +1 -1
  83. package/tests/harness/e2e.ts +1 -1
  84. package/tests/harness/mcp_test_setup.ts +1 -1
  85. package/tests/harness/mocks.ts +10 -8
  86. package/tests/integration/materialization/materialization_lifecycle.integration.spec.ts +4 -4
  87. package/tests/integration/mcp/mcp_execute_query_tool.integration.spec.ts +27 -48
  88. package/tests/integration/mcp/mcp_resource.integration.spec.ts +26 -35
  89. package/tests/unit/duckdb/attached_databases.test.ts +51 -33
  90. package/tests/unit/ducklake/ducklake.test.ts +24 -22
  91. package/tests/unit/mcp/prompt_happy.test.ts +8 -8
  92. package/dist/app/assets/HomePage-DbZS0N7G.js +0 -1
  93. package/dist/app/assets/MainPage-CBuWkbmr.js +0 -2
  94. package/dist/app/assets/ModelPage-Bt37smot.js +0 -1
  95. package/dist/app/assets/PackagePage-DLZe50WG.js +0 -1
  96. package/dist/app/assets/ProjectPage-FQTEPXP4.js +0 -1
  97. package/dist/app/assets/WorkbookPage-CkAo16ar.js +0 -1
  98. package/src/mcp/resources/project_resource.ts +0 -184
  99. package/src/service/resolve_project.ts +0 -13
@@ -1,28 +1,28 @@
1
1
  import { afterEach, beforeEach, describe, expect, it } from "bun:test";
2
2
  import sinon from "sinon";
3
- import { FrozenConfigError, ConnectionNotFoundError } from "../errors";
4
- import { ConnectionService } from "./connection_service";
5
- import { ProjectStore } from "./project_store";
6
3
  import { components } from "../api";
4
+ import { ConnectionNotFoundError, FrozenConfigError } from "../errors";
5
+ import { ConnectionService } from "./connection_service";
6
+ import { EnvironmentStore } from "./environment_store";
7
7
 
8
8
  type ApiConnection = components["schemas"]["Connection"];
9
9
 
10
10
  describe("service/connection_service", () => {
11
11
  let connectionService: ConnectionService;
12
- let mockProjectStore: Record<string, unknown>;
12
+ let mockEnvironmentStore: Record<string, unknown>;
13
13
  let mockRepository: Record<string, unknown>;
14
14
 
15
15
  beforeEach(() => {
16
16
  mockRepository = {
17
- getProjectByName: sinon.stub(),
17
+ getEnvironmentByName: sinon.stub(),
18
18
  getConnectionByName: sinon.stub(),
19
19
  deleteConnection: sinon.stub(),
20
20
  };
21
21
 
22
- mockProjectStore = {
22
+ mockEnvironmentStore = {
23
23
  finishedInitialization: Promise.resolve(),
24
24
  publisherConfigIsFrozen: false,
25
- getProject: sinon.stub(),
25
+ getEnvironment: sinon.stub(),
26
26
  updateConnection: sinon.stub(),
27
27
  addConnection: sinon.stub(),
28
28
  storageManager: {
@@ -31,7 +31,7 @@ describe("service/connection_service", () => {
31
31
  };
32
32
 
33
33
  connectionService = new ConnectionService(
34
- mockProjectStore as unknown as ProjectStore,
34
+ mockEnvironmentStore as unknown as EnvironmentStore,
35
35
  );
36
36
  });
37
37
 
@@ -51,7 +51,7 @@ describe("service/connection_service", () => {
51
51
 
52
52
  const mockDbConnection = {
53
53
  id: "conn-123",
54
- projectId: "project-123",
54
+ environmentId: "project-123",
55
55
  name: "test-connection",
56
56
  type: "postgres" as const,
57
57
  config: {},
@@ -66,7 +66,7 @@ describe("service/connection_service", () => {
66
66
  },
67
67
  };
68
68
 
69
- (mockRepository.getProjectByName as sinon.SinonStub).resolves(
69
+ (mockRepository.getEnvironmentByName as sinon.SinonStub).resolves(
70
70
  mockDbProject,
71
71
  );
72
72
  (mockRepository.getConnectionByName as sinon.SinonStub).resolves(
@@ -78,17 +78,19 @@ describe("service/connection_service", () => {
78
78
  "test-connection",
79
79
  );
80
80
 
81
- expect(result.dbProject).toEqual(mockDbProject);
81
+ expect(result.dbEnvironment).toEqual(mockDbProject);
82
82
  expect(result.dbConnection).toEqual(mockDbConnection);
83
83
  expect(result.repository).toBeDefined();
84
84
  });
85
85
 
86
86
  it("should throw error when project not found", async () => {
87
- (mockRepository.getProjectByName as sinon.SinonStub).resolves(null);
87
+ (mockRepository.getEnvironmentByName as sinon.SinonStub).resolves(
88
+ null,
89
+ );
88
90
 
89
91
  await expect(
90
92
  connectionService.getConnection("non-existent", "test-connection"),
91
- ).rejects.toThrow('Project "non-existent" not found in database');
93
+ ).rejects.toThrow('Environment "non-existent" not found in database');
92
94
  });
93
95
 
94
96
  it("should throw ConnectionNotFoundError when connection not found", async () => {
@@ -100,7 +102,7 @@ describe("service/connection_service", () => {
100
102
  updatedAt: new Date(),
101
103
  };
102
104
 
103
- (mockRepository.getProjectByName as sinon.SinonStub).resolves(
105
+ (mockRepository.getEnvironmentByName as sinon.SinonStub).resolves(
104
106
  mockDbProject,
105
107
  );
106
108
  (mockRepository.getConnectionByName as sinon.SinonStub).resolves(null);
@@ -139,11 +141,13 @@ describe("service/connection_service", () => {
139
141
  metadata: { location: "/test/path" },
140
142
  };
141
143
 
142
- (mockRepository.getProjectByName as sinon.SinonStub).resolves(
144
+ (mockRepository.getEnvironmentByName as sinon.SinonStub).resolves(
143
145
  mockDbProject,
144
146
  );
145
147
  (mockRepository.getConnectionByName as sinon.SinonStub).resolves(null);
146
- (mockProjectStore.getProject as sinon.SinonStub).resolves(mockProject);
148
+ (mockEnvironmentStore.getEnvironment as sinon.SinonStub).resolves(
149
+ mockProject,
150
+ );
147
151
 
148
152
  await connectionService.addConnection(
149
153
  "test-project",
@@ -152,13 +156,13 @@ describe("service/connection_service", () => {
152
156
  );
153
157
 
154
158
  expect(
155
- (mockProjectStore.addConnection as sinon.SinonStub).called,
159
+ (mockEnvironmentStore.addConnection as sinon.SinonStub).called,
156
160
  ).toBe(true);
157
161
  expect(mockProject.updateConnections.called).toBe(true);
158
162
  });
159
163
 
160
164
  it("should throw FrozenConfigError when config is frozen", async () => {
161
- mockProjectStore.publisherConfigIsFrozen = true;
165
+ mockEnvironmentStore.publisherConfigIsFrozen = true;
162
166
 
163
167
  await expect(
164
168
  connectionService.addConnection("test-project", "new-connection", {
@@ -169,14 +173,16 @@ describe("service/connection_service", () => {
169
173
  });
170
174
 
171
175
  it("should throw error when project not found", async () => {
172
- (mockRepository.getProjectByName as sinon.SinonStub).resolves(null);
176
+ (mockRepository.getEnvironmentByName as sinon.SinonStub).resolves(
177
+ null,
178
+ );
173
179
 
174
180
  await expect(
175
181
  connectionService.addConnection("non-existent", "new-connection", {
176
182
  name: "new-connection",
177
183
  type: "postgres",
178
184
  } as ApiConnection),
179
- ).rejects.toThrow('Project "non-existent" not found in database');
185
+ ).rejects.toThrow('Environment "non-existent" not found in database');
180
186
  });
181
187
 
182
188
  it("should throw error when connection already exists", async () => {
@@ -193,7 +199,7 @@ describe("service/connection_service", () => {
193
199
  name: "existing-connection",
194
200
  };
195
201
 
196
- (mockRepository.getProjectByName as sinon.SinonStub).resolves(
202
+ (mockRepository.getEnvironmentByName as sinon.SinonStub).resolves(
197
203
  mockDbProject,
198
204
  );
199
205
  (mockRepository.getConnectionByName as sinon.SinonStub).resolves(
@@ -210,7 +216,7 @@ describe("service/connection_service", () => {
210
216
  } as ApiConnection,
211
217
  ),
212
218
  ).rejects.toThrow(
213
- 'Connection "existing-connection" already exists in project "test-project"',
219
+ 'Connection "existing-connection" already exists in environment "test-project"',
214
220
  );
215
221
  });
216
222
 
@@ -249,11 +255,13 @@ describe("service/connection_service", () => {
249
255
  metadata: { location: "/test/path" },
250
256
  };
251
257
 
252
- (mockRepository.getProjectByName as sinon.SinonStub).resolves(
258
+ (mockRepository.getEnvironmentByName as sinon.SinonStub).resolves(
253
259
  mockDbProject,
254
260
  );
255
261
  (mockRepository.getConnectionByName as sinon.SinonStub).resolves(null);
256
- (mockProjectStore.getProject as sinon.SinonStub).resolves(mockProject);
262
+ (mockEnvironmentStore.getEnvironment as sinon.SinonStub).resolves(
263
+ mockProject,
264
+ );
257
265
 
258
266
  await connectionService.addConnection(
259
267
  "test-project",
@@ -310,14 +318,16 @@ describe("service/connection_service", () => {
310
318
  "getConnection",
311
319
  );
312
320
  getConnectionStub.resolves({
313
- dbProject: mockDbProject,
321
+ dbEnvironment: mockDbProject,
314
322
  dbConnection: mockDbConnection,
315
323
  repository: mockRepository,
316
324
  } as unknown as Awaited<
317
325
  ReturnType<typeof connectionService.getConnection>
318
326
  >);
319
327
 
320
- (mockProjectStore.getProject as sinon.SinonStub).resolves(mockProject);
328
+ (mockEnvironmentStore.getEnvironment as sinon.SinonStub).resolves(
329
+ mockProject,
330
+ );
321
331
 
322
332
  const updates: Partial<ApiConnection> = {
323
333
  type: "postgres",
@@ -341,7 +351,7 @@ describe("service/connection_service", () => {
341
351
  ).toBe(true);
342
352
 
343
353
  expect(
344
- (mockProjectStore.getProject as sinon.SinonStub).calledWith(
354
+ (mockEnvironmentStore.getEnvironment as sinon.SinonStub).calledWith(
345
355
  "test-project",
346
356
  false,
347
357
  ),
@@ -350,17 +360,17 @@ describe("service/connection_service", () => {
350
360
  expect(mockProject.updateConnections.called).toBe(true);
351
361
 
352
362
  expect(
353
- (mockProjectStore.updateConnection as sinon.SinonStub).called,
363
+ (mockEnvironmentStore.updateConnection as sinon.SinonStub).called,
354
364
  ).toBe(true);
355
365
  const updateCall = (
356
- mockProjectStore.updateConnection as sinon.SinonStub
366
+ mockEnvironmentStore.updateConnection as sinon.SinonStub
357
367
  ).getCall(0);
358
368
  expect(updateCall.args[0].name).toBe("test-connection");
359
369
  expect(updateCall.args[1]).toBe("project-123");
360
370
  });
361
371
 
362
372
  it("should throw FrozenConfigError when config is frozen", async () => {
363
- mockProjectStore.publisherConfigIsFrozen = true;
373
+ mockEnvironmentStore.publisherConfigIsFrozen = true;
364
374
 
365
375
  await expect(
366
376
  connectionService.updateConnection(
@@ -414,14 +424,16 @@ describe("service/connection_service", () => {
414
424
  "getConnection",
415
425
  );
416
426
  getConnectionStub.resolves({
417
- dbProject: mockDbProject,
427
+ dbEnvironment: mockDbProject,
418
428
  dbConnection: connection1,
419
429
  repository: mockRepository,
420
430
  } as unknown as Awaited<
421
431
  ReturnType<typeof connectionService.getConnection>
422
432
  >);
423
433
 
424
- (mockProjectStore.getProject as sinon.SinonStub).resolves(mockProject);
434
+ (mockEnvironmentStore.getEnvironment as sinon.SinonStub).resolves(
435
+ mockProject,
436
+ );
425
437
 
426
438
  await connectionService.updateConnection("test-project", "conn-1", {
427
439
  type: "postgres",
@@ -471,14 +483,16 @@ describe("service/connection_service", () => {
471
483
  "getConnection",
472
484
  );
473
485
  getConnectionStub.resolves({
474
- dbProject: mockDbProject,
486
+ dbEnvironment: mockDbProject,
475
487
  dbConnection: existingConnection,
476
488
  repository: mockRepository,
477
489
  } as unknown as Awaited<
478
490
  ReturnType<typeof connectionService.getConnection>
479
491
  >);
480
492
 
481
- (mockProjectStore.getProject as sinon.SinonStub).resolves(mockProject);
493
+ (mockEnvironmentStore.getEnvironment as sinon.SinonStub).resolves(
494
+ mockProject,
495
+ );
482
496
 
483
497
  const partialUpdate: Partial<ApiConnection> = {
484
498
  type: "postgres",
@@ -498,10 +512,10 @@ describe("service/connection_service", () => {
498
512
  );
499
513
 
500
514
  expect(
501
- (mockProjectStore.updateConnection as sinon.SinonStub).called,
515
+ (mockEnvironmentStore.updateConnection as sinon.SinonStub).called,
502
516
  ).toBe(true);
503
517
  const updateCall = (
504
- mockProjectStore.updateConnection as sinon.SinonStub
518
+ mockEnvironmentStore.updateConnection as sinon.SinonStub
505
519
  ).getCall(0);
506
520
  const updatedConn = updateCall.args[0];
507
521
 
@@ -541,14 +555,16 @@ describe("service/connection_service", () => {
541
555
  "getConnection",
542
556
  );
543
557
  getConnectionStub.resolves({
544
- dbProject: mockDbProject,
558
+ dbEnvironment: mockDbProject,
545
559
  dbConnection: dbConnection,
546
560
  repository: mockRepository,
547
561
  } as unknown as Awaited<
548
562
  ReturnType<typeof connectionService.getConnection>
549
563
  >);
550
564
 
551
- (mockProjectStore.getProject as sinon.SinonStub).resolves(mockProject);
565
+ (mockEnvironmentStore.getEnvironment as sinon.SinonStub).resolves(
566
+ mockProject,
567
+ );
552
568
 
553
569
  await connectionService.updateConnection("test-project", "test-conn", {
554
570
  type: "postgres",
@@ -564,7 +580,7 @@ describe("service/connection_service", () => {
564
580
  expect(getConnectionStub.calledOnce).toBe(true);
565
581
 
566
582
  const updateCall = (
567
- mockProjectStore.updateConnection as sinon.SinonStub
583
+ mockEnvironmentStore.updateConnection as sinon.SinonStub
568
584
  ).getCall(0);
569
585
  expect(updateCall.args[0].name).toBe("test-conn");
570
586
  expect(updateCall.args[0].type).toBe("postgres");
@@ -594,7 +610,9 @@ describe("service/connection_service", () => {
594
610
  ReturnType<typeof connectionService.getConnection>
595
611
  >);
596
612
 
597
- (mockProjectStore.getProject as sinon.SinonStub).resolves(mockProject);
613
+ (mockEnvironmentStore.getEnvironment as sinon.SinonStub).resolves(
614
+ mockProject,
615
+ );
598
616
 
599
617
  await connectionService.deleteConnection(
600
618
  "test-project",
@@ -643,7 +661,9 @@ describe("service/connection_service", () => {
643
661
  } as unknown as Awaited<
644
662
  ReturnType<typeof connectionService.getConnection>
645
663
  >);
646
- (mockProjectStore.getProject as sinon.SinonStub).resolves(mockProject);
664
+ (mockEnvironmentStore.getEnvironment as sinon.SinonStub).resolves(
665
+ mockProject,
666
+ );
647
667
 
648
668
  await connectionService.deleteConnection(
649
669
  "test-project",
@@ -662,7 +682,7 @@ describe("service/connection_service", () => {
662
682
  });
663
683
 
664
684
  it("should throw FrozenConfigError when config is frozen", async () => {
665
- mockProjectStore.publisherConfigIsFrozen = true;
685
+ mockEnvironmentStore.publisherConfigIsFrozen = true;
666
686
 
667
687
  await expect(
668
688
  connectionService.deleteConnection(
@@ -679,7 +699,7 @@ describe("service/connection_service", () => {
679
699
  );
680
700
  getConnectionStub.rejects(
681
701
  new ConnectionNotFoundError(
682
- 'Connection "non-existent" not found in project "test-project"',
702
+ 'Connection "non-existent" not found in environment "test-project"',
683
703
  ),
684
704
  );
685
705