@tinybirdco/sdk 0.0.47 → 0.0.49

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 (107) hide show
  1. package/README.md +53 -3
  2. package/dist/cli/commands/migrate.d.ts.map +1 -1
  3. package/dist/cli/commands/migrate.js +32 -0
  4. package/dist/cli/commands/migrate.js.map +1 -1
  5. package/dist/cli/commands/migrate.test.js +585 -8
  6. package/dist/cli/commands/migrate.test.js.map +1 -1
  7. package/dist/generator/connection.d.ts.map +1 -1
  8. package/dist/generator/connection.js +3 -0
  9. package/dist/generator/connection.js.map +1 -1
  10. package/dist/generator/connection.test.js +8 -0
  11. package/dist/generator/connection.test.js.map +1 -1
  12. package/dist/generator/datasource.d.ts.map +1 -1
  13. package/dist/generator/datasource.js +3 -0
  14. package/dist/generator/datasource.js.map +1 -1
  15. package/dist/generator/datasource.test.js +50 -0
  16. package/dist/generator/datasource.test.js.map +1 -1
  17. package/dist/generator/pipe.d.ts.map +1 -1
  18. package/dist/generator/pipe.js +31 -1
  19. package/dist/generator/pipe.js.map +1 -1
  20. package/dist/generator/pipe.test.js +50 -1
  21. package/dist/generator/pipe.test.js.map +1 -1
  22. package/dist/index.d.ts +3 -2
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +3 -1
  25. package/dist/index.js.map +1 -1
  26. package/dist/index.test.js +3 -0
  27. package/dist/index.test.js.map +1 -1
  28. package/dist/migrate/emit-ts.d.ts.map +1 -1
  29. package/dist/migrate/emit-ts.js +159 -41
  30. package/dist/migrate/emit-ts.js.map +1 -1
  31. package/dist/migrate/parse-connection.d.ts.map +1 -1
  32. package/dist/migrate/parse-connection.js +13 -2
  33. package/dist/migrate/parse-connection.js.map +1 -1
  34. package/dist/migrate/parse-datasource.d.ts.map +1 -1
  35. package/dist/migrate/parse-datasource.js +115 -52
  36. package/dist/migrate/parse-datasource.js.map +1 -1
  37. package/dist/migrate/parse-pipe.d.ts.map +1 -1
  38. package/dist/migrate/parse-pipe.js +257 -46
  39. package/dist/migrate/parse-pipe.js.map +1 -1
  40. package/dist/migrate/parser-utils.d.ts +5 -0
  41. package/dist/migrate/parser-utils.d.ts.map +1 -1
  42. package/dist/migrate/parser-utils.js +22 -0
  43. package/dist/migrate/parser-utils.js.map +1 -1
  44. package/dist/migrate/types.d.ts +25 -3
  45. package/dist/migrate/types.d.ts.map +1 -1
  46. package/dist/schema/connection.d.ts +2 -0
  47. package/dist/schema/connection.d.ts.map +1 -1
  48. package/dist/schema/connection.js.map +1 -1
  49. package/dist/schema/datasource.d.ts +3 -1
  50. package/dist/schema/datasource.d.ts.map +1 -1
  51. package/dist/schema/datasource.js +8 -1
  52. package/dist/schema/datasource.js.map +1 -1
  53. package/dist/schema/datasource.test.js +13 -0
  54. package/dist/schema/datasource.test.js.map +1 -1
  55. package/dist/schema/engines.d.ts.map +1 -1
  56. package/dist/schema/engines.js +3 -0
  57. package/dist/schema/engines.js.map +1 -1
  58. package/dist/schema/engines.test.js +16 -0
  59. package/dist/schema/engines.test.js.map +1 -1
  60. package/dist/schema/pipe.d.ts +90 -3
  61. package/dist/schema/pipe.d.ts.map +1 -1
  62. package/dist/schema/pipe.js +84 -0
  63. package/dist/schema/pipe.js.map +1 -1
  64. package/dist/schema/pipe.test.js +70 -1
  65. package/dist/schema/pipe.test.js.map +1 -1
  66. package/dist/schema/secret.d.ts +6 -0
  67. package/dist/schema/secret.d.ts.map +1 -0
  68. package/dist/schema/secret.js +14 -0
  69. package/dist/schema/secret.js.map +1 -0
  70. package/dist/schema/secret.test.d.ts +2 -0
  71. package/dist/schema/secret.test.d.ts.map +1 -0
  72. package/dist/schema/secret.test.js +14 -0
  73. package/dist/schema/secret.test.js.map +1 -0
  74. package/dist/schema/types.d.ts +5 -0
  75. package/dist/schema/types.d.ts.map +1 -1
  76. package/dist/schema/types.js +6 -0
  77. package/dist/schema/types.js.map +1 -1
  78. package/dist/schema/types.test.js +12 -0
  79. package/dist/schema/types.test.js.map +1 -1
  80. package/package.json +1 -1
  81. package/src/cli/commands/migrate.test.ts +859 -8
  82. package/src/cli/commands/migrate.ts +35 -0
  83. package/src/generator/connection.test.ts +13 -0
  84. package/src/generator/connection.ts +4 -0
  85. package/src/generator/datasource.test.ts +60 -0
  86. package/src/generator/datasource.ts +3 -0
  87. package/src/generator/pipe.test.ts +56 -1
  88. package/src/generator/pipe.ts +41 -1
  89. package/src/index.test.ts +4 -0
  90. package/src/index.ts +12 -0
  91. package/src/migrate/emit-ts.ts +161 -48
  92. package/src/migrate/parse-connection.ts +15 -2
  93. package/src/migrate/parse-datasource.ts +134 -71
  94. package/src/migrate/parse-pipe.ts +364 -69
  95. package/src/migrate/parser-utils.ts +36 -1
  96. package/src/migrate/types.ts +28 -3
  97. package/src/schema/connection.ts +2 -0
  98. package/src/schema/datasource.test.ts +17 -0
  99. package/src/schema/datasource.ts +13 -2
  100. package/src/schema/engines.test.ts +18 -0
  101. package/src/schema/engines.ts +3 -0
  102. package/src/schema/pipe.test.ts +89 -0
  103. package/src/schema/pipe.ts +188 -4
  104. package/src/schema/secret.test.ts +19 -0
  105. package/src/schema/secret.ts +16 -0
  106. package/src/schema/types.test.ts +14 -0
  107. package/src/schema/types.ts +10 -0
@@ -3,6 +3,7 @@ import { toCamelCase } from "../codegen/utils.js";
3
3
  import { parseLiteralFromDatafile, toTsLiteral } from "./parser-utils.js";
4
4
  import type {
5
5
  DatasourceModel,
6
+ DatasourceEngineModel,
6
7
  KafkaConnectionModel,
7
8
  ParsedResource,
8
9
  PipeModel,
@@ -13,6 +14,79 @@ function escapeString(value: string): string {
13
14
  return JSON.stringify(value);
14
15
  }
15
16
 
17
+ function emitObjectKey(key: string): string {
18
+ return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(key) ? key : escapeString(key);
19
+ }
20
+
21
+ interface ParsedSecretTemplate {
22
+ name: string;
23
+ defaultValue?: string;
24
+ }
25
+
26
+ function parseTbSecretTemplate(value: string): ParsedSecretTemplate | null {
27
+ const trimmed = value.trim();
28
+ const regex =
29
+ /^\{\{\s*tb_secret\(\s*["']([^"']+)["'](?:\s*,\s*["']([^"']*)["'])?\s*\)\s*\}\}$/;
30
+ const match = trimmed.match(regex);
31
+ if (!match) {
32
+ return null;
33
+ }
34
+ return {
35
+ name: match[1] ?? "",
36
+ defaultValue: match[2],
37
+ };
38
+ }
39
+
40
+ function emitStringOrSecret(value: string): string {
41
+ const parsed = parseTbSecretTemplate(value);
42
+ if (!parsed) {
43
+ return escapeString(value);
44
+ }
45
+ if (parsed.defaultValue !== undefined) {
46
+ return `secret(${escapeString(parsed.name)}, ${escapeString(parsed.defaultValue)})`;
47
+ }
48
+ return `secret(${escapeString(parsed.name)})`;
49
+ }
50
+
51
+ function hasSecretTemplate(resources: ParsedResource[]): boolean {
52
+ const values: string[] = [];
53
+
54
+ for (const resource of resources) {
55
+ if (resource.kind === "connection") {
56
+ if (resource.connectionType === "kafka") {
57
+ values.push(resource.bootstrapServers);
58
+ if (resource.key) values.push(resource.key);
59
+ if (resource.secret) values.push(resource.secret);
60
+ if (resource.sslCaPem) values.push(resource.sslCaPem);
61
+ if (resource.schemaRegistryUrl) values.push(resource.schemaRegistryUrl);
62
+ } else {
63
+ values.push(resource.region);
64
+ if (resource.arn) values.push(resource.arn);
65
+ if (resource.accessKey) values.push(resource.accessKey);
66
+ if (resource.secret) values.push(resource.secret);
67
+ }
68
+ continue;
69
+ }
70
+
71
+ if (resource.kind === "datasource") {
72
+ if (resource.description) values.push(resource.description);
73
+ if (resource.kafka) {
74
+ values.push(resource.kafka.topic);
75
+ if (resource.kafka.groupId) values.push(resource.kafka.groupId);
76
+ if (resource.kafka.autoOffsetReset) values.push(resource.kafka.autoOffsetReset);
77
+ }
78
+ if (resource.s3) {
79
+ values.push(resource.s3.bucketUri);
80
+ if (resource.s3.schedule) values.push(resource.s3.schedule);
81
+ if (resource.s3.fromTimestamp) values.push(resource.s3.fromTimestamp);
82
+ }
83
+ continue;
84
+ }
85
+ }
86
+
87
+ return values.some((value) => parseTbSecretTemplate(value) !== null);
88
+ }
89
+
16
90
  function normalizedBaseType(type: string): string {
17
91
  let current = type.trim();
18
92
  let updated = true;
@@ -78,7 +152,7 @@ function strictParamBaseValidator(type: string): string {
78
152
  function applyParamOptional(
79
153
  baseValidator: string,
80
154
  required: boolean,
81
- defaultValue: string | number | undefined
155
+ defaultValue: string | number | boolean | undefined
82
156
  ): string {
83
157
  const withDefault = defaultValue !== undefined;
84
158
  if (!withDefault && required) {
@@ -95,6 +169,13 @@ function applyParamOptional(
95
169
  return `${baseValidator}${optionalSuffix}`;
96
170
  }
97
171
 
172
+ function applyParamDescription(validator: string, description: string | undefined): string {
173
+ if (description === undefined) {
174
+ return validator;
175
+ }
176
+ return `${validator}.describe(${JSON.stringify(description)})`;
177
+ }
178
+
98
179
  function engineFunctionName(type: string): string {
99
180
  const map: Record<string, string> = {
100
181
  MergeTree: "mergeTree",
@@ -111,9 +192,8 @@ function engineFunctionName(type: string): string {
111
192
  return functionName;
112
193
  }
113
194
 
114
- function emitEngineOptions(ds: DatasourceModel): string {
195
+ function emitEngineOptions(engine: DatasourceEngineModel): string {
115
196
  const options: string[] = [];
116
- const { engine } = ds;
117
197
 
118
198
  if (engine.sortingKey.length === 1) {
119
199
  options.push(`sortingKey: ${escapeString(engine.sortingKey[0]!)}`);
@@ -141,6 +221,9 @@ function emitEngineOptions(ds: DatasourceModel): string {
141
221
  if (engine.ver) {
142
222
  options.push(`ver: ${escapeString(engine.ver)}`);
143
223
  }
224
+ if (engine.isDeleted) {
225
+ options.push(`isDeleted: ${escapeString(engine.isDeleted)}`);
226
+ }
144
227
  if (engine.sign) {
145
228
  options.push(`sign: ${escapeString(engine.sign)}`);
146
229
  }
@@ -170,13 +253,6 @@ function emitDatasource(ds: DatasourceModel): string {
170
253
  const variableName = toCamelCase(ds.name);
171
254
  const lines: string[] = [];
172
255
  const hasJsonPath = ds.columns.some((column) => column.jsonPath !== undefined);
173
- const hasMissingJsonPath = ds.columns.some((column) => column.jsonPath === undefined);
174
-
175
- if (hasJsonPath && hasMissingJsonPath) {
176
- throw new Error(
177
- `Datasource "${ds.name}" has mixed json path usage. This is not representable in strict mode.`
178
- );
179
- }
180
256
 
181
257
  if (ds.description) {
182
258
  lines.push("/**");
@@ -187,8 +263,8 @@ function emitDatasource(ds: DatasourceModel): string {
187
263
  }
188
264
 
189
265
  lines.push(`export const ${variableName} = defineDatasource(${escapeString(ds.name)}, {`);
190
- if (ds.description) {
191
- lines.push(` description: ${escapeString(ds.description)},`);
266
+ if (ds.description !== undefined) {
267
+ lines.push(` description: ${emitStringOrSecret(ds.description)},`);
192
268
  }
193
269
  if (!hasJsonPath) {
194
270
  lines.push(" jsonPaths: false,");
@@ -197,6 +273,7 @@ function emitDatasource(ds: DatasourceModel): string {
197
273
  lines.push(" schema: {");
198
274
  for (const column of ds.columns) {
199
275
  let validator = strictColumnTypeToValidator(column.type);
276
+ const columnKey = emitObjectKey(column.name);
200
277
 
201
278
  if (column.defaultExpression !== undefined) {
202
279
  const parsedDefault = parseLiteralFromDatafile(column.defaultExpression);
@@ -220,26 +297,28 @@ function emitDatasource(ds: DatasourceModel): string {
220
297
  }
221
298
 
222
299
  if (column.jsonPath) {
223
- lines.push(
224
- ` ${column.name}: column(${validator}, { jsonPath: ${escapeString(column.jsonPath)} }),`
225
- );
226
- } else {
227
- lines.push(` ${column.name}: ${validator},`);
300
+ validator += `.jsonPath(${escapeString(column.jsonPath)})`;
228
301
  }
302
+ lines.push(` ${columnKey}: ${validator},`);
229
303
  }
230
304
  lines.push(" },");
231
- lines.push(` engine: ${emitEngineOptions(ds)},`);
305
+ if (ds.engine) {
306
+ lines.push(` engine: ${emitEngineOptions(ds.engine)},`);
307
+ }
232
308
 
233
309
  if (ds.kafka) {
234
310
  const connectionVar = toCamelCase(ds.kafka.connectionName);
235
311
  lines.push(" kafka: {");
236
312
  lines.push(` connection: ${connectionVar},`);
237
- lines.push(` topic: ${escapeString(ds.kafka.topic)},`);
313
+ lines.push(` topic: ${emitStringOrSecret(ds.kafka.topic)},`);
238
314
  if (ds.kafka.groupId) {
239
- lines.push(` groupId: ${escapeString(ds.kafka.groupId)},`);
315
+ lines.push(` groupId: ${emitStringOrSecret(ds.kafka.groupId)},`);
240
316
  }
241
317
  if (ds.kafka.autoOffsetReset) {
242
- lines.push(` autoOffsetReset: ${escapeString(ds.kafka.autoOffsetReset)},`);
318
+ lines.push(` autoOffsetReset: ${emitStringOrSecret(ds.kafka.autoOffsetReset)},`);
319
+ }
320
+ if (ds.kafka.storeRawValue !== undefined) {
321
+ lines.push(` storeRawValue: ${ds.kafka.storeRawValue},`);
243
322
  }
244
323
  lines.push(" },");
245
324
  }
@@ -248,12 +327,12 @@ function emitDatasource(ds: DatasourceModel): string {
248
327
  const connectionVar = toCamelCase(ds.s3.connectionName);
249
328
  lines.push(" s3: {");
250
329
  lines.push(` connection: ${connectionVar},`);
251
- lines.push(` bucketUri: ${escapeString(ds.s3.bucketUri)},`);
330
+ lines.push(` bucketUri: ${emitStringOrSecret(ds.s3.bucketUri)},`);
252
331
  if (ds.s3.schedule) {
253
- lines.push(` schedule: ${escapeString(ds.s3.schedule)},`);
332
+ lines.push(` schedule: ${emitStringOrSecret(ds.s3.schedule)},`);
254
333
  }
255
334
  if (ds.s3.fromTimestamp) {
256
- lines.push(` fromTimestamp: ${escapeString(ds.s3.fromTimestamp)},`);
335
+ lines.push(` fromTimestamp: ${emitStringOrSecret(ds.s3.fromTimestamp)},`);
257
336
  }
258
337
  lines.push(" },");
259
338
  }
@@ -293,21 +372,24 @@ function emitConnection(connection: KafkaConnectionModel | S3ConnectionModel): s
293
372
  lines.push(
294
373
  `export const ${variableName} = defineKafkaConnection(${escapeString(connection.name)}, {`
295
374
  );
296
- lines.push(` bootstrapServers: ${escapeString(connection.bootstrapServers)},`);
375
+ lines.push(` bootstrapServers: ${emitStringOrSecret(connection.bootstrapServers)},`);
297
376
  if (connection.securityProtocol) {
298
- lines.push(` securityProtocol: ${escapeString(connection.securityProtocol)},`);
377
+ lines.push(` securityProtocol: ${emitStringOrSecret(connection.securityProtocol)},`);
299
378
  }
300
379
  if (connection.saslMechanism) {
301
- lines.push(` saslMechanism: ${escapeString(connection.saslMechanism)},`);
380
+ lines.push(` saslMechanism: ${emitStringOrSecret(connection.saslMechanism)},`);
302
381
  }
303
382
  if (connection.key) {
304
- lines.push(` key: ${escapeString(connection.key)},`);
383
+ lines.push(` key: ${emitStringOrSecret(connection.key)},`);
305
384
  }
306
385
  if (connection.secret) {
307
- lines.push(` secret: ${escapeString(connection.secret)},`);
386
+ lines.push(` secret: ${emitStringOrSecret(connection.secret)},`);
387
+ }
388
+ if (connection.schemaRegistryUrl) {
389
+ lines.push(` schemaRegistryUrl: ${emitStringOrSecret(connection.schemaRegistryUrl)},`);
308
390
  }
309
391
  if (connection.sslCaPem) {
310
- lines.push(` sslCaPem: ${escapeString(connection.sslCaPem)},`);
392
+ lines.push(` sslCaPem: ${emitStringOrSecret(connection.sslCaPem)},`);
311
393
  }
312
394
  lines.push("});");
313
395
  lines.push("");
@@ -317,15 +399,15 @@ function emitConnection(connection: KafkaConnectionModel | S3ConnectionModel): s
317
399
  lines.push(
318
400
  `export const ${variableName} = defineS3Connection(${escapeString(connection.name)}, {`
319
401
  );
320
- lines.push(` region: ${escapeString(connection.region)},`);
402
+ lines.push(` region: ${emitStringOrSecret(connection.region)},`);
321
403
  if (connection.arn) {
322
- lines.push(` arn: ${escapeString(connection.arn)},`);
404
+ lines.push(` arn: ${emitStringOrSecret(connection.arn)},`);
323
405
  }
324
406
  if (connection.accessKey) {
325
- lines.push(` accessKey: ${escapeString(connection.accessKey)},`);
407
+ lines.push(` accessKey: ${emitStringOrSecret(connection.accessKey)},`);
326
408
  }
327
409
  if (connection.secret) {
328
- lines.push(` secret: ${escapeString(connection.secret)},`);
410
+ lines.push(` secret: ${emitStringOrSecret(connection.secret)},`);
329
411
  }
330
412
  lines.push("});");
331
413
  lines.push("");
@@ -350,25 +432,28 @@ function emitPipe(pipe: PipeModel): string {
350
432
  lines.push(`export const ${variableName} = defineMaterializedView(${escapeString(pipe.name)}, {`);
351
433
  } else if (pipe.type === "copy") {
352
434
  lines.push(`export const ${variableName} = defineCopyPipe(${escapeString(pipe.name)}, {`);
435
+ } else if (pipe.type === "sink") {
436
+ lines.push(`export const ${variableName} = defineSinkPipe(${escapeString(pipe.name)}, {`);
353
437
  } else {
354
438
  lines.push(`export const ${variableName} = definePipe(${escapeString(pipe.name)}, {`);
355
439
  }
356
440
 
357
- if (pipe.description) {
441
+ if (pipe.description !== undefined) {
358
442
  lines.push(` description: ${escapeString(pipe.description)},`);
359
443
  }
360
444
 
361
- if (pipe.type === "pipe" || pipe.type === "endpoint") {
445
+ if (pipe.type === "pipe" || pipe.type === "endpoint" || pipe.type === "sink") {
362
446
  if (pipe.params.length > 0) {
363
447
  lines.push(" params: {");
364
448
  for (const param of pipe.params) {
365
449
  const baseValidator = strictParamBaseValidator(param.type);
366
- const validator = applyParamOptional(
450
+ const validatorWithOptional = applyParamOptional(
367
451
  baseValidator,
368
452
  param.required,
369
453
  param.defaultValue
370
454
  );
371
- lines.push(` ${param.name}: ${validator},`);
455
+ const validator = applyParamDescription(validatorWithOptional, param.description);
456
+ lines.push(` ${emitObjectKey(param.name)}: ${validator},`);
372
457
  }
373
458
  lines.push(" },");
374
459
  }
@@ -391,11 +476,35 @@ function emitPipe(pipe: PipeModel): string {
391
476
  }
392
477
  }
393
478
 
479
+ if (pipe.type === "sink") {
480
+ if (!pipe.sink) {
481
+ throw new Error(`Sink pipe "${pipe.name}" is missing sink configuration.`);
482
+ }
483
+ lines.push(" sink: {");
484
+ lines.push(` connection: ${toCamelCase(pipe.sink.connectionName)},`);
485
+ if (pipe.sink.service === "kafka") {
486
+ lines.push(` topic: ${escapeString(pipe.sink.topic)},`);
487
+ lines.push(` schedule: ${escapeString(pipe.sink.schedule)},`);
488
+ } else {
489
+ lines.push(` bucketUri: ${escapeString(pipe.sink.bucketUri)},`);
490
+ lines.push(` fileTemplate: ${escapeString(pipe.sink.fileTemplate)},`);
491
+ lines.push(` schedule: ${escapeString(pipe.sink.schedule)},`);
492
+ lines.push(` format: ${escapeString(pipe.sink.format)},`);
493
+ if (pipe.sink.strategy) {
494
+ lines.push(` strategy: ${escapeString(pipe.sink.strategy)},`);
495
+ }
496
+ if (pipe.sink.compression) {
497
+ lines.push(` compression: ${escapeString(pipe.sink.compression)},`);
498
+ }
499
+ }
500
+ lines.push(" },");
501
+ }
502
+
394
503
  lines.push(" nodes: [");
395
504
  for (const node of pipe.nodes) {
396
505
  lines.push(" node({");
397
506
  lines.push(` name: ${escapeString(node.name)},`);
398
- if (node.description) {
507
+ if (node.description !== undefined) {
399
508
  lines.push(` description: ${escapeString(node.description)},`);
400
509
  }
401
510
  lines.push(" sql: `");
@@ -413,7 +522,7 @@ function emitPipe(pipe: PipeModel): string {
413
522
  }
414
523
  lines.push(" output: {");
415
524
  for (const columnName of endpointOutputColumns) {
416
- lines.push(` ${columnName}: t.string(),`);
525
+ lines.push(` ${emitObjectKey(columnName)}: t.string(),`);
417
526
  }
418
527
  lines.push(" },");
419
528
  }
@@ -443,10 +552,8 @@ export function emitMigrationFileContent(resources: ParsedResource[]): string {
443
552
  (resource): resource is PipeModel => resource.kind === "pipe"
444
553
  );
445
554
 
446
- const needsColumn = datasources.some((ds) =>
447
- ds.columns.some((column) => column.jsonPath !== undefined)
448
- );
449
555
  const needsParams = pipes.some((pipe) => pipe.params.length > 0);
556
+ const needsSecret = hasSecretTemplate(resources);
450
557
 
451
558
  const imports = new Set<string>([
452
559
  "defineDatasource",
@@ -455,7 +562,6 @@ export function emitMigrationFileContent(resources: ParsedResource[]): string {
455
562
  "defineCopyPipe",
456
563
  "node",
457
564
  "t",
458
- "engine",
459
565
  ]);
460
566
  if (connections.some((connection) => connection.connectionType === "kafka")) {
461
567
  imports.add("defineKafkaConnection");
@@ -463,12 +569,18 @@ export function emitMigrationFileContent(resources: ParsedResource[]): string {
463
569
  if (connections.some((connection) => connection.connectionType === "s3")) {
464
570
  imports.add("defineS3Connection");
465
571
  }
466
- if (needsColumn) {
467
- imports.add("column");
468
- }
469
572
  if (needsParams) {
470
573
  imports.add("p");
471
574
  }
575
+ if (pipes.some((pipe) => pipe.type === "sink")) {
576
+ imports.add("defineSinkPipe");
577
+ }
578
+ if (datasources.some((datasource) => datasource.engine !== undefined)) {
579
+ imports.add("engine");
580
+ }
581
+ if (needsSecret) {
582
+ imports.add("secret");
583
+ }
472
584
 
473
585
  const orderedImports = [
474
586
  "defineKafkaConnection",
@@ -477,10 +589,11 @@ export function emitMigrationFileContent(resources: ParsedResource[]): string {
477
589
  "definePipe",
478
590
  "defineMaterializedView",
479
591
  "defineCopyPipe",
592
+ "defineSinkPipe",
480
593
  "node",
481
594
  "t",
482
595
  "engine",
483
- "column",
596
+ "secret",
484
597
  "p",
485
598
  ].filter((name) => imports.has(name));
486
599
 
@@ -27,6 +27,7 @@ export function parseConnectionFile(
27
27
  | undefined;
28
28
  let key: string | undefined;
29
29
  let secret: string | undefined;
30
+ let schemaRegistryUrl: string | undefined;
30
31
  let sslCaPem: string | undefined;
31
32
 
32
33
  let region: string | undefined;
@@ -36,7 +37,7 @@ export function parseConnectionFile(
36
37
 
37
38
  for (const rawLine of lines) {
38
39
  const line = rawLine.trim();
39
- if (isBlank(line)) {
40
+ if (isBlank(line) || line.startsWith("#")) {
40
41
  continue;
41
42
  }
42
43
 
@@ -81,6 +82,9 @@ export function parseConnectionFile(
81
82
  case "KAFKA_SECRET":
82
83
  secret = value;
83
84
  break;
85
+ case "KAFKA_SCHEMA_REGISTRY_URL":
86
+ schemaRegistryUrl = value;
87
+ break;
84
88
  case "KAFKA_SSL_CA_PEM":
85
89
  sslCaPem = value;
86
90
  break;
@@ -144,12 +148,21 @@ export function parseConnectionFile(
144
148
  saslMechanism,
145
149
  key,
146
150
  secret,
151
+ schemaRegistryUrl,
147
152
  sslCaPem,
148
153
  };
149
154
  }
150
155
 
151
156
  if (connectionType === "s3") {
152
- if (bootstrapServers || securityProtocol || saslMechanism || key || secret || sslCaPem) {
157
+ if (
158
+ bootstrapServers ||
159
+ securityProtocol ||
160
+ saslMechanism ||
161
+ key ||
162
+ secret ||
163
+ schemaRegistryUrl ||
164
+ sslCaPem
165
+ ) {
153
166
  throw new MigrationParseError(
154
167
  resource.filePath,
155
168
  "connection",