@relayfile/sdk 0.7.9 → 0.7.11

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/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { RelayFileClient, DEFAULT_RELAYFILE_BASE_URL, type AccessTokenProvider, type ConnectWebSocketOptions, type RelayFileClientOptions, type RelayFileRetryOptions, type WebSocketConnection } from "./client.js";
1
+ export { RelayFileClient, DEFAULT_RELAYFILE_BASE_URL, type AccessTokenProvider, type RelayFileChangeLogOptions, type ConnectWebSocketOptions, type RelayFileClientOptions, type RelayFileRetryOptions, type WebSocketConnection } from "./client.js";
2
2
  export { RelayfileSetup, RELAYFILE_SDK_VERSION, WorkspaceHandle } from "./setup.js";
3
3
  export { type RelayfileCloudLoginOptions, type RelayfileCloudTokenSet, type RelayfileCloudTokenSetupOptions } from "./cloud-login.js";
4
4
  export { CloudAbortError, CloudApiError, CloudTimeoutError, InvalidLocalDirError, InvalidMountModeError, InvalidRemotePathError, IntegrationConnectionTimeoutError, MalformedCloudResponseError, MissingConnectionIdError, MountModeUnavailableError, MountReadyTimeoutError, MountSessionInputError, ProviderNotConnectedError, ProviderNotReadyError, RelayfileSetupError, UnknownProviderError } from "./setup-errors.js";
@@ -10,7 +10,7 @@ export { InvalidStateError, PayloadTooLargeError, QueueFullError, RelayFileApiEr
10
10
  export { IntegrationProvider, computeCanonicalPath } from "./provider.js";
11
11
  export type { WebhookInput, ListProviderFilesOptions, WatchProviderEventsOptions } from "./provider.js";
12
12
  export type { ConnectionProvider, NormalizedWebhook, ProxyHeaders, ProxyMethod, ProxyQuery, ProxyRequest, ProxyResponse, } from "./connection.js";
13
- export type { AckResponse, AckWritebackInput, AckWritebackResponse, AdminIngressAlert, AdminIngressAlertProfile, AdminIngressEffectiveAlertProfile, AdminIngressAlertSeverity, AdminIngressAlertThresholds, AdminIngressAlertTotals, AdminIngressAlertType, AdminIngressStatusResponse, AdminSyncAlert, AdminSyncAlertSeverity, AdminSyncAlertThresholds, AdminSyncAlertTotals, AdminSyncAlertType, AdminSyncStatusResponse, BackendStatusResponse, BulkWriteFile, BulkWriteInput, BulkWriteResponse, CommitForkInput, CommitForkResponse, ConflictErrorResponse, CreateForkInput, ContentIdentity, DeleteFileInput, DeadLetterFeedResponse, DeadLetterItem, DiscardForkInput, 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, ReadFileInput, RelayFileJwtClaims, SyncIngressStatusResponse, SyncProviderStatus, SyncProviderStatusState, SyncRefreshRequest, SyncStatusResponse, TreeEntry, TreeResponse, WritebackActionType, WritebackState, WritebackItem, WriteFileInput, WriteQueuedResponse } from "./types.js";
13
+ export type { AckResponse, AckWritebackInput, AckWritebackResponse, AdminIngressAlert, AdminIngressAlertProfile, AdminIngressEffectiveAlertProfile, AdminIngressAlertSeverity, AdminIngressAlertThresholds, AdminIngressAlertTotals, AdminIngressAlertType, AdminIngressStatusResponse, AdminSyncAlert, AdminSyncAlertSeverity, AdminSyncAlertThresholds, AdminSyncAlertTotals, AdminSyncAlertType, AdminSyncStatusResponse, BackendStatusResponse, BulkWriteFile, BulkWriteInput, BulkWriteResponse, ChangeLogQueryResult, ChangeEvent, ChangeEventActor, ChangeEventResource, ChangeEventSummary, ChangeStreamConnection, ChangeStreamConnectionOptions, CommitForkInput, CommitForkResponse, ConflictErrorResponse, CreateForkInput, ContentIdentity, DeleteFileInput, DeadLetterFeedResponse, DeadLetterItem, DiscardForkInput, ErrorResponse, EventSummary, EventFeedResponse, ExportFormat, ExportJsonResponse, ExportOptions, FileQueryItem, FileQueryResponse, FileReadResponse, FileSemantics, FileWriteRequest, FilesystemEvent, FilesystemEventType, EventOrigin, Expansion, ExpansionLevel, GetEventsOptions, GetAdminSyncStatusOptions, GetAdminIngressStatusOptions, GetOperationsOptions, GetSyncDeadLettersOptions, GetSyncIngressStatusOptions, GetSyncStatusOptions, IngestWebhookInput, ListTreeOptions, OperationFeedResponse, OperationStatus, OperationStatusResponse, QueuedResponse, QueryFilesOptions, ReadFileInput, ReplayOptions, ResourceAtEventResult, SummaryExpansion, FullExpansion, DiffExpansion, ThreadExpansion, RelayFileJwtClaims, SubscribeOptions, Subscription, SyncIngressStatusResponse, SyncProviderStatus, SyncProviderStatusState, SyncRefreshRequest, SyncStatusResponse, TreeEntry, TreeResponse, WritebackActionType, WritebackState, WritebackItem, WriteFileInput, WriteQueuedResponse } from "./types.js";
14
14
  export type { ForkHandle, ForkOptions } from "@relayfile/core";
15
15
  export type { WriteEvent, WriteEventActor, WriteEventOperation, WriteEventSource } from "@relayfile/core";
16
16
  export { WritebackConsumer } from "./writeback-consumer.js";
package/dist/setup.d.ts CHANGED
@@ -102,6 +102,63 @@ export declare class WorkspaceHandle {
102
102
  connectionId: string;
103
103
  replacedConnectionId?: string;
104
104
  }>;
105
+ /**
106
+ * List the upstream resources the current connection's OAuth grant
107
+ * covers. Today only Atlassian-family providers (`jira`, `confluence`)
108
+ * have meaningful entries here — every Atlassian OAuth grant can cover
109
+ * multiple sites (cloudIds), and the operator needs to bind one of them
110
+ * to this workspace via {@link setIntegrationMetadata} before sync can
111
+ * run.
112
+ *
113
+ * Cloud returns 400 `provider_has_no_accessible_resources` for providers
114
+ * that don't model this concept (currently everything non-Atlassian);
115
+ * that error surfaces here as a `CloudApiError` so callers can handle
116
+ * it explicitly rather than treating an empty list as ambiguous.
117
+ *
118
+ * @example
119
+ * ```ts
120
+ * const sites = await workspace.listAccessibleResources("jira")
121
+ * if (sites.length > 1) {
122
+ * const choice = await promptOperator(sites)
123
+ * await workspace.setIntegrationMetadata("jira", {
124
+ * cloudId: choice.id,
125
+ * baseUrl: choice.url
126
+ * })
127
+ * }
128
+ * ```
129
+ */
130
+ listAccessibleResources(provider: WorkspaceIntegrationProvider | string): Promise<Array<{
131
+ id: string;
132
+ url: string;
133
+ name?: string;
134
+ scopes?: string[];
135
+ avatarUrl?: string;
136
+ }>>;
137
+ /**
138
+ * Set the operator-controlled metadata namespace on the workspace's
139
+ * connection for `provider`. The cloud route forwards the payload to
140
+ * Nango's `setMetadata` (full-replacement, not merge), so the value
141
+ * passed here becomes the connection's metadata wholesale. Callers that
142
+ * want merge semantics should read existing metadata first.
143
+ *
144
+ * This is the second half of the post-OAuth picker flow for Jira /
145
+ * Confluence (see {@link listAccessibleResources}), but is intentionally
146
+ * general-purpose — any provider whose sync requires operator-supplied
147
+ * connection-level config (e.g. a non-default API host) can use this.
148
+ *
149
+ * The cloud side rejects top-level keys that look like Nango plumbing
150
+ * (`_*`, `connection_*`, `auth_*`, `provider_config_key`, `connection_id`)
151
+ * with `code: "invalid_metadata"` so a typo can't clobber the connection.
152
+ *
153
+ * @example
154
+ * ```ts
155
+ * await workspace.setIntegrationMetadata("jira", {
156
+ * cloudId: "abc-123",
157
+ * baseUrl: "https://foo.atlassian.net"
158
+ * })
159
+ * ```
160
+ */
161
+ setIntegrationMetadata(provider: WorkspaceIntegrationProvider | string, metadata: Record<string, unknown>): Promise<Record<string, unknown>>;
105
162
  getToken(): string;
106
163
  requestJson(options: Omit<CloudRequestOptions, "tokenProvider">): Promise<unknown>;
107
164
  mountEnv(options?: WorkspaceMountEnvOptions): WorkspaceMountEnv;
package/dist/setup.js CHANGED
@@ -440,6 +440,95 @@ export class WorkspaceHandle {
440
440
  ? { connectionId: boundConnectionId, replacedConnectionId }
441
441
  : { connectionId: boundConnectionId };
442
442
  }
443
+ /**
444
+ * List the upstream resources the current connection's OAuth grant
445
+ * covers. Today only Atlassian-family providers (`jira`, `confluence`)
446
+ * have meaningful entries here — every Atlassian OAuth grant can cover
447
+ * multiple sites (cloudIds), and the operator needs to bind one of them
448
+ * to this workspace via {@link setIntegrationMetadata} before sync can
449
+ * run.
450
+ *
451
+ * Cloud returns 400 `provider_has_no_accessible_resources` for providers
452
+ * that don't model this concept (currently everything non-Atlassian);
453
+ * that error surfaces here as a `CloudApiError` so callers can handle
454
+ * it explicitly rather than treating an empty list as ambiguous.
455
+ *
456
+ * @example
457
+ * ```ts
458
+ * const sites = await workspace.listAccessibleResources("jira")
459
+ * if (sites.length > 1) {
460
+ * const choice = await promptOperator(sites)
461
+ * await workspace.setIntegrationMetadata("jira", {
462
+ * cloudId: choice.id,
463
+ * baseUrl: choice.url
464
+ * })
465
+ * }
466
+ * ```
467
+ */
468
+ async listAccessibleResources(provider) {
469
+ const normalized = normalizeProviderId(provider);
470
+ const response = (await this._setup.requestJson({
471
+ operation: "listAccessibleResources",
472
+ method: "GET",
473
+ path: `api/v1/workspaces/${encodeURIComponent(this.workspaceId)}/integrations/${encodeURIComponent(normalized)}/accessible-resources`,
474
+ tokenProvider: async () => this.getOrRefreshToken()
475
+ }));
476
+ if (!response || !Array.isArray(response.resources)) {
477
+ return [];
478
+ }
479
+ return response.resources
480
+ .filter((entry) => {
481
+ if (!entry || typeof entry !== "object")
482
+ return false;
483
+ const record = entry;
484
+ return (typeof record.id === "string" &&
485
+ record.id.length > 0 &&
486
+ typeof record.url === "string" &&
487
+ record.url.length > 0);
488
+ })
489
+ .map((entry) => ({ ...entry }));
490
+ }
491
+ /**
492
+ * Set the operator-controlled metadata namespace on the workspace's
493
+ * connection for `provider`. The cloud route forwards the payload to
494
+ * Nango's `setMetadata` (full-replacement, not merge), so the value
495
+ * passed here becomes the connection's metadata wholesale. Callers that
496
+ * want merge semantics should read existing metadata first.
497
+ *
498
+ * This is the second half of the post-OAuth picker flow for Jira /
499
+ * Confluence (see {@link listAccessibleResources}), but is intentionally
500
+ * general-purpose — any provider whose sync requires operator-supplied
501
+ * connection-level config (e.g. a non-default API host) can use this.
502
+ *
503
+ * The cloud side rejects top-level keys that look like Nango plumbing
504
+ * (`_*`, `connection_*`, `auth_*`, `provider_config_key`, `connection_id`)
505
+ * with `code: "invalid_metadata"` so a typo can't clobber the connection.
506
+ *
507
+ * @example
508
+ * ```ts
509
+ * await workspace.setIntegrationMetadata("jira", {
510
+ * cloudId: "abc-123",
511
+ * baseUrl: "https://foo.atlassian.net"
512
+ * })
513
+ * ```
514
+ */
515
+ async setIntegrationMetadata(provider, metadata) {
516
+ const normalized = normalizeProviderId(provider);
517
+ if (!isPlainRecord(metadata)) {
518
+ throw new Error("metadata must be a plain object");
519
+ }
520
+ const response = (await this._setup.requestJson({
521
+ operation: "setIntegrationMetadata",
522
+ method: "PUT",
523
+ path: `api/v1/workspaces/${encodeURIComponent(this.workspaceId)}/integrations/${encodeURIComponent(normalized)}/metadata`,
524
+ body: { metadata },
525
+ tokenProvider: async () => this.getOrRefreshToken()
526
+ }));
527
+ if (isPlainRecord(response?.metadata)) {
528
+ return { ...response.metadata };
529
+ }
530
+ throw new Error("invalid cloud response: expected metadata to be a plain object");
531
+ }
443
532
  getToken() {
444
533
  return this._token;
445
534
  }
@@ -644,6 +733,24 @@ class MountedWorkspaceHandleImpl {
644
733
  await safeStopLauncher(this.launcherInstance);
645
734
  }
646
735
  }
736
+ // The metadata + accessible-resources verbs accept `WorkspaceIntegrationProvider | string`
737
+ // so operators can target dynamically-discovered providers (Composio toolkit
738
+ // slugs, future Atlassian-family additions) without an SDK release. We still
739
+ // strip trailing whitespace and lower-case so consumers don't have to.
740
+ function normalizeProviderId(provider) {
741
+ const trimmed = typeof provider === "string" ? provider.trim() : "";
742
+ if (!trimmed) {
743
+ throw new Error("provider is required");
744
+ }
745
+ return trimmed.toLowerCase();
746
+ }
747
+ function isPlainRecord(value) {
748
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
749
+ return false;
750
+ }
751
+ const proto = Object.getPrototypeOf(value);
752
+ return proto === Object.prototype || proto === null;
753
+ }
647
754
  function assertProvider(provider) {
648
755
  if (!WORKSPACE_INTEGRATION_PROVIDERS.includes(provider)) {
649
756
  throw new UnknownProviderError(provider);
package/dist/types.d.ts CHANGED
@@ -136,6 +136,106 @@ export interface FilesystemEvent {
136
136
  correlationId?: string;
137
137
  timestamp: string;
138
138
  }
139
+ export interface ChangeEventResource {
140
+ path: string;
141
+ kind: string;
142
+ id: string;
143
+ provider: string;
144
+ }
145
+ export interface ChangeEventActor {
146
+ id: string;
147
+ displayName?: string;
148
+ }
149
+ export interface ChangeEventSummary {
150
+ title?: string;
151
+ status?: string;
152
+ priority?: string;
153
+ labels?: string[];
154
+ actor?: ChangeEventActor;
155
+ fieldsChanged?: string[];
156
+ /** Optional compact tag list. Producers must cap this at 8 entries. */
157
+ tags?: string[];
158
+ }
159
+ /**
160
+ * Canonical lightweight event summary shape exported for proactive-runtime
161
+ * adapters. `buildSummary(payload)` should return this exact structure.
162
+ */
163
+ export type EventSummary = ChangeEventSummary;
164
+ export type ExpansionLevel = "summary" | "full" | "diff" | "thread";
165
+ export interface SummaryExpansion {
166
+ level: "summary";
167
+ path: string;
168
+ summary: ChangeEventSummary;
169
+ }
170
+ export interface FullExpansion<TData = unknown> {
171
+ level: "full";
172
+ path: string;
173
+ data: TData;
174
+ }
175
+ export interface DiffExpansion {
176
+ level: "diff";
177
+ path: string;
178
+ diff: Record<string, unknown>;
179
+ }
180
+ export interface ThreadExpansion {
181
+ level: "thread";
182
+ path: string;
183
+ thread: Record<string, unknown>;
184
+ }
185
+ export type Expansion<L extends ExpansionLevel = ExpansionLevel> = L extends "summary" ? SummaryExpansion : L extends "full" ? FullExpansion : L extends "diff" ? DiffExpansion : ThreadExpansion;
186
+ /**
187
+ * Proactive runtime relayfile notification envelope.
188
+ *
189
+ * This differs from the lower-level FilesystemEvent feed above. The proactive
190
+ * runtime consumes a small, stable notification that points at the canonical
191
+ * payload in VFS instead of inlining provider payloads directly.
192
+ *
193
+ * M1 exposes the type so downstream packages can compile against the final
194
+ * shape before M2 wires live delivery.
195
+ */
196
+ export interface ChangeEvent {
197
+ id: string;
198
+ workspace: string;
199
+ agentId?: string;
200
+ type: "relayfile.changed";
201
+ occurredAt: string;
202
+ resource: ChangeEventResource;
203
+ summary: ChangeEventSummary;
204
+ expand<L extends ExpansionLevel = "summary">(level?: L): Promise<Expansion<L>>;
205
+ digest?: string;
206
+ }
207
+ export interface SubscribeOptions {
208
+ coalesce?: "none" | "fire-once";
209
+ coalesceMs?: number;
210
+ pathScope?: string[];
211
+ aclToken?: string;
212
+ drainMs?: number;
213
+ }
214
+ export interface Subscription {
215
+ unsubscribe(): Promise<void>;
216
+ }
217
+ export type ReplayOptions = {
218
+ replayOnStart?: "none";
219
+ } | {
220
+ replayOnStart: `since:${string}`;
221
+ } | {
222
+ replayOnStart: `last:${number}`;
223
+ };
224
+ export type ChangeStreamConnectionOptions = ReplayOptions & {
225
+ workspaceId: string;
226
+ aclToken?: string;
227
+ };
228
+ export interface ChangeStreamConnection extends Subscription {
229
+ readonly ready: Promise<void>;
230
+ }
231
+ export interface ResourceAtEventResult {
232
+ path: string;
233
+ data: unknown;
234
+ digest: string;
235
+ }
236
+ export interface ChangeLogQueryResult {
237
+ events: ChangeEvent[];
238
+ }
139
239
  export interface EventFeedResponse {
140
240
  events: FilesystemEvent[];
141
241
  nextCursor: string | null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@relayfile/sdk",
3
- "version": "0.7.9",
3
+ "version": "0.7.11",
4
4
  "description": "TypeScript SDK for relayfile — real-time filesystem for humans and agents",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -22,7 +22,7 @@
22
22
  "prepublishOnly": "npm run build"
23
23
  },
24
24
  "dependencies": {
25
- "@relayfile/core": "0.7.9"
25
+ "@relayfile/core": "0.7.11"
26
26
  },
27
27
  "devDependencies": {
28
28
  "typescript": "^5.7.3",