@relayfile/sdk 0.1.0 → 0.1.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.
- package/README.md +7 -2
- package/dist/client.d.ts +4 -2
- package/dist/client.js +59 -5
- package/dist/composio.d.ts +63 -0
- package/dist/composio.js +233 -0
- package/dist/errors.d.ts +0 -1
- package/dist/errors.js +0 -1
- package/dist/index.d.ts +8 -2
- package/dist/index.js +7 -1
- package/dist/nango.d.ts +47 -0
- package/dist/nango.js +91 -0
- package/dist/provider.d.ts +63 -0
- package/dist/provider.js +115 -0
- package/dist/sync.d.ts +87 -0
- package/dist/sync.js +394 -0
- package/dist/types.d.ts +39 -4
- package/dist/types.js +0 -1
- package/package.json +11 -12
- package/dist/client.d.ts.map +0 -1
- package/dist/client.js.map +0 -1
- package/dist/errors.d.ts.map +0 -1
- package/dist/errors.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js.map +0 -1
package/README.md
CHANGED
|
@@ -20,10 +20,15 @@ const client = new RelayFileClient({
|
|
|
20
20
|
|
|
21
21
|
const workspaceId = "workspace_123";
|
|
22
22
|
|
|
23
|
-
const tree = await client.listTree(workspaceId, {
|
|
23
|
+
const tree = await client.listTree(workspaceId, {
|
|
24
|
+
path: "/",
|
|
25
|
+
depth: 2
|
|
26
|
+
});
|
|
27
|
+
|
|
24
28
|
console.log(tree.entries.map((entry) => entry.path));
|
|
25
29
|
|
|
26
30
|
const file = await client.readFile(workspaceId, "/notes/todo.md");
|
|
31
|
+
|
|
27
32
|
console.log(file.content);
|
|
28
33
|
|
|
29
34
|
await client.writeFile({
|
|
@@ -37,4 +42,4 @@ await client.writeFile({
|
|
|
37
42
|
|
|
38
43
|
## Full Docs
|
|
39
44
|
|
|
40
|
-
Full documentation is available
|
|
45
|
+
Full documentation is available in the [relayfile docs](https://github.com/AgentWorkforce/relayfile/tree/main/docs).
|
package/dist/client.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type AdminIngressStatusResponse, type AdminSyncStatusResponse, type BulkWriteInput, type BulkWriteResponse, type BackendStatusResponse, type AckResponse, type DeleteFileInput, type DeadLetterItem, type DeadLetterFeedResponse, type EventFeedResponse, type ExportJsonResponse, type ExportOptions, type FileQueryResponse, type FileReadResponse, type FilesystemEvent, type GetEventsOptions, type GetAdminIngressStatusOptions, type GetAdminSyncStatusOptions, type GetOperationsOptions, type GetSyncDeadLettersOptions, type GetSyncIngressStatusOptions, type GetSyncStatusOptions, type ListTreeOptions, type OperationFeedResponse, type OperationStatusResponse, type QueuedResponse, type QueryFilesOptions, type SyncIngressStatusResponse, type SyncStatusResponse, type TreeResponse, type WriteFileInput, type WriteQueuedResponse } from "./types.js";
|
|
1
|
+
import { type AdminIngressStatusResponse, type AdminSyncStatusResponse, type BulkWriteInput, type BulkWriteResponse, type BackendStatusResponse, type AckResponse, type DeleteFileInput, type DeadLetterItem, type DeadLetterFeedResponse, type EventFeedResponse, type ExportJsonResponse, type ExportOptions, type FileQueryResponse, type FileReadResponse, type FilesystemEvent, type GetEventsOptions, type GetAdminIngressStatusOptions, type GetAdminSyncStatusOptions, type GetOperationsOptions, type GetSyncDeadLettersOptions, type GetSyncIngressStatusOptions, type GetSyncStatusOptions, type ListTreeOptions, type OperationFeedResponse, type OperationStatusResponse, type QueuedResponse, type QueryFilesOptions, type SyncIngressStatusResponse, type SyncStatusResponse, type TreeResponse, type WriteFileInput, type WriteQueuedResponse, type IngestWebhookInput, type WritebackItem, type AckWritebackInput, type AckWritebackResponse } from "./types.js";
|
|
2
2
|
export type AccessTokenProvider = string | (() => string | Promise<string>);
|
|
3
3
|
export interface RelayFileRetryOptions {
|
|
4
4
|
maxRetries?: number;
|
|
@@ -59,6 +59,9 @@ export declare class RelayFileClient {
|
|
|
59
59
|
replaySyncDeadLetter(workspaceId: string, envelopeId: string, correlationId?: string, signal?: AbortSignal): Promise<QueuedResponse>;
|
|
60
60
|
ackSyncDeadLetter(workspaceId: string, envelopeId: string, correlationId?: string, signal?: AbortSignal): Promise<AckResponse>;
|
|
61
61
|
triggerSyncRefresh(workspaceId: string, provider: string, reason?: string, correlationId?: string, signal?: AbortSignal): Promise<QueuedResponse>;
|
|
62
|
+
ingestWebhook(input: IngestWebhookInput): Promise<QueuedResponse>;
|
|
63
|
+
listPendingWritebacks(workspaceId: string, correlationId?: string, signal?: AbortSignal): Promise<WritebackItem[]>;
|
|
64
|
+
ackWriteback(input: AckWritebackInput): Promise<AckWritebackResponse>;
|
|
62
65
|
private request;
|
|
63
66
|
private performRequest;
|
|
64
67
|
private shouldRetryStatus;
|
|
@@ -70,4 +73,3 @@ export declare class RelayFileClient {
|
|
|
70
73
|
private throwForError;
|
|
71
74
|
}
|
|
72
75
|
export {};
|
|
73
|
-
//# sourceMappingURL=client.d.ts.map
|
package/dist/client.js
CHANGED
|
@@ -57,6 +57,15 @@ function createBlobFromResponse(response) {
|
|
|
57
57
|
}
|
|
58
58
|
return response.arrayBuffer().then((buffer) => new Blob([buffer], { type: response.headers.get("content-type") ?? undefined }));
|
|
59
59
|
}
|
|
60
|
+
function normalizeExportJsonResponse(payload) {
|
|
61
|
+
if (Array.isArray(payload)) {
|
|
62
|
+
return { files: payload };
|
|
63
|
+
}
|
|
64
|
+
const data = (payload ?? {});
|
|
65
|
+
return {
|
|
66
|
+
files: Array.isArray(data.files) ? data.files : []
|
|
67
|
+
};
|
|
68
|
+
}
|
|
60
69
|
class RelayFileWebSocketConnection {
|
|
61
70
|
socket;
|
|
62
71
|
handlers = {
|
|
@@ -92,7 +101,14 @@ class RelayFileWebSocketConnection {
|
|
|
92
101
|
}
|
|
93
102
|
let parsed;
|
|
94
103
|
try {
|
|
95
|
-
|
|
104
|
+
const raw = JSON.parse(event.data);
|
|
105
|
+
if (typeof raw !== "object" || raw === null || typeof raw.type !== "string") {
|
|
106
|
+
throw new Error("Invalid WebSocket event: missing required 'type' field.");
|
|
107
|
+
}
|
|
108
|
+
if (raw.path !== undefined && typeof raw.path !== "string") {
|
|
109
|
+
throw new Error("Invalid WebSocket event: 'path' must be a string.");
|
|
110
|
+
}
|
|
111
|
+
parsed = raw;
|
|
96
112
|
}
|
|
97
113
|
catch (error) {
|
|
98
114
|
const parseError = error instanceof Error ? error : new Error("Failed to parse WebSocket event payload.");
|
|
@@ -202,7 +218,7 @@ export class RelayFileClient {
|
|
|
202
218
|
});
|
|
203
219
|
}
|
|
204
220
|
async bulkWrite(input) {
|
|
205
|
-
|
|
221
|
+
const response = await this.performRequest({
|
|
206
222
|
method: "POST",
|
|
207
223
|
path: `/v1/workspaces/${encodeURIComponent(input.workspaceId)}/fs/bulk`,
|
|
208
224
|
correlationId: input.correlationId,
|
|
@@ -211,6 +227,7 @@ export class RelayFileClient {
|
|
|
211
227
|
},
|
|
212
228
|
signal: input.signal
|
|
213
229
|
});
|
|
230
|
+
return this.readPayload(response);
|
|
214
231
|
}
|
|
215
232
|
async deleteFile(input) {
|
|
216
233
|
const query = buildQuery({ path: input.path });
|
|
@@ -249,7 +266,7 @@ export class RelayFileClient {
|
|
|
249
266
|
accept: format === "json" ? "application/json" : "*/*"
|
|
250
267
|
});
|
|
251
268
|
if (format === "json") {
|
|
252
|
-
return this.readPayload(response);
|
|
269
|
+
return normalizeExportJsonResponse(await this.readPayload(response));
|
|
253
270
|
}
|
|
254
271
|
return createBlobFromResponse(response);
|
|
255
272
|
}
|
|
@@ -436,9 +453,47 @@ export class RelayFileClient {
|
|
|
436
453
|
signal
|
|
437
454
|
});
|
|
438
455
|
}
|
|
456
|
+
async ingestWebhook(input) {
|
|
457
|
+
return this.request({
|
|
458
|
+
method: "POST",
|
|
459
|
+
path: `/v1/workspaces/${encodeURIComponent(input.workspaceId)}/webhooks/ingest`,
|
|
460
|
+
correlationId: input.correlationId,
|
|
461
|
+
body: {
|
|
462
|
+
provider: input.provider,
|
|
463
|
+
event_type: input.event_type,
|
|
464
|
+
path: input.path,
|
|
465
|
+
data: input.data,
|
|
466
|
+
delivery_id: input.delivery_id,
|
|
467
|
+
timestamp: input.timestamp,
|
|
468
|
+
headers: input.headers
|
|
469
|
+
},
|
|
470
|
+
signal: input.signal
|
|
471
|
+
});
|
|
472
|
+
}
|
|
473
|
+
async listPendingWritebacks(workspaceId, correlationId, signal) {
|
|
474
|
+
return this.request({
|
|
475
|
+
method: "GET",
|
|
476
|
+
path: `/v1/workspaces/${encodeURIComponent(workspaceId)}/writeback/pending`,
|
|
477
|
+
correlationId,
|
|
478
|
+
signal
|
|
479
|
+
});
|
|
480
|
+
}
|
|
481
|
+
async ackWriteback(input) {
|
|
482
|
+
return this.request({
|
|
483
|
+
method: "POST",
|
|
484
|
+
path: `/v1/workspaces/${encodeURIComponent(input.workspaceId)}/writeback/${encodeURIComponent(input.itemId)}/ack`,
|
|
485
|
+
correlationId: input.correlationId,
|
|
486
|
+
body: {
|
|
487
|
+
success: input.success,
|
|
488
|
+
error: input.error
|
|
489
|
+
},
|
|
490
|
+
signal: input.signal
|
|
491
|
+
});
|
|
492
|
+
}
|
|
439
493
|
async request(params) {
|
|
440
494
|
const response = await this.performRequest(params);
|
|
441
|
-
|
|
495
|
+
const payload = await this.readPayload(response);
|
|
496
|
+
return payload;
|
|
442
497
|
}
|
|
443
498
|
async performRequest(params) {
|
|
444
499
|
const correlationId = params.correlationId ?? generateCorrelationId();
|
|
@@ -628,4 +683,3 @@ export class RelayFileClient {
|
|
|
628
683
|
});
|
|
629
684
|
}
|
|
630
685
|
}
|
|
631
|
-
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Composio integration bridge for Relayfile.
|
|
3
|
+
*
|
|
4
|
+
* Maps Composio trigger webhook events → Relayfile filesystem paths + semantics.
|
|
5
|
+
*
|
|
6
|
+
* Composio webhook payload format (V3):
|
|
7
|
+
* {
|
|
8
|
+
* "type": "composio.trigger.message",
|
|
9
|
+
* "metadata": {
|
|
10
|
+
* "trigger_slug": "GITHUB_COMMIT_EVENT",
|
|
11
|
+
* "trigger_id": "trig_abc123",
|
|
12
|
+
* "connected_account_id": "ca_xyz789",
|
|
13
|
+
* "user_id": "user_123",
|
|
14
|
+
* "toolkit": "github"
|
|
15
|
+
* },
|
|
16
|
+
* "data": {
|
|
17
|
+
* // trigger-specific payload (e.g., commit author, message, url)
|
|
18
|
+
* }
|
|
19
|
+
* }
|
|
20
|
+
*
|
|
21
|
+
* @see https://docs.composio.dev/docs/triggers
|
|
22
|
+
* @see https://docs.composio.dev/docs/setting-up-triggers/subscribing-to-events
|
|
23
|
+
*/
|
|
24
|
+
import type { QueuedResponse } from "./types.js";
|
|
25
|
+
import { IntegrationProvider, type WebhookInput } from "./provider.js";
|
|
26
|
+
/** Raw webhook payload from Composio (V3 format) */
|
|
27
|
+
export interface ComposioWebhookPayload {
|
|
28
|
+
type: "composio.trigger.message" | "composio.connected_account.expired";
|
|
29
|
+
metadata: {
|
|
30
|
+
trigger_slug: string;
|
|
31
|
+
trigger_id: string;
|
|
32
|
+
connected_account_id: string;
|
|
33
|
+
user_id?: string;
|
|
34
|
+
toolkit: string;
|
|
35
|
+
};
|
|
36
|
+
data: Record<string, unknown>;
|
|
37
|
+
}
|
|
38
|
+
/** Options for creating Composio trigger subscriptions */
|
|
39
|
+
export interface ComposioTriggerOptions {
|
|
40
|
+
/** Composio API key */
|
|
41
|
+
apiKey: string;
|
|
42
|
+
/** Webhook URL to receive events */
|
|
43
|
+
webhookUrl: string;
|
|
44
|
+
/** Base URL for Composio API (default: https://backend.composio.dev) */
|
|
45
|
+
baseUrl?: string;
|
|
46
|
+
}
|
|
47
|
+
export declare class ComposioHelpers extends IntegrationProvider {
|
|
48
|
+
readonly name = "composio";
|
|
49
|
+
/**
|
|
50
|
+
* Ingest a Composio webhook payload into Relayfile.
|
|
51
|
+
*
|
|
52
|
+
* @param workspaceId - Relayfile workspace ID
|
|
53
|
+
* @param rawInput - Raw Composio webhook payload (ComposioWebhookPayload)
|
|
54
|
+
* @param signal - Optional abort signal
|
|
55
|
+
*/
|
|
56
|
+
ingestWebhook(workspaceId: string, rawInput: unknown, signal?: AbortSignal): Promise<QueuedResponse>;
|
|
57
|
+
/**
|
|
58
|
+
* Normalize a Composio webhook payload to the generic WebhookInput format.
|
|
59
|
+
* Useful for custom processing pipelines.
|
|
60
|
+
*/
|
|
61
|
+
normalize(input: ComposioWebhookPayload): WebhookInput;
|
|
62
|
+
private buildSemanticProperties;
|
|
63
|
+
}
|
package/dist/composio.js
ADDED
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Composio integration bridge for Relayfile.
|
|
3
|
+
*
|
|
4
|
+
* Maps Composio trigger webhook events → Relayfile filesystem paths + semantics.
|
|
5
|
+
*
|
|
6
|
+
* Composio webhook payload format (V3):
|
|
7
|
+
* {
|
|
8
|
+
* "type": "composio.trigger.message",
|
|
9
|
+
* "metadata": {
|
|
10
|
+
* "trigger_slug": "GITHUB_COMMIT_EVENT",
|
|
11
|
+
* "trigger_id": "trig_abc123",
|
|
12
|
+
* "connected_account_id": "ca_xyz789",
|
|
13
|
+
* "user_id": "user_123",
|
|
14
|
+
* "toolkit": "github"
|
|
15
|
+
* },
|
|
16
|
+
* "data": {
|
|
17
|
+
* // trigger-specific payload (e.g., commit author, message, url)
|
|
18
|
+
* }
|
|
19
|
+
* }
|
|
20
|
+
*
|
|
21
|
+
* @see https://docs.composio.dev/docs/triggers
|
|
22
|
+
* @see https://docs.composio.dev/docs/setting-up-triggers/subscribing-to-events
|
|
23
|
+
*/
|
|
24
|
+
import { IntegrationProvider, computeCanonicalPath, } from "./provider.js";
|
|
25
|
+
// ---------------------------------------------------------------------------
|
|
26
|
+
// Trigger slug → Relayfile object type mapping
|
|
27
|
+
// ---------------------------------------------------------------------------
|
|
28
|
+
/**
|
|
29
|
+
* Maps Composio trigger slugs to Relayfile object types.
|
|
30
|
+
* The trigger slug format is usually: {TOOLKIT}_{EVENT_NAME}
|
|
31
|
+
* e.g., GITHUB_COMMIT_EVENT → "commits", SLACK_NEW_MESSAGE → "messages"
|
|
32
|
+
*/
|
|
33
|
+
const TRIGGER_OBJECT_TYPE = {
|
|
34
|
+
// GitHub
|
|
35
|
+
GITHUB_COMMIT_EVENT: "commits",
|
|
36
|
+
GITHUB_PULL_REQUEST_EVENT: "pull_requests",
|
|
37
|
+
GITHUB_ISSUE_EVENT: "issues",
|
|
38
|
+
GITHUB_STAR_EVENT: "stars",
|
|
39
|
+
GITHUB_PUSH_EVENT: "pushes",
|
|
40
|
+
// Slack
|
|
41
|
+
SLACK_NEW_MESSAGE: "messages",
|
|
42
|
+
SLACK_CHANNEL_CREATED: "channels",
|
|
43
|
+
SLACK_REACTION_ADDED: "reactions",
|
|
44
|
+
// Gmail
|
|
45
|
+
GMAIL_NEW_EMAIL: "emails",
|
|
46
|
+
// Zendesk
|
|
47
|
+
ZENDESK_NEW_TICKET: "tickets",
|
|
48
|
+
ZENDESK_TICKET_UPDATED: "tickets",
|
|
49
|
+
// Shopify
|
|
50
|
+
SHOPIFY_NEW_ORDER: "orders",
|
|
51
|
+
SHOPIFY_ORDER_UPDATED: "orders",
|
|
52
|
+
// Stripe
|
|
53
|
+
STRIPE_PAYMENT_RECEIVED: "payments",
|
|
54
|
+
STRIPE_INVOICE_CREATED: "invoices",
|
|
55
|
+
// Jira
|
|
56
|
+
JIRA_ISSUE_CREATED: "issues",
|
|
57
|
+
JIRA_ISSUE_UPDATED: "issues",
|
|
58
|
+
// HubSpot
|
|
59
|
+
HUBSPOT_CONTACT_CREATED: "contacts",
|
|
60
|
+
HUBSPOT_DEAL_CREATED: "deals",
|
|
61
|
+
// Notion
|
|
62
|
+
NOTION_PAGE_UPDATED: "pages",
|
|
63
|
+
// Linear
|
|
64
|
+
LINEAR_ISSUE_CREATED: "issues",
|
|
65
|
+
LINEAR_ISSUE_UPDATED: "issues",
|
|
66
|
+
// Intercom
|
|
67
|
+
INTERCOM_NEW_CONVERSATION: "conversations",
|
|
68
|
+
// Freshdesk
|
|
69
|
+
FRESHDESK_TICKET_CREATED: "tickets",
|
|
70
|
+
FRESHDESK_TICKET_UPDATED: "tickets",
|
|
71
|
+
};
|
|
72
|
+
/**
|
|
73
|
+
* Extract event type (created/updated/deleted) from trigger slug.
|
|
74
|
+
*/
|
|
75
|
+
function extractEventType(triggerSlug) {
|
|
76
|
+
const slug = triggerSlug.toUpperCase();
|
|
77
|
+
if (slug.includes("CREATED") || slug.includes("NEW"))
|
|
78
|
+
return "created";
|
|
79
|
+
if (slug.includes("UPDATED") || slug.includes("CHANGED"))
|
|
80
|
+
return "updated";
|
|
81
|
+
if (slug.includes("DELETED") || slug.includes("REMOVED"))
|
|
82
|
+
return "deleted";
|
|
83
|
+
return "event";
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Extract a stable object ID from Composio event data.
|
|
87
|
+
* Different triggers have different ID fields.
|
|
88
|
+
*/
|
|
89
|
+
function extractObjectId(data) {
|
|
90
|
+
// Common ID fields across various providers
|
|
91
|
+
const idFields = ["id", "objectId", "object_id", "ticketId", "issueId", "messageId", "orderId", "commitId"];
|
|
92
|
+
for (const field of idFields) {
|
|
93
|
+
const val = data[field];
|
|
94
|
+
if (typeof val === "string" || typeof val === "number") {
|
|
95
|
+
return String(val);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
// Nested ID patterns
|
|
99
|
+
if (typeof data.issue === "object" && data.issue !== null && "id" in data.issue) {
|
|
100
|
+
return String(data.issue.id);
|
|
101
|
+
}
|
|
102
|
+
if (typeof data.pull_request === "object" && data.pull_request !== null && "id" in data.pull_request) {
|
|
103
|
+
return String(data.pull_request.id);
|
|
104
|
+
}
|
|
105
|
+
// Fallback: hash from trigger_id + timestamp
|
|
106
|
+
return `auto-${Date.now().toString(36)}`;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Infer the object type from trigger slug when not in the mapping table.
|
|
110
|
+
* Format: TOOLKIT_OBJECT_EVENT → "objects" (pluralized)
|
|
111
|
+
*/
|
|
112
|
+
function inferObjectType(triggerSlug) {
|
|
113
|
+
// Remove toolkit prefix and event suffix
|
|
114
|
+
const parts = triggerSlug.toLowerCase().split("_");
|
|
115
|
+
if (parts.length >= 3) {
|
|
116
|
+
// e.g., GITHUB_COMMIT_EVENT → "commit" → "commits"
|
|
117
|
+
const objectPart = parts.slice(1, -1).join("_");
|
|
118
|
+
return objectPart.endsWith("s") ? objectPart : `${objectPart}s`;
|
|
119
|
+
}
|
|
120
|
+
return "events";
|
|
121
|
+
}
|
|
122
|
+
// ---------------------------------------------------------------------------
|
|
123
|
+
// Composio provider implementation
|
|
124
|
+
// ---------------------------------------------------------------------------
|
|
125
|
+
export class ComposioHelpers extends IntegrationProvider {
|
|
126
|
+
name = "composio";
|
|
127
|
+
/**
|
|
128
|
+
* Ingest a Composio webhook payload into Relayfile.
|
|
129
|
+
*
|
|
130
|
+
* @param workspaceId - Relayfile workspace ID
|
|
131
|
+
* @param rawInput - Raw Composio webhook payload (ComposioWebhookPayload)
|
|
132
|
+
* @param signal - Optional abort signal
|
|
133
|
+
*/
|
|
134
|
+
async ingestWebhook(workspaceId, rawInput, signal) {
|
|
135
|
+
const input = rawInput;
|
|
136
|
+
if (input.type === "composio.connected_account.expired") {
|
|
137
|
+
// Handle account expiry as a system event
|
|
138
|
+
return this.client.ingestWebhook({
|
|
139
|
+
workspaceId,
|
|
140
|
+
provider: input.metadata.toolkit || "composio",
|
|
141
|
+
event_type: "account_expired",
|
|
142
|
+
path: `/.system/composio/expired/${input.metadata.connected_account_id}.json`,
|
|
143
|
+
data: {
|
|
144
|
+
connected_account_id: input.metadata.connected_account_id,
|
|
145
|
+
user_id: input.metadata.user_id,
|
|
146
|
+
toolkit: input.metadata.toolkit,
|
|
147
|
+
expired_at: new Date().toISOString(),
|
|
148
|
+
},
|
|
149
|
+
headers: {},
|
|
150
|
+
signal,
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
const toolkit = input.metadata.toolkit;
|
|
154
|
+
const triggerSlug = input.metadata.trigger_slug;
|
|
155
|
+
const objectType = TRIGGER_OBJECT_TYPE[triggerSlug] ?? inferObjectType(triggerSlug);
|
|
156
|
+
const objectId = extractObjectId(input.data);
|
|
157
|
+
const eventType = extractEventType(triggerSlug);
|
|
158
|
+
const path = computeCanonicalPath(toolkit, objectType, objectId);
|
|
159
|
+
const properties = this.buildSemanticProperties(input);
|
|
160
|
+
const semantics = {
|
|
161
|
+
properties,
|
|
162
|
+
relations: [],
|
|
163
|
+
};
|
|
164
|
+
return this.client.ingestWebhook({
|
|
165
|
+
workspaceId,
|
|
166
|
+
provider: toolkit,
|
|
167
|
+
event_type: eventType,
|
|
168
|
+
path,
|
|
169
|
+
data: {
|
|
170
|
+
...input.data,
|
|
171
|
+
semantics,
|
|
172
|
+
},
|
|
173
|
+
headers: {
|
|
174
|
+
"X-Composio-Trigger-Id": input.metadata.trigger_id,
|
|
175
|
+
"X-Composio-Trigger-Slug": triggerSlug,
|
|
176
|
+
"X-Composio-Connected-Account": input.metadata.connected_account_id,
|
|
177
|
+
...(input.metadata.user_id
|
|
178
|
+
? { "X-Composio-User-Id": input.metadata.user_id }
|
|
179
|
+
: {}),
|
|
180
|
+
},
|
|
181
|
+
signal,
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Normalize a Composio webhook payload to the generic WebhookInput format.
|
|
186
|
+
* Useful for custom processing pipelines.
|
|
187
|
+
*/
|
|
188
|
+
normalize(input) {
|
|
189
|
+
const toolkit = input.metadata.toolkit;
|
|
190
|
+
const triggerSlug = input.metadata.trigger_slug;
|
|
191
|
+
return {
|
|
192
|
+
provider: toolkit,
|
|
193
|
+
objectType: TRIGGER_OBJECT_TYPE[triggerSlug] ?? inferObjectType(triggerSlug),
|
|
194
|
+
objectId: extractObjectId(input.data),
|
|
195
|
+
eventType: extractEventType(triggerSlug),
|
|
196
|
+
payload: input.data,
|
|
197
|
+
metadata: {
|
|
198
|
+
"composio.trigger_id": input.metadata.trigger_id,
|
|
199
|
+
"composio.trigger_slug": triggerSlug,
|
|
200
|
+
"composio.connected_account_id": input.metadata.connected_account_id,
|
|
201
|
+
...(input.metadata.user_id
|
|
202
|
+
? { "composio.user_id": input.metadata.user_id }
|
|
203
|
+
: {}),
|
|
204
|
+
},
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
buildSemanticProperties(input) {
|
|
208
|
+
const properties = {
|
|
209
|
+
"composio.trigger_id": input.metadata.trigger_id,
|
|
210
|
+
"composio.trigger_slug": input.metadata.trigger_slug,
|
|
211
|
+
"composio.connected_account_id": input.metadata.connected_account_id,
|
|
212
|
+
provider: input.metadata.toolkit,
|
|
213
|
+
"provider.object_type": TRIGGER_OBJECT_TYPE[input.metadata.trigger_slug] ??
|
|
214
|
+
inferObjectType(input.metadata.trigger_slug),
|
|
215
|
+
"provider.object_id": extractObjectId(input.data),
|
|
216
|
+
};
|
|
217
|
+
if (input.metadata.user_id) {
|
|
218
|
+
properties["composio.user_id"] = input.metadata.user_id;
|
|
219
|
+
}
|
|
220
|
+
// Extract common fields from data
|
|
221
|
+
const data = input.data;
|
|
222
|
+
if (typeof data.status === "string") {
|
|
223
|
+
properties["provider.status"] = data.status;
|
|
224
|
+
}
|
|
225
|
+
if (typeof data.updated_at === "string") {
|
|
226
|
+
properties["provider.updated_at"] = data.updated_at;
|
|
227
|
+
}
|
|
228
|
+
if (typeof data.created_at === "string") {
|
|
229
|
+
properties["provider.created_at"] = data.created_at;
|
|
230
|
+
}
|
|
231
|
+
return properties;
|
|
232
|
+
}
|
|
233
|
+
}
|
package/dist/errors.d.ts
CHANGED
package/dist/errors.js
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
export { RelayFileClient, type ConnectWebSocketOptions, type RelayFileRetryOptions, type WebSocketConnection } from "./client.js";
|
|
2
|
+
export { RelayFileSync, type RelayFileSyncOptions, type RelayFileSyncPong, type RelayFileSyncReconnectOptions, type RelayFileSyncSocket, type RelayFileSyncState } from "./sync.js";
|
|
2
3
|
export { InvalidStateError, PayloadTooLargeError, QueueFullError, RelayFileApiError, RevisionConflictError } from "./errors.js";
|
|
3
|
-
export
|
|
4
|
-
|
|
4
|
+
export { IntegrationProvider, computeCanonicalPath } from "./provider.js";
|
|
5
|
+
export type { WebhookInput, ListProviderFilesOptions, WatchProviderEventsOptions } from "./provider.js";
|
|
6
|
+
export { NangoHelpers } from "./nango.js";
|
|
7
|
+
export type { NangoWebhookInput } from "./nango.js";
|
|
8
|
+
export { ComposioHelpers } from "./composio.js";
|
|
9
|
+
export type { ComposioWebhookPayload, ComposioTriggerOptions } from "./composio.js";
|
|
10
|
+
export type { AckResponse, AckWritebackInput, AckWritebackResponse, AdminIngressAlert, AdminIngressAlertProfile, AdminIngressEffectiveAlertProfile, AdminIngressAlertSeverity, AdminIngressAlertThresholds, AdminIngressAlertTotals, AdminIngressAlertType, AdminIngressStatusResponse, AdminSyncAlert, AdminSyncAlertSeverity, AdminSyncAlertThresholds, AdminSyncAlertTotals, AdminSyncAlertType, AdminSyncStatusResponse, BackendStatusResponse, BulkWriteFile, BulkWriteInput, BulkWriteResponse, ConflictErrorResponse, DeleteFileInput, DeadLetterFeedResponse, DeadLetterItem, ErrorResponse, EventFeedResponse, ExportFormat, ExportJsonResponse, ExportOptions, FileQueryItem, FileQueryResponse, FileReadResponse, FileSemantics, FileWriteRequest, FilesystemEvent, FilesystemEventType, EventOrigin, GetEventsOptions, GetAdminSyncStatusOptions, GetAdminIngressStatusOptions, GetOperationsOptions, GetSyncDeadLettersOptions, GetSyncIngressStatusOptions, GetSyncStatusOptions, IngestWebhookInput, ListTreeOptions, OperationFeedResponse, OperationStatus, OperationStatusResponse, QueuedResponse, QueryFilesOptions, SyncIngressStatusResponse, SyncProviderStatus, SyncProviderStatusState, SyncRefreshRequest, SyncStatusResponse, TreeEntry, TreeResponse, WritebackActionType, WritebackState, WritebackItem, WriteFileInput, WriteQueuedResponse } from "./types.js";
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
1
|
export { RelayFileClient } from "./client.js";
|
|
2
|
+
export { RelayFileSync } from "./sync.js";
|
|
2
3
|
export { InvalidStateError, PayloadTooLargeError, QueueFullError, RelayFileApiError, RevisionConflictError } from "./errors.js";
|
|
3
|
-
|
|
4
|
+
// Integration providers
|
|
5
|
+
export { IntegrationProvider, computeCanonicalPath } from "./provider.js";
|
|
6
|
+
// Nango bridge
|
|
7
|
+
export { NangoHelpers } from "./nango.js";
|
|
8
|
+
// Composio bridge
|
|
9
|
+
export { ComposioHelpers } from "./composio.js";
|
package/dist/nango.d.ts
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Nango integration bridge for Relayfile.
|
|
3
|
+
*
|
|
4
|
+
* Maps Nango sync webhook events → Relayfile filesystem paths + semantics.
|
|
5
|
+
*
|
|
6
|
+
* @see https://docs.nango.dev/integrate/guides/receive-webhooks-from-nango
|
|
7
|
+
*/
|
|
8
|
+
import type { QueuedResponse } from "./types.js";
|
|
9
|
+
import { IntegrationProvider, type WebhookInput } from "./provider.js";
|
|
10
|
+
export interface NangoWebhookInput {
|
|
11
|
+
connectionId: string;
|
|
12
|
+
integrationId: string;
|
|
13
|
+
providerConfigKey?: string;
|
|
14
|
+
model: string;
|
|
15
|
+
objectId: string;
|
|
16
|
+
eventType: string;
|
|
17
|
+
payload: Record<string, unknown>;
|
|
18
|
+
relations?: string[];
|
|
19
|
+
}
|
|
20
|
+
export interface GetProviderFilesOptions {
|
|
21
|
+
provider: string;
|
|
22
|
+
objectType?: string;
|
|
23
|
+
status?: string;
|
|
24
|
+
limit?: number;
|
|
25
|
+
signal?: AbortSignal;
|
|
26
|
+
}
|
|
27
|
+
export interface WatchProviderEventsOptions {
|
|
28
|
+
provider: string;
|
|
29
|
+
pollIntervalMs?: number;
|
|
30
|
+
cursor?: string;
|
|
31
|
+
signal?: AbortSignal;
|
|
32
|
+
}
|
|
33
|
+
export declare class NangoHelpers extends IntegrationProvider {
|
|
34
|
+
readonly name = "nango";
|
|
35
|
+
/**
|
|
36
|
+
* Ingest a Nango webhook event into Relayfile.
|
|
37
|
+
*
|
|
38
|
+
* @param workspaceId - Relayfile workspace ID
|
|
39
|
+
* @param rawInput - NangoWebhookInput
|
|
40
|
+
* @param signal - Optional abort signal
|
|
41
|
+
*/
|
|
42
|
+
ingestWebhook(workspaceId: string, rawInput: unknown, signal?: AbortSignal): Promise<QueuedResponse>;
|
|
43
|
+
/**
|
|
44
|
+
* Normalize a Nango webhook input to the generic WebhookInput format.
|
|
45
|
+
*/
|
|
46
|
+
normalize(input: NangoWebhookInput): WebhookInput;
|
|
47
|
+
}
|
package/dist/nango.js
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Nango integration bridge for Relayfile.
|
|
3
|
+
*
|
|
4
|
+
* Maps Nango sync webhook events → Relayfile filesystem paths + semantics.
|
|
5
|
+
*
|
|
6
|
+
* @see https://docs.nango.dev/integrate/guides/receive-webhooks-from-nango
|
|
7
|
+
*/
|
|
8
|
+
import { IntegrationProvider, computeCanonicalPath, } from "./provider.js";
|
|
9
|
+
// ---------------------------------------------------------------------------
|
|
10
|
+
// Nango provider implementation
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
function buildSemanticProperties(provider, input, payload) {
|
|
13
|
+
const properties = {
|
|
14
|
+
"nango.connection_id": input.connectionId,
|
|
15
|
+
"nango.integration_id": input.integrationId,
|
|
16
|
+
"provider": provider,
|
|
17
|
+
"provider.object_type": input.model,
|
|
18
|
+
"provider.object_id": input.objectId
|
|
19
|
+
};
|
|
20
|
+
if (input.providerConfigKey) {
|
|
21
|
+
properties["nango.provider_config_key"] = input.providerConfigKey;
|
|
22
|
+
}
|
|
23
|
+
if (typeof payload.status === "string") {
|
|
24
|
+
properties["provider.status"] = payload.status;
|
|
25
|
+
}
|
|
26
|
+
if (typeof payload.updated_at === "string") {
|
|
27
|
+
properties["provider.updated_at"] = payload.updated_at;
|
|
28
|
+
}
|
|
29
|
+
if (typeof payload.created_at === "string") {
|
|
30
|
+
properties["provider.created_at"] = payload.created_at;
|
|
31
|
+
}
|
|
32
|
+
return properties;
|
|
33
|
+
}
|
|
34
|
+
export class NangoHelpers extends IntegrationProvider {
|
|
35
|
+
name = "nango";
|
|
36
|
+
/**
|
|
37
|
+
* Ingest a Nango webhook event into Relayfile.
|
|
38
|
+
*
|
|
39
|
+
* @param workspaceId - Relayfile workspace ID
|
|
40
|
+
* @param rawInput - NangoWebhookInput
|
|
41
|
+
* @param signal - Optional abort signal
|
|
42
|
+
*/
|
|
43
|
+
async ingestWebhook(workspaceId, rawInput, signal) {
|
|
44
|
+
const input = rawInput;
|
|
45
|
+
const provider = input.integrationId.split("-")[0] ?? input.integrationId;
|
|
46
|
+
const path = computeCanonicalPath(provider, input.model, input.objectId);
|
|
47
|
+
const properties = buildSemanticProperties(provider, input, input.payload);
|
|
48
|
+
return this.client.ingestWebhook({
|
|
49
|
+
workspaceId,
|
|
50
|
+
provider: provider,
|
|
51
|
+
event_type: input.eventType,
|
|
52
|
+
path,
|
|
53
|
+
data: {
|
|
54
|
+
...input.payload,
|
|
55
|
+
semantics: {
|
|
56
|
+
properties,
|
|
57
|
+
relations: input.relations ?? []
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
headers: {
|
|
61
|
+
"X-Nango-Connection-Id": input.connectionId,
|
|
62
|
+
"X-Nango-Integration-Id": input.integrationId,
|
|
63
|
+
...(input.providerConfigKey
|
|
64
|
+
? { "X-Nango-Provider-Config-Key": input.providerConfigKey }
|
|
65
|
+
: {})
|
|
66
|
+
},
|
|
67
|
+
signal
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Normalize a Nango webhook input to the generic WebhookInput format.
|
|
72
|
+
*/
|
|
73
|
+
normalize(input) {
|
|
74
|
+
const provider = input.integrationId.split("-")[0] ?? input.integrationId;
|
|
75
|
+
return {
|
|
76
|
+
provider,
|
|
77
|
+
objectType: input.model,
|
|
78
|
+
objectId: input.objectId,
|
|
79
|
+
eventType: input.eventType,
|
|
80
|
+
payload: input.payload,
|
|
81
|
+
relations: input.relations,
|
|
82
|
+
metadata: {
|
|
83
|
+
"nango.connection_id": input.connectionId,
|
|
84
|
+
"nango.integration_id": input.integrationId,
|
|
85
|
+
...(input.providerConfigKey
|
|
86
|
+
? { "nango.provider_config_key": input.providerConfigKey }
|
|
87
|
+
: {}),
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
}
|