@useairfoil/producer-linear 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/README.md +71 -0
  2. package/dist/index.d.mts +4027 -0
  3. package/dist/index.mjs +3 -0
  4. package/dist/main.d.mts +1 -0
  5. package/dist/main.mjs +1303 -0
  6. package/dist/main.mjs.map +1 -0
  7. package/dist/manifest.d.mts +114 -0
  8. package/dist/manifest.mjs +161 -0
  9. package/dist/manifest.mjs.map +1 -0
  10. package/dist/rolldown-runtime-D7D4PA-g.mjs +13 -0
  11. package/dist/src-Ci3_ltan.mjs +1691 -0
  12. package/dist/src-Ci3_ltan.mjs.map +1 -0
  13. package/package.json +45 -7
  14. package/src/client/client.ts +200 -0
  15. package/src/connector.ts +151 -0
  16. package/src/create-table.ts +5 -0
  17. package/src/demo/index.ts +137 -0
  18. package/src/demo/initiatives.ts +116 -0
  19. package/src/demo/issues.ts +320 -0
  20. package/src/demo/projects.ts +215 -0
  21. package/src/demo/setup.ts +151 -0
  22. package/src/demo/shared.ts +122 -0
  23. package/src/demo/teams.ts +173 -0
  24. package/src/index.ts +83 -0
  25. package/src/main.ts +22 -0
  26. package/src/manifest.ts +58 -0
  27. package/src/resources/comments.ts +32 -0
  28. package/src/resources/customers.ts +105 -0
  29. package/src/resources/documents.ts +31 -0
  30. package/src/resources/initiatives.ts +136 -0
  31. package/src/resources/issue-history.ts +119 -0
  32. package/src/resources/issues.ts +131 -0
  33. package/src/resources/pages.ts +264 -0
  34. package/src/resources/projects.ts +161 -0
  35. package/src/resources/releases.ts +114 -0
  36. package/src/resources/teams.ts +140 -0
  37. package/src/sandbox.ts +35 -0
  38. package/src/schemas/comments.ts +32 -0
  39. package/src/schemas/customers.ts +80 -0
  40. package/src/schemas/documents.ts +32 -0
  41. package/src/schemas/initiatives.ts +119 -0
  42. package/src/schemas/issues.ts +180 -0
  43. package/src/schemas/projects.ts +154 -0
  44. package/src/schemas/releases.ts +119 -0
  45. package/src/schemas/shared.ts +66 -0
  46. package/src/schemas/teams.ts +144 -0
  47. package/src/start.ts +47 -0
  48. package/src/tables.ts +83 -0
  49. package/src/webhook/route.ts +50 -0
  50. package/src/webhook/signature.ts +28 -0
package/dist/main.mjs ADDED
@@ -0,0 +1,1303 @@
1
+ #!/usr/bin/env node
2
+ import { LinearConfigDef } from "./manifest.mjs";
3
+ import { A as InitiativeToProjectSchema, C as IssueHistorySchema, D as InitiativeLabelSchema, E as IssueSchema, F as CustomerStatusSchema, I as CustomerTierSchema, L as CommentSchema, M as DocumentSchema, N as CustomerNeedSchema, O as InitiativeRelationSchema, P as CustomerSchema, S as AttachmentSchema, T as IssueRelationSchema, _ as ProjectMilestoneSchema, a as CycleSchema, b as ProjectStatusSchema, c as TeamSchema, d as IssueToReleaseSchema, f as ReleaseNoteSchema, g as ProjectLabelSchema, h as ReleaseStageSchema, j as InitiativeUpdateSchema, k as InitiativeSchema, l as UserSchema, m as ReleaseSchema, o as ExternalUserSchema, p as ReleasePipelineSchema, r as layerConfig, s as TeamMembershipSchema, t as LinearConnector, u as WorkflowStateSchema, v as ProjectRelationSchema, w as IssueLabelSchema, x as ProjectUpdateSchema, y as ProjectSchema } from "./src-Ci3_ltan.mjs";
4
+ import { ConnectorApp, Demo, Ingestor, RuntimeConfig, StateStore, Telemetry } from "@useairfoil/connector-kit";
5
+ import { Config, DateTime, Duration, Effect, Layer, Logger, Schema } from "effect";
6
+ import { FetchHttpClient } from "effect/http";
7
+ import { NodeRuntime, NodeServices } from "@effect/platform-node";
8
+ import { Command } from "effect/cli";
9
+ import { PgClient } from "@effect/sql-pg";
10
+ //#region package.json
11
+ var version = "0.0.1";
12
+ //#endregion
13
+ //#region src/tables.ts
14
+ const tableSchemas = {
15
+ issues: IssueSchema,
16
+ issue_history: IssueHistorySchema,
17
+ comments: CommentSchema,
18
+ issue_relations: IssueRelationSchema,
19
+ attachments: AttachmentSchema,
20
+ issue_labels: IssueLabelSchema,
21
+ workflow_states: WorkflowStateSchema,
22
+ teams: TeamSchema,
23
+ team_memberships: TeamMembershipSchema,
24
+ users: UserSchema,
25
+ external_users: ExternalUserSchema,
26
+ cycles: CycleSchema,
27
+ projects: ProjectSchema,
28
+ project_milestones: ProjectMilestoneSchema,
29
+ project_updates: ProjectUpdateSchema,
30
+ project_statuses: ProjectStatusSchema,
31
+ project_labels: ProjectLabelSchema,
32
+ project_relations: ProjectRelationSchema,
33
+ initiatives: InitiativeSchema,
34
+ initiative_updates: InitiativeUpdateSchema,
35
+ initiative_labels: InitiativeLabelSchema,
36
+ initiative_relations: InitiativeRelationSchema,
37
+ initiative_to_projects: InitiativeToProjectSchema,
38
+ documents: DocumentSchema,
39
+ customers: CustomerSchema,
40
+ customer_needs: CustomerNeedSchema,
41
+ customer_statuses: CustomerStatusSchema,
42
+ customer_tiers: CustomerTierSchema,
43
+ releases: ReleaseSchema,
44
+ release_notes: ReleaseNoteSchema,
45
+ release_pipelines: ReleasePipelineSchema,
46
+ release_stages: ReleaseStageSchema,
47
+ issue_to_releases: IssueToReleaseSchema
48
+ };
49
+ //#endregion
50
+ //#region src/create-table.ts
51
+ const createTableCommand = ConnectorApp.makeCreateTableCommand(tableSchemas);
52
+ //#endregion
53
+ //#region src/demo/shared.ts
54
+ const hour = Duration.toMillis(Duration.hours(1));
55
+ const day = Duration.toMillis(Duration.days(1));
56
+ const workspace = "https://linear.app/acme";
57
+ const uuid = (kind, index, part = 0) => `${kind.toString(16).padStart(8, "0")}-${part.toString(16).padStart(4, "0")}-4000-8000-${index.toString(16).padStart(12, "0")}`;
58
+ const dateOnly = (date) => DateTime.formatIsoDateUtc(DateTime.fromDateUnsafe(date));
59
+ const teams = [
60
+ {
61
+ key: "ENG",
62
+ name: "Engineering",
63
+ cycles: true,
64
+ triage: false
65
+ },
66
+ {
67
+ key: "DES",
68
+ name: "Design",
69
+ cycles: true,
70
+ triage: false
71
+ },
72
+ {
73
+ key: "PRD",
74
+ name: "Product",
75
+ cycles: false,
76
+ triage: false
77
+ },
78
+ {
79
+ key: "SUP",
80
+ name: "Support",
81
+ cycles: false,
82
+ triage: true
83
+ }
84
+ ];
85
+ const states = [
86
+ {
87
+ name: "Triage",
88
+ type: "triage",
89
+ color: "#FC7840"
90
+ },
91
+ {
92
+ name: "Backlog",
93
+ type: "backlog",
94
+ color: "#BEC2C8"
95
+ },
96
+ {
97
+ name: "Todo",
98
+ type: "unstarted",
99
+ color: "#E2E2E2"
100
+ },
101
+ {
102
+ name: "In Progress",
103
+ type: "started",
104
+ color: "#F2C94C"
105
+ },
106
+ {
107
+ name: "In Review",
108
+ type: "started",
109
+ color: "#0F783C"
110
+ },
111
+ {
112
+ name: "Done",
113
+ type: "completed",
114
+ color: "#5E6AD2"
115
+ },
116
+ {
117
+ name: "Canceled",
118
+ type: "canceled",
119
+ color: "#95A2B3"
120
+ }
121
+ ];
122
+ const issueLabels = [
123
+ {
124
+ name: "Bug",
125
+ color: "#EB5757"
126
+ },
127
+ {
128
+ name: "Feature",
129
+ color: "#BB87FC"
130
+ },
131
+ {
132
+ name: "Improvement",
133
+ color: "#4EA7FC"
134
+ },
135
+ {
136
+ name: "Docs",
137
+ color: "#4CB782"
138
+ }
139
+ ];
140
+ const projectStatuses = [
141
+ {
142
+ name: "Backlog",
143
+ type: "backlog",
144
+ color: "#bec2c8"
145
+ },
146
+ {
147
+ name: "Planned",
148
+ type: "planned",
149
+ color: "#e2e2e2"
150
+ },
151
+ {
152
+ name: "In Progress",
153
+ type: "started",
154
+ color: "#f2c94c"
155
+ },
156
+ {
157
+ name: "Paused",
158
+ type: "paused",
159
+ color: "#95a2b3"
160
+ },
161
+ {
162
+ name: "Completed",
163
+ type: "completed",
164
+ color: "#5e6ad2"
165
+ },
166
+ {
167
+ name: "Canceled",
168
+ type: "canceled",
169
+ color: "#95a2b3"
170
+ }
171
+ ];
172
+ const projects = [
173
+ "Onboarding revamp",
174
+ "Billing v2",
175
+ "Mobile offline mode",
176
+ "Search relevance",
177
+ "SSO for enterprise",
178
+ "Design system 2.0",
179
+ "Usage analytics",
180
+ "API rate limits"
181
+ ];
182
+ const priorities = [
183
+ "No priority",
184
+ "Urgent",
185
+ "High",
186
+ "Medium",
187
+ "Low"
188
+ ];
189
+ const teamId = (t) => uuid(1, t);
190
+ const stateId = (t, s) => uuid(2, t, s);
191
+ const userId = (u) => uuid(3, u);
192
+ const labelId = (l) => uuid(4, l);
193
+ const projectId = (p) => uuid(5, p);
194
+ const milestoneId = (p, m) => uuid(6, p, m);
195
+ const cycleId = (t, n) => uuid(7, t, n);
196
+ const customerId = (c) => uuid(8, c);
197
+ const pipelineId = uuid(9, 0);
198
+ const releaseId = (m) => uuid(10, m);
199
+ const initiativeId = (i) => uuid(11, i);
200
+ const issueId = (index) => uuid(12, index);
201
+ const cycleStart = (now, n) => /* @__PURE__ */ new Date(now.getTime() - (26 - n) * 2 * 7 * day);
202
+ const stamp = (created, updated) => ({
203
+ version: updated,
204
+ created_at: created,
205
+ updated_at: updated,
206
+ archived_at: null
207
+ });
208
+ const nameFor = (faker) => {
209
+ const first = faker.person.firstName();
210
+ const last = faker.person.lastName();
211
+ return {
212
+ first,
213
+ last,
214
+ name: `${first} ${last}`
215
+ };
216
+ };
217
+ /** Date helpers for one run. `at` keeps a time from going past now. */
218
+ const clock = ({ faker, now }) => {
219
+ const at = (time) => new Date(Math.min(time, now.getTime()));
220
+ const later = (from, min, max) => at(from.getTime() + faker.number.int({
221
+ min,
222
+ max
223
+ }));
224
+ return {
225
+ at,
226
+ later
227
+ };
228
+ };
229
+ const verbs = [
230
+ "Fix",
231
+ "Add",
232
+ "Improve",
233
+ "Update",
234
+ "Remove",
235
+ "Support"
236
+ ];
237
+ //#endregion
238
+ //#region src/demo/issues.ts
239
+ /** One group is one issue, with its history, comments, and links. */
240
+ const issueRows = (index, context) => {
241
+ const { faker, now } = context;
242
+ const { at, later } = clock(context);
243
+ const rows = {
244
+ issues: [],
245
+ issue_history: [],
246
+ comments: [],
247
+ issue_relations: [],
248
+ attachments: [],
249
+ customer_needs: [],
250
+ issue_to_releases: []
251
+ };
252
+ const t = index % teams.length;
253
+ const team = teams[t] ?? teams[0];
254
+ const number = Math.floor(index / teams.length) + 1;
255
+ const identifier = `${team.key}-${number}`;
256
+ const id = issueId(index);
257
+ const title = `${faker.helpers.arrayElement(verbs)} ${faker.hacker.adjective()} ${faker.hacker.noun()}`;
258
+ const slug = title.toLowerCase().replaceAll(" ", "-");
259
+ const url = `${workspace}/issue/${identifier}/${slug}`;
260
+ const creator = faker.number.int({ max: 15 });
261
+ const assignee = faker.helpers.maybe(() => faker.number.int({ max: 15 }), { probability: .85 });
262
+ const created = at(now.getTime() - faker.number.int({
263
+ min: day,
264
+ max: 360 * day
265
+ }));
266
+ const outcome = faker.helpers.weightedArrayElement([
267
+ {
268
+ weight: 55,
269
+ value: "Done"
270
+ },
271
+ {
272
+ weight: 8,
273
+ value: "Canceled"
274
+ },
275
+ {
276
+ weight: 12,
277
+ value: "In Progress"
278
+ },
279
+ {
280
+ weight: 5,
281
+ value: "In Review"
282
+ },
283
+ {
284
+ weight: 10,
285
+ value: "Todo"
286
+ },
287
+ {
288
+ weight: 10,
289
+ value: "Backlog"
290
+ }
291
+ ]);
292
+ const started = outcome === "Done" || outcome === "In Progress" || outcome === "In Review" ? later(created, hour, 20 * day) : null;
293
+ const completed = outcome === "Done" && started ? later(started, hour, 14 * day) : null;
294
+ const canceled = outcome === "Canceled" ? later(created, day, 30 * day) : null;
295
+ const triaged = team.triage ? later(created, 6e4, day) : null;
296
+ const project = faker.helpers.maybe(() => faker.number.int({ max: projects.length - 1 }), { probability: .6 });
297
+ const cycleNumber = team.cycles && started ? Math.max(0, Math.min(26, 26 - Math.ceil((now.getTime() - started.getTime()) / (14 * day)))) : null;
298
+ const label = faker.number.int({ max: issueLabels.length - 1 });
299
+ const priority = faker.helpers.weightedArrayElement([
300
+ {
301
+ weight: 10,
302
+ value: 0
303
+ },
304
+ {
305
+ weight: 5,
306
+ value: 1
307
+ },
308
+ {
309
+ weight: 25,
310
+ value: 2
311
+ },
312
+ {
313
+ weight: 40,
314
+ value: 3
315
+ },
316
+ {
317
+ weight: 20,
318
+ value: 4
319
+ }
320
+ ]);
321
+ const estimate = team.key === "ENG" ? faker.helpers.arrayElement([
322
+ 1,
323
+ 2,
324
+ 3,
325
+ 5,
326
+ 8
327
+ ]) : null;
328
+ const stateIndex = states.findIndex((state) => state.name === outcome);
329
+ const changes = [{
330
+ at: created,
331
+ from: null,
332
+ to: team.triage ? 0 : 1
333
+ }];
334
+ if (triaged) changes.push({
335
+ at: triaged,
336
+ from: 0,
337
+ to: 1
338
+ });
339
+ if (started) changes.push({
340
+ at: started,
341
+ from: 1,
342
+ to: 3
343
+ });
344
+ if (outcome === "In Review" && started) changes.push({
345
+ at: later(started, day, 5 * day),
346
+ from: 3,
347
+ to: 4
348
+ });
349
+ if (completed) changes.push({
350
+ at: completed,
351
+ from: 3,
352
+ to: 5
353
+ });
354
+ if (canceled) changes.push({
355
+ at: canceled,
356
+ from: 1,
357
+ to: 6
358
+ });
359
+ if (outcome === "Todo") changes.push({
360
+ at: later(created, 6e4, 3 * day),
361
+ from: 1,
362
+ to: 2
363
+ });
364
+ changes.forEach((change, h) => {
365
+ rows.issue_history.push({
366
+ id: uuid(30, index, h),
367
+ ...stamp(change.at, change.at),
368
+ issue_id: id,
369
+ actor_id: userId(h === 0 ? creator : assignee ?? creator),
370
+ from_state_id: change.from === null ? null : stateId(t, change.from),
371
+ to_state_id: stateId(t, change.to),
372
+ from_assignee_id: null,
373
+ to_assignee_id: h === 0 && assignee !== void 0 ? userId(assignee) : null,
374
+ from_cycle_id: null,
375
+ to_cycle_id: change.to === 3 && cycleNumber !== null ? cycleId(t, cycleNumber) : null,
376
+ from_project_id: null,
377
+ to_project_id: h === 0 && project !== void 0 ? projectId(project) : null,
378
+ from_parent_id: null,
379
+ to_parent_id: null,
380
+ from_team_id: null,
381
+ to_team_id: null,
382
+ from_priority: null,
383
+ to_priority: h === 0 ? priority : null,
384
+ from_estimate: null,
385
+ to_estimate: h === 0 ? estimate : null,
386
+ from_due_date: null,
387
+ to_due_date: null,
388
+ from_title: null,
389
+ to_title: null,
390
+ added_label_ids: h === 0 ? [labelId(label)] : null,
391
+ removed_label_ids: null,
392
+ attachment_id: null,
393
+ customer_need_id: null,
394
+ to_converted_project_id: null,
395
+ updated_description: null,
396
+ archived: null,
397
+ trashed: null,
398
+ auto_archived: null,
399
+ auto_closed: null
400
+ });
401
+ });
402
+ const comments = Array.from({ length: faker.number.int({ max: 3 }) }, (_, c) => {
403
+ const posted = later(created, 6e4, 10 * day);
404
+ return {
405
+ id: uuid(31, index, c),
406
+ ...stamp(posted, posted),
407
+ _deleted: false,
408
+ body: faker.helpers.arrayElement([
409
+ "I can reproduce this on staging.",
410
+ "Picking this up now.",
411
+ "Added a fix behind a feature flag.",
412
+ "Can we pair on this tomorrow?",
413
+ "Customer confirmed it works now."
414
+ ]),
415
+ user_id: userId(faker.number.int({ max: 15 })),
416
+ external_user_id: null,
417
+ issue_id: id,
418
+ project_id: null,
419
+ project_update_id: null,
420
+ initiative_id: null,
421
+ initiative_update_id: null,
422
+ document_content_id: null,
423
+ parent_id: null,
424
+ quoted_text: null,
425
+ edited_at: null,
426
+ resolved_at: null,
427
+ resolving_user_id: null,
428
+ url: `${url}#comment-${uuid(31, index, c).slice(-8)}`
429
+ };
430
+ });
431
+ rows.comments.push(...comments);
432
+ if (index >= teams.length && faker.datatype.boolean({ probability: .1 })) rows.issue_relations.push({
433
+ id: uuid(32, index),
434
+ ...stamp(created, created),
435
+ issue_id: id,
436
+ related_issue_id: issueId(index - teams.length),
437
+ type: faker.helpers.arrayElement([
438
+ "blocks",
439
+ "related",
440
+ "duplicate"
441
+ ])
442
+ });
443
+ if (team.key === "ENG" && started) {
444
+ const prNumber = 1e3 + index;
445
+ rows.attachments.push({
446
+ id: uuid(33, index),
447
+ ...stamp(started, completed ?? started),
448
+ _deleted: false,
449
+ issue_id: id,
450
+ creator_id: assignee === void 0 ? null : userId(assignee),
451
+ external_user_creator_id: null,
452
+ title: `${title} #${prNumber}`,
453
+ subtitle: completed ? "Merged" : "Open",
454
+ url: `https://github.com/acme-labs/web/pull/${prNumber}`,
455
+ source_type: "github"
456
+ });
457
+ }
458
+ if (faker.datatype.boolean({ probability: .15 })) {
459
+ const asked = later(created, 0, 5 * day);
460
+ rows.customer_needs.push({
461
+ id: uuid(34, index),
462
+ ...stamp(asked, asked),
463
+ _deleted: false,
464
+ customer_id: customerId(faker.number.int({ max: 11 })),
465
+ issue_id: id,
466
+ project_id: null,
467
+ original_issue_id: id,
468
+ comment_id: null,
469
+ attachment_id: null,
470
+ creator_id: userId(creator),
471
+ body: "Their team asked for this on the last call.",
472
+ priority: faker.helpers.arrayElement([
473
+ 0,
474
+ 0,
475
+ 1
476
+ ]),
477
+ url: null
478
+ });
479
+ }
480
+ if (team.key === "ENG" && completed) {
481
+ const month = Math.floor((now.getTime() - completed.getTime()) / (30 * day));
482
+ if (month < 12) rows.issue_to_releases.push({
483
+ id: uuid(35, index),
484
+ ...stamp(completed, completed),
485
+ issue_id: id,
486
+ release_id: releaseId(month)
487
+ });
488
+ }
489
+ const updated = new Date(Math.max(...changes.map((change) => change.at.getTime()), ...comments.map((row) => row.created_at.getTime())));
490
+ rows.issues.push({
491
+ id,
492
+ ...stamp(created, updated),
493
+ _deleted: false,
494
+ identifier,
495
+ number,
496
+ title,
497
+ description: `${faker.hacker.phrase()}\n\n**Steps**\n\n1. Open the page\n2. Try the action\n3. See the error`,
498
+ url,
499
+ branch_name: `${identifier.toLowerCase()}-${slug}`,
500
+ priority,
501
+ priority_label: priorities[priority] ?? "No priority",
502
+ estimate,
503
+ due_date: priority === 1 ? dateOnly(new Date(created.getTime() + 7 * day)) : null,
504
+ creator_id: userId(creator),
505
+ assignee_id: assignee === void 0 ? null : userId(assignee),
506
+ delegate_id: null,
507
+ snoozed_by_id: null,
508
+ state_id: stateId(t, stateIndex),
509
+ team_id: teamId(t),
510
+ project_id: project === void 0 ? null : projectId(project),
511
+ project_milestone_id: project === void 0 ? null : milestoneId(project, faker.number.int({ max: 2 })),
512
+ cycle_id: cycleNumber === null ? null : cycleId(t, cycleNumber),
513
+ parent_id: null,
514
+ source_comment_id: null,
515
+ external_user_creator_id: null,
516
+ label_ids: [labelId(label)],
517
+ previous_identifiers: [],
518
+ started_at: started,
519
+ completed_at: completed,
520
+ canceled_at: canceled,
521
+ started_triage_at: team.triage ? created : null,
522
+ triaged_at: triaged,
523
+ auto_closed_at: null,
524
+ auto_archived_at: null,
525
+ added_to_cycle_at: cycleNumber === null ? null : started,
526
+ added_to_project_at: project === void 0 ? null : created,
527
+ added_to_team_at: created,
528
+ snoozed_until_at: null,
529
+ sla_type: null,
530
+ sla_started_at: null,
531
+ sla_breaches_at: null,
532
+ customer_ticket_count: BigInt(rows.customer_needs.length),
533
+ integration_source_type: null,
534
+ trashed: false
535
+ });
536
+ return rows;
537
+ };
538
+ //#endregion
539
+ //#region src/demo/initiatives.ts
540
+ /** Initiatives with their labels, updates, relations, and projects. */
541
+ const initiativeTables = ({ now }, founded) => {
542
+ const set = stamp(founded, founded);
543
+ const initiatives = [
544
+ "Enterprise readiness",
545
+ "Self-serve growth",
546
+ "Platform reliability"
547
+ ];
548
+ return {
549
+ initiatives: initiatives.map((name, i) => ({
550
+ id: initiativeId(i),
551
+ ...stamp(founded, now),
552
+ _deleted: false,
553
+ name,
554
+ description: `${name} for this year`,
555
+ content: null,
556
+ url: `${workspace}/initiative/${name.toLowerCase().replaceAll(" ", "-")}`,
557
+ icon: null,
558
+ color: null,
559
+ status: "Active",
560
+ health: "onTrack",
561
+ health_updated_at: /* @__PURE__ */ new Date(now.getTime() - 7 * day),
562
+ priority: BigInt(i + 1),
563
+ owner_id: userId(i),
564
+ creator_id: userId(0),
565
+ parent_initiative_id: null,
566
+ target_date: dateOnly(new Date(now.getTime() + 90 * day)),
567
+ started_at: founded,
568
+ completed_at: null,
569
+ canceled_at: null,
570
+ label_ids: [uuid(20, i % 2)],
571
+ visibility: "workspace",
572
+ trashed: false
573
+ })),
574
+ initiative_labels: ["Company goal", "Team goal"].map((name, l) => ({
575
+ id: uuid(20, l),
576
+ ...set,
577
+ name,
578
+ description: null,
579
+ color: "#5E6AD2",
580
+ is_group: false,
581
+ parent_id: null,
582
+ creator_id: userId(0),
583
+ retired_at: null
584
+ })),
585
+ initiative_updates: initiatives.flatMap((_, i) => Array.from({ length: 6 }, (_, k) => {
586
+ const posted = /* @__PURE__ */ new Date(now.getTime() - (6 - k) * 30 * day);
587
+ return {
588
+ id: uuid(21, i, k),
589
+ ...stamp(posted, posted),
590
+ _deleted: false,
591
+ initiative_id: initiativeId(i),
592
+ user_id: userId(i),
593
+ body: "Monthly check-in: projects are moving and the main risks are covered.",
594
+ health: "onTrack",
595
+ url: `${workspace}/initiative/${i}/updates#${k}`,
596
+ edited_at: null,
597
+ comment_count: 0n
598
+ };
599
+ })),
600
+ initiative_relations: [{
601
+ id: uuid(22, 0),
602
+ ...set,
603
+ initiative_id: initiativeId(0),
604
+ related_initiative_id: initiativeId(2),
605
+ sort_order: 0,
606
+ user_id: userId(0)
607
+ }],
608
+ initiative_to_projects: projects.map((_, p) => ({
609
+ id: uuid(23, p),
610
+ ...set,
611
+ initiative_id: initiativeId(p % initiatives.length),
612
+ project_id: projectId(p),
613
+ sort_order: String(p)
614
+ }))
615
+ };
616
+ };
617
+ //#endregion
618
+ //#region src/demo/projects.ts
619
+ /** Projects with their milestones, updates, specs, and relations. */
620
+ const projectTables = ({ faker, now }, founded) => {
621
+ const set = stamp(founded, founded);
622
+ const statusRows = projectStatuses.map((status, s) => ({
623
+ id: uuid(15, s),
624
+ ...set,
625
+ name: status.name,
626
+ type: status.type,
627
+ color: status.color,
628
+ description: null,
629
+ position: s
630
+ }));
631
+ const projectLabels = [
632
+ "Q1",
633
+ "Q2",
634
+ "Customer request",
635
+ "Tech debt"
636
+ ].map((name, l) => ({
637
+ id: uuid(16, l),
638
+ ...set,
639
+ _deleted: false,
640
+ name,
641
+ description: null,
642
+ color: faker.color.rgb({ casing: "upper" }),
643
+ is_group: false,
644
+ parent_id: null,
645
+ creator_id: userId(1),
646
+ retired_at: null
647
+ }));
648
+ const projectRows = [];
649
+ const milestones = [];
650
+ const updates = [];
651
+ const documents = [];
652
+ projects.forEach((name, p) => {
653
+ const started = /* @__PURE__ */ new Date(now.getTime() - (360 - p * 40) * day);
654
+ const target = new Date(started.getTime() + 120 * day);
655
+ const completed = target < now;
656
+ const status = completed ? 4 : p % 3 === 2 ? 1 : 2;
657
+ const lead = p * 3 % 16;
658
+ const health = completed ? null : faker.helpers.arrayElement([
659
+ "onTrack",
660
+ "onTrack",
661
+ "atRisk",
662
+ "offTrack"
663
+ ]);
664
+ const updated = completed ? target : now;
665
+ const slug = name.toLowerCase().replaceAll(" ", "-");
666
+ projectRows.push({
667
+ id: projectId(p),
668
+ ...stamp(started, updated),
669
+ _deleted: false,
670
+ name,
671
+ description: `${name} for the ${teams[p % teams.length]?.name ?? "Engineering"} team`,
672
+ content: `## Goal\n\nShip ${name.toLowerCase()} by ${dateOnly(target)}.`,
673
+ url: `${workspace}/project/${slug}-${p.toString(16).padStart(12, "0")}`,
674
+ icon: null,
675
+ color: faker.color.rgb({ casing: "upper" }),
676
+ status_id: uuid(15, status),
677
+ priority: BigInt(1 + p % 4),
678
+ priority_label: priorities[1 + p % 4] ?? "Medium",
679
+ health,
680
+ health_updated_at: health ? /* @__PURE__ */ new Date(now.getTime() - 3 * day) : null,
681
+ progress: completed ? 1 : faker.number.float({
682
+ min: .1,
683
+ max: .8,
684
+ fractionDigits: 2
685
+ }),
686
+ scope: faker.number.int({
687
+ min: 20,
688
+ max: 80
689
+ }),
690
+ lead_id: userId(lead),
691
+ creator_id: userId(lead),
692
+ converted_from_issue_id: null,
693
+ start_date: dateOnly(started),
694
+ target_date: dateOnly(target),
695
+ started_at: status === 1 ? null : started,
696
+ completed_at: completed ? target : null,
697
+ canceled_at: null,
698
+ auto_archived_at: null,
699
+ label_ids: [uuid(16, p % 4)],
700
+ team_ids: [teamId(p % teams.length)],
701
+ member_ids: [userId(lead), userId((lead + 1) % 16)],
702
+ trashed: false
703
+ });
704
+ [
705
+ "Alpha",
706
+ "Beta",
707
+ "GA"
708
+ ].forEach((stage, m) => {
709
+ const milestoneTarget = new Date(started.getTime() + (m + 1) * 40 * day);
710
+ milestones.push({
711
+ id: milestoneId(p, m),
712
+ ...stamp(started, started),
713
+ name: stage,
714
+ description: null,
715
+ project_id: projectId(p),
716
+ target_date: dateOnly(milestoneTarget),
717
+ status: milestoneTarget <= now ? "done" : m === 0 || milestoneTarget.getTime() - now.getTime() < 40 * day ? "next" : "unstarted",
718
+ progress: milestoneTarget <= now ? 1 : 0,
719
+ sort_order: m
720
+ });
721
+ });
722
+ for (let week = started.getTime() + 7 * day; week <= Math.min(updated.getTime(), now.getTime()); week += 7 * day) {
723
+ const posted = new Date(week);
724
+ updates.push({
725
+ id: uuid(17, p, updates.length),
726
+ ...stamp(posted, posted),
727
+ _deleted: false,
728
+ project_id: projectId(p),
729
+ user_id: userId(lead),
730
+ body: faker.helpers.arrayElement([
731
+ "Good week. The main flows are done and we're testing edge cases.",
732
+ "We hit a snag with the migration. It may slip a few days.",
733
+ "On track. Design review is done and we start the rollout next week."
734
+ ]),
735
+ health: faker.helpers.arrayElement([
736
+ "onTrack",
737
+ "onTrack",
738
+ "atRisk"
739
+ ]),
740
+ url: `${workspace}/project/${slug}/updates#${updates.length}`,
741
+ edited_at: null,
742
+ comment_count: 0n
743
+ });
744
+ }
745
+ documents.push({
746
+ id: uuid(18, p),
747
+ ...stamp(started, started),
748
+ _deleted: false,
749
+ title: `${name} spec`,
750
+ content: `# ${name}\n\n## Problem\n\nCustomers asked for this.\n\n## Plan\n\nShip it in three milestones.`,
751
+ url: `${workspace}/document/${slug}-spec-${p.toString(16).padStart(12, "0")}`,
752
+ icon: null,
753
+ color: null,
754
+ creator_id: userId(lead),
755
+ updated_by_id: userId(lead),
756
+ project_id: projectId(p),
757
+ initiative_id: null,
758
+ issue_id: null,
759
+ cycle_id: null,
760
+ team_id: null,
761
+ parent_document_id: null,
762
+ hidden_at: null,
763
+ trashed: false
764
+ });
765
+ });
766
+ return {
767
+ project_statuses: statusRows,
768
+ project_labels: projectLabels,
769
+ projects: projectRows,
770
+ project_milestones: milestones,
771
+ project_updates: updates,
772
+ project_relations: [{
773
+ id: uuid(19, 0),
774
+ ...set,
775
+ type: "dependency",
776
+ project_id: projectId(4),
777
+ project_milestone_id: null,
778
+ anchor_type: "start",
779
+ related_project_id: projectId(1),
780
+ related_project_milestone_id: null,
781
+ related_anchor_type: "end",
782
+ user_id: userId(0)
783
+ }, {
784
+ id: uuid(19, 1),
785
+ ...set,
786
+ type: "dependency",
787
+ project_id: projectId(6),
788
+ project_milestone_id: null,
789
+ anchor_type: "start",
790
+ related_project_id: projectId(3),
791
+ related_project_milestone_id: null,
792
+ related_anchor_type: "end",
793
+ user_id: userId(1)
794
+ }],
795
+ documents
796
+ };
797
+ };
798
+ //#endregion
799
+ //#region src/demo/teams.ts
800
+ /** Teams with their workflow states, users, labels, and cycles. */
801
+ const teamTables = ({ faker, now }, founded) => {
802
+ const set = stamp(founded, founded);
803
+ const teamRows = teams.map((team, t) => ({
804
+ id: teamId(t),
805
+ ...set,
806
+ name: team.name,
807
+ key: team.key,
808
+ display_name: team.name,
809
+ description: null,
810
+ visibility: "public",
811
+ parent_id: null,
812
+ timezone: "America/New_York",
813
+ cycles_enabled: team.cycles,
814
+ cycle_duration: 2,
815
+ cycle_cooldown_time: 0,
816
+ cycle_start_day: 1,
817
+ triage_enabled: team.triage,
818
+ issue_estimation_type: team.key === "ENG" ? "fibonacci" : "notUsed",
819
+ default_issue_estimate: team.key === "ENG" ? 1 : 0,
820
+ auto_archive_period: 6,
821
+ auto_close_period: 6,
822
+ retired_at: null
823
+ }));
824
+ const stateRows = teams.flatMap((team, t) => states.filter((state) => state.type !== "triage" || team.triage).map((state, s) => ({
825
+ id: stateId(t, states.indexOf(state)),
826
+ ...set,
827
+ name: state.name,
828
+ type: state.type,
829
+ color: state.color,
830
+ description: null,
831
+ position: s,
832
+ team_id: teamId(t)
833
+ })));
834
+ const users = Array.from({ length: 16 }, (_, u) => {
835
+ const person = nameFor(faker);
836
+ const joined = new Date(founded.getTime() + u * 20 * day);
837
+ return {
838
+ id: userId(u),
839
+ ...stamp(joined, joined),
840
+ _deleted: false,
841
+ name: person.name,
842
+ display_name: person.first.toLowerCase(),
843
+ email: faker.internet.exampleEmail({
844
+ firstName: person.first,
845
+ lastName: person.last
846
+ }).toLowerCase(),
847
+ avatar_url: null,
848
+ title: faker.person.jobTitle(),
849
+ timezone: faker.helpers.arrayElement([
850
+ "America/New_York",
851
+ "Europe/London",
852
+ "Europe/Berlin"
853
+ ]),
854
+ active: true,
855
+ admin: u < 2,
856
+ owner: u === 0,
857
+ guest: false,
858
+ app: false,
859
+ last_seen: new Date(now.getTime() - faker.number.int({
860
+ min: 6e4,
861
+ max: 3 * day
862
+ })),
863
+ url: `${workspace}/profiles/${person.first.toLowerCase()}`
864
+ };
865
+ });
866
+ return {
867
+ teams: teamRows,
868
+ workflow_states: stateRows,
869
+ users,
870
+ team_memberships: users.map((user, u) => ({
871
+ id: uuid(13, u),
872
+ ...stamp(user.created_at, user.created_at),
873
+ team_id: teamId(u % teams.length),
874
+ user_id: user.id,
875
+ owner: u < teams.length
876
+ })),
877
+ external_users: [
878
+ "Slack",
879
+ "Intercom",
880
+ "Zendesk"
881
+ ].map((source, e) => {
882
+ const person = nameFor(faker);
883
+ return {
884
+ id: uuid(14, e),
885
+ ...set,
886
+ name: person.name,
887
+ display_name: `${person.name} (${source})`,
888
+ email: faker.internet.exampleEmail({
889
+ firstName: person.first,
890
+ lastName: person.last
891
+ }).toLowerCase(),
892
+ avatar_url: null,
893
+ last_seen: new Date(now.getTime() - faker.number.int({
894
+ min: day,
895
+ max: 30 * day
896
+ }))
897
+ };
898
+ }),
899
+ issue_labels: issueLabels.map((label, l) => ({
900
+ id: labelId(l),
901
+ ...set,
902
+ _deleted: false,
903
+ name: label.name,
904
+ description: null,
905
+ color: label.color,
906
+ is_group: false,
907
+ parent_id: null,
908
+ team_id: null,
909
+ creator_id: userId(0),
910
+ retired_at: null
911
+ })),
912
+ cycles: teams.flatMap((team, t) => team.cycles ? Array.from({ length: 27 }, (_, n) => {
913
+ const starts = cycleStart(now, n);
914
+ const ends = new Date(starts.getTime() + 14 * day);
915
+ const done = ends <= now;
916
+ return {
917
+ id: cycleId(t, n),
918
+ ...stamp(starts, done ? ends : now),
919
+ _deleted: false,
920
+ number: n + 1,
921
+ name: null,
922
+ description: null,
923
+ team_id: teamId(t),
924
+ starts_at: starts,
925
+ ends_at: ends,
926
+ completed_at: done ? ends : null,
927
+ auto_archived_at: null,
928
+ progress: done ? 1 : .4
929
+ };
930
+ }) : [])
931
+ };
932
+ };
933
+ //#endregion
934
+ //#region src/demo/setup.ts
935
+ /** The workspace, written once before any issue. */
936
+ const setupRows = (context) => {
937
+ const { faker, now } = context;
938
+ const founded = /* @__PURE__ */ new Date(now.getTime() - 900 * day);
939
+ const set = stamp(founded, founded);
940
+ const teamSetup = teamTables(context, founded);
941
+ const projectSetup = projectTables(context, founded);
942
+ const initiativeSetup = initiativeTables(context, founded);
943
+ const customerStatuses = [
944
+ "Active",
945
+ "Trial",
946
+ "Churned"
947
+ ].map((name, s) => ({
948
+ id: uuid(24, s),
949
+ ...set,
950
+ name: name.toLowerCase(),
951
+ display_name: name,
952
+ description: null,
953
+ color: [
954
+ "#4CB782",
955
+ "#F2C94C",
956
+ "#95A2B3"
957
+ ][s] ?? "#95A2B3",
958
+ position: s
959
+ }));
960
+ const customerTiers = [
961
+ "Enterprise",
962
+ "Growth",
963
+ "Starter"
964
+ ].map((name, s) => ({
965
+ id: uuid(25, s),
966
+ ...set,
967
+ name: name.toLowerCase(),
968
+ display_name: name,
969
+ description: null,
970
+ color: [
971
+ "#5E6AD2",
972
+ "#4EA7FC",
973
+ "#BEC2C8"
974
+ ][s] ?? "#BEC2C8",
975
+ position: s
976
+ }));
977
+ const customers = Array.from({ length: 12 }, (_, c) => {
978
+ const name = faker.company.name();
979
+ const domain = `${name.toLowerCase().replaceAll(/[^a-z]+/g, "")}.example.com`;
980
+ const tier = c % 3;
981
+ return {
982
+ id: customerId(c),
983
+ ...stamp(founded, now),
984
+ _deleted: false,
985
+ name,
986
+ domains: [domain],
987
+ external_ids: [],
988
+ logo_url: null,
989
+ owner_id: userId(c % 16),
990
+ status_id: uuid(24, c === 11 ? 2 : c % 5 === 4 ? 1 : 0),
991
+ tier_id: uuid(25, tier),
992
+ revenue: BigInt([
993
+ 25e4,
994
+ 6e4,
995
+ 12e3
996
+ ][tier] ?? 12e3),
997
+ size: [
998
+ 2e3,
999
+ 300,
1000
+ 40
1001
+ ][tier] ?? 40,
1002
+ approximate_need_count: 0,
1003
+ url: `${workspace}/customer/${name.toLowerCase().replaceAll(/[^a-z]+/g, "-")}`
1004
+ };
1005
+ });
1006
+ const pipeline = [{
1007
+ id: pipelineId,
1008
+ ...set,
1009
+ name: "Web app",
1010
+ type: "scheduled",
1011
+ is_production: true,
1012
+ url: `${workspace}/releases/web-app`,
1013
+ include_path_patterns: ["apps/web/**"],
1014
+ approximate_release_count: BigInt(12),
1015
+ trashed: false
1016
+ }];
1017
+ const stages = [
1018
+ "Planned",
1019
+ "In progress",
1020
+ "Released"
1021
+ ].map((name, s) => ({
1022
+ id: uuid(26, s),
1023
+ ...set,
1024
+ name,
1025
+ type: [
1026
+ "planned",
1027
+ "started",
1028
+ "completed"
1029
+ ][s] ?? "completed",
1030
+ color: [
1031
+ "#BEC2C8",
1032
+ "#F2C94C",
1033
+ "#5E6AD2"
1034
+ ][s] ?? "#5E6AD2",
1035
+ position: s,
1036
+ frozen: false,
1037
+ pipeline_id: pipelineId
1038
+ }));
1039
+ const releases = Array.from({ length: 12 }, (_, m) => {
1040
+ const released = /* @__PURE__ */ new Date(now.getTime() - m * 30 * day);
1041
+ const current = m === 0;
1042
+ return {
1043
+ id: releaseId(m),
1044
+ ...stamp(/* @__PURE__ */ new Date(released.getTime() - 30 * day), current ? now : released),
1045
+ name: `Release 2.${12 - m}.0`,
1046
+ description: null,
1047
+ release_version: `2.${12 - m}.0`,
1048
+ url: `${workspace}/releases/web-app/2.${12 - m}.0`,
1049
+ commit_sha: current ? null : faker.git.commitSha(),
1050
+ pipeline_id: pipelineId,
1051
+ stage_id: uuid(26, current ? 1 : 2),
1052
+ creator_id: userId(0),
1053
+ start_date: dateOnly(/* @__PURE__ */ new Date(released.getTime() - 30 * day)),
1054
+ target_date: dateOnly(released),
1055
+ started_at: /* @__PURE__ */ new Date(released.getTime() - 30 * day),
1056
+ completed_at: current ? null : released,
1057
+ canceled_at: null,
1058
+ trashed: false
1059
+ };
1060
+ });
1061
+ const releaseNotes = releases.filter((release) => release.completed_at !== null).map((release, k) => ({
1062
+ id: uuid(27, k),
1063
+ ...stamp(release.completed_at ?? now, release.completed_at ?? now),
1064
+ title: `What's new in ${release.release_version}`,
1065
+ content: "Faster search, clearer billing pages, and many small fixes.",
1066
+ url: `${release.url}/notes`,
1067
+ pipeline_id: pipelineId,
1068
+ release_ids: [release.id]
1069
+ }));
1070
+ return {
1071
+ ...teamSetup,
1072
+ ...projectSetup,
1073
+ ...initiativeSetup,
1074
+ customer_statuses: customerStatuses,
1075
+ customer_tiers: customerTiers,
1076
+ customers,
1077
+ release_pipelines: pipeline,
1078
+ release_stages: stages,
1079
+ releases,
1080
+ release_notes: releaseNotes
1081
+ };
1082
+ };
1083
+ //#endregion
1084
+ //#region src/demo/index.ts
1085
+ const demo = Demo.define({
1086
+ name: "producer-linear",
1087
+ setup: {
1088
+ tables: [
1089
+ Demo.table({
1090
+ name: "teams",
1091
+ rowSchema: TeamSchema,
1092
+ version: "version"
1093
+ }),
1094
+ Demo.table({
1095
+ name: "workflow_states",
1096
+ rowSchema: WorkflowStateSchema,
1097
+ version: "version"
1098
+ }),
1099
+ Demo.table({
1100
+ name: "users",
1101
+ rowSchema: UserSchema,
1102
+ version: "version"
1103
+ }),
1104
+ Demo.table({
1105
+ name: "team_memberships",
1106
+ rowSchema: TeamMembershipSchema,
1107
+ version: "version"
1108
+ }),
1109
+ Demo.table({
1110
+ name: "external_users",
1111
+ rowSchema: ExternalUserSchema,
1112
+ version: "version"
1113
+ }),
1114
+ Demo.table({
1115
+ name: "issue_labels",
1116
+ rowSchema: IssueLabelSchema,
1117
+ version: "version"
1118
+ }),
1119
+ Demo.table({
1120
+ name: "cycles",
1121
+ rowSchema: CycleSchema,
1122
+ version: "version"
1123
+ }),
1124
+ Demo.table({
1125
+ name: "project_statuses",
1126
+ rowSchema: ProjectStatusSchema,
1127
+ version: "version"
1128
+ }),
1129
+ Demo.table({
1130
+ name: "project_labels",
1131
+ rowSchema: ProjectLabelSchema,
1132
+ version: "version"
1133
+ }),
1134
+ Demo.table({
1135
+ name: "projects",
1136
+ rowSchema: ProjectSchema,
1137
+ version: "version"
1138
+ }),
1139
+ Demo.table({
1140
+ name: "project_milestones",
1141
+ rowSchema: ProjectMilestoneSchema,
1142
+ version: "version"
1143
+ }),
1144
+ Demo.table({
1145
+ name: "project_updates",
1146
+ rowSchema: ProjectUpdateSchema,
1147
+ version: "version"
1148
+ }),
1149
+ Demo.table({
1150
+ name: "project_relations",
1151
+ rowSchema: ProjectRelationSchema,
1152
+ version: "version"
1153
+ }),
1154
+ Demo.table({
1155
+ name: "documents",
1156
+ rowSchema: DocumentSchema,
1157
+ version: "version"
1158
+ }),
1159
+ Demo.table({
1160
+ name: "initiatives",
1161
+ rowSchema: InitiativeSchema,
1162
+ version: "version"
1163
+ }),
1164
+ Demo.table({
1165
+ name: "initiative_labels",
1166
+ rowSchema: InitiativeLabelSchema,
1167
+ version: "version"
1168
+ }),
1169
+ Demo.table({
1170
+ name: "initiative_updates",
1171
+ rowSchema: InitiativeUpdateSchema,
1172
+ version: "version"
1173
+ }),
1174
+ Demo.table({
1175
+ name: "initiative_relations",
1176
+ rowSchema: InitiativeRelationSchema,
1177
+ version: "version"
1178
+ }),
1179
+ Demo.table({
1180
+ name: "initiative_to_projects",
1181
+ rowSchema: InitiativeToProjectSchema,
1182
+ version: "version"
1183
+ }),
1184
+ Demo.table({
1185
+ name: "customer_statuses",
1186
+ rowSchema: CustomerStatusSchema,
1187
+ version: "version"
1188
+ }),
1189
+ Demo.table({
1190
+ name: "customer_tiers",
1191
+ rowSchema: CustomerTierSchema,
1192
+ version: "version"
1193
+ }),
1194
+ Demo.table({
1195
+ name: "customers",
1196
+ rowSchema: CustomerSchema,
1197
+ version: "version"
1198
+ }),
1199
+ Demo.table({
1200
+ name: "release_pipelines",
1201
+ rowSchema: ReleasePipelineSchema,
1202
+ version: "version"
1203
+ }),
1204
+ Demo.table({
1205
+ name: "release_stages",
1206
+ rowSchema: ReleaseStageSchema,
1207
+ version: "version"
1208
+ }),
1209
+ Demo.table({
1210
+ name: "releases",
1211
+ rowSchema: ReleaseSchema,
1212
+ version: "version"
1213
+ }),
1214
+ Demo.table({
1215
+ name: "release_notes",
1216
+ rowSchema: ReleaseNoteSchema,
1217
+ version: "version"
1218
+ })
1219
+ ],
1220
+ rows: setupRows
1221
+ },
1222
+ group: {
1223
+ tables: [
1224
+ Demo.table({
1225
+ name: "issues",
1226
+ rowSchema: IssueSchema,
1227
+ version: "version"
1228
+ }),
1229
+ Demo.table({
1230
+ name: "issue_history",
1231
+ rowSchema: IssueHistorySchema,
1232
+ version: "version"
1233
+ }),
1234
+ Demo.table({
1235
+ name: "comments",
1236
+ rowSchema: CommentSchema,
1237
+ version: "version"
1238
+ }),
1239
+ Demo.table({
1240
+ name: "issue_relations",
1241
+ rowSchema: IssueRelationSchema,
1242
+ version: "version"
1243
+ }),
1244
+ Demo.table({
1245
+ name: "attachments",
1246
+ rowSchema: AttachmentSchema,
1247
+ version: "version"
1248
+ }),
1249
+ Demo.table({
1250
+ name: "customer_needs",
1251
+ rowSchema: CustomerNeedSchema,
1252
+ version: "version"
1253
+ }),
1254
+ Demo.table({
1255
+ name: "issue_to_releases",
1256
+ rowSchema: IssueToReleaseSchema,
1257
+ version: "version"
1258
+ })
1259
+ ],
1260
+ rows: issueRows
1261
+ }
1262
+ });
1263
+ const demoCommand = ConnectorApp.makeDemoCommand(demo).pipe(Command.provide(RuntimeConfig.layerHosted()));
1264
+ //#endregion
1265
+ //#region src/sandbox.ts
1266
+ const ConnectorLayer$1 = layerConfig(LinearConfigDef.config);
1267
+ const TelemetryLayer$1 = Layer.mergeAll(Telemetry.layerOtlp(), Telemetry.layerMetricsConsoleDump());
1268
+ const sandboxCommand = Command.make("sandbox", {}, () => Effect.gen(function* () {
1269
+ const port = yield* RuntimeConfig.httpPort;
1270
+ const entrypoint = yield* LinearConnector;
1271
+ return yield* ConnectorApp.start(entrypoint, { port });
1272
+ }).pipe(Effect.annotateLogs({ component: "linear" }), Effect.provide(Layer.mergeAll(StateStore.layerMemory, Ingestor.layerConsole, ConnectorLayer$1, Logger.layer([Logger.consolePretty()]), TelemetryLayer$1)))).pipe(Command.withDescription("Run the connector locally and log ingested data"));
1273
+ //#endregion
1274
+ //#region src/start.ts
1275
+ const ConnectorLayer = layerConfig(LinearConfigDef.config);
1276
+ const TelemetryLayer = Telemetry.layerOtlp();
1277
+ const PostgresLayer = PgClient.layerConfig({
1278
+ url: Config.schema(Schema.Redacted(Schema.NonEmptyString), RuntimeConfig.PlatformRuntimeKey.postgresConnectionString),
1279
+ maxConnections: Config.succeed(2),
1280
+ connectTimeout: Config.succeed("5 seconds"),
1281
+ applicationName: Config.succeed("airfoil-producer-linear")
1282
+ });
1283
+ const StateStoreLayer = StateStore.layerSql().pipe(Layer.provide(PostgresLayer));
1284
+ const startCommand = Command.make("start", {}, () => Effect.gen(function* () {
1285
+ const port = yield* RuntimeConfig.httpPort;
1286
+ const entrypoint = yield* LinearConnector;
1287
+ return yield* ConnectorApp.start(entrypoint, { port }).pipe(Effect.provide(Ingestor.layerWingsConfig(entrypoint)));
1288
+ }).pipe(Effect.annotateLogs({ component: "linear" }), Effect.provide(Layer.mergeAll(StateStoreLayer, ConnectorLayer, Logger.layer([Logger.consolePretty()]), TelemetryLayer)), Effect.provide(RuntimeConfig.layerHosted()))).pipe(Command.withDescription("Run the production connector against Wings"));
1289
+ //#endregion
1290
+ //#region src/main.ts
1291
+ const BootstrapLayer = Layer.mergeAll(FetchHttpClient.layer, NodeServices.layer);
1292
+ const program = Command.make("producer-linear", {}, () => Effect.void).pipe(Command.withSubcommands([
1293
+ startCommand,
1294
+ sandboxCommand,
1295
+ createTableCommand,
1296
+ demoCommand
1297
+ ]));
1298
+ const cli = Command.run(program, { version });
1299
+ NodeRuntime.runMain(cli.pipe(Effect.provide(BootstrapLayer), Effect.scoped));
1300
+ //#endregion
1301
+ export {};
1302
+
1303
+ //# sourceMappingURL=main.mjs.map