windmill-client 1.733.1 → 1.734.0

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/client.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { DenoS3LightClientSettings, S3ObjectRecord, type S3Object } from "./s3Types";
2
2
  export { type S3Object, type S3ObjectRecord, type S3ObjectURI, } from "./s3Types";
3
- export { datatable, ducklake, type SqlTemplateFunction, type DatatableSqlTemplateFunction, } from "./sqlUtils";
3
+ export { datatable, ducklake, upsertPartition, appendPartition, type SqlTemplateFunction, type DatatableSqlTemplateFunction, type DucklakeMaterializeOptions, type SqlStatement, } from "./sqlUtils";
4
4
  export type Sql = string;
5
5
  export type Email = string;
6
6
  export type Base64 = string;
@@ -13,6 +13,7 @@ export declare function workerHasInternalServer(): boolean;
13
13
  * @param baseUrl - API base URL (defaults to BASE_INTERNAL_URL or BASE_URL env variable)
14
14
  */
15
15
  export declare function setClient(token?: string, baseUrl?: string): void;
16
+ export declare const getEnv: (key: string) => string | undefined;
16
17
  /**
17
18
  * Create a client configuration from env variables
18
19
  * @returns client configuration
package/dist/client.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import { OpenAPI } from "./core/OpenAPI.mjs";
2
2
  import { AppService, HelpersService, JobService, KafkaTriggerService, MetricsService, OidcService, ResourceService, UserService, VariableService } from "./services.gen.mjs";
3
- import { datatable, ducklake } from "./sqlUtils.mjs";
3
+ import { appendPartition, datatable, ducklake, upsertPartition } from "./sqlUtils.mjs";
4
4
 
5
5
  //#region src/client.ts
6
6
  const SHARED_FOLDER = "/shared";
@@ -1346,4 +1346,4 @@ async function commitKafkaOffsets(triggerPath, topic, partition, offset) {
1346
1346
  }
1347
1347
 
1348
1348
  //#endregion
1349
- export { SHARED_FOLDER, StepSuspend, WorkflowCtx, _workflowCtx, appendToResultStream, base64ToUint8Array, commitKafkaOffsets, databaseUrlFromResource, deleteS3File, denoS3LightClientSettings, getFlowUserState, getIdToken, getInternalState, getPresignedS3PublicUrl, getPresignedS3PublicUrls, getProgress, getResource, getResult, getResultMaybe, getResumeEndpoints, getResumeUrls, getRootJobId, getState, getStatePath, getVariable, getWorkspace, loadS3File, loadS3FileStream, parallel, parseS3Object, requestInteractiveSlackApproval, requestInteractiveTeamsApproval, resolveDefaultResource, runFlow, runFlowAsync, runScript, runScriptAsync, runScriptByHash, runScriptByHashAsync, runScriptByPath, runScriptByPathAsync, setClient, setFlowUserState, setInternalState, setProgress, setResource, setState, setVariable, setWorkflowCtx, signS3Object, signS3Objects, sleep, step, streamResult, task, taskFlow, taskScript, uint8ArrayToBase64, usernameToEmail, waitForApproval, waitJob, workerHasInternalServer, workflow, writeS3File };
1349
+ export { SHARED_FOLDER, StepSuspend, WorkflowCtx, _workflowCtx, appendToResultStream, base64ToUint8Array, commitKafkaOffsets, databaseUrlFromResource, deleteS3File, denoS3LightClientSettings, getEnv, getFlowUserState, getIdToken, getInternalState, getPresignedS3PublicUrl, getPresignedS3PublicUrls, getProgress, getResource, getResult, getResultMaybe, getResumeEndpoints, getResumeUrls, getRootJobId, getState, getStatePath, getVariable, getWorkspace, loadS3File, loadS3FileStream, parallel, parseS3Object, requestInteractiveSlackApproval, requestInteractiveTeamsApproval, resolveDefaultResource, runFlow, runFlowAsync, runScript, runScriptAsync, runScriptByHash, runScriptByHashAsync, runScriptByPath, runScriptByPathAsync, setClient, setFlowUserState, setInternalState, setProgress, setResource, setState, setVariable, setWorkflowCtx, signS3Object, signS3Objects, sleep, step, streamResult, task, taskFlow, taskScript, uint8ArrayToBase64, usernameToEmail, waitForApproval, waitJob, workerHasInternalServer, workflow, writeS3File };
@@ -29,7 +29,7 @@ const OpenAPI = {
29
29
  PASSWORD: void 0,
30
30
  TOKEN: getEnv("WM_TOKEN"),
31
31
  USERNAME: void 0,
32
- VERSION: "1.733.1",
32
+ VERSION: "1.734.0",
33
33
  WITH_CREDENTIALS: true,
34
34
  interceptors: {
35
35
  request: new Interceptors(),
package/dist/index.d.ts CHANGED
@@ -4,8 +4,8 @@ export { OpenAPI, type OpenAPIConfig } from './core/OpenAPI';
4
4
  export * from './services.gen';
5
5
  export * from './types.gen';
6
6
  export type { DenoS3LightClientSettings } from "./s3Types";
7
- export { type Base64, setClient, getVariable, setVariable, getResource, setResource, getResumeUrls, setState, setProgress, getProgress, getState, getIdToken, denoS3LightClientSettings, loadS3FileStream, loadS3File, writeS3File, deleteS3File, signS3Objects, signS3Object, getPresignedS3PublicUrls, getPresignedS3PublicUrl, task, taskScript, taskFlow, workflow, step, sleep, parallel, waitForApproval, type TaskOptions, WorkflowCtx, _workflowCtx, setWorkflowCtx, StepSuspend, runScript, runScriptAsync, runScriptByPath, runScriptByHash, runScriptByPathAsync, runScriptByHashAsync, runFlow, runFlowAsync, waitJob, getRootJobId, setFlowUserState, getFlowUserState, usernameToEmail, requestInteractiveSlackApproval, type Sql, requestInteractiveTeamsApproval, appendToResultStream, streamResult, datatable, ducklake, type DatatableSqlTemplateFunction, type SqlTemplateFunction, type S3Object, type S3ObjectRecord, type S3ObjectURI, commitKafkaOffsets } from "./client";
8
- import { setClient, getVariable, setVariable, getResource, setResource, getResumeUrls, setState, setProgress, getProgress, getState, getIdToken, denoS3LightClientSettings, loadS3FileStream, loadS3File, writeS3File, deleteS3File, signS3Objects, signS3Object, getPresignedS3PublicUrls, getPresignedS3PublicUrl, task, taskScript, taskFlow, workflow, step, sleep, parallel, waitForApproval, WorkflowCtx, setWorkflowCtx, StepSuspend, runScript, runScriptAsync, runScriptByPath, runScriptByHash, runScriptByPathAsync, runScriptByHashAsync, runFlow, runFlowAsync, waitJob, getRootJobId, setFlowUserState, getFlowUserState, usernameToEmail, requestInteractiveSlackApproval, requestInteractiveTeamsApproval, appendToResultStream, streamResult, datatable, ducklake, getWorkspace, getStatePath, getInternalState, setInternalState, getResumeEndpoints, getResult, getResultMaybe, resolveDefaultResource, databaseUrlFromResource, base64ToUint8Array, uint8ArrayToBase64, parseS3Object, commitKafkaOffsets } from "./client";
7
+ export { type Base64, setClient, getVariable, setVariable, getResource, setResource, getResumeUrls, setState, setProgress, getProgress, getState, getIdToken, denoS3LightClientSettings, loadS3FileStream, loadS3File, writeS3File, deleteS3File, signS3Objects, signS3Object, getPresignedS3PublicUrls, getPresignedS3PublicUrl, task, taskScript, taskFlow, workflow, step, sleep, parallel, waitForApproval, type TaskOptions, WorkflowCtx, _workflowCtx, setWorkflowCtx, StepSuspend, runScript, runScriptAsync, runScriptByPath, runScriptByHash, runScriptByPathAsync, runScriptByHashAsync, runFlow, runFlowAsync, waitJob, getRootJobId, setFlowUserState, getFlowUserState, usernameToEmail, requestInteractiveSlackApproval, type Sql, requestInteractiveTeamsApproval, appendToResultStream, streamResult, datatable, ducklake, upsertPartition, appendPartition, type DucklakeMaterializeOptions, type SqlStatement, type DatatableSqlTemplateFunction, type SqlTemplateFunction, type S3Object, type S3ObjectRecord, type S3ObjectURI, commitKafkaOffsets } from "./client";
8
+ import { setClient, getVariable, setVariable, getResource, setResource, getResumeUrls, setState, setProgress, getProgress, getState, getIdToken, denoS3LightClientSettings, loadS3FileStream, loadS3File, writeS3File, deleteS3File, signS3Objects, signS3Object, getPresignedS3PublicUrls, getPresignedS3PublicUrl, task, taskScript, taskFlow, workflow, step, sleep, parallel, waitForApproval, WorkflowCtx, setWorkflowCtx, StepSuspend, runScript, runScriptAsync, runScriptByPath, runScriptByHash, runScriptByPathAsync, runScriptByHashAsync, runFlow, runFlowAsync, waitJob, getRootJobId, setFlowUserState, getFlowUserState, usernameToEmail, requestInteractiveSlackApproval, requestInteractiveTeamsApproval, appendToResultStream, streamResult, datatable, ducklake, upsertPartition, appendPartition, getWorkspace, getStatePath, getInternalState, setInternalState, getResumeEndpoints, getResult, getResultMaybe, resolveDefaultResource, databaseUrlFromResource, base64ToUint8Array, uint8ArrayToBase64, parseS3Object, commitKafkaOffsets } from "./client";
9
9
  import { AdminService, AuditService, FlowService, GranularAclService, GroupService, JobService, ResourceService, VariableService, ScriptService, ScheduleService, SettingsService, UserService, WorkspaceService, TeamsService } from "./services.gen";
10
10
  declare const wmill: {
11
11
  setClient: typeof setClient;
@@ -59,6 +59,8 @@ declare const wmill: {
59
59
  streamResult: typeof streamResult;
60
60
  datatable: typeof datatable;
61
61
  ducklake: typeof ducklake;
62
+ upsertPartition: typeof upsertPartition;
63
+ appendPartition: typeof appendPartition;
62
64
  SHARED_FOLDER: string;
63
65
  getWorkspace: typeof getWorkspace;
64
66
  getStatePath: typeof getStatePath;
package/dist/index.js CHANGED
@@ -126,7 +126,7 @@ const OpenAPI = {
126
126
  PASSWORD: void 0,
127
127
  TOKEN: getEnv$1("WM_TOKEN"),
128
128
  USERNAME: void 0,
129
- VERSION: "1.733.1",
129
+ VERSION: "1.734.0",
130
130
  WITH_CREDENTIALS: true,
131
131
  interceptors: {
132
132
  request: new Interceptors(),
@@ -15005,6 +15005,127 @@ function ducklake(name = "main") {
15005
15005
  let { name: n, schema } = parseName(name);
15006
15006
  return buildSqlTemplateFunction(ducklakeProvider(n, schema));
15007
15007
  }
15008
+ /** Idempotently materialize `selectSql` into a ducklake table for one
15009
+ * partition (or the whole table when `partition` is omitted) — the client-side
15010
+ * equivalent of the `// materialize` engine.
15011
+ * With `uniqueKey` it upserts the slice (delete-by-key + insert); otherwise it
15012
+ * replaces it (whole table → `CREATE OR REPLACE`; partition → delete + insert).
15013
+ * Safe to re-run for the same partition (backfill / failure-recovery).
15014
+ *
15015
+ * Returns a lazy statement — call `.execute()` to run it:
15016
+ * `await wmill.upsertPartition({ table, selectSql, partition }).execute()`. */
15017
+ function upsertPartition(opts) {
15018
+ return finishMaterialize(buildUpsertStatement(opts), opts);
15019
+ }
15020
+ function buildUpsertStatement(opts) {
15021
+ let { name: n, schema } = parseName(opts.ducklake ?? "main");
15022
+ let sql = buildSqlTemplateFunction(ducklakeProvider(n, schema));
15023
+ let pcol = sql.raw(opts.partitionCol ?? "_wm_partition");
15024
+ let t = sql.raw(`dl.${opts.table}`);
15025
+ let body = sql.raw(opts.selectSql);
15026
+ if (opts.partition === void 0) {
15027
+ if (opts.uniqueKey) {
15028
+ let uk = sql.raw(opts.uniqueKey);
15029
+ return sql`CREATE TABLE IF NOT EXISTS ${t} AS SELECT * FROM (${body}) WHERE false;
15030
+ BEGIN TRANSACTION;
15031
+ DELETE FROM ${t} WHERE ${uk} IN (SELECT ${uk} FROM (${body}));
15032
+ INSERT INTO ${t} SELECT * FROM (${body});
15033
+ COMMIT;`;
15034
+ }
15035
+ return sql`CREATE OR REPLACE TABLE ${t} AS SELECT * FROM (${body});`;
15036
+ }
15037
+ if (opts.uniqueKey) {
15038
+ let uk = sql.raw(opts.uniqueKey);
15039
+ return sql`CREATE TABLE IF NOT EXISTS ${t} AS SELECT *, CAST(NULL AS VARCHAR) AS ${pcol} FROM (${body}) WHERE false;
15040
+ ALTER TABLE ${t} SET PARTITIONED BY (${pcol});
15041
+ BEGIN TRANSACTION;
15042
+ DELETE FROM ${t} WHERE ${pcol} = ${opts.partition} AND ${uk} IN (SELECT ${uk} FROM (${body}));
15043
+ INSERT INTO ${t} SELECT *, ${opts.partition} AS ${pcol} FROM (${body});
15044
+ COMMIT;`;
15045
+ }
15046
+ return sql`CREATE TABLE IF NOT EXISTS ${t} AS SELECT *, CAST(NULL AS VARCHAR) AS ${pcol} FROM (${body}) WHERE false;
15047
+ ALTER TABLE ${t} SET PARTITIONED BY (${pcol});
15048
+ BEGIN TRANSACTION;
15049
+ DELETE FROM ${t} WHERE ${pcol} = ${opts.partition};
15050
+ INSERT INTO ${t} SELECT *, ${opts.partition} AS ${pcol} FROM (${body});
15051
+ COMMIT;`;
15052
+ }
15053
+ /** INSERT-only materialization (no dedup/replace) for append-only tables.
15054
+ * Re-running the same partition duplicates rows — use only for immutable
15055
+ * event-log sources.
15056
+ *
15057
+ * Returns a lazy statement — call `.execute()` to run it:
15058
+ * `await wmill.appendPartition({ table, selectSql, partition }).execute()`. */
15059
+ function appendPartition(opts) {
15060
+ return finishMaterialize(buildAppendStatement(opts), opts);
15061
+ }
15062
+ function buildAppendStatement(opts) {
15063
+ let { name: n, schema } = parseName(opts.ducklake ?? "main");
15064
+ let sql = buildSqlTemplateFunction(ducklakeProvider(n, schema));
15065
+ let pcol = sql.raw(opts.partitionCol ?? "_wm_partition");
15066
+ let t = sql.raw(`dl.${opts.table}`);
15067
+ let body = sql.raw(opts.selectSql);
15068
+ if (opts.partition === void 0) return sql`CREATE TABLE IF NOT EXISTS ${t} AS SELECT * FROM (${body}) WHERE false;
15069
+ INSERT INTO ${t} SELECT * FROM (${body});`;
15070
+ return sql`CREATE TABLE IF NOT EXISTS ${t} AS SELECT *, CAST(NULL AS VARCHAR) AS ${pcol} FROM (${body}) WHERE false;
15071
+ ALTER TABLE ${t} SET PARTITIONED BY (${pcol});
15072
+ INSERT INTO ${t} SELECT *, ${opts.partition} AS ${pcol} FROM (${body});`;
15073
+ }
15074
+ function finishMaterialize(stmt, opts) {
15075
+ if (getEnv("WM_PIPELINE") !== "true") return stmt;
15076
+ let { name: n, schema } = parseName(opts.ducklake ?? "main");
15077
+ let sql = buildSqlTemplateFunction(ducklakeProvider(n, schema));
15078
+ let t = sql.raw(`dl.${opts.table}`);
15079
+ let pcol = opts.partitionCol ?? "_wm_partition";
15080
+ let where = opts.partition !== void 0 ? sql.raw(`WHERE ${pcol} = '${String(opts.partition).replace(/'/g, "''")}'`) : sql.raw("");
15081
+ let summary = sql`SELECT (SELECT count(*) FROM ${t} ${where}) AS rows, (SELECT max(snapshot_id) FROM ducklake_snapshots('dl')) AS snapshot_id`;
15082
+ let assetPath = schema ? `${n}/${schema}.${opts.table}` : `${n}/${opts.table}`;
15083
+ let partition = opts.partition ?? "";
15084
+ let run = async () => {
15085
+ try {
15086
+ await stmt.execute();
15087
+ } catch (e) {
15088
+ await recordMaterialization(assetPath, partition, "failed", null, null, String(e));
15089
+ throw e;
15090
+ }
15091
+ let snapshot_id = null;
15092
+ let row_count = null;
15093
+ try {
15094
+ let s = await summary.fetchOne();
15095
+ snapshot_id = s?.snapshot_id ?? null;
15096
+ row_count = s?.rows ?? null;
15097
+ } catch {}
15098
+ await recordMaterialization(assetPath, partition, "materialized", snapshot_id, row_count, null);
15099
+ };
15100
+ return {
15101
+ ...stmt,
15102
+ execute: () => run(),
15103
+ fetch: () => run(),
15104
+ fetchOne: () => run(),
15105
+ fetchOneScalar: () => run()
15106
+ };
15107
+ }
15108
+ async function recordMaterialization(assetPath, partition, status, snapshot_id, row_count, error) {
15109
+ try {
15110
+ await fetch(`${OpenAPI.BASE}/w/${getWorkspace()}/assets/record_materialization`, {
15111
+ method: "POST",
15112
+ headers: {
15113
+ "content-type": "application/json",
15114
+ authorization: `Bearer ${OpenAPI.TOKEN}`
15115
+ },
15116
+ body: JSON.stringify({
15117
+ asset_kind: "ducklake",
15118
+ asset_path: assetPath,
15119
+ partition,
15120
+ status,
15121
+ snapshot_id,
15122
+ row_count,
15123
+ job_id: getEnv("WM_JOB_ID") ?? null,
15124
+ error
15125
+ })
15126
+ });
15127
+ } catch {}
15128
+ }
15008
15129
  function inferSqlType(value) {
15009
15130
  if (typeof value === "bigint") return "BIGINT";
15010
15131
  if (typeof value === "number") {
@@ -16449,6 +16570,8 @@ const wmill = {
16449
16570
  streamResult,
16450
16571
  datatable,
16451
16572
  ducklake,
16573
+ upsertPartition,
16574
+ appendPartition,
16452
16575
  SHARED_FOLDER,
16453
16576
  getWorkspace,
16454
16577
  getStatePath,
@@ -16552,6 +16675,7 @@ Object.defineProperty(exports, '_workflowCtx', {
16552
16675
  return _workflowCtx;
16553
16676
  }
16554
16677
  });
16678
+ exports.appendPartition = appendPartition;
16555
16679
  exports.appendToResultStream = appendToResultStream;
16556
16680
  exports.commitKafkaOffsets = commitKafkaOffsets;
16557
16681
  exports.datatable = datatable;
@@ -16597,6 +16721,7 @@ exports.streamResult = streamResult;
16597
16721
  exports.task = task;
16598
16722
  exports.taskFlow = taskFlow;
16599
16723
  exports.taskScript = taskScript;
16724
+ exports.upsertPartition = upsertPartition;
16600
16725
  exports.usernameToEmail = usernameToEmail;
16601
16726
  exports.waitForApproval = waitForApproval;
16602
16727
  exports.waitJob = waitJob;
package/dist/index.mjs CHANGED
@@ -2,7 +2,7 @@ import { ApiError } from "./core/ApiError.mjs";
2
2
  import { CancelError, CancelablePromise } from "./core/CancelablePromise.mjs";
3
3
  import { OpenAPI } from "./core/OpenAPI.mjs";
4
4
  import { AdminService, AgentWorkersService, AppService, AssetService, AuditService, AzureTriggerService, CaptureService, ConcurrencyGroupsService, ConfigService, DocumentationService, DraftService, EmailTriggerService, FavoriteService, FlowConversationsService, FlowService, FolderService, GcpTriggerService, GitSyncService, GranularAclService, GroupService, HealthService, HelpersService, HttpTriggerService, IndexSearchService, InputService, IntegrationService, JobService, KafkaTriggerService, McpOauthService, McpService, MetricsService, MqttTriggerService, NativeTriggerService, NatsTriggerService, NpmProxyService, OauthService, OidcService, OpenapiService, PathAutocompleteService, PostgresTriggerService, RawAppService, ResourceService, ScheduleService, ScriptService, ServiceLogsService, SettingService, SettingsService, SqsTriggerService, TeamsService, TokenService, TriggerService, UserService, VariableService, VolumeService, WebsocketTriggerService, WorkerService, WorkspaceDependenciesService, WorkspaceIntegrationService, WorkspaceService } from "./services.gen.mjs";
5
- import { datatable, ducklake } from "./sqlUtils.mjs";
5
+ import { appendPartition, datatable, ducklake, upsertPartition } from "./sqlUtils.mjs";
6
6
  import { SHARED_FOLDER, StepSuspend, WorkflowCtx, _workflowCtx, appendToResultStream, base64ToUint8Array, commitKafkaOffsets, databaseUrlFromResource, deleteS3File, denoS3LightClientSettings, getFlowUserState, getIdToken, getInternalState, getPresignedS3PublicUrl, getPresignedS3PublicUrls, getProgress, getResource, getResult, getResultMaybe, getResumeEndpoints, getResumeUrls, getRootJobId, getState, getStatePath, getVariable, getWorkspace, loadS3File, loadS3FileStream, parallel, parseS3Object, requestInteractiveSlackApproval, requestInteractiveTeamsApproval, resolveDefaultResource, runFlow, runFlowAsync, runScript, runScriptAsync, runScriptByHash, runScriptByHashAsync, runScriptByPath, runScriptByPathAsync, setClient, setFlowUserState, setInternalState, setProgress, setResource, setState, setVariable, setWorkflowCtx, signS3Object, signS3Objects, sleep, step, streamResult, task, taskFlow, taskScript, uint8ArrayToBase64, usernameToEmail, waitForApproval, waitJob, workflow, writeS3File } from "./client.mjs";
7
7
 
8
8
  //#region src/index.ts
@@ -58,6 +58,8 @@ const wmill = {
58
58
  streamResult,
59
59
  datatable,
60
60
  ducklake,
61
+ upsertPartition,
62
+ appendPartition,
61
63
  SHARED_FOLDER,
62
64
  getWorkspace,
63
65
  getStatePath,
@@ -90,4 +92,4 @@ const wmill = {
90
92
  var src_default = wmill;
91
93
 
92
94
  //#endregion
93
- export { AdminService, AgentWorkersService, ApiError, AppService, AssetService, AuditService, AzureTriggerService, CancelError, CancelablePromise, CaptureService, ConcurrencyGroupsService, ConfigService, DocumentationService, DraftService, EmailTriggerService, FavoriteService, FlowConversationsService, FlowService, FolderService, GcpTriggerService, GitSyncService, GranularAclService, GroupService, HealthService, HelpersService, HttpTriggerService, IndexSearchService, InputService, IntegrationService, JobService, KafkaTriggerService, McpOauthService, McpService, MetricsService, MqttTriggerService, NativeTriggerService, NatsTriggerService, NpmProxyService, OauthService, OidcService, OpenAPI, OpenapiService, PathAutocompleteService, PostgresTriggerService, RawAppService, ResourceService, ScheduleService, ScriptService, ServiceLogsService, SettingService, SettingsService, SqsTriggerService, StepSuspend, TeamsService, TokenService, TriggerService, UserService, VariableService, VolumeService, WebsocketTriggerService, WorkerService, WorkflowCtx, WorkspaceDependenciesService, WorkspaceIntegrationService, WorkspaceService, _workflowCtx, appendToResultStream, commitKafkaOffsets, datatable, src_default as default, deleteS3File, denoS3LightClientSettings, ducklake, getFlowUserState, getIdToken, getPresignedS3PublicUrl, getPresignedS3PublicUrls, getProgress, getResource, getResumeUrls, getRootJobId, getState, getVariable, loadS3File, loadS3FileStream, parallel, requestInteractiveSlackApproval, requestInteractiveTeamsApproval, runFlow, runFlowAsync, runScript, runScriptAsync, runScriptByHash, runScriptByHashAsync, runScriptByPath, runScriptByPathAsync, setClient, setFlowUserState, setProgress, setResource, setState, setVariable, setWorkflowCtx, signS3Object, signS3Objects, sleep, step, streamResult, task, taskFlow, taskScript, usernameToEmail, waitForApproval, waitJob, workflow, writeS3File };
95
+ export { AdminService, AgentWorkersService, ApiError, AppService, AssetService, AuditService, AzureTriggerService, CancelError, CancelablePromise, CaptureService, ConcurrencyGroupsService, ConfigService, DocumentationService, DraftService, EmailTriggerService, FavoriteService, FlowConversationsService, FlowService, FolderService, GcpTriggerService, GitSyncService, GranularAclService, GroupService, HealthService, HelpersService, HttpTriggerService, IndexSearchService, InputService, IntegrationService, JobService, KafkaTriggerService, McpOauthService, McpService, MetricsService, MqttTriggerService, NativeTriggerService, NatsTriggerService, NpmProxyService, OauthService, OidcService, OpenAPI, OpenapiService, PathAutocompleteService, PostgresTriggerService, RawAppService, ResourceService, ScheduleService, ScriptService, ServiceLogsService, SettingService, SettingsService, SqsTriggerService, StepSuspend, TeamsService, TokenService, TriggerService, UserService, VariableService, VolumeService, WebsocketTriggerService, WorkerService, WorkflowCtx, WorkspaceDependenciesService, WorkspaceIntegrationService, WorkspaceService, _workflowCtx, appendPartition, appendToResultStream, commitKafkaOffsets, datatable, src_default as default, deleteS3File, denoS3LightClientSettings, ducklake, getFlowUserState, getIdToken, getPresignedS3PublicUrl, getPresignedS3PublicUrls, getProgress, getResource, getResumeUrls, getRootJobId, getState, getVariable, loadS3File, loadS3FileStream, parallel, requestInteractiveSlackApproval, requestInteractiveTeamsApproval, runFlow, runFlowAsync, runScript, runScriptAsync, runScriptByHash, runScriptByHashAsync, runScriptByPath, runScriptByPathAsync, setClient, setFlowUserState, setProgress, setResource, setState, setVariable, setWorkflowCtx, signS3Object, signS3Objects, sleep, step, streamResult, task, taskFlow, taskScript, upsertPartition, usernameToEmail, waitForApproval, waitJob, workflow, writeS3File };
@@ -86,4 +86,39 @@ export declare function datatable(name?: string): DatatableSqlTemplateFunction;
86
86
  * let sql = wmill.ducklake("my_lake:analytics")
87
87
  */
88
88
  export declare function ducklake(name?: string): SqlTemplateFunction;
89
+ /** Options for the ducklake materialization helpers. `partition` is bound as a
90
+ * DuckDB arg (never interpolated); `selectSql`, `table`, `schema`, `uniqueKey`
91
+ * are trusted structural SQL inlined via `raw`. */
92
+ export interface DucklakeMaterializeOptions {
93
+ /** ducklake name (default "main"), optionally "name:schema". */
94
+ ducklake?: string;
95
+ /** target table within the ducklake. */
96
+ table: string;
97
+ /** the SELECT producing the rows for this slice. */
98
+ selectSql: string;
99
+ /** the partition value (bound). Omit for a whole-table materialization — no
100
+ * partition column, and replace becomes a `CREATE OR REPLACE TABLE`. */
101
+ partition?: string;
102
+ /** dedup key → upsert in slice (delete-by-key + insert); omit → replace (delete partition + insert). */
103
+ uniqueKey?: string;
104
+ /** physical partition column (default "_wm_partition"). */
105
+ partitionCol?: string;
106
+ }
107
+ /** Idempotently materialize `selectSql` into a ducklake table for one
108
+ * partition (or the whole table when `partition` is omitted) — the client-side
109
+ * equivalent of the `// materialize` engine.
110
+ * With `uniqueKey` it upserts the slice (delete-by-key + insert); otherwise it
111
+ * replaces it (whole table → `CREATE OR REPLACE`; partition → delete + insert).
112
+ * Safe to re-run for the same partition (backfill / failure-recovery).
113
+ *
114
+ * Returns a lazy statement — call `.execute()` to run it:
115
+ * `await wmill.upsertPartition({ table, selectSql, partition }).execute()`. */
116
+ export declare function upsertPartition(opts: DucklakeMaterializeOptions): SqlStatement<any>;
117
+ /** INSERT-only materialization (no dedup/replace) for append-only tables.
118
+ * Re-running the same partition duplicates rows — use only for immutable
119
+ * event-log sources.
120
+ *
121
+ * Returns a lazy statement — call `.execute()` to run it:
122
+ * `await wmill.appendPartition({ table, selectSql, partition }).execute()`. */
123
+ export declare function appendPartition(opts: Omit<DucklakeMaterializeOptions, "uniqueKey">): SqlStatement<any>;
89
124
  export {};
package/dist/sqlUtils.mjs CHANGED
@@ -1,5 +1,6 @@
1
+ import { OpenAPI } from "./core/OpenAPI.mjs";
1
2
  import { JobService } from "./services.gen.mjs";
2
- import { getWorkspace, workerHasInternalServer } from "./client.mjs";
3
+ import { getEnv, getWorkspace, workerHasInternalServer } from "./client.mjs";
3
4
 
4
5
  //#region src/sqlUtils.ts
5
6
  /**
@@ -33,7 +34,7 @@ function ducklakeProvider(name, schema) {
33
34
  };
34
35
  }
35
36
  function buildSqlStatement(provider, content, contentBody, args) {
36
- async function fetch({ resultCollection } = {}) {
37
+ async function fetch$1({ resultCollection } = {}) {
37
38
  let finalContent = content;
38
39
  if (resultCollection) finalContent = `-- result_collection=${resultCollection}\n${finalContent}`;
39
40
  try {
@@ -72,16 +73,16 @@ function buildSqlStatement(provider, content, contentBody, args) {
72
73
  return {
73
74
  content,
74
75
  args,
75
- fetch,
76
- fetchOne: (params) => fetch({
76
+ fetch: fetch$1,
77
+ fetchOne: (params) => fetch$1({
77
78
  ...params,
78
79
  resultCollection: "last_statement_first_row"
79
80
  }),
80
- fetchOneScalar: (params) => fetch({
81
+ fetchOneScalar: (params) => fetch$1({
81
82
  ...params,
82
83
  resultCollection: "last_statement_first_row_scalar"
83
84
  }),
84
- execute: (params) => fetch(params)
85
+ execute: (params) => fetch$1(params)
85
86
  };
86
87
  }
87
88
  function serializeArgValue(v) {
@@ -188,6 +189,127 @@ function ducklake(name = "main") {
188
189
  let { name: n, schema } = parseName(name);
189
190
  return buildSqlTemplateFunction(ducklakeProvider(n, schema));
190
191
  }
192
+ /** Idempotently materialize `selectSql` into a ducklake table for one
193
+ * partition (or the whole table when `partition` is omitted) — the client-side
194
+ * equivalent of the `// materialize` engine.
195
+ * With `uniqueKey` it upserts the slice (delete-by-key + insert); otherwise it
196
+ * replaces it (whole table → `CREATE OR REPLACE`; partition → delete + insert).
197
+ * Safe to re-run for the same partition (backfill / failure-recovery).
198
+ *
199
+ * Returns a lazy statement — call `.execute()` to run it:
200
+ * `await wmill.upsertPartition({ table, selectSql, partition }).execute()`. */
201
+ function upsertPartition(opts) {
202
+ return finishMaterialize(buildUpsertStatement(opts), opts);
203
+ }
204
+ function buildUpsertStatement(opts) {
205
+ let { name: n, schema } = parseName(opts.ducklake ?? "main");
206
+ let sql = buildSqlTemplateFunction(ducklakeProvider(n, schema));
207
+ let pcol = sql.raw(opts.partitionCol ?? "_wm_partition");
208
+ let t = sql.raw(`dl.${opts.table}`);
209
+ let body = sql.raw(opts.selectSql);
210
+ if (opts.partition === void 0) {
211
+ if (opts.uniqueKey) {
212
+ let uk = sql.raw(opts.uniqueKey);
213
+ return sql`CREATE TABLE IF NOT EXISTS ${t} AS SELECT * FROM (${body}) WHERE false;
214
+ BEGIN TRANSACTION;
215
+ DELETE FROM ${t} WHERE ${uk} IN (SELECT ${uk} FROM (${body}));
216
+ INSERT INTO ${t} SELECT * FROM (${body});
217
+ COMMIT;`;
218
+ }
219
+ return sql`CREATE OR REPLACE TABLE ${t} AS SELECT * FROM (${body});`;
220
+ }
221
+ if (opts.uniqueKey) {
222
+ let uk = sql.raw(opts.uniqueKey);
223
+ return sql`CREATE TABLE IF NOT EXISTS ${t} AS SELECT *, CAST(NULL AS VARCHAR) AS ${pcol} FROM (${body}) WHERE false;
224
+ ALTER TABLE ${t} SET PARTITIONED BY (${pcol});
225
+ BEGIN TRANSACTION;
226
+ DELETE FROM ${t} WHERE ${pcol} = ${opts.partition} AND ${uk} IN (SELECT ${uk} FROM (${body}));
227
+ INSERT INTO ${t} SELECT *, ${opts.partition} AS ${pcol} FROM (${body});
228
+ COMMIT;`;
229
+ }
230
+ return sql`CREATE TABLE IF NOT EXISTS ${t} AS SELECT *, CAST(NULL AS VARCHAR) AS ${pcol} FROM (${body}) WHERE false;
231
+ ALTER TABLE ${t} SET PARTITIONED BY (${pcol});
232
+ BEGIN TRANSACTION;
233
+ DELETE FROM ${t} WHERE ${pcol} = ${opts.partition};
234
+ INSERT INTO ${t} SELECT *, ${opts.partition} AS ${pcol} FROM (${body});
235
+ COMMIT;`;
236
+ }
237
+ /** INSERT-only materialization (no dedup/replace) for append-only tables.
238
+ * Re-running the same partition duplicates rows — use only for immutable
239
+ * event-log sources.
240
+ *
241
+ * Returns a lazy statement — call `.execute()` to run it:
242
+ * `await wmill.appendPartition({ table, selectSql, partition }).execute()`. */
243
+ function appendPartition(opts) {
244
+ return finishMaterialize(buildAppendStatement(opts), opts);
245
+ }
246
+ function buildAppendStatement(opts) {
247
+ let { name: n, schema } = parseName(opts.ducklake ?? "main");
248
+ let sql = buildSqlTemplateFunction(ducklakeProvider(n, schema));
249
+ let pcol = sql.raw(opts.partitionCol ?? "_wm_partition");
250
+ let t = sql.raw(`dl.${opts.table}`);
251
+ let body = sql.raw(opts.selectSql);
252
+ if (opts.partition === void 0) return sql`CREATE TABLE IF NOT EXISTS ${t} AS SELECT * FROM (${body}) WHERE false;
253
+ INSERT INTO ${t} SELECT * FROM (${body});`;
254
+ return sql`CREATE TABLE IF NOT EXISTS ${t} AS SELECT *, CAST(NULL AS VARCHAR) AS ${pcol} FROM (${body}) WHERE false;
255
+ ALTER TABLE ${t} SET PARTITIONED BY (${pcol});
256
+ INSERT INTO ${t} SELECT *, ${opts.partition} AS ${pcol} FROM (${body});`;
257
+ }
258
+ function finishMaterialize(stmt, opts) {
259
+ if (getEnv("WM_PIPELINE") !== "true") return stmt;
260
+ let { name: n, schema } = parseName(opts.ducklake ?? "main");
261
+ let sql = buildSqlTemplateFunction(ducklakeProvider(n, schema));
262
+ let t = sql.raw(`dl.${opts.table}`);
263
+ let pcol = opts.partitionCol ?? "_wm_partition";
264
+ let where = opts.partition !== void 0 ? sql.raw(`WHERE ${pcol} = '${String(opts.partition).replace(/'/g, "''")}'`) : sql.raw("");
265
+ let summary = sql`SELECT (SELECT count(*) FROM ${t} ${where}) AS rows, (SELECT max(snapshot_id) FROM ducklake_snapshots('dl')) AS snapshot_id`;
266
+ let assetPath = schema ? `${n}/${schema}.${opts.table}` : `${n}/${opts.table}`;
267
+ let partition = opts.partition ?? "";
268
+ let run = async () => {
269
+ try {
270
+ await stmt.execute();
271
+ } catch (e) {
272
+ await recordMaterialization(assetPath, partition, "failed", null, null, String(e));
273
+ throw e;
274
+ }
275
+ let snapshot_id = null;
276
+ let row_count = null;
277
+ try {
278
+ let s = await summary.fetchOne();
279
+ snapshot_id = s?.snapshot_id ?? null;
280
+ row_count = s?.rows ?? null;
281
+ } catch {}
282
+ await recordMaterialization(assetPath, partition, "materialized", snapshot_id, row_count, null);
283
+ };
284
+ return {
285
+ ...stmt,
286
+ execute: () => run(),
287
+ fetch: () => run(),
288
+ fetchOne: () => run(),
289
+ fetchOneScalar: () => run()
290
+ };
291
+ }
292
+ async function recordMaterialization(assetPath, partition, status, snapshot_id, row_count, error) {
293
+ try {
294
+ await fetch(`${OpenAPI.BASE}/w/${getWorkspace()}/assets/record_materialization`, {
295
+ method: "POST",
296
+ headers: {
297
+ "content-type": "application/json",
298
+ authorization: `Bearer ${OpenAPI.TOKEN}`
299
+ },
300
+ body: JSON.stringify({
301
+ asset_kind: "ducklake",
302
+ asset_path: assetPath,
303
+ partition,
304
+ status,
305
+ snapshot_id,
306
+ row_count,
307
+ job_id: getEnv("WM_JOB_ID") ?? null,
308
+ error
309
+ })
310
+ });
311
+ } catch {}
312
+ }
191
313
  function inferSqlType(value) {
192
314
  if (typeof value === "bigint") return "BIGINT";
193
315
  if (typeof value === "number") {
@@ -235,4 +357,4 @@ function parseName(name) {
235
357
  }
236
358
 
237
359
  //#endregion
238
- export { datatable, ducklake };
360
+ export { appendPartition, datatable, ducklake, upsertPartition };
@@ -1538,6 +1538,10 @@ export type Script = {
1538
1538
  export type NewScript = {
1539
1539
  path: string;
1540
1540
  parent_hash?: string;
1541
+ /**
1542
+ * When true, the backend resolves the parent to the current deployed head for this path within the transaction (ignoring parent_hash), instead of failing with a "lineage must be linear" error when the supplied parent_hash is stale.
1543
+ */
1544
+ auto_parent?: boolean;
1541
1545
  summary: string;
1542
1546
  description?: string;
1543
1547
  content: string;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "windmill-client",
3
3
  "description": "Windmill SDK client for browsers and Node.js",
4
- "version": "1.733.1",
4
+ "version": "1.734.0",
5
5
  "author": "Ruben Fiszel",
6
6
  "license": "Apache 2.0",
7
7
  "homepage": "https://github.com/windmill-labs/windmill/tree/main/typescript-client#readme",