@phpsandbox/sdk 0.1.2 → 0.1.6

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.
@@ -0,0 +1,73 @@
1
+ import type { Client, PaginatedApiResponse } from './index.js';
2
+ export type FeedbackType = 'bug' | 'suggestion' | 'question' | 'other';
3
+ export type FeedbackStatus = 'open' | 'resolved' | 'archived';
4
+ export type FeedbackSource = 'sdk' | 'widget';
5
+ export type FeedbackWidgetTarget = 'preview' | 'publication';
6
+ export interface FeedbackWidgetConfig {
7
+ targets: FeedbackWidgetTarget[];
8
+ label?: string;
9
+ types?: FeedbackType[];
10
+ }
11
+ export interface ConfigureFeedbackInput {
12
+ widget: FeedbackWidgetConfig | null;
13
+ }
14
+ export interface SubmitFeedbackInput {
15
+ type: FeedbackType;
16
+ message: string;
17
+ author?: {
18
+ externalId?: string;
19
+ name?: string;
20
+ email?: string;
21
+ };
22
+ context?: {
23
+ url?: string;
24
+ path?: string;
25
+ };
26
+ metadata?: Record<string, unknown>;
27
+ }
28
+ export interface FeedbackData {
29
+ id: string;
30
+ type: FeedbackType;
31
+ message: string;
32
+ status: FeedbackStatus;
33
+ source: FeedbackSource;
34
+ author: {
35
+ source: 'external' | 'phpsandbox';
36
+ externalId: string | null;
37
+ phpsandboxUserId: number | null;
38
+ name: string | null;
39
+ email: string | null;
40
+ };
41
+ context: {
42
+ url: string | null;
43
+ path: string | null;
44
+ publication: {
45
+ id: string;
46
+ releaseId: string | null;
47
+ } | null;
48
+ };
49
+ metadata: Record<string, unknown>;
50
+ createdAt: string;
51
+ updatedAt: string;
52
+ }
53
+ export interface FeedbackListOptions {
54
+ type?: FeedbackType;
55
+ status?: FeedbackStatus;
56
+ source?: FeedbackSource;
57
+ page?: number;
58
+ }
59
+ export interface UpdateFeedbackInput {
60
+ status: FeedbackStatus;
61
+ }
62
+ export declare class Feedback {
63
+ private readonly client;
64
+ private readonly notebookId;
65
+ constructor(client: Client, notebookId: string);
66
+ configure(input: ConfigureFeedbackInput): Promise<ConfigureFeedbackInput>;
67
+ configuration(): Promise<ConfigureFeedbackInput>;
68
+ submit(input: SubmitFeedbackInput): Promise<FeedbackData>;
69
+ list(options?: FeedbackListOptions): Promise<PaginatedApiResponse<FeedbackData>>;
70
+ get(id: string): Promise<FeedbackData>;
71
+ update(id: string, input: UpdateFeedbackInput): Promise<FeedbackData>;
72
+ private path;
73
+ }
@@ -0,0 +1,38 @@
1
+ export class Feedback {
2
+ constructor(client, notebookId) {
3
+ this.client = client;
4
+ this.notebookId = notebookId;
5
+ }
6
+ async configure(input) {
7
+ const response = await this.client.put(this.path('/configuration'), input);
8
+ return response.data;
9
+ }
10
+ async configuration() {
11
+ const response = await this.client.get(this.path('/configuration'));
12
+ return response.data;
13
+ }
14
+ async submit(input) {
15
+ const response = await this.client.post(this.path(), input);
16
+ return response.data;
17
+ }
18
+ async list(options = {}) {
19
+ const query = new URLSearchParams();
20
+ for (const [name, value] of Object.entries(options)) {
21
+ if (value !== undefined)
22
+ query.set(name, String(value));
23
+ }
24
+ const response = await this.client.get(`${this.path()}${query.size === 0 ? '' : `?${query.toString()}`}`);
25
+ return response.data;
26
+ }
27
+ async get(id) {
28
+ const response = await this.client.get(this.path(`/${encodeURIComponent(id)}`));
29
+ return response.data;
30
+ }
31
+ async update(id, input) {
32
+ const response = await this.client.patch(this.path(`/${encodeURIComponent(id)}`), input);
33
+ return response.data;
34
+ }
35
+ path(suffix = '') {
36
+ return `/notebook/${this.notebookId}/feedback${suffix}`;
37
+ }
38
+ }
@@ -1,10 +1,5 @@
1
1
  import type { Action, Disposable, NotebookInstance } from './index.js';
2
2
  import { ErrorEvent } from './types.js';
3
- export interface FileInfo {
4
- binary: boolean;
5
- contents: string | null;
6
- language: string;
7
- }
8
3
  export interface FileResult {
9
4
  name: string;
10
5
  directory: string;
@@ -68,6 +63,9 @@ export interface FileListOptions {
68
63
  export interface FileTailOptions {
69
64
  lines?: number;
70
65
  }
66
+ export interface FileFollowOptions extends FileTailOptions {
67
+ signal?: AbortSignal;
68
+ }
71
69
  export interface FileLineRange {
72
70
  start: number;
73
71
  end: number;
@@ -358,24 +356,6 @@ export interface ReadFileRangeResult {
358
356
  error: string | null;
359
357
  }
360
358
  export interface FilesystemActions {
361
- 'fs.info': Action<{
362
- path: string;
363
- }, FileInfo>;
364
- 'fs.write': Action<{
365
- path: string;
366
- contents: string;
367
- }, boolean>;
368
- 'fs.mkdir': Action<{
369
- path: string;
370
- }, boolean>;
371
- 'fs.remove': Action<{
372
- path: string;
373
- type: 'file' | 'directory';
374
- }, boolean>;
375
- 'fs.move': Action<{
376
- from: string;
377
- to: string;
378
- }, boolean>;
379
359
  'fs.find': Action<{
380
360
  query: string;
381
361
  options: FileSearchOptions;
@@ -403,6 +383,14 @@ export interface FilesystemActions {
403
383
  'fs.cancelRead': Action<{
404
384
  id: string;
405
385
  }, boolean>;
386
+ 'fs.follow': Action<{
387
+ id: string;
388
+ path: string;
389
+ lines: number;
390
+ }, boolean>;
391
+ 'fs.cancelFollow': Action<{
392
+ id: string;
393
+ }, boolean>;
406
394
  'fs.writeStream': Action<{
407
395
  id: string;
408
396
  path: string;
@@ -461,7 +449,9 @@ export interface FilesystemActions {
461
449
  'fs.tail': Action<{
462
450
  path: string;
463
451
  lines: number;
464
- }, string>;
452
+ }, {
453
+ content: string;
454
+ }>;
465
455
  }
466
456
  interface FilesystemEventData {
467
457
  'fs.watch': FileChange;
@@ -471,6 +461,10 @@ interface FilesystemEventData {
471
461
  id: string;
472
462
  data: Uint8Array;
473
463
  };
464
+ 'fs.follow': {
465
+ id: string;
466
+ data: Uint8Array;
467
+ };
474
468
  }
475
469
  type PrefixKey<K extends keyof FilesystemEventData> = `${K}.${string}`;
476
470
  export type FilesystemEvents = FilesystemEventData & {
@@ -505,6 +499,7 @@ export declare class Filesystem {
505
499
  readText(path: string): Promise<string>;
506
500
  readLines(path: string, range: FileLineRange): Promise<FileLineRangeResult>;
507
501
  readStream(path: string): ReadableStream<Uint8Array>;
502
+ follow(path: string, options?: FileFollowOptions): ReadableStream<Uint8Array>;
508
503
  find(query: string, options?: Partial<FileSearchOptions>): Promise<FileResult[]>;
509
504
  search(query: TextSearchQuery, options?: Partial<TextSearchOptions>, onMatch?: (result: TextSearchResult | false) => boolean | Promise<boolean> | void | Promise<void>): Promise<[boolean, TextSearchMatch[]]>;
510
505
  tail(path: string, options?: FileTailOptions): Promise<string>;
@@ -1,3 +1,4 @@
1
+ import { UnsupportedRuntimeTransportError } from './errors/index.js';
1
2
  import { ErrorEvent } from './types.js';
2
3
  import { nanoid } from 'nanoid';
3
4
  export var FileType;
@@ -204,6 +205,77 @@ export class Filesystem {
204
205
  },
205
206
  });
206
207
  }
208
+ follow(path, options = {}) {
209
+ if (this.okra.runtimeTransport === 'rest') {
210
+ return new ReadableStream({
211
+ start(controller) {
212
+ controller.error(new UnsupportedRuntimeTransportError('Following files requires the realtime transport.'));
213
+ },
214
+ });
215
+ }
216
+ const id = nanoid();
217
+ let disposable = null;
218
+ let abort = null;
219
+ let started = false;
220
+ let closed = false;
221
+ const stop = async () => {
222
+ if (closed) {
223
+ return;
224
+ }
225
+ closed = true;
226
+ disposable?.dispose();
227
+ disposable = null;
228
+ if (abort && options.signal) {
229
+ options.signal.removeEventListener('abort', abort);
230
+ }
231
+ abort = null;
232
+ if (started) {
233
+ await this.okra.invoke('fs.cancelFollow', { id }).catch(() => false);
234
+ }
235
+ };
236
+ return new ReadableStream({
237
+ start: (controller) => {
238
+ disposable = this.okra.listen(`fs.follow.${id}`, (event) => {
239
+ if (!closed) {
240
+ controller.enqueue(event.data);
241
+ }
242
+ });
243
+ if (options.signal) {
244
+ abort = () => {
245
+ void stop().finally(() => controller.error(options.signal?.reason ?? new Error('Aborted')));
246
+ };
247
+ if (options.signal.aborted) {
248
+ abort();
249
+ return;
250
+ }
251
+ options.signal.addEventListener('abort', abort, { once: true });
252
+ }
253
+ started = true;
254
+ void this.okra.invoke('fs.follow', { id, path, lines: options.lines ?? 10 }).then(() => {
255
+ if (!closed) {
256
+ closed = true;
257
+ disposable?.dispose();
258
+ if (abort && options.signal) {
259
+ options.signal.removeEventListener('abort', abort);
260
+ }
261
+ abort = null;
262
+ controller.close();
263
+ }
264
+ }).catch((error) => {
265
+ if (!closed) {
266
+ closed = true;
267
+ disposable?.dispose();
268
+ if (abort && options.signal) {
269
+ options.signal.removeEventListener('abort', abort);
270
+ }
271
+ abort = null;
272
+ controller.error(error);
273
+ }
274
+ });
275
+ },
276
+ cancel: stop,
277
+ });
278
+ }
207
279
  find(query, options = {
208
280
  useIgnoreFiles: false,
209
281
  followSymlinks: false,
@@ -284,7 +356,9 @@ export class Filesystem {
284
356
  .finally(() => disposable.dispose());
285
357
  }
286
358
  tail(path, options = {}) {
287
- return this.okra.invoke('fs.tail', { path, lines: options.lines ?? 10 }).catch((e) => this.handleError(e));
359
+ return this.okra.invoke('fs.tail', { path, lines: options.lines ?? 10 })
360
+ .then(({ content }) => content)
361
+ .catch((e) => this.handleError(e));
288
362
  }
289
363
  stat(path) {
290
364
  return this.okra.invoke('fs.stat', { path }).catch((e) => this.handleError(e));
package/dist/git.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { Client, SecretRef } from './index.js';
1
+ import type { Client } from './index.js';
2
2
  import { Action, NotebookInstance } from './index.js';
3
3
  export interface GitLog {
4
4
  hash: string;
@@ -50,35 +50,37 @@ export interface GitCredentials {
50
50
  expiresAt: string;
51
51
  }
52
52
  export type GitProvider = 'github' | (string & {});
53
- export type GitRepositoryVisibility = 'private' | 'public';
54
53
  export type GitSyncDirection = 'pull' | 'push' | 'both';
55
54
  export interface GitSyncAuthor {
56
55
  name: string;
57
56
  email: string;
58
57
  }
59
- export interface GitSyncTargetInput {
58
+ export interface GitTargetConfiguration {
60
59
  provider: GitProvider;
61
60
  repository: string;
62
61
  author: GitSyncAuthor;
63
62
  branch?: string;
64
- credential: SecretRef;
65
- direction?: GitSyncDirection;
66
- visibility?: GitRepositoryVisibility;
67
63
  setDefault?: boolean;
68
64
  }
69
- export interface GitSyncTargetData {
65
+ export type CreateGitTargetInput = GitTargetConfiguration;
66
+ export interface GitSyncExistingTargetInput {
67
+ direction?: GitSyncDirection;
68
+ author?: GitSyncAuthor;
69
+ force?: boolean;
70
+ }
71
+ export interface GitTargetData {
70
72
  id: string;
71
73
  provider: GitProvider;
72
74
  repository: string;
73
75
  url: string | null;
74
76
  branch: string;
75
- credentialConfigured: boolean;
76
77
  default: boolean;
77
78
  lastCommitSha: string | null;
78
79
  lastSyncedAt: string | null;
79
80
  createdAt: string | null;
80
81
  updatedAt: string | null;
81
82
  }
83
+ export type GitTargetReference = string | GitTarget;
82
84
  export interface GitCheckoutResult extends GitRef {
83
85
  branch: string;
84
86
  created: boolean;
@@ -213,11 +215,10 @@ export interface GitActions {
213
215
  export default class Git {
214
216
  protected okra: NotebookInstance;
215
217
  private readonly client;
218
+ readonly targets: GitTargetApi;
216
219
  constructor(okra: NotebookInstance, client: Client);
217
220
  checkpoint(author: string, message: string, branch?: string, allowEmpty?: boolean): Promise<GitRef>;
218
221
  checkout(branch: string, create?: boolean): Promise<GitCheckoutResult>;
219
- sync(input: GitSyncTargetInput): Promise<GitSyncTargetData>;
220
- syncTargets(): Promise<GitSyncTargetData[]>;
221
222
  log(ref?: string): Promise<GitLog[]>;
222
223
  diff(input: GitDiffInput): Promise<GitDiffPreview>;
223
224
  merge(input: GitMergeInput): Promise<GitMergeResult>;
@@ -233,6 +234,22 @@ export default class Git {
233
234
  status(): Promise<GitStatus>;
234
235
  private normalizeRemoteInput;
235
236
  private gitUrlForNotebook;
236
- private omitUndefined;
237
+ }
238
+ export declare class GitTargetApi {
239
+ private readonly notebookId;
240
+ private readonly client;
241
+ constructor(notebookId: string, client: Client);
242
+ create(input: CreateGitTargetInput): Promise<GitTarget>;
243
+ list(): Promise<GitTarget[]>;
244
+ get(target: GitTargetReference): Promise<GitTarget>;
245
+ sync(target: GitTargetReference, input?: GitSyncExistingTargetInput): Promise<GitTarget>;
246
+ }
247
+ export declare class GitTarget {
248
+ readonly data: GitTargetData;
249
+ private readonly notebookId;
250
+ private readonly client;
251
+ constructor(data: GitTargetData, notebookId: string, client: Client);
252
+ get id(): string;
253
+ sync(input?: GitSyncExistingTargetInput): Promise<GitTarget>;
237
254
  }
238
255
  export {};
package/dist/git.js CHANGED
@@ -2,6 +2,7 @@ export default class Git {
2
2
  constructor(okra, client) {
3
3
  this.okra = okra;
4
4
  this.client = client;
5
+ this.targets = new GitTargetApi(okra.data.id, client);
5
6
  }
6
7
  checkpoint(author, message, branch = 'main', allowEmpty = false) {
7
8
  return this.okra.invoke('git.checkpoint', { author, message, branch, allowEmpty });
@@ -9,14 +10,6 @@ export default class Git {
9
10
  checkout(branch, create = true) {
10
11
  return this.okra.invoke('git.checkout', { branch, create });
11
12
  }
12
- async sync(input) {
13
- const response = await this.client.post(`/notebook/${this.okra.data.id}/git/sync-targets`, this.omitUndefined({ ...input }));
14
- return response.data;
15
- }
16
- async syncTargets() {
17
- const response = await this.client.get(`/notebook/${this.okra.data.id}/git/sync-targets`);
18
- return response.data;
19
- }
20
13
  log(ref = 'main') {
21
14
  return this.okra.invoke('git.log', { ref });
22
15
  }
@@ -85,7 +78,45 @@ export default class Git {
85
78
  url.hash = '';
86
79
  return url.toString();
87
80
  }
88
- omitUndefined(input) {
89
- return Object.fromEntries(Object.entries(input).filter(([, value]) => value !== undefined));
81
+ }
82
+ export class GitTargetApi {
83
+ constructor(notebookId, client) {
84
+ this.notebookId = notebookId;
85
+ this.client = client;
86
+ }
87
+ async create(input) {
88
+ const response = await this.client.post(`/notebook/${this.notebookId}/git/targets`, omitUndefined({ ...input }));
89
+ return new GitTarget(response.data, this.notebookId, this.client);
90
+ }
91
+ async list() {
92
+ const response = await this.client.get(`/notebook/${this.notebookId}/git/targets`);
93
+ return response.data.map((target) => new GitTarget(target, this.notebookId, this.client));
94
+ }
95
+ async get(target) {
96
+ const response = await this.client.get(`/notebook/${this.notebookId}/git/targets/${encodeURIComponent(gitTargetId(target))}`);
97
+ return new GitTarget(response.data, this.notebookId, this.client);
98
+ }
99
+ async sync(target, input = {}) {
100
+ const response = await this.client.post(`/notebook/${this.notebookId}/git/targets/${encodeURIComponent(gitTargetId(target))}/sync`, omitUndefined({ ...input }));
101
+ return new GitTarget(response.data, this.notebookId, this.client);
90
102
  }
91
103
  }
104
+ export class GitTarget {
105
+ constructor(data, notebookId, client) {
106
+ this.data = data;
107
+ this.notebookId = notebookId;
108
+ this.client = client;
109
+ }
110
+ get id() {
111
+ return this.data.id;
112
+ }
113
+ sync(input = {}) {
114
+ return new GitTargetApi(this.notebookId, this.client).sync(this, input);
115
+ }
116
+ }
117
+ function gitTargetId(target) {
118
+ return typeof target === 'string' ? target : target.id;
119
+ }
120
+ function omitUndefined(input) {
121
+ return Object.fromEntries(Object.entries(input).filter(([, value]) => value !== undefined));
122
+ }
package/dist/index.d.ts CHANGED
@@ -17,6 +17,9 @@ import { Disposable } from './types.js';
17
17
  import { NotebookUnavailableError } from './errors/index.js';
18
18
  import { PublicationApi, NotebookPublicationApi, type PublicationInstance, type PublicationRun, type PublishInput } from './publications.js';
19
19
  import { ServerApi } from './servers.js';
20
+ import { Feedback } from './feedback.js';
21
+ import { IntegrationApi } from './integrations.js';
22
+ import { SandboxIntegrationApi } from './sandbox-integrations.js';
20
23
  export * from './types.js';
21
24
  export * from './lsp.js';
22
25
  export * from './filesystem.js';
@@ -34,6 +37,9 @@ export * from './utils/promise.js';
34
37
  export * from './errors/index.js';
35
38
  export * from './publications.js';
36
39
  export * from './servers.js';
40
+ export * from './feedback.js';
41
+ export * from './integrations.js';
42
+ export * from './sandbox-integrations.js';
37
43
  interface Result<TType extends 'success' | 'error' | 'running', TData extends object> {
38
44
  type: TType;
39
45
  message: string;
@@ -314,6 +320,7 @@ export declare class Client {
314
320
  readonly notebook: NotebookApi;
315
321
  readonly publications: PublicationApi;
316
322
  readonly servers: ServerApi;
323
+ readonly integrations: IntegrationApi;
317
324
  readonly options: PHPSandboxClientOptions;
318
325
  protected runtimeTransportValue: RuntimeTransport;
319
326
  get runtimeTransport(): RuntimeTransport;
@@ -333,6 +340,9 @@ export declare class Client {
333
340
  put<T extends unknown>(path: string, body?: unknown): Promise<{
334
341
  data: T;
335
342
  }>;
343
+ patch<T extends unknown>(path: string, body?: unknown): Promise<{
344
+ data: T;
345
+ }>;
336
346
  stream(path: string): Promise<ReadableStream<Uint8Array>>;
337
347
  sse(url: string): Promise<ReadableStream<Uint8Array>>;
338
348
  private makeRequest;
@@ -404,8 +414,10 @@ export declare class NotebookInstance {
404
414
  readonly services: Services;
405
415
  readonly config: Config;
406
416
  readonly secrets: NotebookSecrets;
417
+ readonly integrations: SandboxIntegrationApi;
407
418
  readonly preview: NotebookPreview;
408
419
  readonly mail: NotebookMail;
420
+ readonly feedback: Feedback;
409
421
  private readonly socket;
410
422
  private readonly restInvoker;
411
423
  readonly emitter: EventDispatcher;
package/dist/index.js CHANGED
@@ -31,6 +31,9 @@ import { NotebookUnavailableError, UnsupportedRuntimeTransportError } from './er
31
31
  import { PublicationApi, NotebookPublicationApi } from './publications.js';
32
32
  import { ServerApi } from './servers.js';
33
33
  import { RestRuntimeInvoker } from './runtime/rest.js';
34
+ import { Feedback } from './feedback.js';
35
+ import { IntegrationApi } from './integrations.js';
36
+ import { SandboxIntegrationApi } from './sandbox-integrations.js';
34
37
  export * from './types.js';
35
38
  export * from './lsp.js';
36
39
  export * from './filesystem.js';
@@ -48,6 +51,9 @@ export * from './utils/promise.js';
48
51
  export * from './errors/index.js';
49
52
  export * from './publications.js';
50
53
  export * from './servers.js';
54
+ export * from './feedback.js';
55
+ export * from './integrations.js';
56
+ export * from './sandbox-integrations.js';
51
57
  function normalizeNotebookSecretInputs(input) {
52
58
  if (Array.isArray(input)) {
53
59
  return input;
@@ -159,6 +165,7 @@ export class Client {
159
165
  this.publications = new PublicationApi(this);
160
166
  this.notebook = new NotebookApi(this);
161
167
  this.servers = new ServerApi(this);
168
+ this.integrations = new IntegrationApi(this);
162
169
  this.options = Object.assign({ startClosed: true }, options);
163
170
  this.baseUrl = normalizeApiBaseUrl(url);
164
171
  if (options.fetch) {
@@ -182,6 +189,9 @@ export class Client {
182
189
  put(path, body) {
183
190
  return this.makeRequest('PUT', path, { body: body === undefined ? undefined : JSON.stringify(body) });
184
191
  }
192
+ patch(path, body) {
193
+ return this.makeRequest('PATCH', path, { body: body === undefined ? undefined : JSON.stringify(body) });
194
+ }
185
195
  async stream(path) {
186
196
  const response = await this.fetch(new Request(new URL(path.replace(/^\//, ''), this.baseUrl), {
187
197
  method: 'GET',
@@ -390,8 +400,10 @@ export class NotebookInstance {
390
400
  this.services = new Services(this);
391
401
  this.config = new Config(this);
392
402
  this.secrets = new NotebookSecrets(client, this.data.id);
403
+ this.integrations = new SandboxIntegrationApi(this.data.id, client);
393
404
  this.preview = new NotebookPreview(client, this.data.id);
394
405
  this.mail = new NotebookMail(client, this.data.id);
406
+ this.feedback = new Feedback(client, this.data.id);
395
407
  }
396
408
  async ready() {
397
409
  if (this.restInvoker !== null) {
@@ -0,0 +1,43 @@
1
+ import type { Client } from './index.js';
2
+ export type IntegrationProvider = 'cloudflare' | 'github' | 'laravel-cloud';
3
+ export type IntegrationAuthorizationType = 'token';
4
+ export interface IntegrationAuthorization {
5
+ type: IntegrationAuthorizationType;
6
+ token: string;
7
+ }
8
+ export interface LinkIntegrationInput {
9
+ provider: IntegrationProvider;
10
+ label?: string | null;
11
+ authorization: IntegrationAuthorization;
12
+ }
13
+ export interface UpdateIntegrationInput {
14
+ label?: string | null;
15
+ authorization?: IntegrationAuthorization;
16
+ }
17
+ export interface IntegrationData {
18
+ id: string;
19
+ provider: IntegrationProvider;
20
+ label: string | null;
21
+ createdAt: string | null;
22
+ }
23
+ export type IntegrationReference = string | Integration;
24
+ export declare class IntegrationApi {
25
+ private readonly client;
26
+ constructor(client: Client);
27
+ link(input: LinkIntegrationInput): Promise<Integration>;
28
+ list(): Promise<Integration[]>;
29
+ get(integration: IntegrationReference): Promise<Integration>;
30
+ update(integration: IntegrationReference, input: UpdateIntegrationInput): Promise<Integration>;
31
+ unlink(integration: IntegrationReference): Promise<void>;
32
+ }
33
+ export declare class Integration {
34
+ readonly data: IntegrationData;
35
+ private readonly client;
36
+ constructor(data: IntegrationData, client: Client);
37
+ get id(): string;
38
+ get provider(): IntegrationProvider;
39
+ get label(): string | null;
40
+ update(input: UpdateIntegrationInput): Promise<Integration>;
41
+ unlink(): Promise<void>;
42
+ }
43
+ export declare function integrationId(integration: IntegrationReference): string;
@@ -0,0 +1,48 @@
1
+ export class IntegrationApi {
2
+ constructor(client) {
3
+ this.client = client;
4
+ }
5
+ async link(input) {
6
+ const response = await this.client.post('/integrations', input);
7
+ return new Integration(response.data, this.client);
8
+ }
9
+ async list() {
10
+ const response = await this.client.get('/integrations');
11
+ return response.data.map((integration) => new Integration(integration, this.client));
12
+ }
13
+ async get(integration) {
14
+ const response = await this.client.get(`/integrations/${encodeURIComponent(integrationId(integration))}`);
15
+ return new Integration(response.data, this.client);
16
+ }
17
+ async update(integration, input) {
18
+ const response = await this.client.patch(`/integrations/${encodeURIComponent(integrationId(integration))}`, input);
19
+ return new Integration(response.data, this.client);
20
+ }
21
+ async unlink(integration) {
22
+ await this.client.delete(`/integrations/${encodeURIComponent(integrationId(integration))}`);
23
+ }
24
+ }
25
+ export class Integration {
26
+ constructor(data, client) {
27
+ this.data = data;
28
+ this.client = client;
29
+ }
30
+ get id() {
31
+ return this.data.id;
32
+ }
33
+ get provider() {
34
+ return this.data.provider;
35
+ }
36
+ get label() {
37
+ return this.data.label;
38
+ }
39
+ update(input) {
40
+ return new IntegrationApi(this.client).update(this, input);
41
+ }
42
+ unlink() {
43
+ return new IntegrationApi(this.client).unlink(this);
44
+ }
45
+ }
46
+ export function integrationId(integration) {
47
+ return typeof integration === 'string' ? integration : integration.id;
48
+ }