@shipfox/api-integration-linear 2.0.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.
Files changed (151) hide show
  1. package/.turbo/turbo-build.log +2 -0
  2. package/.turbo/turbo-type$colon$emit.log +1 -0
  3. package/.turbo/turbo-type.log +1 -0
  4. package/CHANGELOG.md +89 -0
  5. package/LICENSE +21 -0
  6. package/README.md +88 -0
  7. package/dist/api/client.d.ts +29 -0
  8. package/dist/api/client.d.ts.map +1 -0
  9. package/dist/api/client.js +189 -0
  10. package/dist/api/client.js.map +1 -0
  11. package/dist/config.d.ts +8 -0
  12. package/dist/config.d.ts.map +1 -0
  13. package/dist/config.js +22 -0
  14. package/dist/config.js.map +1 -0
  15. package/dist/core/agent-tools-provider.d.ts +32 -0
  16. package/dist/core/agent-tools-provider.d.ts.map +1 -0
  17. package/dist/core/agent-tools-provider.js +63 -0
  18. package/dist/core/agent-tools-provider.js.map +1 -0
  19. package/dist/core/agent-tools.d.ts +10 -0
  20. package/dist/core/agent-tools.d.ts.map +1 -0
  21. package/dist/core/agent-tools.js +920 -0
  22. package/dist/core/agent-tools.js.map +1 -0
  23. package/dist/core/disconnect.d.ts +18 -0
  24. package/dist/core/disconnect.d.ts.map +1 -0
  25. package/dist/core/disconnect.js +23 -0
  26. package/dist/core/disconnect.js.map +1 -0
  27. package/dist/core/errors.d.ts +35 -0
  28. package/dist/core/errors.d.ts.map +1 -0
  29. package/dist/core/errors.js +59 -0
  30. package/dist/core/errors.js.map +1 -0
  31. package/dist/core/install.d.ts +47 -0
  32. package/dist/core/install.d.ts.map +1 -0
  33. package/dist/core/install.js +102 -0
  34. package/dist/core/install.js.map +1 -0
  35. package/dist/core/scopes.d.ts +4 -0
  36. package/dist/core/scopes.d.ts.map +1 -0
  37. package/dist/core/scopes.js +17 -0
  38. package/dist/core/scopes.js.map +1 -0
  39. package/dist/core/state.d.ts +12 -0
  40. package/dist/core/state.d.ts.map +1 -0
  41. package/dist/core/state.js +54 -0
  42. package/dist/core/state.js.map +1 -0
  43. package/dist/core/tokens.d.ts +39 -0
  44. package/dist/core/tokens.d.ts.map +1 -0
  45. package/dist/core/tokens.js +117 -0
  46. package/dist/core/tokens.js.map +1 -0
  47. package/dist/core/webhook.d.ts +16 -0
  48. package/dist/core/webhook.d.ts.map +1 -0
  49. package/dist/core/webhook.js +105 -0
  50. package/dist/core/webhook.js.map +1 -0
  51. package/dist/db/db.d.ts +369 -0
  52. package/dist/db/db.d.ts.map +1 -0
  53. package/dist/db/db.js +18 -0
  54. package/dist/db/db.js.map +1 -0
  55. package/dist/db/installations.d.ts +53 -0
  56. package/dist/db/installations.d.ts.map +1 -0
  57. package/dist/db/installations.js +125 -0
  58. package/dist/db/installations.js.map +1 -0
  59. package/dist/db/migrations.d.ts +2 -0
  60. package/dist/db/migrations.d.ts.map +1 -0
  61. package/dist/db/migrations.js +5 -0
  62. package/dist/db/migrations.js.map +1 -0
  63. package/dist/db/schema/common.d.ts +2 -0
  64. package/dist/db/schema/common.d.ts.map +1 -0
  65. package/dist/db/schema/common.js +4 -0
  66. package/dist/db/schema/common.js.map +1 -0
  67. package/dist/db/schema/installations.d.ts +186 -0
  68. package/dist/db/schema/installations.d.ts.map +1 -0
  69. package/dist/db/schema/installations.js +40 -0
  70. package/dist/db/schema/installations.js.map +1 -0
  71. package/dist/index.d.ts +53 -0
  72. package/dist/index.d.ts.map +1 -0
  73. package/dist/index.js +56 -0
  74. package/dist/index.js.map +1 -0
  75. package/dist/presentation/dto/integrations.d.ts +17 -0
  76. package/dist/presentation/dto/integrations.d.ts.map +1 -0
  77. package/dist/presentation/dto/integrations.js +6 -0
  78. package/dist/presentation/dto/integrations.js.map +1 -0
  79. package/dist/presentation/e2eRoutes/create-connection.d.ts +16 -0
  80. package/dist/presentation/e2eRoutes/create-connection.d.ts.map +1 -0
  81. package/dist/presentation/e2eRoutes/create-connection.js +64 -0
  82. package/dist/presentation/e2eRoutes/create-connection.js.map +1 -0
  83. package/dist/presentation/e2eRoutes/index.d.ts +5 -0
  84. package/dist/presentation/e2eRoutes/index.d.ts.map +1 -0
  85. package/dist/presentation/e2eRoutes/index.js +11 -0
  86. package/dist/presentation/e2eRoutes/index.js.map +1 -0
  87. package/dist/presentation/routes/errors.d.ts +2 -0
  88. package/dist/presentation/routes/errors.d.ts.map +1 -0
  89. package/dist/presentation/routes/errors.js +65 -0
  90. package/dist/presentation/routes/errors.js.map +1 -0
  91. package/dist/presentation/routes/install.d.ts +19 -0
  92. package/dist/presentation/routes/install.d.ts.map +1 -0
  93. package/dist/presentation/routes/install.js +100 -0
  94. package/dist/presentation/routes/install.js.map +1 -0
  95. package/dist/presentation/routes/webhooks.d.ts +11 -0
  96. package/dist/presentation/routes/webhooks.d.ts.map +1 -0
  97. package/dist/presentation/routes/webhooks.js +136 -0
  98. package/dist/presentation/routes/webhooks.js.map +1 -0
  99. package/dist/tsconfig.test.tsbuildinfo +1 -0
  100. package/drizzle/0000_initial.sql +15 -0
  101. package/drizzle/meta/0000_snapshot.json +126 -0
  102. package/drizzle/meta/_journal.json +13 -0
  103. package/drizzle.config.ts +7 -0
  104. package/package.json +72 -0
  105. package/src/api/client.test.ts +366 -0
  106. package/src/api/client.ts +281 -0
  107. package/src/config.test.ts +34 -0
  108. package/src/config.ts +22 -0
  109. package/src/connection-external-url.test.ts +64 -0
  110. package/src/core/agent-tools-provider.test.ts +245 -0
  111. package/src/core/agent-tools-provider.ts +106 -0
  112. package/src/core/agent-tools.ts +918 -0
  113. package/src/core/disconnect.test.ts +45 -0
  114. package/src/core/disconnect.ts +27 -0
  115. package/src/core/errors.ts +71 -0
  116. package/src/core/install.ts +162 -0
  117. package/src/core/scopes.ts +18 -0
  118. package/src/core/state.test.ts +51 -0
  119. package/src/core/state.ts +85 -0
  120. package/src/core/tokens.test.ts +281 -0
  121. package/src/core/tokens.ts +219 -0
  122. package/src/core/webhook.test.ts +318 -0
  123. package/src/core/webhook.ts +146 -0
  124. package/src/db/db.ts +18 -0
  125. package/src/db/installations.test.ts +182 -0
  126. package/src/db/installations.ts +215 -0
  127. package/src/db/migrations.ts +4 -0
  128. package/src/db/schema/common.ts +3 -0
  129. package/src/db/schema/installations.ts +42 -0
  130. package/src/index.test.ts +20 -0
  131. package/src/index.ts +153 -0
  132. package/src/presentation/dto/integrations.ts +9 -0
  133. package/src/presentation/e2eRoutes/create-connection.ts +85 -0
  134. package/src/presentation/e2eRoutes/index.test.ts +193 -0
  135. package/src/presentation/e2eRoutes/index.ts +14 -0
  136. package/src/presentation/routes/errors.ts +60 -0
  137. package/src/presentation/routes/install.test.ts +460 -0
  138. package/src/presentation/routes/install.ts +132 -0
  139. package/src/presentation/routes/webhooks.test.ts +407 -0
  140. package/src/presentation/routes/webhooks.ts +154 -0
  141. package/test/api-secrets.d.ts +28 -0
  142. package/test/env.ts +13 -0
  143. package/test/factories/index.ts +1 -0
  144. package/test/globalSetup.ts +23 -0
  145. package/test/index.ts +1 -0
  146. package/test/setup.ts +17 -0
  147. package/tsconfig.build.json +9 -0
  148. package/tsconfig.build.tsbuildinfo +1 -0
  149. package/tsconfig.json +3 -0
  150. package/tsconfig.test.json +9 -0
  151. package/vitest.config.ts +12 -0
@@ -0,0 +1,186 @@
1
+ import type { LinearInstallation } from '#db/installations.js';
2
+ export declare const linearInstallations: import("drizzle-orm/pg-core").PgTableWithColumns<{
3
+ name: "installations";
4
+ schema: undefined;
5
+ columns: {
6
+ id: import("drizzle-orm/pg-core").PgColumn<{
7
+ name: "id";
8
+ tableName: "installations";
9
+ dataType: "string";
10
+ columnType: "PgUUID";
11
+ data: string;
12
+ driverParam: string;
13
+ notNull: true;
14
+ hasDefault: true;
15
+ isPrimaryKey: true;
16
+ isAutoincrement: false;
17
+ hasRuntimeDefault: false;
18
+ enumValues: undefined;
19
+ baseColumn: never;
20
+ identity: undefined;
21
+ generated: undefined;
22
+ }, {}, {}>;
23
+ connectionId: import("drizzle-orm/pg-core").PgColumn<{
24
+ name: "connection_id";
25
+ tableName: "installations";
26
+ dataType: "string";
27
+ columnType: "PgUUID";
28
+ data: string;
29
+ driverParam: string;
30
+ notNull: true;
31
+ hasDefault: false;
32
+ isPrimaryKey: false;
33
+ isAutoincrement: false;
34
+ hasRuntimeDefault: false;
35
+ enumValues: undefined;
36
+ baseColumn: never;
37
+ identity: undefined;
38
+ generated: undefined;
39
+ }, {}, {}>;
40
+ organizationId: import("drizzle-orm/pg-core").PgColumn<{
41
+ name: "organization_id";
42
+ tableName: "installations";
43
+ dataType: "string";
44
+ columnType: "PgText";
45
+ data: string;
46
+ driverParam: string;
47
+ notNull: true;
48
+ hasDefault: false;
49
+ isPrimaryKey: false;
50
+ isAutoincrement: false;
51
+ hasRuntimeDefault: false;
52
+ enumValues: [string, ...string[]];
53
+ baseColumn: never;
54
+ identity: undefined;
55
+ generated: undefined;
56
+ }, {}, {}>;
57
+ organizationUrlKey: import("drizzle-orm/pg-core").PgColumn<{
58
+ name: "organization_url_key";
59
+ tableName: "installations";
60
+ dataType: "string";
61
+ columnType: "PgText";
62
+ data: string;
63
+ driverParam: string;
64
+ notNull: true;
65
+ hasDefault: false;
66
+ isPrimaryKey: false;
67
+ isAutoincrement: false;
68
+ hasRuntimeDefault: false;
69
+ enumValues: [string, ...string[]];
70
+ baseColumn: never;
71
+ identity: undefined;
72
+ generated: undefined;
73
+ }, {}, {}>;
74
+ appUserId: import("drizzle-orm/pg-core").PgColumn<{
75
+ name: "app_user_id";
76
+ tableName: "installations";
77
+ dataType: "string";
78
+ columnType: "PgText";
79
+ data: string;
80
+ driverParam: string;
81
+ notNull: true;
82
+ hasDefault: false;
83
+ isPrimaryKey: false;
84
+ isAutoincrement: false;
85
+ hasRuntimeDefault: false;
86
+ enumValues: [string, ...string[]];
87
+ baseColumn: never;
88
+ identity: undefined;
89
+ generated: undefined;
90
+ }, {}, {}>;
91
+ scopes: import("drizzle-orm/pg-core").PgColumn<{
92
+ name: "scopes";
93
+ tableName: "installations";
94
+ dataType: "json";
95
+ columnType: "PgJsonb";
96
+ data: string[];
97
+ driverParam: unknown;
98
+ notNull: true;
99
+ hasDefault: false;
100
+ isPrimaryKey: false;
101
+ isAutoincrement: false;
102
+ hasRuntimeDefault: false;
103
+ enumValues: undefined;
104
+ baseColumn: never;
105
+ identity: undefined;
106
+ generated: undefined;
107
+ }, {}, {
108
+ $type: string[];
109
+ }>;
110
+ tokenExpiresAt: import("drizzle-orm/pg-core").PgColumn<{
111
+ name: "token_expires_at";
112
+ tableName: "installations";
113
+ dataType: "date";
114
+ columnType: "PgTimestamp";
115
+ data: Date;
116
+ driverParam: string;
117
+ notNull: false;
118
+ hasDefault: false;
119
+ isPrimaryKey: false;
120
+ isAutoincrement: false;
121
+ hasRuntimeDefault: false;
122
+ enumValues: undefined;
123
+ baseColumn: never;
124
+ identity: undefined;
125
+ generated: undefined;
126
+ }, {}, {}>;
127
+ status: import("drizzle-orm/pg-core").PgColumn<{
128
+ name: "status";
129
+ tableName: "installations";
130
+ dataType: "string";
131
+ columnType: "PgText";
132
+ data: import("#db/installations.js").LinearInstallationStatus;
133
+ driverParam: string;
134
+ notNull: true;
135
+ hasDefault: false;
136
+ isPrimaryKey: false;
137
+ isAutoincrement: false;
138
+ hasRuntimeDefault: false;
139
+ enumValues: [string, ...string[]];
140
+ baseColumn: never;
141
+ identity: undefined;
142
+ generated: undefined;
143
+ }, {}, {
144
+ $type: import("#db/installations.js").LinearInstallationStatus;
145
+ }>;
146
+ createdAt: import("drizzle-orm/pg-core").PgColumn<{
147
+ name: "created_at";
148
+ tableName: "installations";
149
+ dataType: "date";
150
+ columnType: "PgTimestamp";
151
+ data: Date;
152
+ driverParam: string;
153
+ notNull: true;
154
+ hasDefault: true;
155
+ isPrimaryKey: false;
156
+ isAutoincrement: false;
157
+ hasRuntimeDefault: false;
158
+ enumValues: undefined;
159
+ baseColumn: never;
160
+ identity: undefined;
161
+ generated: undefined;
162
+ }, {}, {}>;
163
+ updatedAt: import("drizzle-orm/pg-core").PgColumn<{
164
+ name: "updated_at";
165
+ tableName: "installations";
166
+ dataType: "date";
167
+ columnType: "PgTimestamp";
168
+ data: Date;
169
+ driverParam: string;
170
+ notNull: true;
171
+ hasDefault: true;
172
+ isPrimaryKey: false;
173
+ isAutoincrement: false;
174
+ hasRuntimeDefault: false;
175
+ enumValues: undefined;
176
+ baseColumn: never;
177
+ identity: undefined;
178
+ generated: undefined;
179
+ }, {}, {}>;
180
+ };
181
+ dialect: "pg";
182
+ }>;
183
+ export type LinearInstallationDb = typeof linearInstallations.$inferSelect;
184
+ export type LinearInstallationCreateDb = typeof linearInstallations.$inferInsert;
185
+ export declare function toLinearInstallation(row: LinearInstallationDb): LinearInstallation;
186
+ //# sourceMappingURL=installations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"installations.d.ts","sourceRoot":"","sources":["../../../src/db/schema/installations.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,sBAAsB,CAAC;AAG7D,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAkB/B,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG,OAAO,mBAAmB,CAAC,YAAY,CAAC;AAC3E,MAAM,MAAM,0BAA0B,GAAG,OAAO,mBAAmB,CAAC,YAAY,CAAC;AAEjF,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,oBAAoB,GAAG,kBAAkB,CAalF"}
@@ -0,0 +1,40 @@
1
+ import { uuidv7PrimaryKey } from '@shipfox/node-drizzle';
2
+ import { jsonb, text, timestamp, uniqueIndex, uuid } from 'drizzle-orm/pg-core';
3
+ import { pgTable } from './common.js';
4
+ export const linearInstallations = pgTable('installations', {
5
+ id: uuidv7PrimaryKey(),
6
+ connectionId: uuid('connection_id').notNull(),
7
+ organizationId: text('organization_id').notNull(),
8
+ organizationUrlKey: text('organization_url_key').notNull(),
9
+ appUserId: text('app_user_id').notNull(),
10
+ scopes: jsonb('scopes').notNull().$type(),
11
+ tokenExpiresAt: timestamp('token_expires_at', {
12
+ withTimezone: true
13
+ }),
14
+ status: text('status').notNull().$type(),
15
+ createdAt: timestamp('created_at', {
16
+ withTimezone: true
17
+ }).notNull().defaultNow(),
18
+ updatedAt: timestamp('updated_at', {
19
+ withTimezone: true
20
+ }).notNull().defaultNow()
21
+ }, (table)=>[
22
+ uniqueIndex('integrations_linear_installations_connection_unique').on(table.connectionId),
23
+ uniqueIndex('integrations_linear_installations_organization_unique').on(table.organizationId)
24
+ ]);
25
+ export function toLinearInstallation(row) {
26
+ return {
27
+ id: row.id,
28
+ connectionId: row.connectionId,
29
+ organizationId: row.organizationId,
30
+ organizationUrlKey: row.organizationUrlKey,
31
+ appUserId: row.appUserId,
32
+ scopes: row.scopes,
33
+ tokenExpiresAt: row.tokenExpiresAt,
34
+ status: row.status,
35
+ createdAt: row.createdAt,
36
+ updatedAt: row.updatedAt
37
+ };
38
+ }
39
+
40
+ //# sourceMappingURL=installations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/db/schema/installations.ts"],"sourcesContent":["import {uuidv7PrimaryKey} from '@shipfox/node-drizzle';\nimport {jsonb, text, timestamp, uniqueIndex, uuid} from 'drizzle-orm/pg-core';\nimport type {LinearInstallation} from '#db/installations.js';\nimport {pgTable} from './common.js';\n\nexport const linearInstallations = pgTable(\n 'installations',\n {\n id: uuidv7PrimaryKey(),\n connectionId: uuid('connection_id').notNull(),\n organizationId: text('organization_id').notNull(),\n organizationUrlKey: text('organization_url_key').notNull(),\n appUserId: text('app_user_id').notNull(),\n scopes: jsonb('scopes').notNull().$type<string[]>(),\n tokenExpiresAt: timestamp('token_expires_at', {withTimezone: true}),\n status: text('status').notNull().$type<LinearInstallation['status']>(),\n createdAt: timestamp('created_at', {withTimezone: true}).notNull().defaultNow(),\n updatedAt: timestamp('updated_at', {withTimezone: true}).notNull().defaultNow(),\n },\n (table) => [\n uniqueIndex('integrations_linear_installations_connection_unique').on(table.connectionId),\n uniqueIndex('integrations_linear_installations_organization_unique').on(table.organizationId),\n ],\n);\n\nexport type LinearInstallationDb = typeof linearInstallations.$inferSelect;\nexport type LinearInstallationCreateDb = typeof linearInstallations.$inferInsert;\n\nexport function toLinearInstallation(row: LinearInstallationDb): LinearInstallation {\n return {\n id: row.id,\n connectionId: row.connectionId,\n organizationId: row.organizationId,\n organizationUrlKey: row.organizationUrlKey,\n appUserId: row.appUserId,\n scopes: row.scopes,\n tokenExpiresAt: row.tokenExpiresAt,\n status: row.status,\n createdAt: row.createdAt,\n updatedAt: row.updatedAt,\n };\n}\n"],"names":["uuidv7PrimaryKey","jsonb","text","timestamp","uniqueIndex","uuid","pgTable","linearInstallations","id","connectionId","notNull","organizationId","organizationUrlKey","appUserId","scopes","$type","tokenExpiresAt","withTimezone","status","createdAt","defaultNow","updatedAt","table","on","toLinearInstallation","row"],"mappings":"AAAA,SAAQA,gBAAgB,QAAO,wBAAwB;AACvD,SAAQC,KAAK,EAAEC,IAAI,EAAEC,SAAS,EAAEC,WAAW,EAAEC,IAAI,QAAO,sBAAsB;AAE9E,SAAQC,OAAO,QAAO,cAAc;AAEpC,OAAO,MAAMC,sBAAsBD,QACjC,iBACA;IACEE,IAAIR;IACJS,cAAcJ,KAAK,iBAAiBK,OAAO;IAC3CC,gBAAgBT,KAAK,mBAAmBQ,OAAO;IAC/CE,oBAAoBV,KAAK,wBAAwBQ,OAAO;IACxDG,WAAWX,KAAK,eAAeQ,OAAO;IACtCI,QAAQb,MAAM,UAAUS,OAAO,GAAGK,KAAK;IACvCC,gBAAgBb,UAAU,oBAAoB;QAACc,cAAc;IAAI;IACjEC,QAAQhB,KAAK,UAAUQ,OAAO,GAAGK,KAAK;IACtCI,WAAWhB,UAAU,cAAc;QAACc,cAAc;IAAI,GAAGP,OAAO,GAAGU,UAAU;IAC7EC,WAAWlB,UAAU,cAAc;QAACc,cAAc;IAAI,GAAGP,OAAO,GAAGU,UAAU;AAC/E,GACA,CAACE,QAAU;QACTlB,YAAY,uDAAuDmB,EAAE,CAACD,MAAMb,YAAY;QACxFL,YAAY,yDAAyDmB,EAAE,CAACD,MAAMX,cAAc;KAC7F,EACD;AAKF,OAAO,SAASa,qBAAqBC,GAAyB;IAC5D,OAAO;QACLjB,IAAIiB,IAAIjB,EAAE;QACVC,cAAcgB,IAAIhB,YAAY;QAC9BE,gBAAgBc,IAAId,cAAc;QAClCC,oBAAoBa,IAAIb,kBAAkB;QAC1CC,WAAWY,IAAIZ,SAAS;QACxBC,QAAQW,IAAIX,MAAM;QAClBE,gBAAgBS,IAAIT,cAAc;QAClCE,QAAQO,IAAIP,MAAM;QAClBC,WAAWM,IAAIN,SAAS;QACxBE,WAAWI,IAAIJ,SAAS;IAC1B;AACF"}
@@ -0,0 +1,53 @@
1
+ import { type LinearApiClient } from '#api/client.js';
2
+ import { config } from '#config.js';
3
+ import { LinearAgentToolsProvider } from '#core/agent-tools-provider.js';
4
+ import type { LinearTokenStore } from '#core/tokens.js';
5
+ import { closeDb, db } from '#db/db.js';
6
+ import { getLinearInstallationByConnectionId } from '#db/installations.js';
7
+ import { migrationsPath } from '#db/migrations.js';
8
+ import { type CreateLinearIntegrationRoutesOptions } from '#presentation/routes/install.js';
9
+ import { type CreateLinearWebhookRoutesOptions } from '#presentation/routes/webhooks.js';
10
+ export type { LinearProvider } from '@shipfox/api-integration-linear-dto';
11
+ export type { LinearApiClient, LinearAuthorization, LinearIdentity } from '#api/client.js';
12
+ export { createLinearApiClient } from '#api/client.js';
13
+ export type { LinearAgentToolCatalogEntry, LinearAgentToolCategory, LinearAgentToolId, LinearAgentToolRequiredScope, } from '#core/agent-tools.js';
14
+ export { linearAgentToolCatalog, linearAgentToolSelectionCatalog, } from '#core/agent-tools.js';
15
+ export { type DisconnectLinearInstallationParams, disconnectLinearInstallation, } from '#core/disconnect.js';
16
+ export { LinearAccessTokenMissingError, LinearAuthorizationScopeMismatchError, LinearConnectionAlreadyLinkedError, LinearConnectionNotFoundError, LinearInstallationAlreadyLinkedError, LinearInstallStateActorMismatchError, LinearInstallStateError, LinearIntegrationProviderError, LinearOAuthCallbackError, LinearTokenUnrefreshableError, } from '#core/errors.js';
17
+ export type { ConnectLinearInstallationInput, HandleLinearCallbackParams } from '#core/install.js';
18
+ export { handleLinearCallback, handleLinearOAuthCallbackError } from '#core/install.js';
19
+ export { assertLinearAuthorizationScopes, formatLinearOAuthScopes, LINEAR_OAUTH_SCOPES, } from '#core/scopes.js';
20
+ export type { LinearInstallStateClaims } from '#core/state.js';
21
+ export { signLinearInstallState, verifyLinearInstallState } from '#core/state.js';
22
+ export type { CreateLinearTokenStoreParams, GetLinearAccessTokenParams, LinearConnectionResolverResult, LinearSecretsStore, LinearTokenStore, StoreLinearTokensParams, } from '#core/tokens.js';
23
+ export { createLinearTokenStore, linearSecretsNamespace, } from '#core/tokens.js';
24
+ export type { HandleLinearWebhookOutcome, HandleLinearWebhookParams } from '#core/webhook.js';
25
+ export { handleLinearWebhook } from '#core/webhook.js';
26
+ export type { LinearInstallation, LinearInstallationStatus, UpdateLinearInstallationTokenExpiryParams, UpsertLinearInstallationParams, } from '#db/installations.js';
27
+ export { getLinearInstallationByConnectionId, getLinearInstallationByOrganizationId, markLinearInstallationRevoked, updateLinearInstallationTokenExpiry, upsertLinearInstallation, withLinearRefreshLock, } from '#db/installations.js';
28
+ export { type CreateLinearE2eRoutesOptions, createLinearE2eRoutes, } from '#presentation/e2eRoutes/index.js';
29
+ export { closeDb, config, db, migrationsPath };
30
+ export interface CreateLinearIntegrationProviderOptions {
31
+ linear?: LinearApiClient | undefined;
32
+ agentTools?: {
33
+ tokenStore: Pick<LinearTokenStore, 'getAccessToken'>;
34
+ endpoint?: string | URL | undefined;
35
+ callTimeoutMs?: number | undefined;
36
+ } | undefined;
37
+ getLinearInstallationByConnectionId?: typeof getLinearInstallationByConnectionId | undefined;
38
+ routes?: (Omit<CreateLinearIntegrationRoutesOptions, 'linear' | 'connectionCapabilities'> & Partial<CreateLinearWebhookRoutesOptions>) | undefined;
39
+ }
40
+ export declare function createLinearIntegrationProvider(options?: CreateLinearIntegrationProviderOptions): {
41
+ provider: string;
42
+ displayName: string;
43
+ adapters: {
44
+ agent_tools: LinearAgentToolsProvider;
45
+ } | {
46
+ agent_tools?: never;
47
+ };
48
+ connectionExternalUrl(connection: {
49
+ id: string;
50
+ }): Promise<string | undefined>;
51
+ routes: import("@shipfox/node-fastify").RouteGroup[];
52
+ };
53
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js ADDED
@@ -0,0 +1,56 @@
1
+ import { LINEAR_PROVIDER } from '@shipfox/api-integration-linear-dto';
2
+ import { createLinearApiClient } from '#api/client.js';
3
+ import { config } from '#config.js';
4
+ import { LinearAgentToolsProvider } from '#core/agent-tools-provider.js';
5
+ import { closeDb, db } from '#db/db.js';
6
+ import { getLinearInstallationByConnectionId } from '#db/installations.js';
7
+ import { migrationsPath } from '#db/migrations.js';
8
+ import { createLinearIntegrationRoutes } from '#presentation/routes/install.js';
9
+ import { createLinearWebhookRoutes } from '#presentation/routes/webhooks.js';
10
+ export { createLinearApiClient } from '#api/client.js';
11
+ export { linearAgentToolCatalog, linearAgentToolSelectionCatalog } from '#core/agent-tools.js';
12
+ export { disconnectLinearInstallation } from '#core/disconnect.js';
13
+ export { LinearAccessTokenMissingError, LinearAuthorizationScopeMismatchError, LinearConnectionAlreadyLinkedError, LinearConnectionNotFoundError, LinearInstallationAlreadyLinkedError, LinearInstallStateActorMismatchError, LinearInstallStateError, LinearIntegrationProviderError, LinearOAuthCallbackError, LinearTokenUnrefreshableError } from '#core/errors.js';
14
+ export { handleLinearCallback, handleLinearOAuthCallbackError } from '#core/install.js';
15
+ export { assertLinearAuthorizationScopes, formatLinearOAuthScopes, LINEAR_OAUTH_SCOPES } from '#core/scopes.js';
16
+ export { signLinearInstallState, verifyLinearInstallState } from '#core/state.js';
17
+ export { createLinearTokenStore, linearSecretsNamespace } from '#core/tokens.js';
18
+ export { handleLinearWebhook } from '#core/webhook.js';
19
+ export { getLinearInstallationByConnectionId, getLinearInstallationByOrganizationId, markLinearInstallationRevoked, updateLinearInstallationTokenExpiry, upsertLinearInstallation, withLinearRefreshLock } from '#db/installations.js';
20
+ export { createLinearE2eRoutes } from '#presentation/e2eRoutes/index.js';
21
+ export { closeDb, config, db, migrationsPath };
22
+ export function createLinearIntegrationProvider(options = {}) {
23
+ const linear = options.linear ?? createLinearApiClient();
24
+ const getInstallationByConnectionId = options.getLinearInstallationByConnectionId ?? getLinearInstallationByConnectionId;
25
+ const adapters = options.agentTools ? {
26
+ agent_tools: new LinearAgentToolsProvider(options.agentTools)
27
+ } : {};
28
+ const routes = options.routes ? [
29
+ createLinearIntegrationRoutes({
30
+ linear,
31
+ connectionCapabilities: adapters.agent_tools ? [
32
+ 'agent_tools'
33
+ ] : [],
34
+ ...options.routes
35
+ })
36
+ ] : [];
37
+ if (options.routes && hasLinearWebhookRoutesOptions(options.routes)) {
38
+ routes.push(createLinearWebhookRoutes(options.routes));
39
+ }
40
+ return {
41
+ provider: LINEAR_PROVIDER,
42
+ displayName: 'Linear',
43
+ adapters,
44
+ async connectionExternalUrl (connection) {
45
+ const installation = await getInstallationByConnectionId(connection.id);
46
+ if (!installation?.organizationUrlKey) return undefined;
47
+ return `https://linear.app/${encodeURIComponent(installation.organizationUrlKey)}/settings`;
48
+ },
49
+ routes
50
+ };
51
+ }
52
+ function hasLinearWebhookRoutesOptions(routes) {
53
+ return routes.coreDb !== undefined && routes.publishIntegrationEventReceived !== undefined && routes.recordDeliveryOnly !== undefined && routes.getIntegrationConnectionById !== undefined;
54
+ }
55
+
56
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import {LINEAR_PROVIDER} from '@shipfox/api-integration-linear-dto';\nimport {createLinearApiClient, type LinearApiClient} from '#api/client.js';\nimport {config} from '#config.js';\nimport {LinearAgentToolsProvider} from '#core/agent-tools-provider.js';\nimport type {LinearTokenStore} from '#core/tokens.js';\nimport {closeDb, db} from '#db/db.js';\nimport {getLinearInstallationByConnectionId} from '#db/installations.js';\nimport {migrationsPath} from '#db/migrations.js';\nimport {\n type CreateLinearIntegrationRoutesOptions,\n createLinearIntegrationRoutes,\n} from '#presentation/routes/install.js';\nimport {\n type CreateLinearWebhookRoutesOptions,\n createLinearWebhookRoutes,\n} from '#presentation/routes/webhooks.js';\n\nexport type {LinearProvider} from '@shipfox/api-integration-linear-dto';\nexport type {LinearApiClient, LinearAuthorization, LinearIdentity} from '#api/client.js';\nexport {createLinearApiClient} from '#api/client.js';\nexport type {\n LinearAgentToolCatalogEntry,\n LinearAgentToolCategory,\n LinearAgentToolId,\n LinearAgentToolRequiredScope,\n} from '#core/agent-tools.js';\nexport {\n linearAgentToolCatalog,\n linearAgentToolSelectionCatalog,\n} from '#core/agent-tools.js';\nexport {\n type DisconnectLinearInstallationParams,\n disconnectLinearInstallation,\n} from '#core/disconnect.js';\nexport {\n LinearAccessTokenMissingError,\n LinearAuthorizationScopeMismatchError,\n LinearConnectionAlreadyLinkedError,\n LinearConnectionNotFoundError,\n LinearInstallationAlreadyLinkedError,\n LinearInstallStateActorMismatchError,\n LinearInstallStateError,\n LinearIntegrationProviderError,\n LinearOAuthCallbackError,\n LinearTokenUnrefreshableError,\n} from '#core/errors.js';\nexport type {ConnectLinearInstallationInput, HandleLinearCallbackParams} from '#core/install.js';\nexport {handleLinearCallback, handleLinearOAuthCallbackError} from '#core/install.js';\nexport {\n assertLinearAuthorizationScopes,\n formatLinearOAuthScopes,\n LINEAR_OAUTH_SCOPES,\n} from '#core/scopes.js';\nexport type {LinearInstallStateClaims} from '#core/state.js';\nexport {signLinearInstallState, verifyLinearInstallState} from '#core/state.js';\nexport type {\n CreateLinearTokenStoreParams,\n GetLinearAccessTokenParams,\n LinearConnectionResolverResult,\n LinearSecretsStore,\n LinearTokenStore,\n StoreLinearTokensParams,\n} from '#core/tokens.js';\nexport {\n createLinearTokenStore,\n linearSecretsNamespace,\n} from '#core/tokens.js';\nexport type {HandleLinearWebhookOutcome, HandleLinearWebhookParams} from '#core/webhook.js';\nexport {handleLinearWebhook} from '#core/webhook.js';\nexport type {\n LinearInstallation,\n LinearInstallationStatus,\n UpdateLinearInstallationTokenExpiryParams,\n UpsertLinearInstallationParams,\n} from '#db/installations.js';\nexport {\n getLinearInstallationByConnectionId,\n getLinearInstallationByOrganizationId,\n markLinearInstallationRevoked,\n updateLinearInstallationTokenExpiry,\n upsertLinearInstallation,\n withLinearRefreshLock,\n} from '#db/installations.js';\nexport {\n type CreateLinearE2eRoutesOptions,\n createLinearE2eRoutes,\n} from '#presentation/e2eRoutes/index.js';\nexport {closeDb, config, db, migrationsPath};\n\nexport interface CreateLinearIntegrationProviderOptions {\n linear?: LinearApiClient | undefined;\n agentTools?:\n | {\n tokenStore: Pick<LinearTokenStore, 'getAccessToken'>;\n endpoint?: string | URL | undefined;\n callTimeoutMs?: number | undefined;\n }\n | undefined;\n getLinearInstallationByConnectionId?: typeof getLinearInstallationByConnectionId | undefined;\n routes?:\n | (Omit<CreateLinearIntegrationRoutesOptions, 'linear' | 'connectionCapabilities'> &\n Partial<CreateLinearWebhookRoutesOptions>)\n | undefined;\n}\n\nexport function createLinearIntegrationProvider(\n options: CreateLinearIntegrationProviderOptions = {},\n) {\n const linear = options.linear ?? createLinearApiClient();\n const getInstallationByConnectionId =\n options.getLinearInstallationByConnectionId ?? getLinearInstallationByConnectionId;\n const adapters = options.agentTools\n ? {\n agent_tools: new LinearAgentToolsProvider(options.agentTools),\n }\n : {};\n\n const routes = options.routes\n ? [\n createLinearIntegrationRoutes({\n linear,\n connectionCapabilities: adapters.agent_tools ? ['agent_tools'] : [],\n ...options.routes,\n }),\n ]\n : [];\n if (options.routes && hasLinearWebhookRoutesOptions(options.routes)) {\n routes.push(createLinearWebhookRoutes(options.routes));\n }\n\n return {\n provider: LINEAR_PROVIDER,\n displayName: 'Linear',\n adapters,\n async connectionExternalUrl(connection: {id: string}): Promise<string | undefined> {\n const installation = await getInstallationByConnectionId(connection.id);\n if (!installation?.organizationUrlKey) return undefined;\n return `https://linear.app/${encodeURIComponent(installation.organizationUrlKey)}/settings`;\n },\n routes,\n };\n}\n\nfunction hasLinearWebhookRoutesOptions(\n routes: Partial<CreateLinearWebhookRoutesOptions>,\n): routes is CreateLinearWebhookRoutesOptions {\n return (\n routes.coreDb !== undefined &&\n routes.publishIntegrationEventReceived !== undefined &&\n routes.recordDeliveryOnly !== undefined &&\n routes.getIntegrationConnectionById !== undefined\n );\n}\n"],"names":["LINEAR_PROVIDER","createLinearApiClient","config","LinearAgentToolsProvider","closeDb","db","getLinearInstallationByConnectionId","migrationsPath","createLinearIntegrationRoutes","createLinearWebhookRoutes","linearAgentToolCatalog","linearAgentToolSelectionCatalog","disconnectLinearInstallation","LinearAccessTokenMissingError","LinearAuthorizationScopeMismatchError","LinearConnectionAlreadyLinkedError","LinearConnectionNotFoundError","LinearInstallationAlreadyLinkedError","LinearInstallStateActorMismatchError","LinearInstallStateError","LinearIntegrationProviderError","LinearOAuthCallbackError","LinearTokenUnrefreshableError","handleLinearCallback","handleLinearOAuthCallbackError","assertLinearAuthorizationScopes","formatLinearOAuthScopes","LINEAR_OAUTH_SCOPES","signLinearInstallState","verifyLinearInstallState","createLinearTokenStore","linearSecretsNamespace","handleLinearWebhook","getLinearInstallationByOrganizationId","markLinearInstallationRevoked","updateLinearInstallationTokenExpiry","upsertLinearInstallation","withLinearRefreshLock","createLinearE2eRoutes","createLinearIntegrationProvider","options","linear","getInstallationByConnectionId","adapters","agentTools","agent_tools","routes","connectionCapabilities","hasLinearWebhookRoutesOptions","push","provider","displayName","connectionExternalUrl","connection","installation","id","organizationUrlKey","undefined","encodeURIComponent","coreDb","publishIntegrationEventReceived","recordDeliveryOnly","getIntegrationConnectionById"],"mappings":"AAAA,SAAQA,eAAe,QAAO,sCAAsC;AACpE,SAAQC,qBAAqB,QAA6B,iBAAiB;AAC3E,SAAQC,MAAM,QAAO,aAAa;AAClC,SAAQC,wBAAwB,QAAO,gCAAgC;AAEvE,SAAQC,OAAO,EAAEC,EAAE,QAAO,YAAY;AACtC,SAAQC,mCAAmC,QAAO,uBAAuB;AACzE,SAAQC,cAAc,QAAO,oBAAoB;AACjD,SAEEC,6BAA6B,QACxB,kCAAkC;AACzC,SAEEC,yBAAyB,QACpB,mCAAmC;AAI1C,SAAQR,qBAAqB,QAAO,iBAAiB;AAOrD,SACES,sBAAsB,EACtBC,+BAA+B,QAC1B,uBAAuB;AAC9B,SAEEC,4BAA4B,QACvB,sBAAsB;AAC7B,SACEC,6BAA6B,EAC7BC,qCAAqC,EACrCC,kCAAkC,EAClCC,6BAA6B,EAC7BC,oCAAoC,EACpCC,oCAAoC,EACpCC,uBAAuB,EACvBC,8BAA8B,EAC9BC,wBAAwB,EACxBC,6BAA6B,QACxB,kBAAkB;AAEzB,SAAQC,oBAAoB,EAAEC,8BAA8B,QAAO,mBAAmB;AACtF,SACEC,+BAA+B,EAC/BC,uBAAuB,EACvBC,mBAAmB,QACd,kBAAkB;AAEzB,SAAQC,sBAAsB,EAAEC,wBAAwB,QAAO,iBAAiB;AAShF,SACEC,sBAAsB,EACtBC,sBAAsB,QACjB,kBAAkB;AAEzB,SAAQC,mBAAmB,QAAO,mBAAmB;AAOrD,SACE1B,mCAAmC,EACnC2B,qCAAqC,EACrCC,6BAA6B,EAC7BC,mCAAmC,EACnCC,wBAAwB,EACxBC,qBAAqB,QAChB,uBAAuB;AAC9B,SAEEC,qBAAqB,QAChB,mCAAmC;AAC1C,SAAQlC,OAAO,EAAEF,MAAM,EAAEG,EAAE,EAAEE,cAAc,GAAE;AAkB7C,OAAO,SAASgC,gCACdC,UAAkD,CAAC,CAAC;IAEpD,MAAMC,SAASD,QAAQC,MAAM,IAAIxC;IACjC,MAAMyC,gCACJF,QAAQlC,mCAAmC,IAAIA;IACjD,MAAMqC,WAAWH,QAAQI,UAAU,GAC/B;QACEC,aAAa,IAAI1C,yBAAyBqC,QAAQI,UAAU;IAC9D,IACA,CAAC;IAEL,MAAME,SAASN,QAAQM,MAAM,GACzB;QACEtC,8BAA8B;YAC5BiC;YACAM,wBAAwBJ,SAASE,WAAW,GAAG;gBAAC;aAAc,GAAG,EAAE;YACnE,GAAGL,QAAQM,MAAM;QACnB;KACD,GACD,EAAE;IACN,IAAIN,QAAQM,MAAM,IAAIE,8BAA8BR,QAAQM,MAAM,GAAG;QACnEA,OAAOG,IAAI,CAACxC,0BAA0B+B,QAAQM,MAAM;IACtD;IAEA,OAAO;QACLI,UAAUlD;QACVmD,aAAa;QACbR;QACA,MAAMS,uBAAsBC,UAAwB;YAClD,MAAMC,eAAe,MAAMZ,8BAA8BW,WAAWE,EAAE;YACtE,IAAI,CAACD,cAAcE,oBAAoB,OAAOC;YAC9C,OAAO,CAAC,mBAAmB,EAAEC,mBAAmBJ,aAAaE,kBAAkB,EAAE,SAAS,CAAC;QAC7F;QACAV;IACF;AACF;AAEA,SAASE,8BACPF,MAAiD;IAEjD,OACEA,OAAOa,MAAM,KAAKF,aAClBX,OAAOc,+BAA+B,KAAKH,aAC3CX,OAAOe,kBAAkB,KAAKJ,aAC9BX,OAAOgB,4BAA4B,KAAKL;AAE5C"}
@@ -0,0 +1,17 @@
1
+ import type { IntegrationCapability, IntegrationConnection } from '@shipfox/api-integration-core-dto';
2
+ export declare function toIntegrationConnectionDto(connection: IntegrationConnection, params: {
3
+ capabilities: IntegrationCapability[];
4
+ }): {
5
+ created_at: string;
6
+ updated_at: string;
7
+ external_url?: string;
8
+ id: string;
9
+ workspace_id: string;
10
+ provider: string;
11
+ external_account_id: string;
12
+ slug: string;
13
+ display_name: string;
14
+ lifecycle_status: import("@shipfox/api-integration-core-dto").IntegrationConnectionLifecycleStatus;
15
+ capabilities: IntegrationCapability[];
16
+ };
17
+ //# sourceMappingURL=integrations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"integrations.d.ts","sourceRoot":"","sources":["../../../src/presentation/dto/integrations.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,qBAAqB,EAAE,qBAAqB,EAAC,MAAM,mCAAmC,CAAC;AAGpG,wBAAgB,0BAA0B,CACxC,UAAU,EAAE,qBAAqB,EACjC,MAAM,EAAE;IAAC,YAAY,EAAE,qBAAqB,EAAE,CAAA;CAAC;;;;;;;;;;;;EAGhD"}
@@ -0,0 +1,6 @@
1
+ import { toIntegrationConnectionDto as toCoreIntegrationConnectionDto } from '@shipfox/api-integration-core-dto';
2
+ export function toIntegrationConnectionDto(connection, params) {
3
+ return toCoreIntegrationConnectionDto(connection, params);
4
+ }
5
+
6
+ //# sourceMappingURL=integrations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/presentation/dto/integrations.ts"],"sourcesContent":["import type {IntegrationCapability, IntegrationConnection} from '@shipfox/api-integration-core-dto';\nimport {toIntegrationConnectionDto as toCoreIntegrationConnectionDto} from '@shipfox/api-integration-core-dto';\n\nexport function toIntegrationConnectionDto(\n connection: IntegrationConnection,\n params: {capabilities: IntegrationCapability[]},\n) {\n return toCoreIntegrationConnectionDto(connection, params);\n}\n"],"names":["toIntegrationConnectionDto","toCoreIntegrationConnectionDto","connection","params"],"mappings":"AACA,SAAQA,8BAA8BC,8BAA8B,QAAO,oCAAoC;AAE/G,OAAO,SAASD,2BACdE,UAAiC,EACjCC,MAA+C;IAE/C,OAAOF,+BAA+BC,YAAYC;AACpD"}
@@ -0,0 +1,16 @@
1
+ import type { IntegrationCapability, IntegrationConnection } from '@shipfox/api-integration-core-dto';
2
+ import type { ConnectLinearInstallationInput } from '#core/install.js';
3
+ import type { LinearTokenStore } from '#core/tokens.js';
4
+ export interface CreateE2eLinearConnectionRouteOptions {
5
+ tokenStore: Pick<LinearTokenStore, 'storeTokens'>;
6
+ getExistingLinearConnection: (input: {
7
+ organizationId: string;
8
+ }) => Promise<IntegrationConnection<'linear'> | undefined>;
9
+ connectLinearInstallation: (input: ConnectLinearInstallationInput) => Promise<IntegrationConnection<'linear'>>;
10
+ disconnectLinearInstallation: (input: {
11
+ connectionId: string;
12
+ }) => Promise<void>;
13
+ connectionCapabilities: IntegrationCapability[];
14
+ }
15
+ export declare function createE2eLinearConnectionRoute(options: CreateE2eLinearConnectionRouteOptions): import("@shipfox/node-fastify").RouteDefinition;
16
+ //# sourceMappingURL=create-connection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-connection.d.ts","sourceRoot":"","sources":["../../../src/presentation/e2eRoutes/create-connection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,qBAAqB,EAAE,qBAAqB,EAAC,MAAM,mCAAmC,CAAC;AAOpG,OAAO,KAAK,EAAC,8BAA8B,EAAC,MAAM,kBAAkB,CAAC;AACrE,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,iBAAiB,CAAC;AAGtD,MAAM,WAAW,qCAAqC;IACpD,UAAU,EAAE,IAAI,CAAC,gBAAgB,EAAE,aAAa,CAAC,CAAC;IAClD,2BAA2B,EAAE,CAAC,KAAK,EAAE;QACnC,cAAc,EAAE,MAAM,CAAC;KACxB,KAAK,OAAO,CAAC,qBAAqB,CAAC,QAAQ,CAAC,GAAG,SAAS,CAAC,CAAC;IAC3D,yBAAyB,EAAE,CACzB,KAAK,EAAE,8BAA8B,KAClC,OAAO,CAAC,qBAAqB,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC9C,4BAA4B,EAAE,CAAC,KAAK,EAAE;QAAC,YAAY,EAAE,MAAM,CAAA;KAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/E,sBAAsB,EAAE,qBAAqB,EAAE,CAAC;CACjD;AAED,wBAAgB,8BAA8B,CAAC,OAAO,EAAE,qCAAqC,mDA+C5F"}
@@ -0,0 +1,64 @@
1
+ import { createE2eLinearConnectionBodySchema, createE2eLinearConnectionResponseSchema } from '@shipfox/api-integration-linear-dto';
2
+ import { ClientError, defineRoute } from '@shipfox/node-fastify';
3
+ import { logger } from '@shipfox/node-opentelemetry';
4
+ import { toIntegrationConnectionDto } from '#presentation/dto/integrations.js';
5
+ export function createE2eLinearConnectionRoute(options) {
6
+ return defineRoute({
7
+ method: 'POST',
8
+ path: '/linear-connections',
9
+ description: 'Create a synthetic Linear connection for E2E tests.',
10
+ schema: {
11
+ body: createE2eLinearConnectionBodySchema,
12
+ response: {
13
+ 201: createE2eLinearConnectionResponseSchema
14
+ }
15
+ },
16
+ handler: async (request, reply)=>{
17
+ const body = request.body;
18
+ const existing = await options.getExistingLinearConnection({
19
+ organizationId: body.organization_id
20
+ });
21
+ if (existing && existing.workspaceId !== body.workspace_id) {
22
+ throw new ClientError('Linear organization is already connected to another workspace', 'linear-connection-workspace-mismatch', {
23
+ status: 409
24
+ });
25
+ }
26
+ const connection = existing ?? await options.connectLinearInstallation({
27
+ workspaceId: body.workspace_id,
28
+ organizationId: body.organization_id,
29
+ organizationUrlKey: body.organization_url_key,
30
+ appUserId: body.app_user_id,
31
+ scopes: body.scopes,
32
+ tokenExpiresAt: null,
33
+ displayName: body.display_name
34
+ });
35
+ try {
36
+ await options.tokenStore.storeTokens({
37
+ connectionId: connection.id,
38
+ accessToken: body.access_token
39
+ });
40
+ } catch (error) {
41
+ if (!existing) await bestEffortDisconnectLinearInstallation(options, connection.id);
42
+ throw error;
43
+ }
44
+ reply.code(201);
45
+ return toIntegrationConnectionDto(connection, {
46
+ capabilities: options.connectionCapabilities
47
+ });
48
+ }
49
+ });
50
+ }
51
+ async function bestEffortDisconnectLinearInstallation(options, connectionId) {
52
+ try {
53
+ await options.disconnectLinearInstallation({
54
+ connectionId
55
+ });
56
+ } catch (error) {
57
+ logger().warn({
58
+ err: error,
59
+ connectionId
60
+ }, 'Linear E2E connection compensation failed after token storage rejection');
61
+ }
62
+ }
63
+
64
+ //# sourceMappingURL=create-connection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/presentation/e2eRoutes/create-connection.ts"],"sourcesContent":["import type {IntegrationCapability, IntegrationConnection} from '@shipfox/api-integration-core-dto';\nimport {\n createE2eLinearConnectionBodySchema,\n createE2eLinearConnectionResponseSchema,\n} from '@shipfox/api-integration-linear-dto';\nimport {ClientError, defineRoute} from '@shipfox/node-fastify';\nimport {logger} from '@shipfox/node-opentelemetry';\nimport type {ConnectLinearInstallationInput} from '#core/install.js';\nimport type {LinearTokenStore} from '#core/tokens.js';\nimport {toIntegrationConnectionDto} from '#presentation/dto/integrations.js';\n\nexport interface CreateE2eLinearConnectionRouteOptions {\n tokenStore: Pick<LinearTokenStore, 'storeTokens'>;\n getExistingLinearConnection: (input: {\n organizationId: string;\n }) => Promise<IntegrationConnection<'linear'> | undefined>;\n connectLinearInstallation: (\n input: ConnectLinearInstallationInput,\n ) => Promise<IntegrationConnection<'linear'>>;\n disconnectLinearInstallation: (input: {connectionId: string}) => Promise<void>;\n connectionCapabilities: IntegrationCapability[];\n}\n\nexport function createE2eLinearConnectionRoute(options: CreateE2eLinearConnectionRouteOptions) {\n return defineRoute({\n method: 'POST',\n path: '/linear-connections',\n description: 'Create a synthetic Linear connection for E2E tests.',\n schema: {\n body: createE2eLinearConnectionBodySchema,\n response: {201: createE2eLinearConnectionResponseSchema},\n },\n handler: async (request, reply) => {\n const body = request.body;\n const existing = await options.getExistingLinearConnection({\n organizationId: body.organization_id,\n });\n if (existing && existing.workspaceId !== body.workspace_id) {\n throw new ClientError(\n 'Linear organization is already connected to another workspace',\n 'linear-connection-workspace-mismatch',\n {status: 409},\n );\n }\n const connection =\n existing ??\n (await options.connectLinearInstallation({\n workspaceId: body.workspace_id,\n organizationId: body.organization_id,\n organizationUrlKey: body.organization_url_key,\n appUserId: body.app_user_id,\n scopes: body.scopes,\n tokenExpiresAt: null,\n displayName: body.display_name,\n }));\n\n try {\n await options.tokenStore.storeTokens({\n connectionId: connection.id,\n accessToken: body.access_token,\n });\n } catch (error) {\n if (!existing) await bestEffortDisconnectLinearInstallation(options, connection.id);\n throw error;\n }\n\n reply.code(201);\n return toIntegrationConnectionDto(connection, {capabilities: options.connectionCapabilities});\n },\n });\n}\n\nasync function bestEffortDisconnectLinearInstallation(\n options: CreateE2eLinearConnectionRouteOptions,\n connectionId: string,\n): Promise<void> {\n try {\n await options.disconnectLinearInstallation({connectionId});\n } catch (error) {\n logger().warn(\n {err: error, connectionId},\n 'Linear E2E connection compensation failed after token storage rejection',\n );\n }\n}\n"],"names":["createE2eLinearConnectionBodySchema","createE2eLinearConnectionResponseSchema","ClientError","defineRoute","logger","toIntegrationConnectionDto","createE2eLinearConnectionRoute","options","method","path","description","schema","body","response","handler","request","reply","existing","getExistingLinearConnection","organizationId","organization_id","workspaceId","workspace_id","status","connection","connectLinearInstallation","organizationUrlKey","organization_url_key","appUserId","app_user_id","scopes","tokenExpiresAt","displayName","display_name","tokenStore","storeTokens","connectionId","id","accessToken","access_token","error","bestEffortDisconnectLinearInstallation","code","capabilities","connectionCapabilities","disconnectLinearInstallation","warn","err"],"mappings":"AACA,SACEA,mCAAmC,EACnCC,uCAAuC,QAClC,sCAAsC;AAC7C,SAAQC,WAAW,EAAEC,WAAW,QAAO,wBAAwB;AAC/D,SAAQC,MAAM,QAAO,8BAA8B;AAGnD,SAAQC,0BAA0B,QAAO,oCAAoC;AAc7E,OAAO,SAASC,+BAA+BC,OAA8C;IAC3F,OAAOJ,YAAY;QACjBK,QAAQ;QACRC,MAAM;QACNC,aAAa;QACbC,QAAQ;YACNC,MAAMZ;YACNa,UAAU;gBAAC,KAAKZ;YAAuC;QACzD;QACAa,SAAS,OAAOC,SAASC;YACvB,MAAMJ,OAAOG,QAAQH,IAAI;YACzB,MAAMK,WAAW,MAAMV,QAAQW,2BAA2B,CAAC;gBACzDC,gBAAgBP,KAAKQ,eAAe;YACtC;YACA,IAAIH,YAAYA,SAASI,WAAW,KAAKT,KAAKU,YAAY,EAAE;gBAC1D,MAAM,IAAIpB,YACR,iEACA,wCACA;oBAACqB,QAAQ;gBAAG;YAEhB;YACA,MAAMC,aACJP,YACC,MAAMV,QAAQkB,yBAAyB,CAAC;gBACvCJ,aAAaT,KAAKU,YAAY;gBAC9BH,gBAAgBP,KAAKQ,eAAe;gBACpCM,oBAAoBd,KAAKe,oBAAoB;gBAC7CC,WAAWhB,KAAKiB,WAAW;gBAC3BC,QAAQlB,KAAKkB,MAAM;gBACnBC,gBAAgB;gBAChBC,aAAapB,KAAKqB,YAAY;YAChC;YAEF,IAAI;gBACF,MAAM1B,QAAQ2B,UAAU,CAACC,WAAW,CAAC;oBACnCC,cAAcZ,WAAWa,EAAE;oBAC3BC,aAAa1B,KAAK2B,YAAY;gBAChC;YACF,EAAE,OAAOC,OAAO;gBACd,IAAI,CAACvB,UAAU,MAAMwB,uCAAuClC,SAASiB,WAAWa,EAAE;gBAClF,MAAMG;YACR;YAEAxB,MAAM0B,IAAI,CAAC;YACX,OAAOrC,2BAA2BmB,YAAY;gBAACmB,cAAcpC,QAAQqC,sBAAsB;YAAA;QAC7F;IACF;AACF;AAEA,eAAeH,uCACblC,OAA8C,EAC9C6B,YAAoB;IAEpB,IAAI;QACF,MAAM7B,QAAQsC,4BAA4B,CAAC;YAACT;QAAY;IAC1D,EAAE,OAAOI,OAAO;QACdpC,SAAS0C,IAAI,CACX;YAACC,KAAKP;YAAOJ;QAAY,GACzB;IAEJ;AACF"}
@@ -0,0 +1,5 @@
1
+ import type { RouteGroup } from '@shipfox/node-fastify';
2
+ import { type CreateE2eLinearConnectionRouteOptions } from './create-connection.js';
3
+ export type CreateLinearE2eRoutesOptions = CreateE2eLinearConnectionRouteOptions;
4
+ export declare function createLinearE2eRoutes(options: CreateLinearE2eRoutesOptions): RouteGroup;
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/presentation/e2eRoutes/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,uBAAuB,CAAC;AACtD,OAAO,EACL,KAAK,qCAAqC,EAE3C,MAAM,wBAAwB,CAAC;AAEhC,MAAM,MAAM,4BAA4B,GAAG,qCAAqC,CAAC;AAEjF,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,4BAA4B,GAAG,UAAU,CAKvF"}
@@ -0,0 +1,11 @@
1
+ import { createE2eLinearConnectionRoute } from './create-connection.js';
2
+ export function createLinearE2eRoutes(options) {
3
+ return {
4
+ prefix: '/integrations',
5
+ routes: [
6
+ createE2eLinearConnectionRoute(options)
7
+ ]
8
+ };
9
+ }
10
+
11
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/presentation/e2eRoutes/index.ts"],"sourcesContent":["import type {RouteGroup} from '@shipfox/node-fastify';\nimport {\n type CreateE2eLinearConnectionRouteOptions,\n createE2eLinearConnectionRoute,\n} from './create-connection.js';\n\nexport type CreateLinearE2eRoutesOptions = CreateE2eLinearConnectionRouteOptions;\n\nexport function createLinearE2eRoutes(options: CreateLinearE2eRoutesOptions): RouteGroup {\n return {\n prefix: '/integrations',\n routes: [createE2eLinearConnectionRoute(options)],\n };\n}\n"],"names":["createE2eLinearConnectionRoute","createLinearE2eRoutes","options","prefix","routes"],"mappings":"AACA,SAEEA,8BAA8B,QACzB,yBAAyB;AAIhC,OAAO,SAASC,sBAAsBC,OAAqC;IACzE,OAAO;QACLC,QAAQ;QACRC,QAAQ;YAACJ,+BAA+BE;SAAS;IACnD;AACF"}
@@ -0,0 +1,2 @@
1
+ export declare function linearRouteErrorHandler(error: unknown): never;
2
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../src/presentation/routes/errors.ts"],"names":[],"mappings":"AAqBA,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,CAsC7D"}
@@ -0,0 +1,65 @@
1
+ import { ConnectionSlugConflictError } from '@shipfox/api-integration-core-dto';
2
+ import { ClientError } from '@shipfox/node-fastify';
3
+ import { LinearAuthorizationScopeMismatchError, LinearConnectionAlreadyLinkedError, LinearInstallationAlreadyLinkedError, LinearInstallStateActorMismatchError, LinearInstallStateError, LinearIntegrationProviderError, LinearOAuthCallbackError } from '#core/errors.js';
4
+ function providerStatus(reason) {
5
+ if (reason === 'rate-limited') return 429;
6
+ if (reason === 'timeout' || reason === 'provider-unavailable') return 503;
7
+ return 422;
8
+ }
9
+ export function linearRouteErrorHandler(error) {
10
+ if (error instanceof LinearInstallStateError) {
11
+ throw new ClientError(error.message, 'invalid-linear-install-state', {
12
+ status: 400
13
+ });
14
+ }
15
+ if (error instanceof LinearInstallStateActorMismatchError) {
16
+ throw new ClientError(error.message, 'linear-install-state-actor-mismatch', {
17
+ status: 403
18
+ });
19
+ }
20
+ if (error instanceof LinearInstallationAlreadyLinkedError) {
21
+ throw new ClientError(error.message, 'linear-installation-already-linked', {
22
+ status: 409
23
+ });
24
+ }
25
+ if (error instanceof LinearConnectionAlreadyLinkedError) {
26
+ throw new ClientError(error.message, 'linear-connection-already-linked', {
27
+ status: 409
28
+ });
29
+ }
30
+ if (error instanceof LinearAuthorizationScopeMismatchError) {
31
+ throw new ClientError(error.message, 'linear-authorization-scope-mismatch', {
32
+ status: 422,
33
+ details: {
34
+ missing_scopes: error.missingScopes
35
+ }
36
+ });
37
+ }
38
+ if (error instanceof LinearOAuthCallbackError) {
39
+ throw new ClientError(error.message, 'linear-oauth-callback-error', {
40
+ status: 422,
41
+ details: {
42
+ error: error.providerError,
43
+ ...error.providerDescription ? {
44
+ error_description: error.providerDescription
45
+ } : {}
46
+ }
47
+ });
48
+ }
49
+ if (error instanceof ConnectionSlugConflictError) {
50
+ throw new ClientError(error.message, 'slug-conflict', {
51
+ status: 409
52
+ });
53
+ }
54
+ if (error instanceof LinearIntegrationProviderError) {
55
+ throw new ClientError(error.message, error.reason, {
56
+ details: {
57
+ retry_after_seconds: error.retryAfterSeconds
58
+ },
59
+ status: providerStatus(error.reason)
60
+ });
61
+ }
62
+ throw error;
63
+ }
64
+
65
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/presentation/routes/errors.ts"],"sourcesContent":["import {\n ConnectionSlugConflictError,\n type IntegrationProviderErrorReason,\n} from '@shipfox/api-integration-core-dto';\nimport {ClientError} from '@shipfox/node-fastify';\nimport {\n LinearAuthorizationScopeMismatchError,\n LinearConnectionAlreadyLinkedError,\n LinearInstallationAlreadyLinkedError,\n LinearInstallStateActorMismatchError,\n LinearInstallStateError,\n LinearIntegrationProviderError,\n LinearOAuthCallbackError,\n} from '#core/errors.js';\n\nfunction providerStatus(reason: IntegrationProviderErrorReason): number {\n if (reason === 'rate-limited') return 429;\n if (reason === 'timeout' || reason === 'provider-unavailable') return 503;\n return 422;\n}\n\nexport function linearRouteErrorHandler(error: unknown): never {\n if (error instanceof LinearInstallStateError) {\n throw new ClientError(error.message, 'invalid-linear-install-state', {status: 400});\n }\n if (error instanceof LinearInstallStateActorMismatchError) {\n throw new ClientError(error.message, 'linear-install-state-actor-mismatch', {status: 403});\n }\n if (error instanceof LinearInstallationAlreadyLinkedError) {\n throw new ClientError(error.message, 'linear-installation-already-linked', {status: 409});\n }\n if (error instanceof LinearConnectionAlreadyLinkedError) {\n throw new ClientError(error.message, 'linear-connection-already-linked', {status: 409});\n }\n if (error instanceof LinearAuthorizationScopeMismatchError) {\n throw new ClientError(error.message, 'linear-authorization-scope-mismatch', {\n status: 422,\n details: {missing_scopes: error.missingScopes},\n });\n }\n if (error instanceof LinearOAuthCallbackError) {\n throw new ClientError(error.message, 'linear-oauth-callback-error', {\n status: 422,\n details: {\n error: error.providerError,\n ...(error.providerDescription ? {error_description: error.providerDescription} : {}),\n },\n });\n }\n if (error instanceof ConnectionSlugConflictError) {\n throw new ClientError(error.message, 'slug-conflict', {status: 409});\n }\n if (error instanceof LinearIntegrationProviderError) {\n throw new ClientError(error.message, error.reason, {\n details: {retry_after_seconds: error.retryAfterSeconds},\n status: providerStatus(error.reason),\n });\n }\n throw error;\n}\n"],"names":["ConnectionSlugConflictError","ClientError","LinearAuthorizationScopeMismatchError","LinearConnectionAlreadyLinkedError","LinearInstallationAlreadyLinkedError","LinearInstallStateActorMismatchError","LinearInstallStateError","LinearIntegrationProviderError","LinearOAuthCallbackError","providerStatus","reason","linearRouteErrorHandler","error","message","status","details","missing_scopes","missingScopes","providerError","providerDescription","error_description","retry_after_seconds","retryAfterSeconds"],"mappings":"AAAA,SACEA,2BAA2B,QAEtB,oCAAoC;AAC3C,SAAQC,WAAW,QAAO,wBAAwB;AAClD,SACEC,qCAAqC,EACrCC,kCAAkC,EAClCC,oCAAoC,EACpCC,oCAAoC,EACpCC,uBAAuB,EACvBC,8BAA8B,EAC9BC,wBAAwB,QACnB,kBAAkB;AAEzB,SAASC,eAAeC,MAAsC;IAC5D,IAAIA,WAAW,gBAAgB,OAAO;IACtC,IAAIA,WAAW,aAAaA,WAAW,wBAAwB,OAAO;IACtE,OAAO;AACT;AAEA,OAAO,SAASC,wBAAwBC,KAAc;IACpD,IAAIA,iBAAiBN,yBAAyB;QAC5C,MAAM,IAAIL,YAAYW,MAAMC,OAAO,EAAE,gCAAgC;YAACC,QAAQ;QAAG;IACnF;IACA,IAAIF,iBAAiBP,sCAAsC;QACzD,MAAM,IAAIJ,YAAYW,MAAMC,OAAO,EAAE,uCAAuC;YAACC,QAAQ;QAAG;IAC1F;IACA,IAAIF,iBAAiBR,sCAAsC;QACzD,MAAM,IAAIH,YAAYW,MAAMC,OAAO,EAAE,sCAAsC;YAACC,QAAQ;QAAG;IACzF;IACA,IAAIF,iBAAiBT,oCAAoC;QACvD,MAAM,IAAIF,YAAYW,MAAMC,OAAO,EAAE,oCAAoC;YAACC,QAAQ;QAAG;IACvF;IACA,IAAIF,iBAAiBV,uCAAuC;QAC1D,MAAM,IAAID,YAAYW,MAAMC,OAAO,EAAE,uCAAuC;YAC1EC,QAAQ;YACRC,SAAS;gBAACC,gBAAgBJ,MAAMK,aAAa;YAAA;QAC/C;IACF;IACA,IAAIL,iBAAiBJ,0BAA0B;QAC7C,MAAM,IAAIP,YAAYW,MAAMC,OAAO,EAAE,+BAA+B;YAClEC,QAAQ;YACRC,SAAS;gBACPH,OAAOA,MAAMM,aAAa;gBAC1B,GAAIN,MAAMO,mBAAmB,GAAG;oBAACC,mBAAmBR,MAAMO,mBAAmB;gBAAA,IAAI,CAAC,CAAC;YACrF;QACF;IACF;IACA,IAAIP,iBAAiBZ,6BAA6B;QAChD,MAAM,IAAIC,YAAYW,MAAMC,OAAO,EAAE,iBAAiB;YAACC,QAAQ;QAAG;IACpE;IACA,IAAIF,iBAAiBL,gCAAgC;QACnD,MAAM,IAAIN,YAAYW,MAAMC,OAAO,EAAED,MAAMF,MAAM,EAAE;YACjDK,SAAS;gBAACM,qBAAqBT,MAAMU,iBAAiB;YAAA;YACtDR,QAAQL,eAAeG,MAAMF,MAAM;QACrC;IACF;IACA,MAAME;AACR"}