@pantechdynamic/sdk 0.1.0 → 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/CHANGELOG.md CHANGED
@@ -4,6 +4,25 @@ A new version heading here (`## X.Y.Z (YYYY-MM-DD)`) pushed to main is
4
4
  tagged `vX.Y.Z` and published to npm. Add changes under `## Unreleased`
5
5
  until then.
6
6
 
7
+ ## 0.2.0 (2026-10-28)
8
+
9
+ - `client.migrate`, for moving from another cloud: `migrate.connections`
10
+ (`list`, `listAll`, `create`, `get`, `update` for the name, role ARN or a retry, `delete`)
11
+ connects an AWS account through a read-only role; `migrate.scans` (`list`, `listAll`,
12
+ `start`, `get` with `{ include: "inventory" }`) reads what runs there; `migrate.migrations`
13
+ (`list`, `listAll`, `create`, `get`, `rename`, `delete`, `updateItem`, `exportTerraform`) plans
14
+ the move with a price comparison and a Terraform export.
15
+ - `migrate.connections.wait()` and `migrate.scans.wait()`, which reject with the new
16
+ `CloudFailedError` when the connection or scan fails.
17
+ - `examples/migrate-from-aws.ts`.
18
+ - Types follow the current public API, including Kubernetes clusters' `node_health`,
19
+ `ready_nodes` and `nodes_checked_at`, and a load balancer's `protocol`.
20
+ - Fixed: request fields the API defaults (`endpoint_access`, `control_nodes`, a firewall rule's
21
+ `direction` and `action`, `algorithm`, `purpose`, `admin_username`, `retention_count`,
22
+ `enabled`, `autoscaling_enabled`) are optional in the types, as they are in the API.
23
+ - Agent sessions, which answer only AI apps connected through Pantech's MCP server, have no
24
+ methods yet; `scripts/not-in-sdk.json` lists them and `npm run generate` leaves out their types.
25
+
7
26
  ## 0.1.0 (2026-10-24)
8
27
 
9
28
  - First release: a client for every operation in the Pantech Dynamics public API
package/README.md CHANGED
@@ -6,7 +6,7 @@
6
6
 
7
7
  The official client for the [Pantech Dynamics public API](https://docs.pantechdynamics.com/api):
8
8
  instances, VPC networks, firewalls, public IPs, load balancers, volumes, snapshots, managed
9
- databases, managed Kubernetes, SSH keys, webhooks, billing and usage.
9
+ databases, managed Kubernetes, SSH keys, webhooks, billing, usage, and moving from another cloud.
10
10
 
11
11
  - Zero runtime dependencies. Uses the global `fetch` and Web Crypto, so it runs on Node.js 18+,
12
12
  Bun, Deno and edge runtimes.
@@ -75,9 +75,11 @@ Every method takes per-call options last: `{ signal, timeout, maxRetries, idempo
75
75
  | Databases | `databases.*`, `databases.snapshots.*`, `databaseOrders.wait(order)` |
76
76
  | SSH keys, webhooks | `sshKeys.*`, `webhooks.*`, `webhooks.deliveries.*` |
77
77
  | Billing and usage | `billing.credit.get()`, `billing.credit.purchases.create(...)`, `billing.receipts.getPdf(id)`, `usage.get()` |
78
+ | Move from another cloud | `migrate.connections.*`, `migrate.scans.*`, `migrate.migrations.*` |
78
79
  | Operations | `operations.get(id)`, `operations.wait(id)`, `operations.stream(id)` |
79
80
 
80
- Every operation in the public spec has a method; `test/coverage.test.ts` fails if one is missing.
81
+ Every operation in the public spec has a method, except agent sessions, which answer only AI apps
82
+ connected through Pantech's MCP server; `test/coverage.test.ts` fails if one is missing.
81
83
  For anything else, `client.request({ method, path, query, body })` sends a raw request with the
82
84
  same auth, retries and errors.
83
85
 
@@ -101,7 +103,29 @@ for await (const o of client.operations.stream("op_…")) console.log(o.status);
101
103
  ```
102
104
 
103
105
  A failed operation rejects with `OperationFailedError` (`code`, `detail` from its `failure`), a
104
- failed or unpaid order with `OrderFailedError`, and a wait that runs out with `WaitTimeoutError`.
106
+ failed or unpaid order with `OrderFailedError`, a failed cloud connection or scan with
107
+ `CloudFailedError`, and a wait that runs out with `WaitTimeoutError`.
108
+
109
+ ## Move from another cloud
110
+
111
+ `client.migrate` connects an AWS account through a read-only role that only Pantech can assume (no
112
+ access keys are shared), scans what runs there, and plans the move with a price comparison and a
113
+ Terraform export. Nothing is created on Pantech until you apply the Terraform.
114
+
115
+ ```ts
116
+ let conn = await client.migrate.connections.create({ name: "Production AWS" });
117
+ console.log(conn.setup.quick_create_url); // create the stack in AWS, then send its RoleArn output
118
+ await client.migrate.connections.update(conn.id, { role_arn: "arn:aws:iam::…:role/…" });
119
+ conn = await client.migrate.connections.wait(conn.id); // CloudFailedError if the role cannot be assumed
120
+
121
+ const scan = await client.migrate.scans.wait((await client.migrate.scans.start(conn.id)).id);
122
+ const plan = await client.migrate.migrations.create({ scan_id: scan.id, name: "Move to Pantech" });
123
+ console.log(plan.estimate?.pantech_monthly_minor, plan.estimate?.source_monthly_minor);
124
+ const { files } = await client.migrate.migrations.exportTerraform(plan.id); // main.tf, variables.tf
125
+ ```
126
+
127
+ `migrate.migrations.updateItem(id, { key, excluded: true })` leaves an item out, or changes its
128
+ plan, size, address range or role, before you export. See `examples/migrate-from-aws.ts`.
105
129
 
106
130
  ## Errors
107
131
 
@@ -156,7 +180,7 @@ the timestamp is too old. On Node.js 18, start node with `--experimental-global-
156
180
 
157
181
  ## Examples
158
182
 
159
- `examples/` has `create-instance.ts`, `list.ts` and `webhook-receiver.ts`. With Node.js 23.6+:
183
+ `examples/` has `create-instance.ts`, `list.ts`, `webhook-receiver.ts` and `migrate-from-aws.ts`. With Node.js 23.6+:
160
184
  `npm run build && PANTECH_API_KEY=PAN_… node examples/list.ts`.
161
185
 
162
186
  ## Development
package/dist/index.cjs CHANGED
@@ -88,6 +88,18 @@ var OrderFailedError = class extends PantechError {
88
88
  this.order = order;
89
89
  }
90
90
  };
91
+ var CloudFailedError = class extends PantechError {
92
+ name = "CloudFailedError";
93
+ /** `connection` or `scan`. */
94
+ kind;
95
+ /** The failed connection or scan, as the API returned it. */
96
+ resource;
97
+ constructor(message, kind, resource, init = {}) {
98
+ super(message, init);
99
+ this.kind = kind;
100
+ this.resource = resource;
101
+ }
102
+ };
91
103
  var WaitTimeoutError = class extends PantechError {
92
104
  name = "WaitTimeoutError";
93
105
  };
@@ -775,6 +787,136 @@ var MeResource = class extends APIResource {
775
787
  }
776
788
  };
777
789
 
790
+ // src/resources/migrate.ts
791
+ var CONNECTION_WAIT_MS = 10 * 6e4;
792
+ var SCAN_WAIT_MS = 30 * 6e4;
793
+ function cloudFailed(kind, id, failure, resource) {
794
+ const detail = failure?.message ?? `The ${kind} failed.`;
795
+ const code = failure?.code;
796
+ return new CloudFailedError(
797
+ code ? `Cloud ${kind} ${id} failed: ${detail} (${code})` : `Cloud ${kind} ${id} failed: ${detail}`,
798
+ kind,
799
+ resource,
800
+ { code, detail }
801
+ );
802
+ }
803
+ var Migrate = class extends APIResource {
804
+ /** Connections to AWS accounts through a read-only role only Pantech can assume. */
805
+ connections = new CloudConnections(this._client);
806
+ /** Reads of everything a connection's role can see. */
807
+ scans = new CloudScans(this._client);
808
+ /** Plans to move what a scan found to Pantech. Nothing is created until you apply the Terraform. */
809
+ migrations = new Migrations(this._client);
810
+ };
811
+ var CloudConnections = class extends APIResource {
812
+ list(params = {}, options) {
813
+ return this._get("/cloud-connections", params, options);
814
+ }
815
+ listAll(params = {}, options) {
816
+ return this._listAll("/cloud-connections", params, options);
817
+ }
818
+ /**
819
+ * Starts a connection. Its `setup` holds the CloudFormation template (and,
820
+ * when offered, a one-click `quick_create_url`) that creates the read-only
821
+ * role in your AWS account; send the stack's `RoleArn` output with `update`.
822
+ */
823
+ create(body, options) {
824
+ return this._post("/cloud-connections", body, options);
825
+ }
826
+ get(connectionId, options) {
827
+ return this._get(path`/cloud-connections/${connectionId}`, void 0, options);
828
+ }
829
+ /** Renames the connection, sets its `role_arn`, or retries a failed check (`retry: true`). */
830
+ update(connectionId, body, options) {
831
+ return this._patch(path`/cloud-connections/${connectionId}`, body, options);
832
+ }
833
+ /** Removes the connection and its scans; plans made from it stay. Delete the stack in AWS to revoke the role there. */
834
+ delete(connectionId, options) {
835
+ return this._delete(path`/cloud-connections/${connectionId}`, options);
836
+ }
837
+ /**
838
+ * Polls the connection until it is `connected` (resolves with it) or its
839
+ * check fails (rejects with CloudFailedError). Set the role ARN with
840
+ * `update` first. Default timeout 10 minutes, polling every 5 seconds.
841
+ */
842
+ wait(connectionId, options = {}) {
843
+ return poll(
844
+ () => this.get(connectionId, { signal: options.signal }),
845
+ (c) => {
846
+ if (c.status === "failed") throw cloudFailed("connection", c.id, c.failure, c);
847
+ return c.status === "connected";
848
+ },
849
+ `Cloud connection ${connectionId}`,
850
+ { timeoutMs: CONNECTION_WAIT_MS, pollIntervalMs: 5e3, ...options }
851
+ );
852
+ }
853
+ };
854
+ var CloudScans = class extends APIResource {
855
+ /** A connection's scans, newest first, without their inventories. */
856
+ list(connectionId, params = {}, options) {
857
+ return this._get(path`/cloud-connections/${connectionId}/scans`, params, options);
858
+ }
859
+ listAll(connectionId, params = {}, options) {
860
+ return this._listAll(path`/cloud-connections/${connectionId}/scans`, params, options);
861
+ }
862
+ /** Queues a scan of a connected account. Follow it with `wait`. */
863
+ start(connectionId, options) {
864
+ return this._post(path`/cloud-connections/${connectionId}/scans`, void 0, options);
865
+ }
866
+ /** A scan's status and counts. Pass `{ include: "inventory" }` for everything it found. */
867
+ get(scanId, params = {}, options) {
868
+ return this._get(path`/cloud-scans/${scanId}`, params, options);
869
+ }
870
+ /**
871
+ * Polls the scan until it `succeeded` (resolves with it, without its
872
+ * inventory) or failed (rejects with CloudFailedError). Default timeout 30
873
+ * minutes, polling every 10 seconds.
874
+ */
875
+ wait(scanId, options = {}) {
876
+ return poll(
877
+ () => this.get(scanId, {}, { signal: options.signal }),
878
+ (s) => {
879
+ if (s.status === "failed") throw cloudFailed("scan", s.id, s.failure, s);
880
+ return s.status === "succeeded";
881
+ },
882
+ `Cloud scan ${scanId}`,
883
+ { timeoutMs: SCAN_WAIT_MS, pollIntervalMs: 1e4, ...options }
884
+ );
885
+ }
886
+ };
887
+ var Migrations = class extends APIResource {
888
+ /** Your migration plans, newest first, without their items or estimate. */
889
+ list(params = {}, options) {
890
+ return this._get("/migrations", params, options);
891
+ }
892
+ listAll(params = {}, options) {
893
+ return this._listAll("/migrations", params, options);
894
+ }
895
+ /** Builds a plan, with a price comparison, from a scan that succeeded. Nothing is created on Pantech. */
896
+ create(body, options) {
897
+ return this._post("/migrations", body, options);
898
+ }
899
+ /** A plan with every item, and a price comparison computed now. */
900
+ get(migrationId, options) {
901
+ return this._get(path`/migrations/${migrationId}`, void 0, options);
902
+ }
903
+ rename(migrationId, body, options) {
904
+ return this._patch(path`/migrations/${migrationId}`, body, options);
905
+ }
906
+ /** Deletes the plan. Nothing on Pantech or in the other cloud is touched. */
907
+ delete(migrationId, options) {
908
+ return this._delete(path`/migrations/${migrationId}`, options);
909
+ }
910
+ /** Changes one item, named by its `key`: exclude it, or change its plan, size, range, role or email. */
911
+ updateItem(migrationId, body, options) {
912
+ return this._patch(path`/migrations/${migrationId}/items`, body, options);
913
+ }
914
+ /** The plan's planned items as Terraform: `main.tf` and `variables.tf`. */
915
+ exportTerraform(migrationId, options) {
916
+ return this._get(path`/migrations/${migrationId}/terraform`, void 0, options);
917
+ }
918
+ };
919
+
778
920
  // src/resources/networks.ts
779
921
  var Networks = class extends APIResource {
780
922
  /** A network's subnets: `client.networks.subnets.list(networkId)`. */
@@ -1185,7 +1327,7 @@ var WebhookDeliveries = class extends APIResource {
1185
1327
  };
1186
1328
 
1187
1329
  // src/version.ts
1188
- var VERSION = "0.1.0";
1330
+ var VERSION = "0.2.0";
1189
1331
 
1190
1332
  // src/client.ts
1191
1333
  var DEFAULT_BASE_URL = "https://api.pantechdynamics.com/public/v1";
@@ -1230,6 +1372,8 @@ var Pantech = class {
1230
1372
  databaseOrders;
1231
1373
  sshKeys;
1232
1374
  webhooks;
1375
+ /** Move from another cloud: connections, scans and migration plans. */
1376
+ migrate;
1233
1377
  operations;
1234
1378
  constructor(options = {}) {
1235
1379
  const apiKey = options.apiKey ?? readEnv("PANTECH_API_KEY");
@@ -1271,6 +1415,7 @@ var Pantech = class {
1271
1415
  this.databaseOrders = new DatabaseOrders(this);
1272
1416
  this.sshKeys = new SshKeys(this);
1273
1417
  this.webhooks = new Webhooks(this);
1418
+ this.migrate = new Migrate(this);
1274
1419
  }
1275
1420
  /**
1276
1421
  * Sends one request and returns its decoded body (undefined for an empty
@@ -1490,6 +1635,7 @@ exports.APIConnectionError = APIConnectionError;
1490
1635
  exports.APITimeoutError = APITimeoutError;
1491
1636
  exports.AuthenticationError = AuthenticationError;
1492
1637
  exports.BadRequestError = BadRequestError;
1638
+ exports.CloudFailedError = CloudFailedError;
1493
1639
  exports.ConflictError = ConflictError;
1494
1640
  exports.DEFAULT_BASE_URL = DEFAULT_BASE_URL;
1495
1641
  exports.DEFAULT_WEBHOOK_TOLERANCE_SECONDS = DEFAULT_WEBHOOK_TOLERANCE_SECONDS;