lakesync 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +74 -0
- package/dist/adapter.d.ts +369 -0
- package/dist/adapter.js +39 -0
- package/dist/adapter.js.map +1 -0
- package/dist/analyst.d.ts +268 -0
- package/dist/analyst.js +495 -0
- package/dist/analyst.js.map +1 -0
- package/dist/auth-CAVutXzx.d.ts +30 -0
- package/dist/base-poller-Qo_SmCZs.d.ts +82 -0
- package/dist/catalogue.d.ts +65 -0
- package/dist/catalogue.js +17 -0
- package/dist/catalogue.js.map +1 -0
- package/dist/chunk-4ARO6KTJ.js +257 -0
- package/dist/chunk-4ARO6KTJ.js.map +1 -0
- package/dist/chunk-5YOFCJQ7.js +1115 -0
- package/dist/chunk-5YOFCJQ7.js.map +1 -0
- package/dist/chunk-7D4SUZUM.js +38 -0
- package/dist/chunk-7D4SUZUM.js.map +1 -0
- package/dist/chunk-BNJOGBYK.js +335 -0
- package/dist/chunk-BNJOGBYK.js.map +1 -0
- package/dist/chunk-ICNT7I3K.js +1180 -0
- package/dist/chunk-ICNT7I3K.js.map +1 -0
- package/dist/chunk-P5DRFKIT.js +413 -0
- package/dist/chunk-P5DRFKIT.js.map +1 -0
- package/dist/chunk-X3RO5SYJ.js +880 -0
- package/dist/chunk-X3RO5SYJ.js.map +1 -0
- package/dist/client.d.ts +428 -0
- package/dist/client.js +2048 -0
- package/dist/client.js.map +1 -0
- package/dist/compactor.d.ts +342 -0
- package/dist/compactor.js +793 -0
- package/dist/compactor.js.map +1 -0
- package/dist/coordinator-CxckTzYW.d.ts +396 -0
- package/dist/db-types-BR6Kt4uf.d.ts +29 -0
- package/dist/gateway-D5SaaMvT.d.ts +337 -0
- package/dist/gateway-server.d.ts +306 -0
- package/dist/gateway-server.js +4663 -0
- package/dist/gateway-server.js.map +1 -0
- package/dist/gateway.d.ts +196 -0
- package/dist/gateway.js +79 -0
- package/dist/gateway.js.map +1 -0
- package/dist/hlc-DiD8QNG3.d.ts +70 -0
- package/dist/index.d.ts +245 -0
- package/dist/index.js +102 -0
- package/dist/index.js.map +1 -0
- package/dist/json-dYtqiL0F.d.ts +18 -0
- package/dist/nessie-client-DrNikVXy.d.ts +160 -0
- package/dist/parquet.d.ts +78 -0
- package/dist/parquet.js +15 -0
- package/dist/parquet.js.map +1 -0
- package/dist/proto.d.ts +434 -0
- package/dist/proto.js +67 -0
- package/dist/proto.js.map +1 -0
- package/dist/react.d.ts +147 -0
- package/dist/react.js +224 -0
- package/dist/react.js.map +1 -0
- package/dist/resolver-C3Wphi6O.d.ts +10 -0
- package/dist/result-CojzlFE2.d.ts +64 -0
- package/dist/src-QU2YLPZY.js +383 -0
- package/dist/src-QU2YLPZY.js.map +1 -0
- package/dist/src-WYBF5LOI.js +102 -0
- package/dist/src-WYBF5LOI.js.map +1 -0
- package/dist/src-WZNPHANQ.js +426 -0
- package/dist/src-WZNPHANQ.js.map +1 -0
- package/dist/types-Bs-QyOe-.d.ts +143 -0
- package/dist/types-DAQL_vU_.d.ts +118 -0
- package/dist/types-DSC_EiwR.d.ts +45 -0
- package/dist/types-V_jVu2sA.d.ts +73 -0
- package/package.json +119 -0
|
@@ -0,0 +1,383 @@
|
|
|
1
|
+
import {
|
|
2
|
+
BaseSourcePoller,
|
|
3
|
+
Err,
|
|
4
|
+
LakeSyncError,
|
|
5
|
+
Ok,
|
|
6
|
+
extractDelta
|
|
7
|
+
} from "./chunk-ICNT7I3K.js";
|
|
8
|
+
import "./chunk-7D4SUZUM.js";
|
|
9
|
+
|
|
10
|
+
// ../connector-jira/src/errors.ts
|
|
11
|
+
var JiraApiError = class extends LakeSyncError {
|
|
12
|
+
/** HTTP status code returned by Jira. */
|
|
13
|
+
statusCode;
|
|
14
|
+
/** Raw response body from Jira. */
|
|
15
|
+
responseBody;
|
|
16
|
+
constructor(statusCode, responseBody, cause) {
|
|
17
|
+
super(`Jira API error (${statusCode}): ${responseBody}`, "JIRA_API_ERROR", cause);
|
|
18
|
+
this.statusCode = statusCode;
|
|
19
|
+
this.responseBody = responseBody;
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
var JiraRateLimitError = class extends LakeSyncError {
|
|
23
|
+
/** Milliseconds to wait before retrying. */
|
|
24
|
+
retryAfterMs;
|
|
25
|
+
constructor(retryAfterMs, cause) {
|
|
26
|
+
super(`Jira rate limited \u2014 retry after ${retryAfterMs}ms`, "JIRA_RATE_LIMITED", cause);
|
|
27
|
+
this.retryAfterMs = retryAfterMs;
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
// ../connector-jira/src/client.ts
|
|
32
|
+
var MAX_RESULTS = 100;
|
|
33
|
+
var MAX_RATE_LIMIT_RETRIES = 3;
|
|
34
|
+
var DEFAULT_RETRY_AFTER_MS = 1e4;
|
|
35
|
+
var ISSUE_FIELDS = [
|
|
36
|
+
"summary",
|
|
37
|
+
"description",
|
|
38
|
+
"status",
|
|
39
|
+
"priority",
|
|
40
|
+
"assignee",
|
|
41
|
+
"reporter",
|
|
42
|
+
"labels",
|
|
43
|
+
"created",
|
|
44
|
+
"updated",
|
|
45
|
+
"project",
|
|
46
|
+
"issuetype"
|
|
47
|
+
];
|
|
48
|
+
var JiraClient = class {
|
|
49
|
+
baseUrl;
|
|
50
|
+
authHeader;
|
|
51
|
+
constructor(config) {
|
|
52
|
+
this.baseUrl = `https://${config.domain}.atlassian.net`;
|
|
53
|
+
this.authHeader = `Basic ${btoa(`${config.email}:${config.apiToken}`)}`;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Search for issues via JQL with auto-pagination.
|
|
57
|
+
*
|
|
58
|
+
* Uses the `/rest/api/3/search/jql` endpoint with token-based pagination.
|
|
59
|
+
* When `updatedSince` is provided, appends `AND updated >= "date"` to the JQL.
|
|
60
|
+
* Empty JQL is replaced with `project is not EMPTY` (the new endpoint
|
|
61
|
+
* rejects unbounded queries).
|
|
62
|
+
*
|
|
63
|
+
* @param limit — optional cap on the total number of issues returned.
|
|
64
|
+
*/
|
|
65
|
+
async searchIssues(jql, updatedSince, limit) {
|
|
66
|
+
let effectiveJql = jql || "";
|
|
67
|
+
if (updatedSince) {
|
|
68
|
+
const clause = `updated >= "${updatedSince}"`;
|
|
69
|
+
effectiveJql = effectiveJql.length > 0 ? `(${effectiveJql}) AND ${clause}` : clause;
|
|
70
|
+
}
|
|
71
|
+
if (effectiveJql.length === 0) {
|
|
72
|
+
effectiveJql = "project is not EMPTY";
|
|
73
|
+
}
|
|
74
|
+
const allIssues = [];
|
|
75
|
+
let nextPageToken;
|
|
76
|
+
const pageSize = limit !== void 0 ? Math.min(limit, MAX_RESULTS) : MAX_RESULTS;
|
|
77
|
+
while (true) {
|
|
78
|
+
const body = {
|
|
79
|
+
jql: effectiveJql,
|
|
80
|
+
maxResults: pageSize,
|
|
81
|
+
fields: ISSUE_FIELDS
|
|
82
|
+
};
|
|
83
|
+
if (nextPageToken) {
|
|
84
|
+
body.nextPageToken = nextPageToken;
|
|
85
|
+
}
|
|
86
|
+
const result = await this.request("/rest/api/3/search/jql", "POST", body);
|
|
87
|
+
if (!result.ok) return result;
|
|
88
|
+
const page = result.value;
|
|
89
|
+
for (const issue of page.issues) {
|
|
90
|
+
allIssues.push(issue);
|
|
91
|
+
}
|
|
92
|
+
if (limit !== void 0 && allIssues.length >= limit) break;
|
|
93
|
+
if (page.isLast || !page.nextPageToken) break;
|
|
94
|
+
nextPageToken = page.nextPageToken;
|
|
95
|
+
}
|
|
96
|
+
return Ok(limit !== void 0 ? allIssues.slice(0, limit) : allIssues);
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Fetch all comments for a given issue key with auto-pagination.
|
|
100
|
+
*/
|
|
101
|
+
async getComments(issueKey) {
|
|
102
|
+
const allComments = [];
|
|
103
|
+
let startAt = 0;
|
|
104
|
+
while (true) {
|
|
105
|
+
const result = await this.request(
|
|
106
|
+
`/rest/api/3/issue/${encodeURIComponent(issueKey)}/comment?startAt=${startAt}&maxResults=${MAX_RESULTS}`,
|
|
107
|
+
"GET"
|
|
108
|
+
);
|
|
109
|
+
if (!result.ok) return result;
|
|
110
|
+
const page = result.value;
|
|
111
|
+
for (const comment of page.comments) {
|
|
112
|
+
allComments.push(comment);
|
|
113
|
+
}
|
|
114
|
+
startAt += page.maxResults;
|
|
115
|
+
if (startAt >= page.total) break;
|
|
116
|
+
}
|
|
117
|
+
return Ok(allComments);
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Fetch all projects with auto-pagination.
|
|
121
|
+
*/
|
|
122
|
+
async getProjects() {
|
|
123
|
+
const allProjects = [];
|
|
124
|
+
let startAt = 0;
|
|
125
|
+
while (true) {
|
|
126
|
+
const result = await this.request(
|
|
127
|
+
`/rest/api/3/project/search?startAt=${startAt}&maxResults=${MAX_RESULTS}`,
|
|
128
|
+
"GET"
|
|
129
|
+
);
|
|
130
|
+
if (!result.ok) return result;
|
|
131
|
+
const page = result.value;
|
|
132
|
+
for (const project of page.values) {
|
|
133
|
+
allProjects.push(project);
|
|
134
|
+
}
|
|
135
|
+
startAt += page.maxResults;
|
|
136
|
+
if (startAt >= page.total) break;
|
|
137
|
+
}
|
|
138
|
+
return Ok(allProjects);
|
|
139
|
+
}
|
|
140
|
+
// -----------------------------------------------------------------------
|
|
141
|
+
// Internal HTTP helpers
|
|
142
|
+
// -----------------------------------------------------------------------
|
|
143
|
+
/** Make an HTTP request with rate-limit retry logic. */
|
|
144
|
+
async request(path, method, body) {
|
|
145
|
+
let lastError;
|
|
146
|
+
for (let attempt = 0; attempt <= MAX_RATE_LIMIT_RETRIES; attempt++) {
|
|
147
|
+
const headers = {
|
|
148
|
+
Authorization: this.authHeader,
|
|
149
|
+
Accept: "application/json"
|
|
150
|
+
};
|
|
151
|
+
const init = { method, headers };
|
|
152
|
+
if (body !== void 0) {
|
|
153
|
+
headers["Content-Type"] = "application/json";
|
|
154
|
+
init.body = JSON.stringify(body);
|
|
155
|
+
}
|
|
156
|
+
const response = await fetch(`${this.baseUrl}${path}`, init);
|
|
157
|
+
if (response.ok) {
|
|
158
|
+
const data = await response.json();
|
|
159
|
+
return Ok(data);
|
|
160
|
+
}
|
|
161
|
+
if (response.status === 429) {
|
|
162
|
+
const retryAfter = response.headers.get("Retry-After");
|
|
163
|
+
const waitMs = retryAfter ? Number.parseInt(retryAfter, 10) * 1e3 : DEFAULT_RETRY_AFTER_MS;
|
|
164
|
+
if (attempt < MAX_RATE_LIMIT_RETRIES) {
|
|
165
|
+
await sleep(waitMs);
|
|
166
|
+
lastError = new JiraApiError(429, `Rate limited, retried after ${waitMs}ms`);
|
|
167
|
+
continue;
|
|
168
|
+
}
|
|
169
|
+
return Err(new JiraRateLimitError(waitMs));
|
|
170
|
+
}
|
|
171
|
+
const responseBody = await response.text();
|
|
172
|
+
return Err(new JiraApiError(response.status, responseBody));
|
|
173
|
+
}
|
|
174
|
+
return Err(lastError ?? new JiraApiError(0, "Unknown error after retries"));
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
function sleep(ms) {
|
|
178
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// ../connector-jira/src/mapping.ts
|
|
182
|
+
function mapIssue(issue) {
|
|
183
|
+
const f = issue.fields;
|
|
184
|
+
return {
|
|
185
|
+
rowId: issue.key,
|
|
186
|
+
row: {
|
|
187
|
+
jira_id: issue.id,
|
|
188
|
+
key: issue.key,
|
|
189
|
+
summary: f.summary ?? null,
|
|
190
|
+
description: f.description != null ? JSON.stringify(f.description) : null,
|
|
191
|
+
status: f.status?.name ?? null,
|
|
192
|
+
priority: f.priority?.name ?? null,
|
|
193
|
+
issue_type: f.issuetype?.name ?? null,
|
|
194
|
+
assignee_name: f.assignee?.displayName ?? null,
|
|
195
|
+
assignee_email: f.assignee?.emailAddress ?? null,
|
|
196
|
+
reporter_name: f.reporter?.displayName ?? null,
|
|
197
|
+
reporter_email: f.reporter?.emailAddress ?? null,
|
|
198
|
+
labels: f.labels != null ? JSON.stringify(f.labels) : null,
|
|
199
|
+
project_key: f.project?.key ?? null,
|
|
200
|
+
project_name: f.project?.name ?? null,
|
|
201
|
+
created: f.created ?? null,
|
|
202
|
+
updated: f.updated ?? null
|
|
203
|
+
}
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
function mapComment(issueKey, comment) {
|
|
207
|
+
return {
|
|
208
|
+
rowId: `${issueKey}:${comment.id}`,
|
|
209
|
+
row: {
|
|
210
|
+
jira_id: comment.id,
|
|
211
|
+
issue_key: issueKey,
|
|
212
|
+
body: comment.body != null ? JSON.stringify(comment.body) : null,
|
|
213
|
+
author_name: comment.author?.displayName ?? null,
|
|
214
|
+
author_email: comment.author?.emailAddress ?? null,
|
|
215
|
+
created: comment.created ?? null,
|
|
216
|
+
updated: comment.updated ?? null
|
|
217
|
+
}
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
function mapProject(project) {
|
|
221
|
+
return {
|
|
222
|
+
rowId: project.key,
|
|
223
|
+
row: {
|
|
224
|
+
jira_id: project.id,
|
|
225
|
+
key: project.key,
|
|
226
|
+
name: project.name,
|
|
227
|
+
project_type: project.projectTypeKey ?? null,
|
|
228
|
+
lead_name: project.lead?.displayName ?? null
|
|
229
|
+
}
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// ../connector-jira/src/poller.ts
|
|
234
|
+
var DEFAULT_INTERVAL_MS = 3e4;
|
|
235
|
+
var JiraSourcePoller = class extends BaseSourcePoller {
|
|
236
|
+
connectionConfig;
|
|
237
|
+
client;
|
|
238
|
+
/** Cursor: max `fields.updated` value from the last issue poll. */
|
|
239
|
+
lastUpdated;
|
|
240
|
+
/** In-memory snapshot for comment diff (keyed by rowId). */
|
|
241
|
+
commentSnapshot = /* @__PURE__ */ new Map();
|
|
242
|
+
/** In-memory snapshot for project diff (keyed by project key). */
|
|
243
|
+
projectSnapshot = /* @__PURE__ */ new Map();
|
|
244
|
+
constructor(connectionConfig, ingestConfig, name, gateway, client) {
|
|
245
|
+
super({
|
|
246
|
+
name,
|
|
247
|
+
intervalMs: ingestConfig?.intervalMs ?? DEFAULT_INTERVAL_MS,
|
|
248
|
+
gateway,
|
|
249
|
+
memory: {
|
|
250
|
+
chunkSize: ingestConfig?.chunkSize,
|
|
251
|
+
memoryBudgetBytes: ingestConfig?.memoryBudgetBytes
|
|
252
|
+
}
|
|
253
|
+
});
|
|
254
|
+
this.connectionConfig = connectionConfig;
|
|
255
|
+
this.client = client ?? new JiraClient(connectionConfig);
|
|
256
|
+
}
|
|
257
|
+
/** Execute a single poll cycle across all entity types. */
|
|
258
|
+
async poll() {
|
|
259
|
+
const issueKeys = await this.pollIssues();
|
|
260
|
+
const includeComments = this.connectionConfig.includeComments ?? true;
|
|
261
|
+
if (includeComments && issueKeys.length > 0) {
|
|
262
|
+
await this.pollComments(issueKeys);
|
|
263
|
+
}
|
|
264
|
+
const includeProjects = this.connectionConfig.includeProjects ?? true;
|
|
265
|
+
if (includeProjects) {
|
|
266
|
+
await this.pollProjects();
|
|
267
|
+
}
|
|
268
|
+
await this.flushAccumulator();
|
|
269
|
+
}
|
|
270
|
+
// -----------------------------------------------------------------------
|
|
271
|
+
// Issues — cursor strategy via JQL `updated` field
|
|
272
|
+
// -----------------------------------------------------------------------
|
|
273
|
+
async pollIssues() {
|
|
274
|
+
const result = await this.client.searchIssues(
|
|
275
|
+
this.connectionConfig.jql ?? "",
|
|
276
|
+
this.lastUpdated
|
|
277
|
+
);
|
|
278
|
+
if (!result.ok) {
|
|
279
|
+
return [];
|
|
280
|
+
}
|
|
281
|
+
const issues = result.value;
|
|
282
|
+
if (issues.length === 0) {
|
|
283
|
+
return [];
|
|
284
|
+
}
|
|
285
|
+
const issueKeys = [];
|
|
286
|
+
let maxUpdated = this.lastUpdated;
|
|
287
|
+
for (const issue of issues) {
|
|
288
|
+
const { rowId, row } = mapIssue(issue);
|
|
289
|
+
issueKeys.push(issue.key);
|
|
290
|
+
const delta = await extractDelta(null, row, {
|
|
291
|
+
table: "jira_issues",
|
|
292
|
+
rowId,
|
|
293
|
+
clientId: this.clientId,
|
|
294
|
+
hlc: this.hlc.now()
|
|
295
|
+
});
|
|
296
|
+
if (delta) {
|
|
297
|
+
await this.accumulateDelta(delta);
|
|
298
|
+
}
|
|
299
|
+
const updated = issue.fields.updated;
|
|
300
|
+
if (updated && (!maxUpdated || updated > maxUpdated)) {
|
|
301
|
+
maxUpdated = updated;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
this.lastUpdated = maxUpdated;
|
|
305
|
+
return issueKeys;
|
|
306
|
+
}
|
|
307
|
+
// -----------------------------------------------------------------------
|
|
308
|
+
// Comments — diff per-issue
|
|
309
|
+
// -----------------------------------------------------------------------
|
|
310
|
+
async pollComments(issueKeys) {
|
|
311
|
+
for (const issueKey of issueKeys) {
|
|
312
|
+
const result = await this.client.getComments(issueKey);
|
|
313
|
+
if (!result.ok) continue;
|
|
314
|
+
const currentMap = /* @__PURE__ */ new Map();
|
|
315
|
+
for (const comment of result.value) {
|
|
316
|
+
const { rowId, row } = mapComment(issueKey, comment);
|
|
317
|
+
currentMap.set(rowId, row);
|
|
318
|
+
const previous = this.commentSnapshot.get(rowId) ?? null;
|
|
319
|
+
const delta = await extractDelta(previous, row, {
|
|
320
|
+
table: "jira_comments",
|
|
321
|
+
rowId,
|
|
322
|
+
clientId: this.clientId,
|
|
323
|
+
hlc: this.hlc.now()
|
|
324
|
+
});
|
|
325
|
+
if (delta) {
|
|
326
|
+
await this.accumulateDelta(delta);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
for (const [rowId, row] of currentMap) {
|
|
330
|
+
this.commentSnapshot.set(rowId, row);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
// -----------------------------------------------------------------------
|
|
335
|
+
// Projects — full diff
|
|
336
|
+
// -----------------------------------------------------------------------
|
|
337
|
+
async pollProjects() {
|
|
338
|
+
const result = await this.client.getProjects();
|
|
339
|
+
if (!result.ok) return;
|
|
340
|
+
const currentMap = /* @__PURE__ */ new Map();
|
|
341
|
+
for (const project of result.value) {
|
|
342
|
+
const { rowId, row } = mapProject(project);
|
|
343
|
+
currentMap.set(rowId, row);
|
|
344
|
+
}
|
|
345
|
+
const previousMap = this.projectSnapshot;
|
|
346
|
+
for (const [rowId, currentRow] of currentMap) {
|
|
347
|
+
const previousRow = previousMap.get(rowId) ?? null;
|
|
348
|
+
const delta = await extractDelta(previousRow, currentRow, {
|
|
349
|
+
table: "jira_projects",
|
|
350
|
+
rowId,
|
|
351
|
+
clientId: this.clientId,
|
|
352
|
+
hlc: this.hlc.now()
|
|
353
|
+
});
|
|
354
|
+
if (delta) {
|
|
355
|
+
await this.accumulateDelta(delta);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
for (const [rowId, previousRow] of previousMap) {
|
|
359
|
+
if (!currentMap.has(rowId)) {
|
|
360
|
+
const delta = await extractDelta(previousRow, null, {
|
|
361
|
+
table: "jira_projects",
|
|
362
|
+
rowId,
|
|
363
|
+
clientId: this.clientId,
|
|
364
|
+
hlc: this.hlc.now()
|
|
365
|
+
});
|
|
366
|
+
if (delta) {
|
|
367
|
+
await this.accumulateDelta(delta);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
this.projectSnapshot = currentMap;
|
|
372
|
+
}
|
|
373
|
+
};
|
|
374
|
+
export {
|
|
375
|
+
JiraApiError,
|
|
376
|
+
JiraClient,
|
|
377
|
+
JiraRateLimitError,
|
|
378
|
+
JiraSourcePoller,
|
|
379
|
+
mapComment,
|
|
380
|
+
mapIssue,
|
|
381
|
+
mapProject
|
|
382
|
+
};
|
|
383
|
+
//# sourceMappingURL=src-QU2YLPZY.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../connector-jira/src/errors.ts","../../connector-jira/src/client.ts","../../connector-jira/src/mapping.ts","../../connector-jira/src/poller.ts"],"sourcesContent":["import { LakeSyncError } from \"@lakesync/core\";\n\n/** HTTP error from the Jira REST API. */\nexport class JiraApiError extends LakeSyncError {\n\t/** HTTP status code returned by Jira. */\n\treadonly statusCode: number;\n\t/** Raw response body from Jira. */\n\treadonly responseBody: string;\n\n\tconstructor(statusCode: number, responseBody: string, cause?: Error) {\n\t\tsuper(`Jira API error (${statusCode}): ${responseBody}`, \"JIRA_API_ERROR\", cause);\n\t\tthis.statusCode = statusCode;\n\t\tthis.responseBody = responseBody;\n\t}\n}\n\n/** Rate limit error (HTTP 429) from the Jira REST API. */\nexport class JiraRateLimitError extends LakeSyncError {\n\t/** Milliseconds to wait before retrying. */\n\treadonly retryAfterMs: number;\n\n\tconstructor(retryAfterMs: number, cause?: Error) {\n\t\tsuper(`Jira rate limited — retry after ${retryAfterMs}ms`, \"JIRA_RATE_LIMITED\", cause);\n\t\tthis.retryAfterMs = retryAfterMs;\n\t}\n}\n","// ---------------------------------------------------------------------------\n// JiraClient — HTTP wrapper for Jira Cloud REST API v3\n// ---------------------------------------------------------------------------\n\nimport { Err, Ok, type Result } from \"@lakesync/core\";\nimport { JiraApiError, JiraRateLimitError } from \"./errors\";\nimport type {\n\tJiraComment,\n\tJiraCommentPage,\n\tJiraConnectorConfig,\n\tJiraIssue,\n\tJiraProject,\n\tJiraProjectPage,\n\tJiraSearchResponse,\n} from \"./types\";\n\nconst MAX_RESULTS = 100;\nconst MAX_RATE_LIMIT_RETRIES = 3;\nconst DEFAULT_RETRY_AFTER_MS = 10_000;\n\n/** Fields requested for issue search. */\nconst ISSUE_FIELDS = [\n\t\"summary\",\n\t\"description\",\n\t\"status\",\n\t\"priority\",\n\t\"assignee\",\n\t\"reporter\",\n\t\"labels\",\n\t\"created\",\n\t\"updated\",\n\t\"project\",\n\t\"issuetype\",\n];\n\n/**\n * HTTP client for the Jira Cloud REST API v3.\n *\n * Uses Basic authentication (email + API token) and global `fetch`.\n * All public methods return `Result<T, JiraApiError>`.\n */\nexport class JiraClient {\n\tprivate readonly baseUrl: string;\n\tprivate readonly authHeader: string;\n\n\tconstructor(config: JiraConnectorConfig) {\n\t\tthis.baseUrl = `https://${config.domain}.atlassian.net`;\n\t\tthis.authHeader = `Basic ${btoa(`${config.email}:${config.apiToken}`)}`;\n\t}\n\n\t/**\n\t * Search for issues via JQL with auto-pagination.\n\t *\n\t * Uses the `/rest/api/3/search/jql` endpoint with token-based pagination.\n\t * When `updatedSince` is provided, appends `AND updated >= \"date\"` to the JQL.\n\t * Empty JQL is replaced with `project is not EMPTY` (the new endpoint\n\t * rejects unbounded queries).\n\t *\n\t * @param limit — optional cap on the total number of issues returned.\n\t */\n\tasync searchIssues(\n\t\tjql: string,\n\t\tupdatedSince?: string,\n\t\tlimit?: number,\n\t): Promise<Result<JiraIssue[], JiraApiError | JiraRateLimitError>> {\n\t\tlet effectiveJql = jql || \"\";\n\n\t\tif (updatedSince) {\n\t\t\tconst clause = `updated >= \"${updatedSince}\"`;\n\t\t\teffectiveJql = effectiveJql.length > 0 ? `(${effectiveJql}) AND ${clause}` : clause;\n\t\t}\n\n\t\t// The /search/jql endpoint rejects unbounded queries\n\t\tif (effectiveJql.length === 0) {\n\t\t\teffectiveJql = \"project is not EMPTY\";\n\t\t}\n\n\t\tconst allIssues: JiraIssue[] = [];\n\t\tlet nextPageToken: string | undefined;\n\t\tconst pageSize = limit !== undefined ? Math.min(limit, MAX_RESULTS) : MAX_RESULTS;\n\n\t\twhile (true) {\n\t\t\tconst body: Record<string, unknown> = {\n\t\t\t\tjql: effectiveJql,\n\t\t\t\tmaxResults: pageSize,\n\t\t\t\tfields: ISSUE_FIELDS,\n\t\t\t};\n\t\t\tif (nextPageToken) {\n\t\t\t\tbody.nextPageToken = nextPageToken;\n\t\t\t}\n\n\t\t\tconst result = await this.request<JiraSearchResponse>(\"/rest/api/3/search/jql\", \"POST\", body);\n\n\t\t\tif (!result.ok) return result;\n\n\t\t\tconst page = result.value;\n\t\t\tfor (const issue of page.issues) {\n\t\t\t\tallIssues.push(issue);\n\t\t\t}\n\n\t\t\tif (limit !== undefined && allIssues.length >= limit) break;\n\t\t\tif (page.isLast || !page.nextPageToken) break;\n\t\t\tnextPageToken = page.nextPageToken;\n\t\t}\n\n\t\treturn Ok(limit !== undefined ? allIssues.slice(0, limit) : allIssues);\n\t}\n\n\t/**\n\t * Fetch all comments for a given issue key with auto-pagination.\n\t */\n\tasync getComments(\n\t\tissueKey: string,\n\t): Promise<Result<JiraComment[], JiraApiError | JiraRateLimitError>> {\n\t\tconst allComments: JiraComment[] = [];\n\t\tlet startAt = 0;\n\n\t\twhile (true) {\n\t\t\tconst result = await this.request<JiraCommentPage>(\n\t\t\t\t`/rest/api/3/issue/${encodeURIComponent(issueKey)}/comment?startAt=${startAt}&maxResults=${MAX_RESULTS}`,\n\t\t\t\t\"GET\",\n\t\t\t);\n\n\t\t\tif (!result.ok) return result;\n\n\t\t\tconst page = result.value;\n\t\t\tfor (const comment of page.comments) {\n\t\t\t\tallComments.push(comment);\n\t\t\t}\n\n\t\t\tstartAt += page.maxResults;\n\t\t\tif (startAt >= page.total) break;\n\t\t}\n\n\t\treturn Ok(allComments);\n\t}\n\n\t/**\n\t * Fetch all projects with auto-pagination.\n\t */\n\tasync getProjects(): Promise<Result<JiraProject[], JiraApiError | JiraRateLimitError>> {\n\t\tconst allProjects: JiraProject[] = [];\n\t\tlet startAt = 0;\n\n\t\twhile (true) {\n\t\t\tconst result = await this.request<JiraProjectPage>(\n\t\t\t\t`/rest/api/3/project/search?startAt=${startAt}&maxResults=${MAX_RESULTS}`,\n\t\t\t\t\"GET\",\n\t\t\t);\n\n\t\t\tif (!result.ok) return result;\n\n\t\t\tconst page = result.value;\n\t\t\tfor (const project of page.values) {\n\t\t\t\tallProjects.push(project);\n\t\t\t}\n\n\t\t\tstartAt += page.maxResults;\n\t\t\tif (startAt >= page.total) break;\n\t\t}\n\n\t\treturn Ok(allProjects);\n\t}\n\n\t// -----------------------------------------------------------------------\n\t// Internal HTTP helpers\n\t// -----------------------------------------------------------------------\n\n\t/** Make an HTTP request with rate-limit retry logic. */\n\tprivate async request<T>(\n\t\tpath: string,\n\t\tmethod: \"GET\" | \"POST\",\n\t\tbody?: unknown,\n\t): Promise<Result<T, JiraApiError | JiraRateLimitError>> {\n\t\tlet lastError: JiraApiError | undefined;\n\n\t\tfor (let attempt = 0; attempt <= MAX_RATE_LIMIT_RETRIES; attempt++) {\n\t\t\tconst headers: Record<string, string> = {\n\t\t\t\tAuthorization: this.authHeader,\n\t\t\t\tAccept: \"application/json\",\n\t\t\t};\n\n\t\t\tconst init: RequestInit = { method, headers };\n\n\t\t\tif (body !== undefined) {\n\t\t\t\theaders[\"Content-Type\"] = \"application/json\";\n\t\t\t\tinit.body = JSON.stringify(body);\n\t\t\t}\n\n\t\t\tconst response = await fetch(`${this.baseUrl}${path}`, init);\n\n\t\t\tif (response.ok) {\n\t\t\t\tconst data = (await response.json()) as T;\n\t\t\t\treturn Ok(data);\n\t\t\t}\n\n\t\t\tif (response.status === 429) {\n\t\t\t\tconst retryAfter = response.headers.get(\"Retry-After\");\n\t\t\t\tconst waitMs = retryAfter ? Number.parseInt(retryAfter, 10) * 1000 : DEFAULT_RETRY_AFTER_MS;\n\n\t\t\t\tif (attempt < MAX_RATE_LIMIT_RETRIES) {\n\t\t\t\t\tawait sleep(waitMs);\n\t\t\t\t\tlastError = new JiraApiError(429, `Rate limited, retried after ${waitMs}ms`);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\treturn Err(new JiraRateLimitError(waitMs));\n\t\t\t}\n\n\t\t\tconst responseBody = await response.text();\n\t\t\treturn Err(new JiraApiError(response.status, responseBody));\n\t\t}\n\n\t\treturn Err(lastError ?? new JiraApiError(0, \"Unknown error after retries\"));\n\t}\n}\n\n/** Sleep for the given number of milliseconds. */\nfunction sleep(ms: number): Promise<void> {\n\treturn new Promise((resolve) => setTimeout(resolve, ms));\n}\n","// ---------------------------------------------------------------------------\n// Jira Entity → Flat LakeSync Row Mapping\n// ---------------------------------------------------------------------------\n\nimport type { JiraComment, JiraIssue, JiraProject } from \"./types\";\n\n/**\n * Map a Jira issue to a flat row for the `jira_issues` table.\n *\n * The row ID is the issue key (e.g. \"PROJ-123\").\n */\nexport function mapIssue(issue: JiraIssue): { rowId: string; row: Record<string, unknown> } {\n\tconst f = issue.fields;\n\treturn {\n\t\trowId: issue.key,\n\t\trow: {\n\t\t\tjira_id: issue.id,\n\t\t\tkey: issue.key,\n\t\t\tsummary: f.summary ?? null,\n\t\t\tdescription: f.description != null ? JSON.stringify(f.description) : null,\n\t\t\tstatus: f.status?.name ?? null,\n\t\t\tpriority: f.priority?.name ?? null,\n\t\t\tissue_type: f.issuetype?.name ?? null,\n\t\t\tassignee_name: f.assignee?.displayName ?? null,\n\t\t\tassignee_email: f.assignee?.emailAddress ?? null,\n\t\t\treporter_name: f.reporter?.displayName ?? null,\n\t\t\treporter_email: f.reporter?.emailAddress ?? null,\n\t\t\tlabels: f.labels != null ? JSON.stringify(f.labels) : null,\n\t\t\tproject_key: f.project?.key ?? null,\n\t\t\tproject_name: f.project?.name ?? null,\n\t\t\tcreated: f.created ?? null,\n\t\t\tupdated: f.updated ?? null,\n\t\t},\n\t};\n}\n\n/**\n * Map a Jira comment to a flat row for the `jira_comments` table.\n *\n * The row ID is \"{issueKey}:{commentId}\".\n */\nexport function mapComment(\n\tissueKey: string,\n\tcomment: JiraComment,\n): { rowId: string; row: Record<string, unknown> } {\n\treturn {\n\t\trowId: `${issueKey}:${comment.id}`,\n\t\trow: {\n\t\t\tjira_id: comment.id,\n\t\t\tissue_key: issueKey,\n\t\t\tbody: comment.body != null ? JSON.stringify(comment.body) : null,\n\t\t\tauthor_name: comment.author?.displayName ?? null,\n\t\t\tauthor_email: comment.author?.emailAddress ?? null,\n\t\t\tcreated: comment.created ?? null,\n\t\t\tupdated: comment.updated ?? null,\n\t\t},\n\t};\n}\n\n/**\n * Map a Jira project to a flat row for the `jira_projects` table.\n *\n * The row ID is the project key (e.g. \"PROJ\").\n */\nexport function mapProject(project: JiraProject): { rowId: string; row: Record<string, unknown> } {\n\treturn {\n\t\trowId: project.key,\n\t\trow: {\n\t\t\tjira_id: project.id,\n\t\t\tkey: project.key,\n\t\t\tname: project.name,\n\t\t\tproject_type: project.projectTypeKey ?? null,\n\t\t\tlead_name: project.lead?.displayName ?? null,\n\t\t},\n\t};\n}\n","// ---------------------------------------------------------------------------\n// JiraSourcePoller — polls Jira Cloud and pushes deltas to SyncGateway\n// ---------------------------------------------------------------------------\n\nimport { BaseSourcePoller, extractDelta, type PushTarget } from \"@lakesync/core\";\nimport { JiraClient } from \"./client\";\nimport { mapComment, mapIssue, mapProject } from \"./mapping\";\nimport type { JiraConnectorConfig, JiraIngestConfig } from \"./types\";\n\nconst DEFAULT_INTERVAL_MS = 30_000;\n\n/**\n * Polls Jira Cloud for issues, comments, and projects and pushes\n * detected changes into a gateway via streaming accumulation.\n *\n * Uses {@link BaseSourcePoller.accumulateDelta} to push deltas in\n * memory-bounded chunks instead of collecting all deltas in a single array.\n */\nexport class JiraSourcePoller extends BaseSourcePoller {\n\tprivate readonly connectionConfig: JiraConnectorConfig;\n\tprivate readonly client: JiraClient;\n\n\t/** Cursor: max `fields.updated` value from the last issue poll. */\n\tprivate lastUpdated: string | undefined;\n\n\t/** In-memory snapshot for comment diff (keyed by rowId). */\n\tprivate commentSnapshot = new Map<string, Record<string, unknown>>();\n\n\t/** In-memory snapshot for project diff (keyed by project key). */\n\tprivate projectSnapshot = new Map<string, Record<string, unknown>>();\n\n\tconstructor(\n\t\tconnectionConfig: JiraConnectorConfig,\n\t\tingestConfig: JiraIngestConfig | undefined,\n\t\tname: string,\n\t\tgateway: PushTarget,\n\t\tclient?: JiraClient,\n\t) {\n\t\tsuper({\n\t\t\tname,\n\t\t\tintervalMs: ingestConfig?.intervalMs ?? DEFAULT_INTERVAL_MS,\n\t\t\tgateway,\n\t\t\tmemory: {\n\t\t\t\tchunkSize: ingestConfig?.chunkSize,\n\t\t\t\tmemoryBudgetBytes: ingestConfig?.memoryBudgetBytes,\n\t\t\t},\n\t\t});\n\t\tthis.connectionConfig = connectionConfig;\n\t\tthis.client = client ?? new JiraClient(connectionConfig);\n\t}\n\n\t/** Execute a single poll cycle across all entity types. */\n\tasync poll(): Promise<void> {\n\t\t// 1. Issues (cursor strategy via `updated` field)\n\t\tconst issueKeys = await this.pollIssues();\n\n\t\t// 2. Comments (diff per-issue, only for issues returned in this poll)\n\t\tconst includeComments = this.connectionConfig.includeComments ?? true;\n\t\tif (includeComments && issueKeys.length > 0) {\n\t\t\tawait this.pollComments(issueKeys);\n\t\t}\n\n\t\t// 3. Projects (full diff)\n\t\tconst includeProjects = this.connectionConfig.includeProjects ?? true;\n\t\tif (includeProjects) {\n\t\t\tawait this.pollProjects();\n\t\t}\n\n\t\tawait this.flushAccumulator();\n\t}\n\n\t// -----------------------------------------------------------------------\n\t// Issues — cursor strategy via JQL `updated` field\n\t// -----------------------------------------------------------------------\n\n\tprivate async pollIssues(): Promise<string[]> {\n\t\tconst result = await this.client.searchIssues(\n\t\t\tthis.connectionConfig.jql ?? \"\",\n\t\t\tthis.lastUpdated,\n\t\t);\n\n\t\tif (!result.ok) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst issues = result.value;\n\t\tif (issues.length === 0) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst issueKeys: string[] = [];\n\t\tlet maxUpdated = this.lastUpdated;\n\n\t\tfor (const issue of issues) {\n\t\t\tconst { rowId, row } = mapIssue(issue);\n\t\t\tissueKeys.push(issue.key);\n\n\t\t\tconst delta = await extractDelta(null, row, {\n\t\t\t\ttable: \"jira_issues\",\n\t\t\t\trowId,\n\t\t\t\tclientId: this.clientId,\n\t\t\t\thlc: this.hlc.now(),\n\t\t\t});\n\n\t\t\tif (delta) {\n\t\t\t\tawait this.accumulateDelta(delta);\n\t\t\t}\n\n\t\t\t// Track max updated timestamp for cursor advancement\n\t\t\tconst updated = issue.fields.updated;\n\t\t\tif (updated && (!maxUpdated || updated > maxUpdated)) {\n\t\t\t\tmaxUpdated = updated;\n\t\t\t}\n\t\t}\n\n\t\tthis.lastUpdated = maxUpdated;\n\t\treturn issueKeys;\n\t}\n\n\t// -----------------------------------------------------------------------\n\t// Comments — diff per-issue\n\t// -----------------------------------------------------------------------\n\n\tprivate async pollComments(issueKeys: string[]): Promise<void> {\n\t\tfor (const issueKey of issueKeys) {\n\t\t\tconst result = await this.client.getComments(issueKey);\n\t\t\tif (!result.ok) continue;\n\n\t\t\tconst currentMap = new Map<string, Record<string, unknown>>();\n\n\t\t\tfor (const comment of result.value) {\n\t\t\t\tconst { rowId, row } = mapComment(issueKey, comment);\n\t\t\t\tcurrentMap.set(rowId, row);\n\n\t\t\t\tconst previous = this.commentSnapshot.get(rowId) ?? null;\n\t\t\t\tconst delta = await extractDelta(previous, row, {\n\t\t\t\t\ttable: \"jira_comments\",\n\t\t\t\t\trowId,\n\t\t\t\t\tclientId: this.clientId,\n\t\t\t\t\thlc: this.hlc.now(),\n\t\t\t\t});\n\n\t\t\t\tif (delta) {\n\t\t\t\t\tawait this.accumulateDelta(delta);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Update snapshot for this issue's comments\n\t\t\tfor (const [rowId, row] of currentMap) {\n\t\t\t\tthis.commentSnapshot.set(rowId, row);\n\t\t\t}\n\t\t}\n\t}\n\n\t// -----------------------------------------------------------------------\n\t// Projects — full diff\n\t// -----------------------------------------------------------------------\n\n\tprivate async pollProjects(): Promise<void> {\n\t\tconst result = await this.client.getProjects();\n\t\tif (!result.ok) return;\n\n\t\tconst currentMap = new Map<string, Record<string, unknown>>();\n\n\t\tfor (const project of result.value) {\n\t\t\tconst { rowId, row } = mapProject(project);\n\t\t\tcurrentMap.set(rowId, row);\n\t\t}\n\n\t\tconst previousMap = this.projectSnapshot;\n\n\t\t// Detect inserts and updates\n\t\tfor (const [rowId, currentRow] of currentMap) {\n\t\t\tconst previousRow = previousMap.get(rowId) ?? null;\n\n\t\t\tconst delta = await extractDelta(previousRow, currentRow, {\n\t\t\t\ttable: \"jira_projects\",\n\t\t\t\trowId,\n\t\t\t\tclientId: this.clientId,\n\t\t\t\thlc: this.hlc.now(),\n\t\t\t});\n\n\t\t\tif (delta) {\n\t\t\t\tawait this.accumulateDelta(delta);\n\t\t\t}\n\t\t}\n\n\t\t// Detect deletes: rows in previous snapshot missing from current\n\t\tfor (const [rowId, previousRow] of previousMap) {\n\t\t\tif (!currentMap.has(rowId)) {\n\t\t\t\tconst delta = await extractDelta(previousRow, null, {\n\t\t\t\t\ttable: \"jira_projects\",\n\t\t\t\t\trowId,\n\t\t\t\t\tclientId: this.clientId,\n\t\t\t\t\thlc: this.hlc.now(),\n\t\t\t\t});\n\n\t\t\t\tif (delta) {\n\t\t\t\t\tawait this.accumulateDelta(delta);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Replace snapshot\n\t\tthis.projectSnapshot = currentMap;\n\t}\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ActionExecutionError,
|
|
3
|
+
ActionNotSupportedError,
|
|
4
|
+
ActionValidationError,
|
|
5
|
+
AdapterError,
|
|
6
|
+
AdapterNotFoundError,
|
|
7
|
+
AuthError,
|
|
8
|
+
BackpressureError,
|
|
9
|
+
BaseSourcePoller,
|
|
10
|
+
CONNECTOR_TYPES,
|
|
11
|
+
ClockDriftError,
|
|
12
|
+
ConflictError,
|
|
13
|
+
ConnectorValidationError,
|
|
14
|
+
Err,
|
|
15
|
+
FlushError,
|
|
16
|
+
HLC,
|
|
17
|
+
LWWResolver,
|
|
18
|
+
LakeSyncError,
|
|
19
|
+
Ok,
|
|
20
|
+
SchemaError,
|
|
21
|
+
SyncRuleError,
|
|
22
|
+
applyDelta,
|
|
23
|
+
assertValidIdentifier,
|
|
24
|
+
bigintReplacer,
|
|
25
|
+
bigintReviver,
|
|
26
|
+
createPassAllRules,
|
|
27
|
+
createUserScopedRules,
|
|
28
|
+
deltaMatchesBucket,
|
|
29
|
+
extractDelta,
|
|
30
|
+
filterDeltas,
|
|
31
|
+
flatMapResult,
|
|
32
|
+
fromPromise,
|
|
33
|
+
generateActionId,
|
|
34
|
+
isActionError,
|
|
35
|
+
isActionHandler,
|
|
36
|
+
isIngestTarget,
|
|
37
|
+
isValidIdentifier,
|
|
38
|
+
mapResult,
|
|
39
|
+
quoteIdentifier,
|
|
40
|
+
resolveClientBuckets,
|
|
41
|
+
resolveFilterValue,
|
|
42
|
+
resolveLWW,
|
|
43
|
+
rowKey,
|
|
44
|
+
toError,
|
|
45
|
+
unwrapOrThrow,
|
|
46
|
+
validateAction,
|
|
47
|
+
validateConnectorConfig,
|
|
48
|
+
validateSyncRules,
|
|
49
|
+
verifyToken
|
|
50
|
+
} from "./chunk-ICNT7I3K.js";
|
|
51
|
+
import "./chunk-7D4SUZUM.js";
|
|
52
|
+
export {
|
|
53
|
+
ActionExecutionError,
|
|
54
|
+
ActionNotSupportedError,
|
|
55
|
+
ActionValidationError,
|
|
56
|
+
AdapterError,
|
|
57
|
+
AdapterNotFoundError,
|
|
58
|
+
AuthError,
|
|
59
|
+
BackpressureError,
|
|
60
|
+
BaseSourcePoller,
|
|
61
|
+
CONNECTOR_TYPES,
|
|
62
|
+
ClockDriftError,
|
|
63
|
+
ConflictError,
|
|
64
|
+
ConnectorValidationError,
|
|
65
|
+
Err,
|
|
66
|
+
FlushError,
|
|
67
|
+
HLC,
|
|
68
|
+
LWWResolver,
|
|
69
|
+
LakeSyncError,
|
|
70
|
+
Ok,
|
|
71
|
+
SchemaError,
|
|
72
|
+
SyncRuleError,
|
|
73
|
+
applyDelta,
|
|
74
|
+
assertValidIdentifier,
|
|
75
|
+
bigintReplacer,
|
|
76
|
+
bigintReviver,
|
|
77
|
+
createPassAllRules,
|
|
78
|
+
createUserScopedRules,
|
|
79
|
+
deltaMatchesBucket,
|
|
80
|
+
extractDelta,
|
|
81
|
+
filterDeltas,
|
|
82
|
+
flatMapResult,
|
|
83
|
+
fromPromise,
|
|
84
|
+
generateActionId,
|
|
85
|
+
isActionError,
|
|
86
|
+
isActionHandler,
|
|
87
|
+
isIngestTarget,
|
|
88
|
+
isValidIdentifier,
|
|
89
|
+
mapResult,
|
|
90
|
+
quoteIdentifier,
|
|
91
|
+
resolveClientBuckets,
|
|
92
|
+
resolveFilterValue,
|
|
93
|
+
resolveLWW,
|
|
94
|
+
rowKey,
|
|
95
|
+
toError,
|
|
96
|
+
unwrapOrThrow,
|
|
97
|
+
validateAction,
|
|
98
|
+
validateConnectorConfig,
|
|
99
|
+
validateSyncRules,
|
|
100
|
+
verifyToken
|
|
101
|
+
};
|
|
102
|
+
//# sourceMappingURL=src-WYBF5LOI.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|