@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.
- package/LICENSE +1 -1
- package/README.md +9 -233
- package/package.json +39 -171
- package/dist/accounts/index.d.mts +0 -40
- package/dist/accounts/index.mjs +0 -51
- package/dist/bulk/index.d.mts +0 -71
- package/dist/bulk/index.mjs +0 -65
- package/dist/catalog/index.d.mts +0 -144
- package/dist/catalog/index.mjs +0 -158
- package/dist/client/index.d.mts +0 -44
- package/dist/client/index.mjs +0 -273
- package/dist/common-DfpCwJx5.mjs +0 -92
- package/dist/credential-sets/index.d.mts +0 -3
- package/dist/credential-sets/index.mjs +0 -4
- package/dist/databases/index.d.mts +0 -2
- package/dist/databases/index.mjs +0 -3
- package/dist/errors-60AsF7Su.mjs +0 -95
- package/dist/events/index.d.mts +0 -382
- package/dist/events/index.mjs +0 -291
- package/dist/file-formats/index.d.mts +0 -39
- package/dist/file-formats/index.mjs +0 -48
- package/dist/functions/index.d.mts +0 -53
- package/dist/functions/index.mjs +0 -56
- package/dist/grants/index.d.mts +0 -93
- package/dist/grants/index.mjs +0 -102
- package/dist/index.d.mts +0 -4
- package/dist/index.mjs +0 -6
- package/dist/operations/index.d.mts +0 -1
- package/dist/operations/index.mjs +0 -1
- package/dist/org-admin/index.d.mts +0 -80
- package/dist/org-admin/index.mjs +0 -79
- package/dist/pipes/index.d.mts +0 -119
- package/dist/pipes/index.mjs +0 -106
- package/dist/procedures/index.d.mts +0 -61
- package/dist/procedures/index.mjs +0 -79
- package/dist/results/index.d.mts +0 -16
- package/dist/results/index.mjs +0 -64
- package/dist/retry-B4-9MZIp.mjs +0 -164
- package/dist/retry-w7cTp1QL.d.mts +0 -10
- package/dist/roles/index.d.mts +0 -60
- package/dist/roles/index.mjs +0 -74
- package/dist/rows/index.d.mts +0 -106
- package/dist/rows/index.mjs +0 -223
- package/dist/schemas/index.d.mts +0 -2
- package/dist/schemas/index.mjs +0 -4
- package/dist/schemas-catalog/index.d.mts +0 -2
- package/dist/schemas-catalog/index.mjs +0 -3
- package/dist/shares/index.d.mts +0 -56
- package/dist/shares/index.mjs +0 -77
- package/dist/snowflake-s3-sns-webhook.credential-set-D6bLAWy5.d.mts +0 -50
- package/dist/snowflake-s3-sns-webhook.credential-set-DzR7oWNK.mjs +0 -44
- package/dist/snowflake.credential-set-BxT7Gf3A.d.mts +0 -114
- package/dist/snowflake.credential-set-DE3gXf-a.mjs +0 -106
- package/dist/sql/index.d.mts +0 -84
- package/dist/sql/index.mjs +0 -209
- package/dist/sql-options-2k5xQ-oS.d.mts +0 -32
- package/dist/sql-options-D6GEa21F.mjs +0 -79
- package/dist/sql-safety-BZpAPsq6.mjs +0 -56
- package/dist/stages/index.d.mts +0 -64
- package/dist/stages/index.mjs +0 -81
- package/dist/statements-BumhMhN4.mjs +0 -81
- package/dist/statements-DJL0qVNA.d.mts +0 -238
- package/dist/status-page/index.d.mts +0 -510
- package/dist/status-page/index.mjs +0 -261
- package/dist/streaming/index.d.mts +0 -70
- package/dist/streaming/index.mjs +0 -56
- package/dist/streams/index.d.mts +0 -71
- package/dist/streams/index.mjs +0 -78
- package/dist/tables/index.d.mts +0 -2
- package/dist/tables/index.mjs +0 -3
- package/dist/tasks/index.d.mts +0 -79
- package/dist/tasks/index.mjs +0 -104
- package/dist/triggers/index.d.mts +0 -381
- package/dist/triggers/index.mjs +0 -1100
- package/dist/users/index.d.mts +0 -61
- package/dist/users/index.mjs +0 -67
- package/dist/verification/index.d.mts +0 -201
- package/dist/verification/index.mjs +0 -512
- package/dist/views/index.d.mts +0 -2
- package/dist/views/index.mjs +0 -3
- package/dist/warehouses/index.d.mts +0 -68
- package/dist/warehouses/index.mjs +0 -101
package/dist/triggers/index.mjs
DELETED
|
@@ -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 };
|