@permute/sdk 0.1.2 → 0.2.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.
package/README.md CHANGED
@@ -4,10 +4,103 @@ TypeScript client for the Permute public API.
4
4
 
5
5
  The SDK supports Node.js 20 and newer and includes TypeScript declarations.
6
6
 
7
+ See the [changelog](https://permute.ai/docs/changelog) for release notes and upgrade guidance.
8
+
9
+ ## Dashboard source authoring
10
+
11
+ API-key clients with dashboard write access can read and replace the complete
12
+ TSX source for an existing dashboard. Pass the returned dashboard revision and
13
+ data run back on the write so Permute can reject stale edits:
14
+
15
+ ```ts
16
+ const dashboard = await client.dashboards.getSource('oper_...');
17
+
18
+ await client.dashboards.updateSource(dashboard.dashboardId, {
19
+ source: updatedSource,
20
+ expectedRevision: dashboard.revision,
21
+ expectedDataRunId: dashboard.dataRunId,
22
+ });
23
+ ```
24
+
25
+ The server validates source safety and derives the dashboard data contract from
26
+ the referenced run. Clients cannot supply an authoritative contract.
27
+
7
28
  ```sh
8
29
  npm install @permute/sdk
9
30
  ```
10
31
 
32
+ ## Author data flows with external agents
33
+
34
+ For a runnable example from sample input through publication, see
35
+ [Build and publish a data flow](https://permute.ai/docs/guides/data-flow).
36
+
37
+ Use `operations.list({ kind: 'dataFlow' })` to discover flows, `dataFlows.get(id)`
38
+ to read their edges and operation IDs, and `operations.list({ dataFlowId })` to
39
+ inspect the member operations. Drafts are included (they do not need published output).
40
+ Fetch each operation’s code with `operations.getSource(id)` as needed.
41
+
42
+ ```typescript
43
+ const flow = await client.dataFlows.create({
44
+ name: 'Revenue',
45
+ description: 'Revenue by customer',
46
+ dataSourceIds: ['data_...'],
47
+ });
48
+
49
+ await client.dataFlows.command(flow.operation.id, {
50
+ command: {
51
+ type: 'addTransform',
52
+ expectedRevision: flow.revision,
53
+ input: {
54
+ name: 'Revenue by customer',
55
+ instruction: 'Sum revenue by customer using the agreed revenue definition.',
56
+ inputIds: ['data_...'],
57
+ },
58
+ },
59
+ });
60
+ const updatedFlow = await client.dataFlows.get(flow.operation.id);
61
+ const operationId = updatedFlow.operationIds[0];
62
+ const current = await client.operations.getSource(operationId);
63
+ await client.operations.updateSource(operationId, {
64
+ source: handlerSource,
65
+ expectedRevision: current.revision,
66
+ expectedDataFlowRevision: current.dataFlowRevision,
67
+ expectedUpdatedAt: current.updatedAt,
68
+ });
69
+ const started = await client.operations.run(flow.operation.id, { version: 'draft' });
70
+
71
+ // Poll until the selected workflow's run completes or fails.
72
+ const runs = await client.operations.listRuns(operationId);
73
+ const completed = runs.items.find((run) => run.workflowId === started.workflowId && run.status === 'completed');
74
+ if (completed) {
75
+ const preview = await client.operations.getRunOutput(operationId, completed.id);
76
+ console.log(preview.schemas, preview.tables); // At most 1,000 rows per table.
77
+ }
78
+ ```
79
+
80
+ `handlerSource` is JavaScript using `module.exports = { handler }`. The async
81
+ handler receives `event.query(sql)` for local tables, `event.remoteQuery(connectorId, sql)`
82
+ for live SQL connectors, and `event.currentDate` for relative dates. Imports,
83
+ `require()`, and external package calls are unavailable. Inspect source tables
84
+ before writing SQL. Return arrays of flat row objects or an object of named tables;
85
+ Data Flow operations produce one table. Parent outputs retain their table names;
86
+ inspect a completed parent run with `getRunOutput` before writing dependent SQL.
87
+
88
+ Source updates replace the complete handler and save a draft without starting
89
+ Permute’s coding agent, running code, or publishing. Partial source patches are
90
+ not supported. Read with `getSource` before editing and pass back its `revision`,
91
+ `dataFlowRevision`, and `updatedAt` (as shown above). On a 409 conflict, fetch again
92
+ and reconcile your edits before retrying; do not attach fresh tokens to an old
93
+ replacement without checking the changes. Graph commands use `get`’s numeric flow revision. They support
94
+ `updateFlow`, `addTransform`, `updateNode`, `deleteNode`, `connectNodes`,
95
+ `disconnectNodes`, `publish`, and `deleteFlow`. Fetch the flow after every command.
96
+ Publishing requires a successful run of the current flow version. Deleting a flow
97
+ requires admin access; its owned operations are deleted with it.
98
+
99
+ Data Flow and operation authoring are REST/SDK only. MCP serves end users reading
100
+ and analyzing governed outputs; it does not expose code editing, draft inspection,
101
+ execution, or publication. Hosted connectors also restrict access to selected sources. Flow scheduling and standalone operation
102
+ creation are not part of this surface.
103
+
11
104
  ## Configure
12
105
 
13
106
  ```ts
package/dist/client.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { Workspace, WorkspaceCreateRequest, WorkspaceDeleteResponse, WorkspaceList, WorkspaceUpdateRequest, AnswerRequest, AnswerJobResponse, AnswerResponse, PermuteClientOptions, PermuteRequestOptions, QueryRequest, QueryResponse, SearchRequest, SearchResponse, SourceDetail, SourceList, CustomDatasetCreateRequest, DatasetDeleteResponse, DatasetResponse, FileDatasetCreateRequest, FileDatasetResponse, DatasetRows, CustomDatasetResponse } from './types.js';
1
+ import type { Database, DatabaseList, DatabaseCreateRequest, DatabaseTables, DatabaseTableCreateRequest, DatabaseTableCreated, DatabaseRecords, DatabaseRecordsQuery, DatabaseTransactionRequest, DatabaseTransactionReceipt, ResourceVersionState, ResourceRevisionList, ResourceRevision, ResourceVersionRequest, Fact, FactList, FactWriteRequest, SkillList, SkillContent, SkillWriteRequest, KnowledgeWriteResponse, OperationRunGroup, OperationRunQuery, Operation, OperationList, OperationListQuery, OperationSource, OperationSourceUpdateRequest, OperationUpdateRequest, OperationRunRequest, OperationRunStarted, OperationRunList, OperationRunOutput, DataFlow, DataFlowCreateRequest, DataFlowCommandRequest, DataFlowCommandResponse, Workspace, WorkspaceCreateRequest, WorkspaceDeleteResponse, WorkspaceList, WorkspaceUpdateRequest, AnswerRequest, AnswerJobResponse, AnswerResponse, PermuteClientOptions, PermuteRequestOptions, QueryRequest, QueryResponse, SearchRequest, SearchResponse, SourceDetail, SourceList, CustomDatasetCreateRequest, DatasetDeleteResponse, DatasetResponse, FileDatasetCreateRequest, FileDatasetResponse, DatasetRows, CustomDatasetResponse, DashboardSource, DashboardSourceUpdateRequest } from './types.js';
2
2
  export declare class PermuteApiError extends Error {
3
3
  readonly status: number;
4
4
  readonly code: string;
@@ -60,7 +60,38 @@ export declare class PermuteFileDataset {
60
60
  get status(): FileDatasetResponse['status'];
61
61
  refresh(options?: PermuteRequestOptions): Promise<this>;
62
62
  }
63
+ export interface SkillsClient {
64
+ list(options?: PermuteRequestOptions): Promise<SkillList>;
65
+ get(path: string, options?: PermuteRequestOptions): Promise<SkillContent>;
66
+ update(path: string, request: SkillWriteRequest, options?: PermuteRequestOptions): Promise<KnowledgeWriteResponse>;
67
+ delete(path: string, options?: PermuteRequestOptions): Promise<KnowledgeWriteResponse>;
68
+ }
63
69
  export declare class PermuteClient {
70
+ readonly revisions: {
71
+ list(resourceId: string, options?: PermuteRequestOptions): Promise<ResourceRevisionList>;
72
+ get(resourceId: string, revisionId: string, options?: PermuteRequestOptions): Promise<ResourceRevision>;
73
+ restore(resourceId: string, revisionId: string, request: ResourceVersionRequest, options?: PermuteRequestOptions): Promise<ResourceVersionState>;
74
+ publish(resourceId: string, request: ResourceVersionRequest, options?: PermuteRequestOptions): Promise<ResourceVersionState>;
75
+ };
76
+ readonly facts: {
77
+ list(options?: PermuteRequestOptions): Promise<FactList>;
78
+ get(factId: string, options?: PermuteRequestOptions): Promise<Fact>;
79
+ create(request: FactWriteRequest, options?: PermuteRequestOptions): Promise<Fact>;
80
+ update(factId: string, request: FactWriteRequest, options?: PermuteRequestOptions): Promise<Fact>;
81
+ delete(factId: string, options?: PermuteRequestOptions): Promise<KnowledgeWriteResponse>;
82
+ };
83
+ readonly skills: SkillsClient;
84
+ readonly organizationSkills: SkillsClient;
85
+ readonly databases: {
86
+ list(options?: PermuteRequestOptions): Promise<DatabaseList>;
87
+ create(body: DatabaseCreateRequest, options?: PermuteRequestOptions): Promise<Database>;
88
+ get(databaseId: string, options?: PermuteRequestOptions): Promise<Database>;
89
+ delete(databaseId: string, options?: PermuteRequestOptions): Promise<Database>;
90
+ tables(databaseId: string, options?: PermuteRequestOptions): Promise<DatabaseTables>;
91
+ createTable(databaseId: string, body: DatabaseTableCreateRequest, options?: PermuteRequestOptions): Promise<DatabaseTableCreated>;
92
+ records(databaseId: string, table: string, query?: Partial<DatabaseRecordsQuery>, options?: PermuteRequestOptions): Promise<DatabaseRecords>;
93
+ transact(databaseId: string, body: DatabaseTransactionRequest, options?: PermuteRequestOptions): Promise<DatabaseTransactionReceipt>;
94
+ };
64
95
  readonly workspaces: {
65
96
  list: (options?: PermuteRequestOptions) => Promise<WorkspaceList>;
66
97
  create: (request: WorkspaceCreateRequest, options?: PermuteRequestOptions) => Promise<Workspace>;
@@ -72,6 +103,28 @@ export declare class PermuteClient {
72
103
  list: (options?: PermuteRequestOptions) => Promise<SourceList>;
73
104
  get: (sourceId: string, options?: PermuteRequestOptions) => Promise<SourceDetail>;
74
105
  };
106
+ readonly operations: {
107
+ list: (query?: OperationListQuery, options?: PermuteRequestOptions) => Promise<OperationList>;
108
+ get: (operationId: string, options?: PermuteRequestOptions) => Promise<Operation>;
109
+ update: (operationId: string, request: OperationUpdateRequest, options?: PermuteRequestOptions) => Promise<Operation>;
110
+ getSource: (operationId: string, options?: PermuteRequestOptions) => Promise<OperationSource>;
111
+ updateSource: (operationId: string, request: OperationSourceUpdateRequest, options?: PermuteRequestOptions) => Promise<OperationSource>;
112
+ getRunOutput: (operationId: string, runId: string, options?: PermuteRequestOptions) => Promise<OperationRunOutput>;
113
+ listRuns: {
114
+ (operationId: string, options?: PermuteRequestOptions): Promise<OperationRunList>;
115
+ (query: OperationRunQuery, options?: PermuteRequestOptions): Promise<OperationRunGroup>;
116
+ };
117
+ run: (operationId: string, request: OperationRunRequest, options?: PermuteRequestOptions) => Promise<OperationRunStarted>;
118
+ };
119
+ readonly dataFlows: {
120
+ create: (request: DataFlowCreateRequest, options?: PermuteRequestOptions) => Promise<DataFlow>;
121
+ get: (dataFlowId: string, options?: PermuteRequestOptions) => Promise<DataFlow>;
122
+ command: (dataFlowId: string, request: DataFlowCommandRequest, options?: PermuteRequestOptions) => Promise<DataFlowCommandResponse>;
123
+ };
124
+ readonly dashboards: {
125
+ getSource: (dashboardId: string, options?: PermuteRequestOptions) => Promise<DashboardSource>;
126
+ updateSource: (dashboardId: string, request: DashboardSourceUpdateRequest, options?: PermuteRequestOptions) => Promise<DashboardSource>;
127
+ };
75
128
  readonly datasets: {
76
129
  create: {
77
130
  (request: CustomDatasetCreateRequest, options?: PermuteRequestOptions): Promise<PermuteDataset>;
package/dist/client.js CHANGED
@@ -262,8 +262,16 @@ export class PermuteFileDataset {
262
262
  }
263
263
  }
264
264
  export class PermuteClient {
265
+ revisions;
266
+ facts;
267
+ skills;
268
+ organizationSkills;
269
+ databases;
265
270
  workspaces;
266
271
  sources;
272
+ operations;
273
+ dataFlows;
274
+ dashboards;
267
275
  datasets;
268
276
  apiKey;
269
277
  baseUrl;
@@ -292,6 +300,37 @@ export class PermuteClient {
292
300
  this.workspaceId = options.workspaceId;
293
301
  this.defaultHeaders = options.headers ?? {};
294
302
  this.fetchImpl = fetchImpl.bind(globalThis);
303
+ this.revisions = {
304
+ list: (resourceId, options) => this.request('resourceRevisionsList', { pathParams: { resourceId } }, options),
305
+ get: (resourceId, revisionId, options) => this.request('resourceRevisionsGet', { pathParams: { resourceId, revisionId } }, options),
306
+ restore: (resourceId, revisionId, body, options) => this.request('resourceRevisionsRestore', { pathParams: { resourceId, revisionId }, body }, options),
307
+ publish: (resourceId, body, options) => this.request('resourcesPublish', { pathParams: { resourceId }, body }, options),
308
+ };
309
+ this.facts = {
310
+ list: (options) => this.request('factsList', {}, options),
311
+ get: (factId, options) => this.request('factsGet', { pathParams: { factId } }, options),
312
+ create: (body, options) => this.request('factsCreate', { body }, options),
313
+ update: (factId, body, options) => this.request('factsUpdate', { pathParams: { factId }, body }, options),
314
+ delete: (factId, options) => this.request('factsDelete', { pathParams: { factId } }, options),
315
+ };
316
+ const skillsClient = (prefix) => ({
317
+ list: (options) => this.request(`${prefix}List`, {}, options),
318
+ get: (path, options) => this.request(`${prefix}Get`, { pathParams: { path } }, options),
319
+ update: (path, body, options) => this.request(`${prefix}Update`, { pathParams: { path }, body }, options),
320
+ delete: (path, options) => this.request(`${prefix}Delete`, { pathParams: { path } }, options),
321
+ });
322
+ this.skills = skillsClient('skills');
323
+ this.organizationSkills = skillsClient('organizationSkills');
324
+ this.databases = {
325
+ list: (options) => this.request('databasesList', {}, options),
326
+ create: (body, options) => this.request('databasesCreate', { body }, options),
327
+ get: (databaseId, options) => this.request('databasesGet', { pathParams: { databaseId } }, options),
328
+ delete: (databaseId, options) => this.request('databasesDelete', { pathParams: { databaseId } }, options),
329
+ tables: (databaseId, options) => this.request('databaseTablesList', { pathParams: { databaseId } }, options),
330
+ createTable: (databaseId, body, options) => this.request('databaseTablesCreate', { pathParams: { databaseId }, body }, options),
331
+ records: (databaseId, table, query = {}, options) => this.request('databaseRecordsList', { pathParams: { databaseId, table }, query }, options),
332
+ transact: (databaseId, body, options) => this.request('databaseTransactionsCreate', { pathParams: { databaseId }, body }, options),
333
+ };
295
334
  this.workspaces = {
296
335
  list: (requestOptions) => this.request('workspacesList', {}, requestOptions),
297
336
  create: (request, requestOptions) => this.request('workspacesCreate', { body: request }, requestOptions),
@@ -303,6 +342,27 @@ export class PermuteClient {
303
342
  list: (requestOptions) => this.request('sourcesList', {}, requestOptions),
304
343
  get: (sourceId, requestOptions) => this.request('sourcesGet', { pathParams: { sourceId } }, requestOptions),
305
344
  };
345
+ this.operations = {
346
+ list: (query = {}, options) => this.request('operationsList', { query }, options),
347
+ get: (operationId, options) => this.request('operationsGet', { pathParams: { operationId } }, options),
348
+ update: (operationId, body, options) => this.request('operationsUpdate', { pathParams: { operationId }, body }, options),
349
+ getSource: (operationId, options) => this.request('operationsSourceGet', { pathParams: { operationId } }, options),
350
+ updateSource: (operationId, body, options) => this.request('operationsSourceUpdate', { pathParams: { operationId }, body }, options),
351
+ getRunOutput: (operationId, runId, options) => this.request('operationsRunOutput', { pathParams: { operationId, runId } }, options),
352
+ listRuns: ((input, options) => typeof input === 'string'
353
+ ? this.request('operationsRunsList', { pathParams: { operationId: input } }, options)
354
+ : this.request('operationRunsList', { query: input }, options)),
355
+ run: (operationId, body, options) => this.request('operationsRun', { pathParams: { operationId }, body }, options),
356
+ };
357
+ this.dataFlows = {
358
+ create: (body, options) => this.request('dataFlowsCreate', { body }, options),
359
+ get: (dataFlowId, options) => this.request('dataFlowsGet', { pathParams: { dataFlowId } }, options),
360
+ command: (dataFlowId, body, options) => this.request('dataFlowsCommand', { pathParams: { dataFlowId }, body }, options),
361
+ };
362
+ this.dashboards = {
363
+ getSource: (dashboardId, requestOptions) => this.request('dashboardsSourceGet', { pathParams: { dashboardId } }, requestOptions),
364
+ updateSource: (dashboardId, request, requestOptions) => this.request('dashboardsSourceUpdate', { pathParams: { dashboardId }, body: request }, requestOptions),
365
+ };
306
366
  const readDataset = (datasetId, requestOptions) => this.request('datasetsGet', { pathParams: { datasetId } }, requestOptions);
307
367
  const writeDatasetTables = async (datasetId, request, requestOptions) => {
308
368
  const encoded = encodeDatasetWrite(request);
@@ -499,7 +559,7 @@ export class PermuteClient {
499
559
  }
500
560
  const url = new URL(`${this.baseUrl.replace(/\/+$/, '')}${buildPath(route, input.pathParams)}`);
501
561
  for (const [key, value] of Object.entries(query))
502
- url.searchParams.set(key, value);
562
+ url.searchParams.set(key, String(value));
503
563
  const response = await this.fetchImpl(url.toString(), {
504
564
  method: route.method,
505
565
  headers,
@@ -553,6 +613,6 @@ export class PermuteClient {
553
613
  if (!queryValidator(requestQuery)) {
554
614
  throw validationError(operationId, 'request', queryValidator.errors);
555
615
  }
556
- return requestQuery;
616
+ return Object.fromEntries(Object.entries(requestQuery).map(([key, value]) => [key, String(value)]));
557
617
  }
558
618
  }