@epilot/cli 0.1.82 → 0.1.84

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
@@ -29,7 +29,7 @@ npm install -g @epilot/cli
29
29
 
30
30
  <!-- usage-help -->
31
31
  ```
32
- epilot v0.1.82 — CLI for epilot APIs
32
+ epilot v0.1.84 — CLI for epilot APIs
33
33
 
34
34
  USAGE
35
35
  epilot <api> <operationId> [params...] [flags]
@@ -3,7 +3,7 @@
3
3
  "info": {
4
4
  "title": "Pricing API",
5
5
  "description": "The `pricing-api` hub sets the foundations for the following Pricing APIs:\n\n### Order API\nThis api enables the management of orders in epilot 360, providing features such as:\n - Automatic calculation of totals and price breakdowns for taxes on the Order entity\n - Product and pricing data validation\n\n### Shopping Cart API\nUsed to interact with a cart during a customer's checkout session, providing:\n - An unified data model to model a Shopping Cart\n - Product and pricing data validation\n - Checkout a cart into an order or quote\n\n### Catalog API\nProvides a way to query the entire catalog of products and prices.\n\n### Availability API\nProvides endpoints for querying products availability by a set of predefined dimensions.\n\n### Spot Market API\nProvides endpoints to fetch (historic) spot market price data.\n\n### External Integrations API\nProvides endpoints for external integrations. E.g. GetAG.\n\n### External Catalog API\nProvides endpoints for external catalog.\n\n### Product Recommendations API\nProvides endpoints for product recommendations.\n",
6
- "version": "1.1.0",
6
+ "version": "1.2.0",
7
7
  "termsOfService": "https://epilot.cloud/agb",
8
8
  "contact": {
9
9
  "name": "Support",
@@ -3430,6 +3430,22 @@
3430
3430
  "external-catalog"
3431
3431
  ]
3432
3432
  },
3433
+ "ConditionalPricingErrorCode": {
3434
+ "type": "string",
3435
+ "description": "Machine-readable failure mode of a conditional-pricing operation, allowing clients\nto branch on the kind of failure instead of parsing the error message.\n\n- `NOT_FOUND` (404): the addressed entity, variant or version does not exist\n- `AMBIGUOUS_RESOLUTION` (409): several variants match the given context while a single result was requested\n- `TUPLE_CONFLICT` (409): the condition tuple is already claimed by another variant\n- `VERSION_CONFLICT` (409): a version already exists at the given `valid_from` on that variant\n- `SUPERSEDED_VERSION` (409): the addressed version has been superseded\n- `CONDITION_UNDEFINED` (400): the context names a condition the entity's schema does not define\n- `OPERATOR_UNSUPPORTED` (400): the requested operator is not applicable to the condition's type\n- `CONTEXT_FORMAT_INVALID` (400): a context value is malformed for its condition type\n- `TOO_MANY_MATCHES` (400): a multi-match resolve exceeded its result cap\n- `WRITE_CONFLICT` (409): transient write contention, retryable unlike `TUPLE_CONFLICT`\n\nEach code is emitted with the HTTP status shown above, and only with that status.\n",
3436
+ "enum": [
3437
+ "NOT_FOUND",
3438
+ "AMBIGUOUS_RESOLUTION",
3439
+ "TUPLE_CONFLICT",
3440
+ "VERSION_CONFLICT",
3441
+ "SUPERSEDED_VERSION",
3442
+ "CONDITION_UNDEFINED",
3443
+ "OPERATOR_UNSUPPORTED",
3444
+ "CONTEXT_FORMAT_INVALID",
3445
+ "TOO_MANY_MATCHES",
3446
+ "WRITE_CONFLICT"
3447
+ ]
3448
+ },
3433
3449
  "Error": {
3434
3450
  "required": [
3435
3451
  "message"
@@ -3449,6 +3465,31 @@
3449
3465
  }
3450
3466
  }
3451
3467
  },
3468
+ "ConditionalPricingError": {
3469
+ "description": "An error from a conditional-pricing operation, carrying a machine-readable `code`\nfrom the conditional-pricing vocabulary plus any structured data about the failure,\nso a client can branch on the kind of failure rather than parse the message.\nReferenced only by the operations that emit these codes; every other operation\nkeeps the plain `Error` shape.\n",
3470
+ "allOf": [
3471
+ {
3472
+ "$ref": "#/components/schemas/Error"
3473
+ },
3474
+ {
3475
+ "type": "object",
3476
+ "properties": {
3477
+ "error": {
3478
+ "type": "string",
3479
+ "description": "The error message. Carries the same string as `message`, which the shared `Error`\nschema requires — `error` is the field responses have always used, and every caller\nto date reads. Declared here rather than on the shared `Error` because a request\nvalidation failure puts a list of validation errors in this field instead of a\nstring, and those responses reference `Error` directly.\n"
3480
+ },
3481
+ "code": {
3482
+ "$ref": "#/components/schemas/ConditionalPricingErrorCode"
3483
+ },
3484
+ "details": {
3485
+ "type": "object",
3486
+ "additionalProperties": true,
3487
+ "description": "Structured data about the failure, shaped by the accompanying `code`\n(e.g. the candidate variants of an `ambiguous-resolution`). Only present\nwhen the failure has structured data to report, and never without a `code`.\n"
3488
+ }
3489
+ }
3490
+ }
3491
+ ]
3492
+ },
3452
3493
  "Product": {
3453
3494
  "type": "object",
3454
3495
  "description": "The product entity",
@@ -6967,7 +7008,14 @@
6967
7008
  "description": "The deprecated tax rate applied.\nThis field has been deprecated in favor of the new Tax Management. You should use the new tax fields pointing to a proper tax entity.\n"
6968
7009
  },
6969
7010
  "tax": {
6970
- "$ref": "#/components/schemas/Tax"
7011
+ "oneOf": [
7012
+ {
7013
+ "$ref": "#/components/schemas/Tax"
7014
+ },
7015
+ {
7016
+ "$ref": "#/components/schemas/TaxItem"
7017
+ }
7018
+ ]
6971
7019
  }
6972
7020
  }
6973
7021
  },
@@ -8443,6 +8491,37 @@
8443
8491
  "_updated_at": "2021-02-09T12:41:43.662Z"
8444
8492
  }
8445
8493
  },
8494
+ "TaxItem": {
8495
+ "type": "object",
8496
+ "description": "A minimal, ad-hoc tax rate for line items with no backing tax entity\nin the catalog (e.g. a fully custom/composite price component built\nby a client with no product/price reference to resolve tax from).\nMirrors how PriceItem relates to Price: unlike Tax, this has no\nentity identity — it isn't persisted and can't be looked up by _id,\nso it can't be shared/reused across price items the way a catalog\nTax can.\n",
8497
+ "additionalProperties": false,
8498
+ "required": [
8499
+ "type",
8500
+ "rate"
8501
+ ],
8502
+ "properties": {
8503
+ "type": {
8504
+ "type": "string",
8505
+ "enum": [
8506
+ "VAT",
8507
+ "GST",
8508
+ "Custom"
8509
+ ]
8510
+ },
8511
+ "rate": {
8512
+ "type": "number",
8513
+ "nullable": true
8514
+ },
8515
+ "description": {
8516
+ "type": "string"
8517
+ }
8518
+ },
8519
+ "example": {
8520
+ "rate": 19,
8521
+ "type": "VAT",
8522
+ "description": "Custom 19% VAT"
8523
+ }
8524
+ },
8446
8525
  "TaxBreakdownInfo": {
8447
8526
  "type": "object",
8448
8527
  "properties": {
@@ -3,7 +3,7 @@ import {
3
3
  log,
4
4
  readManifest,
5
5
  writeManifest
6
- } from "./chunk-4TDAAJ6H.js";
6
+ } from "./chunk-QOD77YLW.js";
7
7
  import "./chunk-M3M3C5WH.js";
8
8
  import "./chunk-YHQA2AVG.js";
9
9
  import "./chunk-7ZQ666ZQ.js";
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/commands/app/index.ts
4
+ import { defineCommand } from "citty";
5
+ var app_default = defineCommand({
6
+ meta: {
7
+ name: "app",
8
+ description: "Manage epilot Apps \u2014 create, deploy, and manage app manifests"
9
+ },
10
+ subCommands: {
11
+ init: () => import("./init-345HGB5B.js").then((m) => m.default),
12
+ "add-component": () => import("./add-component-CJIQYDO5.js").then((m) => m.default),
13
+ "remove-component": () => import("./remove-component-LPTHVN4P.js").then((m) => m.default),
14
+ validate: () => import("./validate-TLSOTJAY.js").then((m) => m.default),
15
+ deploy: () => import("./deploy-NRQHZ635.js").then((m) => m.default),
16
+ export: () => import("./export-ZRDJCALM.js").then((m) => m.default),
17
+ versions: () => import("./versions-VA4H3EPK.js").then((m) => m.default),
18
+ review: () => import("./review-OZTM3XBD.js").then((m) => m.default),
19
+ api: () => import("./api-5W2UMWCW.js").then((m) => m.default)
20
+ }
21
+ });
22
+ export {
23
+ app_default as default
24
+ };
@@ -11,7 +11,7 @@ import { defineCommand } from "citty";
11
11
  var main = defineCommand({
12
12
  meta: {
13
13
  name: "epilot",
14
- version: "0.1.82",
14
+ version: "0.1.84",
15
15
  description: "CLI for epilot APIs"
16
16
  },
17
17
  args: {
@@ -31,12 +31,12 @@ var main = defineCommand({
31
31
  profile: () => import("../profile-OZJL5ZPT.js").then((m) => m.default),
32
32
  config: () => import("../config-DGZIMLZK.js").then((m) => m.default),
33
33
  completion: () => import("../completion-N6A4VCAE.js").then((m) => m.default),
34
- upgrade: () => import("../upgrade-YBOBA2V7.js").then((m) => m.default),
34
+ upgrade: () => import("../upgrade-OBVI55D5.js").then((m) => m.default),
35
35
  "access-token": () => import("../access-token-WWE6BDJH.js").then((m) => m.default),
36
36
  address: () => import("../address-EH3C4CVB.js").then((m) => m.default),
37
37
  "address-suggestions": () => import("../address-suggestions-RRSLOBFW.js").then((m) => m.default),
38
38
  "ai-agents": () => import("../ai-agents-53M2KHPI.js").then((m) => m.default),
39
- app: () => import("../app-EULJIEDB.js").then((m) => m.default),
39
+ app: () => import("../app-TIWZ2LQC.js").then((m) => m.default),
40
40
  "audit-logs": () => import("../audit-logs-YFRK3EFU.js").then((m) => m.default),
41
41
  automation: () => import("../automation-4DEE3TUI.js").then((m) => m.default),
42
42
  billing: () => import("../billing-XX4VVOPI.js").then((m) => m.default),
@@ -134,7 +134,7 @@ process.stderr.on("error", (err) => {
134
134
  if (err.code === "EPIPE") process.exit(0);
135
135
  throw err;
136
136
  });
137
- var VERSION = true ? "0.1.82" : (await null).default.version;
137
+ var VERSION = true ? "0.1.84" : (await null).default.version;
138
138
  var reorderedArgv = hoistFlagsAfterSubcommand(process.argv.slice(2));
139
139
  process.argv = [process.argv[0], process.argv[1], ...reorderedArgv];
140
140
  var args = process.argv.slice(2);
@@ -1,7 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
+ loadCredentials,
3
4
  resolveToken
4
5
  } from "./chunk-M3M3C5WH.js";
6
+ import {
7
+ getResolvedProfile
8
+ } from "./chunk-YHQA2AVG.js";
5
9
  import {
6
10
  BOLD,
7
11
  DIM,
@@ -121,6 +125,33 @@ async function request(baseUrl, token, method, path, body) {
121
125
  }
122
126
  return text;
123
127
  }
128
+ var parseJwtPayload = (token) => {
129
+ try {
130
+ const parts = token.split(".");
131
+ if (parts.length !== 3) return null;
132
+ const payload = Buffer.from(parts[1], "base64url").toString("utf-8");
133
+ return JSON.parse(payload);
134
+ } catch {
135
+ return null;
136
+ }
137
+ };
138
+ function resolveOrgId(tokenFlag, profile) {
139
+ const token = resolveToken(tokenFlag, profile);
140
+ const claims = token ? parseJwtPayload(token) : null;
141
+ const fromToken = claims?.org_id ?? claims?.["custom:ivy_org_id"];
142
+ if (fromToken) return fromToken;
143
+ return getResolvedProfile(profile)?.org_id ?? loadCredentials()?.org_id;
144
+ }
145
+ function derivePermissionsBaseUrl(appBaseUrl) {
146
+ try {
147
+ const url = new URL(appBaseUrl);
148
+ if (!url.hostname.startsWith("app.")) return null;
149
+ url.hostname = url.hostname.replace(/^app\./, "permissions.");
150
+ return url.origin;
151
+ } catch {
152
+ return null;
153
+ }
154
+ }
124
155
  function createAppApiClient(opts) {
125
156
  const baseUrl = opts.server ?? DEFAULT_BASE_URL;
126
157
  const getToken = () => {
@@ -150,6 +181,28 @@ function createAppApiClient(opts) {
150
181
  async patchVersion(appId, version, payload) {
151
182
  await request(baseUrl, getToken(), "PATCH", `/v1/app-configurations/${appId}/versions/${version}`, payload);
152
183
  },
184
+ /**
185
+ * Upsert the app's role in the developer's own organization with the
186
+ * manifest grants. The role id is attached to the app version via
187
+ * `role_id`; on installation the App API creates a copy of it (from the
188
+ * version's grants) in the installer's organization.
189
+ */
190
+ async upsertAppRole(params) {
191
+ const permissionsBaseUrl = derivePermissionsBaseUrl(baseUrl);
192
+ if (!permissionsBaseUrl) {
193
+ throw new Error(`Cannot derive permissions API URL from ${baseUrl}`);
194
+ }
195
+ const roleId = `${params.orgId}:${params.appId}`;
196
+ await request(permissionsBaseUrl, getToken(), "PUT", `/v1/permissions/roles/${roleId}`, {
197
+ id: roleId,
198
+ organization_id: params.orgId,
199
+ type: "user_role",
200
+ slug: params.appId,
201
+ name: `Automatically created by App ${params.appName}`,
202
+ grants: params.grants
203
+ });
204
+ return roleId;
205
+ },
153
206
  async cloneVersion(appId, version) {
154
207
  return request(
155
208
  baseUrl,
@@ -358,6 +411,7 @@ export {
358
411
  validateManifest,
359
412
  readManifest,
360
413
  writeManifest,
414
+ resolveOrgId,
361
415
  createAppApiClient,
362
416
  uploadFileToPresignedUrl,
363
417
  uploadDirectoryAsZip,
@@ -4,10 +4,11 @@ import {
4
4
  formatFileSize,
5
5
  log,
6
6
  readManifest,
7
+ resolveOrgId,
7
8
  uploadDirectoryAsZip,
8
9
  uploadFileToPresignedUrl,
9
10
  writeManifest
10
- } from "./chunk-4TDAAJ6H.js";
11
+ } from "./chunk-QOD77YLW.js";
11
12
  import "./chunk-M3M3C5WH.js";
12
13
  import "./chunk-YHQA2AVG.js";
13
14
  import "./chunk-7ZQ666ZQ.js";
@@ -106,10 +107,32 @@ var deploy_default = defineCommand({
106
107
  }
107
108
  if (manifest.permissions?.length || manifest.blueprint?.manifest_id) {
108
109
  if (dryRun) {
110
+ if (manifest.permissions?.length) {
111
+ log.info("[dry-run] Would upsert app role in developer org");
112
+ }
109
113
  log.info("[dry-run] Would update version permissions/blueprint");
110
114
  } else {
115
+ let roleId;
116
+ if (manifest.permissions?.length) {
117
+ const orgId = resolveOrgId(args.token, args.profile);
118
+ if (orgId) {
119
+ try {
120
+ roleId = await client.upsertAppRole({
121
+ orgId,
122
+ appId,
123
+ appName: manifest.name,
124
+ grants: manifest.permissions
125
+ });
126
+ log.success(`Upserted app role ${roleId}`);
127
+ } catch (err) {
128
+ log.warn(`Could not upsert app role: ${err.message}`);
129
+ }
130
+ } else {
131
+ log.warn("Could not resolve org id \u2014 attaching grants without a developer-org role");
132
+ }
133
+ }
111
134
  await client.patchVersion(appId, targetVersion, {
112
- ...manifest.permissions?.length ? { grants: manifest.permissions } : {},
135
+ ...manifest.permissions?.length ? { grants: manifest.permissions, ...roleId ? { role_id: roleId } : {} } : {},
113
136
  ...manifest.blueprint?.manifest_id ? { manifest_id: manifest.blueprint.manifest_id } : {}
114
137
  });
115
138
  log.success(`Updated version ${targetVersion} (permissions/blueprint)`);
@@ -4,7 +4,7 @@ import {
4
4
  log,
5
5
  toManifest,
6
6
  writeManifest
7
- } from "./chunk-4TDAAJ6H.js";
7
+ } from "./chunk-QOD77YLW.js";
8
8
  import "./chunk-M3M3C5WH.js";
9
9
  import "./chunk-YHQA2AVG.js";
10
10
  import "./chunk-7ZQ666ZQ.js";
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  log,
4
4
  writeManifest
5
- } from "./chunk-4TDAAJ6H.js";
5
+ } from "./chunk-QOD77YLW.js";
6
6
  import "./chunk-M3M3C5WH.js";
7
7
  import "./chunk-YHQA2AVG.js";
8
8
  import "./chunk-7ZQ666ZQ.js";
@@ -3,7 +3,7 @@ import {
3
3
  log,
4
4
  readManifest,
5
5
  writeManifest
6
- } from "./chunk-4TDAAJ6H.js";
6
+ } from "./chunk-QOD77YLW.js";
7
7
  import "./chunk-M3M3C5WH.js";
8
8
  import "./chunk-YHQA2AVG.js";
9
9
  import "./chunk-7ZQ666ZQ.js";
@@ -3,7 +3,7 @@ import {
3
3
  createAppApiClient,
4
4
  log,
5
5
  readManifest
6
- } from "./chunk-4TDAAJ6H.js";
6
+ } from "./chunk-QOD77YLW.js";
7
7
  import "./chunk-M3M3C5WH.js";
8
8
  import "./chunk-YHQA2AVG.js";
9
9
  import "./chunk-7ZQ666ZQ.js";
@@ -72,7 +72,7 @@ ${GREEN}${BOLD}Upgraded to @epilot/cli@${latest}${RESET}
72
72
  }
73
73
  });
74
74
  var getCurrentVersion = () => {
75
- if (true) return "0.1.82";
75
+ if (true) return "0.1.84";
76
76
  try {
77
77
  const output = execSync("npm ls -g @epilot/cli --depth=0 --json 2>/dev/null", {
78
78
  encoding: "utf-8",
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  log,
4
4
  validateManifest
5
- } from "./chunk-4TDAAJ6H.js";
5
+ } from "./chunk-QOD77YLW.js";
6
6
  import "./chunk-M3M3C5WH.js";
7
7
  import "./chunk-YHQA2AVG.js";
8
8
  import "./chunk-7ZQ666ZQ.js";
@@ -3,7 +3,7 @@ import {
3
3
  createAppApiClient,
4
4
  log,
5
5
  readManifest
6
- } from "./chunk-4TDAAJ6H.js";
6
+ } from "./chunk-QOD77YLW.js";
7
7
  import "./chunk-M3M3C5WH.js";
8
8
  import "./chunk-YHQA2AVG.js";
9
9
  import {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@epilot/cli",
3
- "version": "0.1.82",
3
+ "version": "0.1.84",
4
4
  "description": "CLI for epilot APIs",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,24 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- // src/commands/app/index.ts
4
- import { defineCommand } from "citty";
5
- var app_default = defineCommand({
6
- meta: {
7
- name: "app",
8
- description: "Manage epilot Apps \u2014 create, deploy, and manage app manifests"
9
- },
10
- subCommands: {
11
- init: () => import("./init-QZTZF2JC.js").then((m) => m.default),
12
- "add-component": () => import("./add-component-IVVCAUGY.js").then((m) => m.default),
13
- "remove-component": () => import("./remove-component-HJA5OA3H.js").then((m) => m.default),
14
- validate: () => import("./validate-QUSO4DR4.js").then((m) => m.default),
15
- deploy: () => import("./deploy-JMJFXUKQ.js").then((m) => m.default),
16
- export: () => import("./export-JDDMBBNS.js").then((m) => m.default),
17
- versions: () => import("./versions-EUTT4SNW.js").then((m) => m.default),
18
- review: () => import("./review-7M27IRW6.js").then((m) => m.default),
19
- api: () => import("./api-5W2UMWCW.js").then((m) => m.default)
20
- }
21
- });
22
- export {
23
- app_default as default
24
- };