@keystrokehq/snowflake 0.0.16 → 0.0.18

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 (82) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +9 -233
  3. package/package.json +39 -171
  4. package/dist/accounts/index.d.mts +0 -40
  5. package/dist/accounts/index.mjs +0 -51
  6. package/dist/bulk/index.d.mts +0 -71
  7. package/dist/bulk/index.mjs +0 -65
  8. package/dist/catalog/index.d.mts +0 -144
  9. package/dist/catalog/index.mjs +0 -158
  10. package/dist/client/index.d.mts +0 -44
  11. package/dist/client/index.mjs +0 -273
  12. package/dist/common-DfpCwJx5.mjs +0 -92
  13. package/dist/credential-sets/index.d.mts +0 -3
  14. package/dist/credential-sets/index.mjs +0 -4
  15. package/dist/databases/index.d.mts +0 -2
  16. package/dist/databases/index.mjs +0 -3
  17. package/dist/errors-60AsF7Su.mjs +0 -95
  18. package/dist/events/index.d.mts +0 -382
  19. package/dist/events/index.mjs +0 -291
  20. package/dist/file-formats/index.d.mts +0 -39
  21. package/dist/file-formats/index.mjs +0 -48
  22. package/dist/functions/index.d.mts +0 -53
  23. package/dist/functions/index.mjs +0 -56
  24. package/dist/grants/index.d.mts +0 -93
  25. package/dist/grants/index.mjs +0 -102
  26. package/dist/index.d.mts +0 -4
  27. package/dist/index.mjs +0 -6
  28. package/dist/operations/index.d.mts +0 -1
  29. package/dist/operations/index.mjs +0 -1
  30. package/dist/org-admin/index.d.mts +0 -80
  31. package/dist/org-admin/index.mjs +0 -79
  32. package/dist/pipes/index.d.mts +0 -119
  33. package/dist/pipes/index.mjs +0 -106
  34. package/dist/procedures/index.d.mts +0 -61
  35. package/dist/procedures/index.mjs +0 -79
  36. package/dist/results/index.d.mts +0 -16
  37. package/dist/results/index.mjs +0 -64
  38. package/dist/retry-B4-9MZIp.mjs +0 -164
  39. package/dist/retry-w7cTp1QL.d.mts +0 -10
  40. package/dist/roles/index.d.mts +0 -60
  41. package/dist/roles/index.mjs +0 -74
  42. package/dist/rows/index.d.mts +0 -106
  43. package/dist/rows/index.mjs +0 -223
  44. package/dist/schemas/index.d.mts +0 -2
  45. package/dist/schemas/index.mjs +0 -4
  46. package/dist/schemas-catalog/index.d.mts +0 -2
  47. package/dist/schemas-catalog/index.mjs +0 -3
  48. package/dist/shares/index.d.mts +0 -56
  49. package/dist/shares/index.mjs +0 -77
  50. package/dist/snowflake-s3-sns-webhook.credential-set-D6bLAWy5.d.mts +0 -50
  51. package/dist/snowflake-s3-sns-webhook.credential-set-DzR7oWNK.mjs +0 -44
  52. package/dist/snowflake.credential-set-BxT7Gf3A.d.mts +0 -114
  53. package/dist/snowflake.credential-set-DE3gXf-a.mjs +0 -106
  54. package/dist/sql/index.d.mts +0 -84
  55. package/dist/sql/index.mjs +0 -209
  56. package/dist/sql-options-2k5xQ-oS.d.mts +0 -32
  57. package/dist/sql-options-D6GEa21F.mjs +0 -79
  58. package/dist/sql-safety-BZpAPsq6.mjs +0 -56
  59. package/dist/stages/index.d.mts +0 -64
  60. package/dist/stages/index.mjs +0 -81
  61. package/dist/statements-BumhMhN4.mjs +0 -81
  62. package/dist/statements-DJL0qVNA.d.mts +0 -238
  63. package/dist/status-page/index.d.mts +0 -510
  64. package/dist/status-page/index.mjs +0 -261
  65. package/dist/streaming/index.d.mts +0 -70
  66. package/dist/streaming/index.mjs +0 -56
  67. package/dist/streams/index.d.mts +0 -71
  68. package/dist/streams/index.mjs +0 -78
  69. package/dist/tables/index.d.mts +0 -2
  70. package/dist/tables/index.mjs +0 -3
  71. package/dist/tasks/index.d.mts +0 -79
  72. package/dist/tasks/index.mjs +0 -104
  73. package/dist/triggers/index.d.mts +0 -381
  74. package/dist/triggers/index.mjs +0 -1100
  75. package/dist/users/index.d.mts +0 -61
  76. package/dist/users/index.mjs +0 -67
  77. package/dist/verification/index.d.mts +0 -201
  78. package/dist/verification/index.mjs +0 -512
  79. package/dist/views/index.d.mts +0 -2
  80. package/dist/views/index.mjs +0 -3
  81. package/dist/warehouses/index.d.mts +0 -68
  82. package/dist/warehouses/index.mjs +0 -101
@@ -1,1100 +0,0 @@
1
- import { i as snowflakeCredentialSet } from "../snowflake.credential-set-DE3gXf-a.mjs";
2
- import { createSnowflakeClient } from "../client/index.mjs";
3
- import { grantChangedEventSchema, pipeLoadEventSchema, scheduledDeltaEventSchema, scheduledSqlEventSchema, shareChangedEventSchema, snowflakeDiffSnapshotEntrySchema, snowflakeObjectLifecycleEventSchema, statementCompletedEventSchema, statusPageComponentChangeEventSchema, statusPageIncidentEventSchema, streamAppendOnlyEventSchema, streamHasDataEventSchema, taskRunEventSchema, warehouseCreditsEventSchema, warehouseQueueEventSchema } from "../events/index.mjs";
4
- import { executeSql } from "../sql/index.mjs";
5
- import { a as quoteLiteral, i as quoteIdentifier, t as buildFqn } from "../sql-safety-BZpAPsq6.mjs";
6
- import { BindingBuilder } from "../rows/index.mjs";
7
- import { getStatusSummary, getUnresolvedIncidents } from "../status-page/index.mjs";
8
- import { z } from "zod";
9
- import { pollingTrigger } from "@keystrokehq/core/trigger";
10
-
11
- //#region ../../packages/integration-authoring/dist/index.mjs
12
- const IntegrationConfigSchema = z.object({
13
- id: z.string().min(1),
14
- name: z.string().min(1),
15
- description: z.string().optional()
16
- });
17
- function resolveMetadata(metadata, defaults) {
18
- return {
19
- id: metadata?.id ?? defaults.defaultId,
20
- description: metadata?.description ?? defaults.defaultDescription
21
- };
22
- }
23
- function resolveAuthorPayload(payload, mapPayload) {
24
- if (!mapPayload) return payload;
25
- return mapPayload(payload);
26
- }
27
- function createIntegrationTriggerBindingFactory(config) {
28
- const bind = (options) => {
29
- const resolvedMetadata = resolveMetadata(options, config);
30
- const baseTrigger = config.createBaseTrigger(resolvedMetadata);
31
- const userTransform = options?.transform;
32
- return baseTrigger({ transform: userTransform || config.mapPayload ? (runtimePayload, request) => {
33
- const authorPayload = resolveAuthorPayload(runtimePayload, config.mapPayload);
34
- if (authorPayload === null) throw new Error(`Trigger "${resolvedMetadata.id}" mapPayload returned null after the trigger filter passed; tighten the trigger filter schema.`);
35
- if (!userTransform) return authorPayload;
36
- return userTransform(authorPayload, request);
37
- } : void 0 });
38
- };
39
- return Object.freeze(bind);
40
- }
41
- function createPollingTriggerBindingFactory(config) {
42
- return createIntegrationTriggerBindingFactory({
43
- defaultId: config.defaultId,
44
- defaultDescription: config.defaultDescription,
45
- mapPayload: config.mapPayload,
46
- createBaseTrigger: (metadata) => pollingTrigger({
47
- id: metadata.id,
48
- description: metadata.description,
49
- schedule: config.schedule,
50
- response: config.response,
51
- poll: config.poll,
52
- ...config.credentialSets ? { credentialSets: config.credentialSets } : {},
53
- ...config.filter ? { filter: config.filter } : {}
54
- })
55
- });
56
- }
57
-
58
- //#endregion
59
- //#region src/triggers/polling.ts
60
- function defineSnowflakePollingTrigger(definition) {
61
- return definition;
62
- }
63
- function splitBindingOptions(input) {
64
- return {
65
- schedule: input?.schedule,
66
- bindOptions: {
67
- ...input?.id ? { id: input.id } : {},
68
- ...input?.description ? { description: input.description } : {},
69
- ...input?.transform ? { transform: input.transform } : {}
70
- }
71
- };
72
- }
73
- function resolveSchedule(override, fallback) {
74
- if (override === void 0) return fallback;
75
- return override;
76
- }
77
- function createSnowflakePollingBindingFactory(definition, params, schedule) {
78
- return createPollingTriggerBindingFactory({
79
- defaultId: definition.defaultId,
80
- defaultDescription: definition.defaultDescription,
81
- schedule: resolveSchedule(schedule, definition.defaultSchedule),
82
- credentialSets: [snowflakeCredentialSet],
83
- response: definition.responseSchema,
84
- poll: (ctx) => {
85
- const snowflakeCtx = ctx;
86
- return definition.poll(params, snowflakeCtx.credentials.snowflake, snowflakeCtx);
87
- }
88
- });
89
- }
90
- function bindSnowflakePollingTrigger(definition, params, input) {
91
- const { schedule, bindOptions } = splitBindingOptions(input);
92
- return createSnowflakePollingBindingFactory(definition, params, schedule)(bindOptions);
93
- }
94
- function isoNow() {
95
- return (/* @__PURE__ */ new Date()).toISOString();
96
- }
97
- function readStringField(row, ...keys) {
98
- for (const key of keys) {
99
- const value = row[key];
100
- if (typeof value === "string" && value.length > 0) return value;
101
- }
102
- }
103
- function readNumberField(row, ...keys) {
104
- for (const key of keys) {
105
- const value = row[key];
106
- if (typeof value === "number" && Number.isFinite(value)) return value;
107
- if (typeof value === "string" && value.length > 0) {
108
- const parsed = Number(value);
109
- if (Number.isFinite(parsed)) return parsed;
110
- }
111
- }
112
- }
113
- function hashStatement(statement) {
114
- let hash = 0;
115
- for (let i = 0; i < statement.length; i += 1) hash = (hash << 5) - hash + statement.charCodeAt(i) | 0;
116
- return `sha-${(hash >>> 0).toString(16)}-${statement.length}`;
117
- }
118
- const streamHasNewRowsDefinition = defineSnowflakePollingTrigger({
119
- responseSchema: streamHasDataEventSchema,
120
- defaultId: "snowflake.stream_has_new_rows",
121
- defaultDescription: "Fires when SYSTEM$STREAM_HAS_DATA returns TRUE for a Snowflake stream (fires at most once per schedule tick).",
122
- defaultSchedule: "1m",
123
- poll: async (params, credentials) => {
124
- const client = createSnowflakeClient(credentials);
125
- const fqn = buildFqn(params.database, params.schema, params.streamName);
126
- const row = (await executeSql(client, {
127
- statement: `SELECT SYSTEM$STREAM_HAS_DATA(${quoteLiteral(fqn)}) AS HAS_DATA`,
128
- warehouse: params.warehouse,
129
- role: params.role
130
- })).rows[0] ?? {};
131
- const raw = row.HAS_DATA ?? row.has_data;
132
- let hasData;
133
- if (typeof raw === "boolean") hasData = raw;
134
- else if (typeof raw === "string") hasData = raw.toLowerCase() === "true";
135
- else hasData = Boolean(raw);
136
- return {
137
- streamName: fqn,
138
- hasData,
139
- checkedAt: isoNow()
140
- };
141
- }
142
- });
143
- function streamHasNewRows(input) {
144
- return bindSnowflakePollingTrigger(streamHasNewRowsDefinition, input, input);
145
- }
146
- const streamAppendOnlyDefinition = defineSnowflakePollingTrigger({
147
- responseSchema: streamAppendOnlyEventSchema,
148
- defaultId: "snowflake.stream_append_only",
149
- defaultDescription: "Emits new inserted rows from a Snowflake stream on each poll. Consumers must progress the stream via downstream DML in a transaction.",
150
- defaultSchedule: "1m",
151
- poll: async (params, credentials) => {
152
- const client = createSnowflakeClient(credentials);
153
- const fqn = buildFqn(params.database, params.schema, params.streamName);
154
- const limit = params.limit ?? 1e3;
155
- const result = await executeSql(client, {
156
- statement: `SELECT * FROM ${fqn} WHERE ${`METADATA$ACTION = 'INSERT'${params.where ? ` AND (${params.where})` : ""}`} LIMIT ${Number(limit)}`,
157
- warehouse: params.warehouse,
158
- role: params.role
159
- });
160
- const rows = result.rows;
161
- return {
162
- streamName: fqn,
163
- rows: [...rows],
164
- columns: [...result.columns],
165
- rowCount: rows.length,
166
- fetchedAt: isoNow()
167
- };
168
- }
169
- });
170
- function streamAppendOnly(input) {
171
- return bindSnowflakePollingTrigger(streamAppendOnlyDefinition, input, input);
172
- }
173
- const scheduledSqlDefinition = defineSnowflakePollingTrigger({
174
- responseSchema: scheduledSqlEventSchema,
175
- defaultId: "snowflake.scheduled_sql",
176
- defaultDescription: "Runs a caller-supplied SQL statement on each schedule tick and emits the full result set.",
177
- defaultSchedule: "5m",
178
- poll: async (params, credentials) => {
179
- const client = createSnowflakeClient(credentials);
180
- let bindings;
181
- if (params.bindings && params.bindings.length > 0) {
182
- const builder = new BindingBuilder();
183
- for (const value of params.bindings) builder.add(value);
184
- bindings = { ...builder.toRecord() };
185
- }
186
- const result = await executeSql(client, {
187
- statement: params.statement,
188
- warehouse: params.warehouse,
189
- role: params.role,
190
- database: params.database,
191
- schema: params.schema,
192
- ...bindings ? { bindings } : {}
193
- });
194
- const rows = result.rows;
195
- return {
196
- statementDigest: hashStatement(params.statement),
197
- rows: [...rows],
198
- columns: [...result.columns],
199
- rowCount: rows.length,
200
- fetchedAt: isoNow()
201
- };
202
- }
203
- });
204
- function scheduledSql(input) {
205
- return bindSnowflakePollingTrigger(scheduledSqlDefinition, input, input);
206
- }
207
- function stringifyCursor(value) {
208
- if (value === null || value === void 0) return null;
209
- if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") return String(value);
210
- if (value instanceof Date) return value.toISOString();
211
- return String(value);
212
- }
213
- const scheduledDeltaDefinition = defineSnowflakePollingTrigger({
214
- responseSchema: scheduledDeltaEventSchema,
215
- defaultId: "snowflake.scheduled_delta",
216
- defaultDescription: "Emits new rows from a Snowflake table where a cursor column exceeds the last observed high-water mark.",
217
- defaultSchedule: "1m",
218
- poll: async (params, credentials, ctx) => {
219
- const client = createSnowflakeClient(credentials);
220
- const fqn = buildFqn(params.database, params.schema, params.table);
221
- const cursor = quoteIdentifier(params.cursorColumn);
222
- const limit = params.limit ?? 1e3;
223
- const selectList = params.columns && params.columns.length > 0 ? params.columns.map((c) => quoteIdentifier(c)).join(", ") : "*";
224
- const priorHighWater = ctx.lastResponse?.highWaterValue ?? (params.initialHighWater !== void 0 ? String(params.initialHighWater) : null);
225
- const clauses = [];
226
- let bindings;
227
- if (priorHighWater !== null) {
228
- clauses.push(`${cursor} > ?`);
229
- bindings = { "1": {
230
- type: "TEXT",
231
- value: priorHighWater
232
- } };
233
- }
234
- if (params.where) clauses.push(`(${params.where})`);
235
- const result = await executeSql(client, {
236
- statement: `SELECT ${selectList} FROM ${fqn}${clauses.length > 0 ? ` WHERE ${clauses.join(" AND ")}` : ""} ORDER BY ${cursor} ASC LIMIT ${Number(limit)}`,
237
- warehouse: params.warehouse,
238
- role: params.role,
239
- ...bindings ? { bindings } : {}
240
- });
241
- const rows = result.rows;
242
- const latest = rows[rows.length - 1]?.[params.cursorColumn] ?? rows[rows.length - 1]?.[params.cursorColumn.toUpperCase()];
243
- const nextHighWater = rows.length > 0 ? stringifyCursor(latest) : priorHighWater;
244
- return {
245
- table: fqn,
246
- cursorColumn: params.cursorColumn,
247
- highWaterValue: nextHighWater,
248
- rows: [...rows],
249
- columns: [...result.columns],
250
- rowCount: rows.length,
251
- fetchedAt: isoNow()
252
- };
253
- }
254
- });
255
- function scheduledDelta(input) {
256
- return bindSnowflakePollingTrigger(scheduledDeltaDefinition, input, input);
257
- }
258
- const DEFAULT_TASK_STATES = [
259
- "SUCCEEDED",
260
- "FAILED",
261
- "FAILED_AND_AUTO_SUSPENDED",
262
- "CANCELLED"
263
- ];
264
- const taskRunCompletedDefinition = defineSnowflakePollingTrigger({
265
- responseSchema: z.object({
266
- events: z.array(taskRunEventSchema),
267
- highWaterValue: z.string().nullable(),
268
- fetchedAt: z.string()
269
- }).catchall(z.unknown()),
270
- defaultId: "snowflake.task_run_completed",
271
- defaultDescription: "Emits terminal task runs polled from INFORMATION_SCHEMA.TASK_HISTORY (SUCCEEDED / FAILED / CANCELLED).",
272
- defaultSchedule: "1m",
273
- poll: async (params, credentials, ctx) => {
274
- const client = createSnowflakeClient(credentials);
275
- const limit = params.limit ?? 200;
276
- const statesPredicate = (params.states ?? DEFAULT_TASK_STATES).map((s) => quoteLiteral(s)).join(", ");
277
- const priorHighWater = ctx.lastResponse?.highWaterValue ?? null;
278
- const lookbackMinutes = params.lookbackMinutes ?? 60;
279
- const since = priorHighWater ?? (/* @__PURE__ */ new Date(Date.now() - lookbackMinutes * 6e4)).toISOString();
280
- const taskFilter = params.taskName ? `, TASK_NAME => ${quoteLiteral(params.taskName)}` : "";
281
- const rows = (await executeSql(client, {
282
- statement: `SELECT * FROM TABLE(INFORMATION_SCHEMA.TASK_HISTORY(${`SCHEDULED_TIME_RANGE_START => TO_TIMESTAMP_LTZ(${quoteLiteral(since)})${taskFilter}, RESULT_LIMIT => ${Number(limit)}`})) WHERE STATE IN (${statesPredicate}) ORDER BY SCHEDULED_TIME ASC`,
283
- warehouse: params.warehouse,
284
- role: params.role,
285
- database: params.database,
286
- schema: params.schema
287
- })).rows;
288
- const events = rows.map((row) => ({
289
- name: readStringField(row, "NAME", "name") ?? "",
290
- databaseName: readStringField(row, "DATABASE_NAME", "database_name"),
291
- schemaName: readStringField(row, "SCHEMA_NAME", "schema_name"),
292
- state: readStringField(row, "STATE", "state") ?? "UNKNOWN",
293
- queryId: readStringField(row, "QUERY_ID", "query_id"),
294
- scheduledTime: readStringField(row, "SCHEDULED_TIME", "scheduled_time"),
295
- completedTime: readStringField(row, "COMPLETED_TIME", "completed_time"),
296
- errorCode: readStringField(row, "ERROR_CODE", "error_code") ?? null,
297
- errorMessage: readStringField(row, "ERROR_MESSAGE", "error_message") ?? null,
298
- attemptNumber: readNumberField(row, "ATTEMPT_NUMBER", "attempt_number"),
299
- runId: readStringField(row, "RUN_ID", "run_id"),
300
- row
301
- }));
302
- const last = rows[rows.length - 1];
303
- return {
304
- events,
305
- highWaterValue: readStringField(last ?? {}, "COMPLETED_TIME", "completed_time") ?? readStringField(last ?? {}, "SCHEDULED_TIME", "scheduled_time") ?? priorHighWater,
306
- fetchedAt: isoNow()
307
- };
308
- }
309
- });
310
- function taskRunCompleted(input) {
311
- return bindSnowflakePollingTrigger(taskRunCompletedDefinition, {
312
- taskName: input?.taskName,
313
- database: input?.database,
314
- schema: input?.schema,
315
- warehouse: input?.warehouse,
316
- role: input?.role,
317
- lookbackMinutes: input?.lookbackMinutes,
318
- limit: input?.limit,
319
- states: input?.states
320
- }, input);
321
- }
322
- const DEFAULT_STATEMENT_STATES = [
323
- "SUCCESS",
324
- "FAIL",
325
- "FAILED_WITH_ERROR",
326
- "CANCELLED",
327
- "INCIDENT"
328
- ];
329
- const statementCompletedDefinition = defineSnowflakePollingTrigger({
330
- responseSchema: z.object({
331
- events: z.array(statementCompletedEventSchema),
332
- highWaterValue: z.string().nullable(),
333
- fetchedAt: z.string()
334
- }).catchall(z.unknown()),
335
- defaultId: "snowflake.statement_completed",
336
- defaultDescription: "Emits terminal statements from INFORMATION_SCHEMA.QUERY_HISTORY, optionally filtered by user / text / warehouse.",
337
- defaultSchedule: "1m",
338
- poll: async (params, credentials, ctx) => {
339
- const client = createSnowflakeClient(credentials);
340
- const limit = params.limit ?? 200;
341
- const states = params.executionStatuses ?? DEFAULT_STATEMENT_STATES;
342
- const priorHighWater = ctx.lastResponse?.highWaterValue ?? null;
343
- const lookbackMinutes = params.lookbackMinutes ?? 30;
344
- const args = [`END_TIME_RANGE_START => TO_TIMESTAMP_LTZ(${quoteLiteral(priorHighWater ?? (/* @__PURE__ */ new Date(Date.now() - lookbackMinutes * 6e4)).toISOString())})`, `RESULT_LIMIT => ${Number(limit)}`];
345
- if (params.userName) args.push(`USER_NAME => ${quoteLiteral(params.userName)}`);
346
- if (params.warehouse) args.push(`WAREHOUSE_NAME => ${quoteLiteral(params.warehouse)}`);
347
- const clauses = [];
348
- if (!params.includeInFlight) {
349
- const statesPredicate = states.map((s) => quoteLiteral(s)).join(", ");
350
- clauses.push(`EXECUTION_STATUS IN (${statesPredicate})`);
351
- }
352
- if (params.queryTextLike) clauses.push(`QUERY_TEXT ILIKE ${quoteLiteral(params.queryTextLike)}`);
353
- const where = clauses.length > 0 ? ` WHERE ${clauses.join(" AND ")}` : "";
354
- const rows = (await executeSql(client, {
355
- statement: `SELECT * FROM TABLE(INFORMATION_SCHEMA.QUERY_HISTORY(${args.join(", ")}))${where} ORDER BY END_TIME ASC`,
356
- warehouse: params.warehouse,
357
- role: params.role,
358
- database: params.database,
359
- schema: params.schema
360
- })).rows;
361
- const events = rows.map((row) => ({
362
- queryId: readStringField(row, "QUERY_ID", "query_id") ?? "",
363
- executionStatus: readStringField(row, "EXECUTION_STATUS", "execution_status") ?? "UNKNOWN",
364
- queryText: readStringField(row, "QUERY_TEXT", "query_text"),
365
- errorCode: readStringField(row, "ERROR_CODE", "error_code") ?? null,
366
- errorMessage: readStringField(row, "ERROR_MESSAGE", "error_message") ?? null,
367
- startTime: readStringField(row, "START_TIME", "start_time"),
368
- endTime: readStringField(row, "END_TIME", "end_time"),
369
- warehouseName: readStringField(row, "WAREHOUSE_NAME", "warehouse_name"),
370
- databaseName: readStringField(row, "DATABASE_NAME", "database_name"),
371
- schemaName: readStringField(row, "SCHEMA_NAME", "schema_name"),
372
- userName: readStringField(row, "USER_NAME", "user_name"),
373
- roleName: readStringField(row, "ROLE_NAME", "role_name"),
374
- totalElapsedTimeMs: readNumberField(row, "TOTAL_ELAPSED_TIME", "total_elapsed_time") ?? null,
375
- row
376
- }));
377
- const last = rows[rows.length - 1];
378
- return {
379
- events,
380
- highWaterValue: readStringField(last ?? {}, "END_TIME", "end_time") ?? readStringField(last ?? {}, "START_TIME", "start_time") ?? priorHighWater,
381
- fetchedAt: isoNow()
382
- };
383
- }
384
- });
385
- function statementCompleted(input) {
386
- return bindSnowflakePollingTrigger(statementCompletedDefinition, {
387
- warehouse: input?.warehouse,
388
- role: input?.role,
389
- database: input?.database,
390
- schema: input?.schema,
391
- userName: input?.userName,
392
- queryTextLike: input?.queryTextLike,
393
- lookbackMinutes: input?.lookbackMinutes,
394
- limit: input?.limit,
395
- executionStatuses: input?.executionStatuses,
396
- includeInFlight: input?.includeInFlight
397
- }, input);
398
- }
399
- const pipeLoadBatchSchema = z.object({
400
- events: z.array(pipeLoadEventSchema),
401
- highWaterValue: z.string().nullable(),
402
- fetchedAt: z.string()
403
- }).catchall(z.unknown());
404
- function buildPipeLoadDefinition(defaultId, defaultDescription, statusPredicate) {
405
- return defineSnowflakePollingTrigger({
406
- responseSchema: pipeLoadBatchSchema,
407
- defaultId,
408
- defaultDescription,
409
- defaultSchedule: "1m",
410
- poll: async (params, credentials, ctx) => {
411
- const client = createSnowflakeClient(credentials);
412
- const limit = params.limit ?? 200;
413
- const priorHighWater = ctx.lastResponse?.highWaterValue ?? null;
414
- const lookbackMinutes = params.lookbackMinutes ?? 60;
415
- const args = [`START_TIME => TO_TIMESTAMP_LTZ(${quoteLiteral(priorHighWater ?? (/* @__PURE__ */ new Date(Date.now() - lookbackMinutes * 6e4)).toISOString())})`];
416
- if (params.tableName) {
417
- const tableFqn = buildFqn(params.database, params.schema, params.tableName);
418
- args.push(`TABLE_NAME => ${quoteLiteral(tableFqn)}`);
419
- }
420
- const pipeFilter = params.pipeName ? ` AND PIPE_NAME = ${quoteLiteral(buildFqn(params.database, params.schema, params.pipeName))}` : "";
421
- const rows = (await executeSql(client, {
422
- statement: `SELECT * FROM TABLE(INFORMATION_SCHEMA.COPY_HISTORY(${args.join(", ")})) WHERE ${statusPredicate}${pipeFilter} ORDER BY LAST_LOAD_TIME ASC LIMIT ${Number(limit)}`,
423
- warehouse: params.warehouse,
424
- role: params.role,
425
- database: params.database,
426
- schema: params.schema
427
- })).rows;
428
- const events = rows.map((row) => ({
429
- pipeName: readStringField(row, "PIPE_NAME", "pipe_name") ?? "",
430
- filePath: readStringField(row, "FILE_NAME", "file_name") ?? "",
431
- status: readStringField(row, "STATUS", "status") ?? "UNKNOWN",
432
- loadTime: readStringField(row, "LAST_LOAD_TIME", "last_load_time"),
433
- rowCount: readNumberField(row, "ROW_COUNT", "row_count") ?? null,
434
- rowParsed: readNumberField(row, "ROW_PARSED", "row_parsed") ?? null,
435
- errorLimit: readNumberField(row, "ERROR_LIMIT", "error_limit") ?? null,
436
- errorsSeen: readNumberField(row, "ERRORS_SEEN", "errors_seen") ?? null,
437
- firstErrorMessage: readStringField(row, "FIRST_ERROR_MESSAGE", "first_error_message") ?? null,
438
- firstErrorLineNumber: readNumberField(row, "FIRST_ERROR_LINE_NUMBER", "first_error_line_number") ?? null,
439
- firstErrorColumnName: readStringField(row, "FIRST_ERROR_COLUMN_NAME", "first_error_column_name") ?? null,
440
- fileSize: readNumberField(row, "FILE_SIZE", "file_size") ?? null,
441
- stageLocation: readStringField(row, "STAGE_LOCATION", "stage_location") ?? null,
442
- row
443
- }));
444
- const last = rows[rows.length - 1];
445
- return {
446
- events,
447
- highWaterValue: readStringField(last ?? {}, "LAST_LOAD_TIME", "last_load_time") ?? priorHighWater,
448
- fetchedAt: isoNow()
449
- };
450
- }
451
- });
452
- }
453
- const pipeLoadCompletedDefinition = buildPipeLoadDefinition("snowflake.pipe_load_completed", "Emits successful Snowpipe loads polled from INFORMATION_SCHEMA.COPY_HISTORY.", `STATUS = 'LOADED'`);
454
- const pipeLoadFailedDefinition = buildPipeLoadDefinition("snowflake.pipe_load_failed", "Emits failed Snowpipe loads polled from INFORMATION_SCHEMA.COPY_HISTORY.", `STATUS IN ('LOAD_FAILED', 'PARTIALLY_LOADED')`);
455
- function pipeLoadCompleted(input) {
456
- return bindSnowflakePollingTrigger(pipeLoadCompletedDefinition, {
457
- pipeName: input?.pipeName,
458
- database: input?.database,
459
- schema: input?.schema,
460
- tableName: input?.tableName,
461
- warehouse: input?.warehouse,
462
- role: input?.role,
463
- lookbackMinutes: input?.lookbackMinutes,
464
- limit: input?.limit
465
- }, input);
466
- }
467
- function pipeLoadFailed(input) {
468
- return bindSnowflakePollingTrigger(pipeLoadFailedDefinition, {
469
- pipeName: input?.pipeName,
470
- database: input?.database,
471
- schema: input?.schema,
472
- tableName: input?.tableName,
473
- warehouse: input?.warehouse,
474
- role: input?.role,
475
- lookbackMinutes: input?.lookbackMinutes,
476
- limit: input?.limit
477
- }, input);
478
- }
479
- /**
480
- * Diff-trigger response envelope carried across polls. The emitted shape
481
- * is `{ events: TEvent[], snapshot: Entry[], fetchedAt: string }`. The
482
- * `snapshot` field is the identity+signature list that the NEXT poll
483
- * will diff against — it is stored in `ctx.lastResponse` and replayed
484
- * into the trigger automatically.
485
- */
486
- const diffSnapshotSchema = z.array(snowflakeDiffSnapshotEntrySchema);
487
- function buildDiffBatchSchema(event) {
488
- return z.object({
489
- events: z.array(event),
490
- snapshot: diffSnapshotSchema,
491
- fetchedAt: z.string()
492
- }).catchall(z.unknown());
493
- }
494
- /**
495
- * Compute the diff between two snapshots. For `created`: entries in
496
- * `current` whose identity is not in `previous`. For `dropped`: entries
497
- * in `previous` whose identity is not in `current`. For `changed`:
498
- * entries in `current` whose signature differs from `previous`'s
499
- * (including entries that are newly present).
500
- */
501
- function diffEntries(current, previous, mode) {
502
- if (previous === void 0) return [];
503
- const prevMap = new Map(previous.map((p) => [p.identity, p]));
504
- const currMap = new Map(current.map((c) => [c.identity, c]));
505
- if (mode === "created") return current.filter((c) => !prevMap.has(c.identity));
506
- if (mode === "dropped") return previous.filter((p) => !currMap.has(p.identity)).map((p) => ({
507
- identity: p.identity,
508
- ...p.signature !== void 0 ? { signature: p.signature } : {},
509
- row: p.row ?? {}
510
- }));
511
- return current.filter((c) => {
512
- const prev = prevMap.get(c.identity);
513
- if (prev === void 0) return true;
514
- return prev.signature !== c.signature;
515
- });
516
- }
517
- function toSnapshotEntries(entries) {
518
- return entries.map((e) => ({
519
- identity: e.identity,
520
- ...e.signature !== void 0 ? { signature: e.signature } : {}
521
- }));
522
- }
523
- const lifecycleBatchSchema = buildDiffBatchSchema(snowflakeObjectLifecycleEventSchema);
524
- function rowToLifecycleEntry(kind, row) {
525
- const name = readStringField(row, "name", "NAME") ?? "";
526
- const database = readStringField(row, "database_name", "DATABASE_NAME");
527
- const schema = readStringField(row, "schema_name", "SCHEMA_NAME");
528
- return {
529
- identity: [
530
- kind,
531
- database ?? "",
532
- schema ?? "",
533
- name
534
- ].join("::"),
535
- row
536
- };
537
- }
538
- function lifecycleEventFromEntry(kind, change, entry, detectedAt) {
539
- const row = entry.row;
540
- return {
541
- kind,
542
- name: readStringField(row, "name", "NAME") ?? "",
543
- change,
544
- identity: entry.identity,
545
- owner: readStringField(row, "owner", "OWNER"),
546
- createdOn: readStringField(row, "created_on", "CREATED_ON"),
547
- detectedAt,
548
- row
549
- };
550
- }
551
- function buildLifecycleDefinition(config) {
552
- return defineSnowflakePollingTrigger({
553
- responseSchema: lifecycleBatchSchema,
554
- defaultId: config.defaultId,
555
- defaultDescription: config.defaultDescription,
556
- defaultSchedule: "5m",
557
- poll: async (params, credentials, ctx) => {
558
- const current = (await executeSql(createSnowflakeClient(credentials), {
559
- statement: config.buildStatement(params),
560
- warehouse: params.warehouse,
561
- role: params.role,
562
- database: params.database,
563
- schema: params.schema
564
- })).rows.map((row) => rowToLifecycleEntry(config.kind, row));
565
- const previousSnapshot = ctx.lastResponse?.snapshot;
566
- const detectedAt = isoNow();
567
- let diffed;
568
- if (previousSnapshot === void 0) diffed = config.change === "created" && params.emitInitialSnapshot ? current : [];
569
- else diffed = diffEntries(current, previousSnapshot, config.change);
570
- return {
571
- events: diffed.map((entry) => lifecycleEventFromEntry(config.kind, config.change, entry, detectedAt)),
572
- snapshot: toSnapshotEntries(current),
573
- fetchedAt: detectedAt
574
- };
575
- }
576
- });
577
- }
578
- function likeClause(like) {
579
- return like ? ` LIKE ${quoteLiteral(like)}` : "";
580
- }
581
- function inScope(params) {
582
- const db = params.in?.database ?? params.database;
583
- const schema = params.in?.schema ?? params.schema;
584
- if (db && schema) return ` IN SCHEMA ${quoteIdentifier(db)}.${quoteIdentifier(schema)}`;
585
- if (db) return ` IN DATABASE ${quoteIdentifier(db)}`;
586
- return "";
587
- }
588
- const userCreatedDefinition = buildLifecycleDefinition({
589
- kind: "USER",
590
- change: "created",
591
- defaultId: "snowflake.user_created",
592
- defaultDescription: "Emits every new user observed via SHOW USERS since the prior poll.",
593
- buildStatement: (params) => `SHOW USERS${likeClause(params.like)}`
594
- });
595
- const userDroppedDefinition = buildLifecycleDefinition({
596
- kind: "USER",
597
- change: "dropped",
598
- defaultId: "snowflake.user_dropped",
599
- defaultDescription: "Emits every user that has disappeared from SHOW USERS since the prior poll.",
600
- buildStatement: (params) => `SHOW USERS${likeClause(params.like)}`
601
- });
602
- function userCreated(input) {
603
- return bindSnowflakePollingTrigger(userCreatedDefinition, {
604
- database: input?.database,
605
- schema: input?.schema,
606
- warehouse: input?.warehouse,
607
- role: input?.role,
608
- like: input?.like,
609
- emitInitialSnapshot: input?.emitInitialSnapshot
610
- }, input);
611
- }
612
- function userDropped(input) {
613
- return bindSnowflakePollingTrigger(userDroppedDefinition, {
614
- database: input?.database,
615
- schema: input?.schema,
616
- warehouse: input?.warehouse,
617
- role: input?.role,
618
- like: input?.like
619
- }, input);
620
- }
621
- const roleCreatedDefinition = buildLifecycleDefinition({
622
- kind: "ROLE",
623
- change: "created",
624
- defaultId: "snowflake.role_created",
625
- defaultDescription: "Emits every new role observed via SHOW ROLES since the prior poll.",
626
- buildStatement: (params) => `SHOW ROLES${likeClause(params.like)}`
627
- });
628
- const roleDroppedDefinition = buildLifecycleDefinition({
629
- kind: "ROLE",
630
- change: "dropped",
631
- defaultId: "snowflake.role_dropped",
632
- defaultDescription: "Emits every role that has disappeared from SHOW ROLES since the prior poll.",
633
- buildStatement: (params) => `SHOW ROLES${likeClause(params.like)}`
634
- });
635
- function roleCreated(input) {
636
- return bindSnowflakePollingTrigger(roleCreatedDefinition, {
637
- warehouse: input?.warehouse,
638
- role: input?.role,
639
- like: input?.like,
640
- emitInitialSnapshot: input?.emitInitialSnapshot
641
- }, input);
642
- }
643
- function roleDropped(input) {
644
- return bindSnowflakePollingTrigger(roleDroppedDefinition, {
645
- warehouse: input?.warehouse,
646
- role: input?.role,
647
- like: input?.like
648
- }, input);
649
- }
650
- const databaseCreatedDefinition = buildLifecycleDefinition({
651
- kind: "DATABASE",
652
- change: "created",
653
- defaultId: "snowflake.database_created",
654
- defaultDescription: "Emits every new database observed via SHOW DATABASES since the prior poll.",
655
- buildStatement: (params) => `SHOW DATABASES${likeClause(params.like)}`
656
- });
657
- const databaseDroppedDefinition = buildLifecycleDefinition({
658
- kind: "DATABASE",
659
- change: "dropped",
660
- defaultId: "snowflake.database_dropped",
661
- defaultDescription: "Emits every database that disappeared from SHOW DATABASES since the prior poll.",
662
- buildStatement: (params) => `SHOW DATABASES${likeClause(params.like)}`
663
- });
664
- function databaseCreated(input) {
665
- return bindSnowflakePollingTrigger(databaseCreatedDefinition, {
666
- warehouse: input?.warehouse,
667
- role: input?.role,
668
- like: input?.like,
669
- emitInitialSnapshot: input?.emitInitialSnapshot
670
- }, input);
671
- }
672
- function databaseDropped(input) {
673
- return bindSnowflakePollingTrigger(databaseDroppedDefinition, {
674
- warehouse: input?.warehouse,
675
- role: input?.role,
676
- like: input?.like
677
- }, input);
678
- }
679
- const tableCreatedDefinition = buildLifecycleDefinition({
680
- kind: "TABLE",
681
- change: "created",
682
- defaultId: "snowflake.table_created",
683
- defaultDescription: "Emits every new table observed via SHOW TABLES since the prior poll.",
684
- buildStatement: (params) => `SHOW TABLES${likeClause(params.like)}${inScope(params)}`
685
- });
686
- const tableDroppedDefinition = buildLifecycleDefinition({
687
- kind: "TABLE",
688
- change: "dropped",
689
- defaultId: "snowflake.table_dropped",
690
- defaultDescription: "Emits every table that disappeared from SHOW TABLES since the prior poll.",
691
- buildStatement: (params) => `SHOW TABLES${likeClause(params.like)}${inScope(params)}`
692
- });
693
- function tableCreated(input) {
694
- return bindSnowflakePollingTrigger(tableCreatedDefinition, {
695
- in: input?.in,
696
- database: input?.database,
697
- schema: input?.schema,
698
- warehouse: input?.warehouse,
699
- role: input?.role,
700
- like: input?.like,
701
- emitInitialSnapshot: input?.emitInitialSnapshot
702
- }, input);
703
- }
704
- function tableDropped(input) {
705
- return bindSnowflakePollingTrigger(tableDroppedDefinition, {
706
- in: input?.in,
707
- database: input?.database,
708
- schema: input?.schema,
709
- warehouse: input?.warehouse,
710
- role: input?.role,
711
- like: input?.like
712
- }, input);
713
- }
714
- const shareChangedBatchSchema = buildDiffBatchSchema(shareChangedEventSchema);
715
- const SHARE_SIGNATURE_FIELDS = [
716
- "kind",
717
- "owner",
718
- "comment",
719
- "to",
720
- "database_name",
721
- "listing_global_name"
722
- ];
723
- function signatureOf(row, fields) {
724
- return fields.map((field) => {
725
- const upper = field.toUpperCase();
726
- const v = row[field] ?? row[upper];
727
- return v === void 0 || v === null ? "" : String(v);
728
- }).join("|");
729
- }
730
- const shareChangedDefinition = defineSnowflakePollingTrigger({
731
- responseSchema: shareChangedBatchSchema,
732
- defaultId: "snowflake.share_changed",
733
- defaultDescription: "Emits share create / drop / modify events observed via SHOW SHARES. Modifications diff against a signature of kind / owner / comment / accounts / listing.",
734
- defaultSchedule: "5m",
735
- poll: async (params, credentials, ctx) => {
736
- const current = (await executeSql(createSnowflakeClient(credentials), {
737
- statement: `SHOW SHARES${likeClause(params.like)}`,
738
- warehouse: params.warehouse,
739
- role: params.role
740
- })).rows.map((row) => ({
741
- identity: `SHARE::${readStringField(row, "name", "NAME") ?? ""}`,
742
- signature: signatureOf(row, SHARE_SIGNATURE_FIELDS),
743
- row
744
- }));
745
- const previousSnapshot = ctx.lastResponse?.snapshot;
746
- const detectedAt = isoNow();
747
- const prevMap = new Map((previousSnapshot ?? []).map((p) => [p.identity, p]));
748
- const currMap = new Map(current.map((c) => [c.identity, c]));
749
- const events = [];
750
- if (previousSnapshot !== void 0) {
751
- for (const entry of current) {
752
- const prev = prevMap.get(entry.identity);
753
- if (prev === void 0) events.push({
754
- name: readStringField(entry.row, "name", "NAME") ?? "",
755
- kind: readStringField(entry.row, "kind", "KIND"),
756
- change: "created",
757
- identity: entry.identity,
758
- detectedAt,
759
- currentRow: entry.row
760
- });
761
- else if (prev.signature !== entry.signature) events.push({
762
- name: readStringField(entry.row, "name", "NAME") ?? "",
763
- kind: readStringField(entry.row, "kind", "KIND"),
764
- change: "modified",
765
- identity: entry.identity,
766
- detectedAt,
767
- currentRow: entry.row
768
- });
769
- }
770
- for (const prev of previousSnapshot) if (!currMap.has(prev.identity)) events.push({
771
- name: prev.identity.replace(/^SHARE::/u, ""),
772
- change: "dropped",
773
- identity: prev.identity,
774
- detectedAt
775
- });
776
- } else if (params.emitInitialSnapshot) for (const entry of current) events.push({
777
- name: readStringField(entry.row, "name", "NAME") ?? "",
778
- kind: readStringField(entry.row, "kind", "KIND"),
779
- change: "created",
780
- identity: entry.identity,
781
- detectedAt,
782
- currentRow: entry.row
783
- });
784
- return {
785
- events,
786
- snapshot: toSnapshotEntries(current),
787
- fetchedAt: detectedAt
788
- };
789
- }
790
- });
791
- function shareChanged(input) {
792
- return bindSnowflakePollingTrigger(shareChangedDefinition, {
793
- warehouse: input?.warehouse,
794
- role: input?.role,
795
- like: input?.like,
796
- emitInitialSnapshot: input?.emitInitialSnapshot
797
- }, input);
798
- }
799
- const grantsChangedBatchSchema = buildDiffBatchSchema(grantChangedEventSchema);
800
- function grantIdentity(row) {
801
- return `${readStringField(row, "privilege", "PRIVILEGE") ?? ""}::${readStringField(row, "granted_on", "GRANTED_ON") ?? ""}::${readStringField(row, "name", "NAME") ?? ""}::${readStringField(row, "granted_to", "GRANTED_TO") ?? ""}::${readStringField(row, "grantee_name", "GRANTEE_NAME") ?? ""}`;
802
- }
803
- function grantStatement(params) {
804
- if ("role" in params.grantee) return `SHOW GRANTS TO ROLE ${quoteIdentifier(params.grantee.role)}`;
805
- if ("user" in params.grantee) return `SHOW GRANTS TO USER ${quoteIdentifier(params.grantee.user)}`;
806
- return `SHOW GRANTS TO SHARE ${quoteIdentifier(params.grantee.share)}`;
807
- }
808
- const grantsChangedDefinition = defineSnowflakePollingTrigger({
809
- responseSchema: grantsChangedBatchSchema,
810
- defaultId: "snowflake.grants_changed",
811
- defaultDescription: "Emits grant / revoke events observed via SHOW GRANTS TO <ROLE|USER|SHARE>. Diffs against the prior poll by (privilege, granted_on, name, grantee).",
812
- defaultSchedule: "5m",
813
- poll: async (params, credentials, ctx) => {
814
- const current = (await executeSql(createSnowflakeClient(credentials), {
815
- statement: grantStatement(params),
816
- warehouse: params.warehouse,
817
- role: params.sessionRole
818
- })).rows.map((row) => ({
819
- identity: grantIdentity(row),
820
- row
821
- }));
822
- const previousSnapshot = ctx.lastResponse?.snapshot;
823
- const detectedAt = isoNow();
824
- const events = [];
825
- if (previousSnapshot !== void 0) {
826
- const prevSet = new Set(previousSnapshot.map((p) => p.identity));
827
- const currSet = new Set(current.map((c) => c.identity));
828
- for (const entry of current) if (!prevSet.has(entry.identity)) events.push(buildGrantEvent(entry.row, "granted", entry.identity, detectedAt));
829
- for (const prev of previousSnapshot) if (!currSet.has(prev.identity)) {
830
- const [privilege, grantedOn, name, granteeType, granteeName] = prev.identity.split("::");
831
- events.push({
832
- privilege: privilege ?? "",
833
- grantedOn: grantedOn ?? "",
834
- objectName: name ?? "",
835
- granteeType,
836
- granteeName: granteeName ?? "",
837
- change: "revoked",
838
- identity: prev.identity,
839
- detectedAt,
840
- row: {}
841
- });
842
- }
843
- }
844
- return {
845
- events,
846
- snapshot: toSnapshotEntries(current),
847
- fetchedAt: detectedAt
848
- };
849
- }
850
- });
851
- function buildGrantEvent(row, change, identity, detectedAt) {
852
- return {
853
- privilege: readStringField(row, "privilege", "PRIVILEGE") ?? "",
854
- grantedOn: readStringField(row, "granted_on", "GRANTED_ON") ?? "",
855
- objectName: readStringField(row, "name", "NAME") ?? "",
856
- granteeName: readStringField(row, "grantee_name", "GRANTEE_NAME") ?? "",
857
- granteeType: readStringField(row, "granted_to", "GRANTED_TO"),
858
- change,
859
- identity,
860
- detectedAt,
861
- row
862
- };
863
- }
864
- function grantsChanged(input) {
865
- return bindSnowflakePollingTrigger(grantsChangedDefinition, input, input);
866
- }
867
- const warehouseCreditsBatchSchema = z.object({
868
- events: z.array(warehouseCreditsEventSchema),
869
- highWaterValue: z.string().nullable(),
870
- fetchedAt: z.string()
871
- }).catchall(z.unknown());
872
- const warehouseQueueBatchSchema = z.object({
873
- events: z.array(warehouseQueueEventSchema),
874
- highWaterValue: z.string().nullable(),
875
- fetchedAt: z.string()
876
- }).catchall(z.unknown());
877
- const warehouseCreditsUsageDefinition = defineSnowflakePollingTrigger({
878
- responseSchema: warehouseCreditsBatchSchema,
879
- defaultId: "snowflake.warehouse_credits_usage",
880
- defaultDescription: "Tails INFORMATION_SCHEMA.WAREHOUSE_METERING_HISTORY and emits per-warehouse credit buckets above an optional minimum.",
881
- defaultSchedule: "5m",
882
- poll: async (params, credentials, ctx) => {
883
- const client = createSnowflakeClient(credentials);
884
- const limit = params.limit ?? 200;
885
- const priorHighWater = ctx.lastResponse?.highWaterValue ?? null;
886
- const lookbackMinutes = params.lookbackMinutes ?? 60;
887
- const args = [`DATE_RANGE_START => TO_TIMESTAMP_LTZ(${quoteLiteral(priorHighWater ?? (/* @__PURE__ */ new Date(Date.now() - lookbackMinutes * 6e4)).toISOString())})`];
888
- if (params.warehouseName) args.push(`WAREHOUSE_NAME => ${quoteLiteral(params.warehouseName)}`);
889
- const clauses = [];
890
- if (params.minimum !== void 0) clauses.push(`CREDITS_USED >= ${Number(params.minimum)}`);
891
- const where = clauses.length > 0 ? ` WHERE ${clauses.join(" AND ")}` : "";
892
- const rows = (await executeSql(client, {
893
- statement: `SELECT * FROM TABLE(INFORMATION_SCHEMA.WAREHOUSE_METERING_HISTORY(${args.join(", ")}))${where} ORDER BY END_TIME ASC LIMIT ${Number(limit)}`,
894
- warehouse: params.warehouse,
895
- role: params.role,
896
- database: params.database,
897
- schema: params.schema
898
- })).rows;
899
- const events = rows.map((row) => ({
900
- warehouseName: readStringField(row, "WAREHOUSE_NAME", "warehouse_name") ?? "",
901
- startTime: readStringField(row, "START_TIME", "start_time"),
902
- endTime: readStringField(row, "END_TIME", "end_time"),
903
- creditsUsed: readNumberField(row, "CREDITS_USED", "credits_used") ?? null,
904
- creditsUsedCompute: readNumberField(row, "CREDITS_USED_COMPUTE", "credits_used_compute") ?? null,
905
- creditsUsedCloudServices: readNumberField(row, "CREDITS_USED_CLOUD_SERVICES", "credits_used_cloud_services") ?? null,
906
- row
907
- }));
908
- const last = rows[rows.length - 1];
909
- return {
910
- events,
911
- highWaterValue: readStringField(last ?? {}, "END_TIME", "end_time") ?? priorHighWater,
912
- fetchedAt: isoNow()
913
- };
914
- }
915
- });
916
- const warehouseQueueDepthDefinition = defineSnowflakePollingTrigger({
917
- responseSchema: warehouseQueueBatchSchema,
918
- defaultId: "snowflake.warehouse_queue_depth",
919
- defaultDescription: "Tails INFORMATION_SCHEMA.WAREHOUSE_LOAD_HISTORY and emits per-interval queue depth above an optional minimum.",
920
- defaultSchedule: "5m",
921
- poll: async (params, credentials, ctx) => {
922
- const client = createSnowflakeClient(credentials);
923
- const limit = params.limit ?? 200;
924
- const priorHighWater = ctx.lastResponse?.highWaterValue ?? null;
925
- const lookbackMinutes = params.lookbackMinutes ?? 60;
926
- const args = [`DATE_RANGE_START => TO_TIMESTAMP_LTZ(${quoteLiteral(priorHighWater ?? (/* @__PURE__ */ new Date(Date.now() - lookbackMinutes * 6e4)).toISOString())})`];
927
- if (params.warehouseName) args.push(`WAREHOUSE_NAME => ${quoteLiteral(params.warehouseName)}`);
928
- const clauses = [];
929
- if (params.minimum !== void 0) clauses.push(`AVG_QUEUED_LOAD >= ${Number(params.minimum)}`);
930
- const where = clauses.length > 0 ? ` WHERE ${clauses.join(" AND ")}` : "";
931
- const rows = (await executeSql(client, {
932
- statement: `SELECT * FROM TABLE(INFORMATION_SCHEMA.WAREHOUSE_LOAD_HISTORY(${args.join(", ")}))${where} ORDER BY END_TIME ASC LIMIT ${Number(limit)}`,
933
- warehouse: params.warehouse,
934
- role: params.role,
935
- database: params.database,
936
- schema: params.schema
937
- })).rows;
938
- const events = rows.map((row) => ({
939
- warehouseName: readStringField(row, "WAREHOUSE_NAME", "warehouse_name") ?? "",
940
- startTime: readStringField(row, "START_TIME", "start_time"),
941
- endTime: readStringField(row, "END_TIME", "end_time"),
942
- avgRunning: readNumberField(row, "AVG_RUNNING", "avg_running") ?? null,
943
- avgQueuedLoad: readNumberField(row, "AVG_QUEUED_LOAD", "avg_queued_load") ?? null,
944
- avgQueuedProvisioning: readNumberField(row, "AVG_QUEUED_PROVISIONING", "avg_queued_provisioning") ?? null,
945
- avgBlocked: readNumberField(row, "AVG_BLOCKED", "avg_blocked") ?? null,
946
- row
947
- }));
948
- const last = rows[rows.length - 1];
949
- return {
950
- events,
951
- highWaterValue: readStringField(last ?? {}, "END_TIME", "end_time") ?? priorHighWater,
952
- fetchedAt: isoNow()
953
- };
954
- }
955
- });
956
- function warehouseCreditsUsage(input) {
957
- return bindSnowflakePollingTrigger(warehouseCreditsUsageDefinition, input ?? {}, input);
958
- }
959
- function warehouseQueueDepth(input) {
960
- return bindSnowflakePollingTrigger(warehouseQueueDepthDefinition, input ?? {}, input);
961
- }
962
- const statusPageIncidentBatchSchema = buildDiffBatchSchema(statusPageIncidentEventSchema);
963
- const statusPageComponentChangeBatchSchema = buildDiffBatchSchema(statusPageComponentChangeEventSchema);
964
- function incidentToEntry(incident) {
965
- const row = incident;
966
- return {
967
- identity: `INCIDENT::${incident.id}`,
968
- signature: `${incident.status}|${incident.updated_at}`,
969
- row
970
- };
971
- }
972
- function componentToEntry(component) {
973
- const row = component;
974
- return {
975
- identity: `COMPONENT::${component.id}`,
976
- signature: component.status,
977
- row
978
- };
979
- }
980
- function extractStatusPageOptions(params) {
981
- const opts = {};
982
- if (params.baseUrl !== void 0) opts.baseUrl = params.baseUrl;
983
- if (params.fetchImpl !== void 0) opts.fetchImpl = params.fetchImpl;
984
- if (params.timeoutMs !== void 0) opts.timeoutMs = params.timeoutMs;
985
- if (params.headers !== void 0) opts.headers = params.headers;
986
- if (params.signal !== void 0) opts.signal = params.signal;
987
- return opts;
988
- }
989
- const statusPageIncidentDefinition = {
990
- responseSchema: statusPageIncidentBatchSchema,
991
- defaultId: "snowflake.status_page_incident",
992
- defaultDescription: "Polls https://status.snowflake.com/api/v2/incidents/unresolved.json and emits newly-appearing or status-changed incidents.",
993
- defaultSchedule: "5m",
994
- poll: async (params, _credentials, ctx) => {
995
- const current = (await getUnresolvedIncidents(extractStatusPageOptions(params))).incidents.map(incidentToEntry);
996
- const previousSnapshot = ctx.lastResponse?.snapshot;
997
- const detectedAt = isoNow();
998
- const events = [];
999
- const prevMap = new Map((previousSnapshot ?? []).map((p) => [p.identity, p]));
1000
- const emitAll = previousSnapshot === void 0 && params.emitInitialSnapshot;
1001
- if (previousSnapshot === void 0 && !emitAll) {} else for (const entry of current) {
1002
- const prev = prevMap.get(entry.identity);
1003
- if (prev === void 0 || prev.signature !== entry.signature) {
1004
- const incident = entry.row;
1005
- events.push({
1006
- id: incident.id,
1007
- name: incident.name,
1008
- status: incident.status,
1009
- impact: incident.impact,
1010
- createdAt: incident.created_at,
1011
- updatedAt: incident.updated_at,
1012
- resolvedAt: incident.resolved_at ?? null,
1013
- shortlink: incident.shortlink,
1014
- detectedAt,
1015
- raw: entry.row
1016
- });
1017
- }
1018
- }
1019
- return {
1020
- events,
1021
- snapshot: toSnapshotEntries(current),
1022
- fetchedAt: detectedAt
1023
- };
1024
- }
1025
- };
1026
- const statusPageComponentChangeDefinition = {
1027
- responseSchema: statusPageComponentChangeBatchSchema,
1028
- defaultId: "snowflake.status_page_component_changed",
1029
- defaultDescription: "Polls https://status.snowflake.com/api/v2/summary.json and emits a change event when any component transitions status.",
1030
- defaultSchedule: "2m",
1031
- poll: async (params, _credentials, ctx) => {
1032
- const current = ((await getStatusSummary(extractStatusPageOptions(params))).components ?? []).map(componentToEntry);
1033
- const previousSnapshot = ctx.lastResponse?.snapshot;
1034
- const detectedAt = isoNow();
1035
- const events = [];
1036
- if (previousSnapshot !== void 0) {
1037
- const prevMap = new Map(previousSnapshot.map((p) => [p.identity, p]));
1038
- for (const entry of current) {
1039
- const prevStatus = prevMap.get(entry.identity)?.signature ?? null;
1040
- if (prevStatus !== entry.signature) {
1041
- const component = entry.row;
1042
- events.push({
1043
- id: component.id,
1044
- name: component.name,
1045
- previousStatus: prevStatus,
1046
- currentStatus: component.status,
1047
- description: component.description ?? void 0,
1048
- changedAt: component.updated_at ?? detectedAt,
1049
- detectedAt,
1050
- raw: entry.row
1051
- });
1052
- }
1053
- }
1054
- }
1055
- return {
1056
- events,
1057
- snapshot: toSnapshotEntries(current),
1058
- fetchedAt: detectedAt
1059
- };
1060
- }
1061
- };
1062
- /**
1063
- * Status-page pollers don't need Snowflake credentials, but they still
1064
- * flow through the Snowflake binding factory so they show up in the
1065
- * polling manifest alongside the rest. Credentials are declared but
1066
- * unused — the poll callback ignores `ctx.credentials['snowflake']`.
1067
- */
1068
- function statusPageIncident(input) {
1069
- return bindSnowflakePollingTrigger(statusPageIncidentDefinition, input ?? {}, input);
1070
- }
1071
- function statusPageComponentChanged(input) {
1072
- return bindSnowflakePollingTrigger(statusPageComponentChangeDefinition, input ?? {}, input);
1073
- }
1074
- const polling = Object.freeze({
1075
- streamHasNewRows,
1076
- streamAppendOnly,
1077
- scheduledSql,
1078
- scheduledDelta,
1079
- taskRunCompleted,
1080
- statementCompleted,
1081
- pipeLoadCompleted,
1082
- pipeLoadFailed,
1083
- userCreated,
1084
- userDropped,
1085
- roleCreated,
1086
- roleDropped,
1087
- databaseCreated,
1088
- databaseDropped,
1089
- tableCreated,
1090
- tableDropped,
1091
- shareChanged,
1092
- grantsChanged,
1093
- warehouseCreditsUsage,
1094
- warehouseQueueDepth,
1095
- statusPageIncident,
1096
- statusPageComponentChanged
1097
- });
1098
-
1099
- //#endregion
1100
- export { databaseCreated, databaseDropped, grantsChanged, pipeLoadCompleted, pipeLoadFailed, polling, roleCreated, roleDropped, scheduledDelta, scheduledSql, shareChanged, statementCompleted, statusPageComponentChanged, statusPageIncident, streamAppendOnly, streamHasNewRows, tableCreated, tableDropped, taskRunCompleted, userCreated, userDropped, warehouseCreditsUsage, warehouseQueueDepth };