@displaydev/cli 0.15.1 → 0.17.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.
@@ -507,6 +507,44 @@ export var ApiClient = /*#__PURE__*/ function() {
507
507
  }).call(this);
508
508
  }
509
509
  },
510
+ {
511
+ key: "setOrgLogo",
512
+ value: /**
513
+ * Upload (or replace) the active org's logo. Multipart `file` field;
514
+ * server validates magic bytes, square aspect, dimensions, and size.
515
+ * Returns the new R2 key + content-addressed version.
516
+ */ function setOrgLogo(params) {
517
+ return _async_to_generator(function() {
518
+ var form, blob;
519
+ return _ts_generator(this, function(_state) {
520
+ form = new FormData();
521
+ blob = new Blob([
522
+ new Uint8Array(params.bytes)
523
+ ], {
524
+ type: params.contentType
525
+ });
526
+ form.append('file', blob, params.filename);
527
+ return [
528
+ 2,
529
+ this.request('POST', '/v1/org/logo', form)
530
+ ];
531
+ });
532
+ }).call(this);
533
+ }
534
+ },
535
+ {
536
+ key: "clearOrgLogo",
537
+ value: /** Clear the active org's logo. Idempotent — 200 even when no logo is set. */ function clearOrgLogo() {
538
+ return _async_to_generator(function() {
539
+ return _ts_generator(this, function(_state) {
540
+ return [
541
+ 2,
542
+ this.request('DELETE', '/v1/org/logo')
543
+ ];
544
+ });
545
+ }).call(this);
546
+ }
547
+ },
510
548
  {
511
549
  key: "find",
512
550
  value: function find(params) {
package/dist/main.js CHANGED
@@ -36,6 +36,19 @@ function _async_to_generator(fn) {
36
36
  });
37
37
  };
38
38
  }
39
+ function _define_property(obj, key, value) {
40
+ if (key in obj) {
41
+ Object.defineProperty(obj, key, {
42
+ value: value,
43
+ enumerable: true,
44
+ configurable: true,
45
+ writable: true
46
+ });
47
+ } else {
48
+ obj[key] = value;
49
+ }
50
+ return obj;
51
+ }
39
52
  function _instanceof(left, right) {
40
53
  "@swc/helpers - instanceof";
41
54
  if (right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance]) {
@@ -50,6 +63,21 @@ function _iterable_to_array(iter) {
50
63
  function _non_iterable_spread() {
51
64
  throw new TypeError("Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
52
65
  }
66
+ function _object_spread(target) {
67
+ for(var i = 1; i < arguments.length; i++){
68
+ var source = arguments[i] != null ? arguments[i] : {};
69
+ var ownKeys = Object.keys(source);
70
+ if (typeof Object.getOwnPropertySymbols === "function") {
71
+ ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function(sym) {
72
+ return Object.getOwnPropertyDescriptor(source, sym).enumerable;
73
+ }));
74
+ }
75
+ ownKeys.forEach(function(key) {
76
+ _define_property(target, key, source[key]);
77
+ });
78
+ }
79
+ return target;
80
+ }
53
81
  function _to_consumable_array(arr) {
54
82
  return _array_without_holes(arr) || _iterable_to_array(arr) || _unsupported_iterable_to_array(arr) || _non_iterable_spread();
55
83
  }
@@ -161,6 +189,7 @@ function _ts_generator(thisArg, body) {
161
189
  }
162
190
  }
163
191
  import { readFile } from 'node:fs/promises';
192
+ import { basename } from 'node:path';
164
193
  import { createInterface } from 'node:readline/promises';
165
194
  import { createRequire } from 'node:module';
166
195
  import { execFileSync } from 'node:child_process';
@@ -935,7 +964,7 @@ function openBrowser(url) {
935
964
  // --- login ---
936
965
  program.command('login').description('Authenticate with display.dev').option('--email <email>', 'Email address').option('--code <code>', 'OTP code (verify step; pair with --email)').option('--api-key [key]', 'Authenticate with an API key').option('--json', 'Machine-readable output (structured status, no prose)').action(function(opts) {
937
966
  return _async_to_generator(function() {
938
- var _process_env_DISPLAYDEV_API_URL, emit, emitErr, apiUrl, client, key, unused, rl, validation, email, rl1, method, check, unused1, err, msg, code, rl2, result, unused2, deviceResult, unused3, device_code, verification_uri_complete, initialInterval, expires_in, token, err1;
967
+ var _process_env_DISPLAYDEV_API_URL, emit, emitErr, apiUrl, client, key, unused, rl, validation, email, rl1, method, check, unused1, err, msg, code, rl2, result, unused2, deviceResult, unused3, device_code, verification_uri_complete, initialInterval, expires_in, tickCapMs, sleep, token, err1;
939
968
  return _ts_generator(this, function(_state) {
940
969
  switch(_state.label){
941
970
  case 0:
@@ -1306,12 +1335,23 @@ program.command('login').description('Authenticate with display.dev').option('--
1306
1335
  ,
1307
1336
  39
1308
1337
  ]);
1338
+ // DISPLAYDEV_TEST_TICK_MS caps each polling sleep so login-sso.spec.ts
1339
+ // doesn't burn real wall-clock seconds on the slow_down branch
1340
+ // (which adds +5s to interval). Same convention as DISPLAYDEV_SKIP_BROWSER.
1341
+ tickCapMs = Number(process.env.DISPLAYDEV_TEST_TICK_MS);
1342
+ sleep = Number.isFinite(tickCapMs) && tickCapMs > 0 ? function(ms) {
1343
+ return new Promise(function(resolve) {
1344
+ return setTimeout(resolve, Math.min(ms, tickCapMs));
1345
+ });
1346
+ } : undefined;
1309
1347
  return [
1310
1348
  4,
1311
- pollDeviceToken(client, device_code, 'dsp-cli', {
1349
+ pollDeviceToken(client, device_code, 'dsp-cli', _object_spread({
1312
1350
  intervalMs: (initialInterval || 5) * 1000,
1313
1351
  expiresAt: Date.now() + (expires_in || 600) * 1000
1314
- })
1352
+ }, sleep ? {
1353
+ sleep: sleep
1354
+ } : {}))
1315
1355
  ];
1316
1356
  case 36:
1317
1357
  token = _state.sent();
@@ -1354,8 +1394,8 @@ program.command('login').description('Authenticate with display.dev').option('--
1354
1394
  });
1355
1395
  })();
1356
1396
  });
1357
- // --- branding ---
1358
- program.command('branding <shortId> <mode>').description('Override display.dev branding for an existing artifact without re-publishing (show|hide|inherit)').action(function(shortId, modeRaw) {
1397
+ // --- set-branding ---
1398
+ program.command('set-branding <shortId> <mode>').description('Override display.dev branding for an existing artifact without re-publishing (show|hide|inherit)').action(function(shortId, modeRaw) {
1359
1399
  return _async_to_generator(function() {
1360
1400
  var mode, auth, client, result, err, msg;
1361
1401
  return _ts_generator(this, function(_state) {
@@ -1413,6 +1453,170 @@ program.command('branding <shortId> <mode>').description('Override display.dev b
1413
1453
  });
1414
1454
  })();
1415
1455
  });
1456
+ // --- set-logo ---
1457
+ program.command('set-logo <file>').description('Upload or replace the org logo (PNG or WebP, square, 32–1024px, ≤256 KB)').action(function(filePath) {
1458
+ return _async_to_generator(function() {
1459
+ var auth, client, bytes, err, msg, lower, contentType, result, err1, _ref, _err_details, upgradeUrl, msg1;
1460
+ return _ts_generator(this, function(_state) {
1461
+ switch(_state.label){
1462
+ case 0:
1463
+ return [
1464
+ 4,
1465
+ resolveAuthOrConfig()
1466
+ ];
1467
+ case 1:
1468
+ auth = _state.sent();
1469
+ client = createClient(auth);
1470
+ _state.label = 2;
1471
+ case 2:
1472
+ _state.trys.push([
1473
+ 2,
1474
+ 4,
1475
+ ,
1476
+ 5
1477
+ ]);
1478
+ return [
1479
+ 4,
1480
+ readFile(filePath)
1481
+ ];
1482
+ case 3:
1483
+ bytes = _state.sent();
1484
+ return [
1485
+ 3,
1486
+ 5
1487
+ ];
1488
+ case 4:
1489
+ err = _state.sent();
1490
+ msg = _instanceof(err, Error) ? err.message : String(err);
1491
+ console.error(msg);
1492
+ process.exit(1);
1493
+ return [
1494
+ 3,
1495
+ 5
1496
+ ];
1497
+ case 5:
1498
+ lower = filePath.toLowerCase();
1499
+ if (lower.endsWith('.png')) {
1500
+ contentType = 'image/png';
1501
+ } else if (lower.endsWith('.webp')) {
1502
+ contentType = 'image/webp';
1503
+ } else {
1504
+ console.error('Logo must be a .png or .webp file.');
1505
+ process.exit(1);
1506
+ }
1507
+ _state.label = 6;
1508
+ case 6:
1509
+ _state.trys.push([
1510
+ 6,
1511
+ 8,
1512
+ ,
1513
+ 9
1514
+ ]);
1515
+ return [
1516
+ 4,
1517
+ client.setOrgLogo({
1518
+ bytes: bytes,
1519
+ contentType: contentType,
1520
+ filename: basename(filePath)
1521
+ })
1522
+ ];
1523
+ case 7:
1524
+ result = _state.sent();
1525
+ console.log("Logo set: ".concat(result.logoContentType, " version=").concat(result.logoVersion));
1526
+ return [
1527
+ 3,
1528
+ 9
1529
+ ];
1530
+ case 8:
1531
+ err1 = _state.sent();
1532
+ if (_instanceof(err1, ApiError) && err1.status === 402) {
1533
+ ;
1534
+ ;
1535
+ upgradeUrl = (_ref = (_err_details = err1.details) === null || _err_details === void 0 ? void 0 : _err_details.upgrade_url) !== null && _ref !== void 0 ? _ref : 'https://app.display.dev/billing';
1536
+ console.error("Error: Setting an org logo requires a paid plan. See ".concat(upgradeUrl));
1537
+ process.exit(1);
1538
+ }
1539
+ if (_instanceof(err1, ApiError) && err1.status === 401) {
1540
+ console.error('Your credential is no longer valid. Run: dsp login (or rotate DISPLAYDEV_API_KEY).');
1541
+ process.exit(1);
1542
+ }
1543
+ if (_instanceof(err1, ApiError) && (err1.status === 400 || err1.status === 403)) {
1544
+ console.error(err1.message);
1545
+ process.exit(1);
1546
+ }
1547
+ msg1 = _instanceof(err1, Error) ? err1.message : String(err1);
1548
+ console.error(msg1);
1549
+ process.exit(1);
1550
+ return [
1551
+ 3,
1552
+ 9
1553
+ ];
1554
+ case 9:
1555
+ return [
1556
+ 2
1557
+ ];
1558
+ }
1559
+ });
1560
+ })();
1561
+ });
1562
+ // --- clear-logo ---
1563
+ program.command('clear-logo').description('Remove the org logo (idempotent — succeeds even if no logo is currently set)').action(function() {
1564
+ return _async_to_generator(function() {
1565
+ var auth, client, err, msg;
1566
+ return _ts_generator(this, function(_state) {
1567
+ switch(_state.label){
1568
+ case 0:
1569
+ return [
1570
+ 4,
1571
+ resolveAuthOrConfig()
1572
+ ];
1573
+ case 1:
1574
+ auth = _state.sent();
1575
+ client = createClient(auth);
1576
+ _state.label = 2;
1577
+ case 2:
1578
+ _state.trys.push([
1579
+ 2,
1580
+ 4,
1581
+ ,
1582
+ 5
1583
+ ]);
1584
+ return [
1585
+ 4,
1586
+ client.clearOrgLogo()
1587
+ ];
1588
+ case 3:
1589
+ _state.sent();
1590
+ console.log('Logo removed.');
1591
+ return [
1592
+ 3,
1593
+ 5
1594
+ ];
1595
+ case 4:
1596
+ err = _state.sent();
1597
+ if (_instanceof(err, ApiError) && err.status === 401) {
1598
+ console.error('Your credential is no longer valid. Run: dsp login (or rotate DISPLAYDEV_API_KEY).');
1599
+ process.exit(1);
1600
+ }
1601
+ if (_instanceof(err, ApiError) && err.status === 403) {
1602
+ console.error(err.message);
1603
+ process.exit(1);
1604
+ }
1605
+ msg = _instanceof(err, Error) ? err.message : String(err);
1606
+ console.error(msg);
1607
+ process.exit(1);
1608
+ return [
1609
+ 3,
1610
+ 5
1611
+ ];
1612
+ case 5:
1613
+ return [
1614
+ 2
1615
+ ];
1616
+ }
1617
+ });
1618
+ })();
1619
+ });
1416
1620
  // --- mcp ---
1417
1621
  program.command('mcp').description('Start MCP server over stdin/stdout').action(function() {
1418
1622
  return _async_to_generator(function() {
@@ -199,7 +199,7 @@ function _ts_generator(thisArg, body) {
199
199
  }
200
200
  }
201
201
  import { readFile } from 'node:fs/promises';
202
- import { resolve } from 'node:path';
202
+ import { basename, resolve } from 'node:path';
203
203
  import { z } from 'zod';
204
204
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
205
205
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
@@ -952,7 +952,7 @@ export function registerTools(server, api) {
952
952
  // Metadata-only: does NOT bump the artifact version. Use the `publish`
953
953
  // tool (with `show_branding`) when you're changing content at the same
954
954
  // time so both writes happen in one transaction.
955
- server.tool('branding', 'Override display.dev branding for an existing artifact without re-publishing. Paid tiers only (free-tier orgs must keep inherit).', {
955
+ server.tool('set_branding', 'Override display.dev branding for an existing artifact without re-publishing. Paid tiers only (free-tier orgs must keep inherit).', {
956
956
  short_id: z.string().describe('Artifact shortId'),
957
957
  show_branding: z.enum([
958
958
  'show',
@@ -995,4 +995,138 @@ export function registerTools(server, api) {
995
995
  });
996
996
  })();
997
997
  });
998
+ server.tool('set_logo', 'Upload or replace the org logo (paid tiers only). Used as the favicon on every artifact the org publishes. Stdio variant reads bytes from a local file path.', {
999
+ file_path: z.string().describe('Path to a local PNG or WebP file. Square, 32×32 to 1024×1024, ≤256 KB.'),
1000
+ content_type: z.enum([
1001
+ 'image/png',
1002
+ 'image/webp'
1003
+ ]).optional().describe('Optional declared MIME type; inferred from the file extension when omitted.')
1004
+ }, function(args) {
1005
+ return _async_to_generator(function() {
1006
+ var bytes, err, contentType, lower, result, err1;
1007
+ return _ts_generator(this, function(_state) {
1008
+ switch(_state.label){
1009
+ case 0:
1010
+ _state.trys.push([
1011
+ 0,
1012
+ 2,
1013
+ ,
1014
+ 3
1015
+ ]);
1016
+ return [
1017
+ 4,
1018
+ readFile(resolve(args.file_path))
1019
+ ];
1020
+ case 1:
1021
+ bytes = _state.sent();
1022
+ return [
1023
+ 3,
1024
+ 3
1025
+ ];
1026
+ case 2:
1027
+ err = _state.sent();
1028
+ return [
1029
+ 2,
1030
+ errorResponse(err)
1031
+ ];
1032
+ case 3:
1033
+ contentType = args.content_type;
1034
+ if (!contentType) {
1035
+ lower = args.file_path.toLowerCase();
1036
+ if (lower.endsWith('.png')) {
1037
+ contentType = 'image/png';
1038
+ } else if (lower.endsWith('.webp')) {
1039
+ contentType = 'image/webp';
1040
+ } else {
1041
+ return [
1042
+ 2,
1043
+ {
1044
+ content: [
1045
+ {
1046
+ type: 'text',
1047
+ text: JSON.stringify({
1048
+ error: 'invalid_input',
1049
+ message: 'Unable to infer content_type from file extension; pass content_type explicitly.'
1050
+ })
1051
+ }
1052
+ ],
1053
+ isError: true
1054
+ }
1055
+ ];
1056
+ }
1057
+ }
1058
+ _state.label = 4;
1059
+ case 4:
1060
+ _state.trys.push([
1061
+ 4,
1062
+ 6,
1063
+ ,
1064
+ 7
1065
+ ]);
1066
+ return [
1067
+ 4,
1068
+ api.setOrgLogo({
1069
+ bytes: bytes,
1070
+ contentType: contentType,
1071
+ filename: basename(args.file_path)
1072
+ })
1073
+ ];
1074
+ case 5:
1075
+ result = _state.sent();
1076
+ return [
1077
+ 2,
1078
+ okResponse(result)
1079
+ ];
1080
+ case 6:
1081
+ err1 = _state.sent();
1082
+ return [
1083
+ 2,
1084
+ errorResponse(err1)
1085
+ ];
1086
+ case 7:
1087
+ return [
1088
+ 2
1089
+ ];
1090
+ }
1091
+ });
1092
+ })();
1093
+ });
1094
+ server.tool('clear_logo', 'Remove the org logo. Idempotent — succeeds even when no logo is currently set.', {}, function() {
1095
+ return _async_to_generator(function() {
1096
+ var err;
1097
+ return _ts_generator(this, function(_state) {
1098
+ switch(_state.label){
1099
+ case 0:
1100
+ _state.trys.push([
1101
+ 0,
1102
+ 2,
1103
+ ,
1104
+ 3
1105
+ ]);
1106
+ return [
1107
+ 4,
1108
+ api.clearOrgLogo()
1109
+ ];
1110
+ case 1:
1111
+ _state.sent();
1112
+ return [
1113
+ 2,
1114
+ okResponse({
1115
+ success: true
1116
+ })
1117
+ ];
1118
+ case 2:
1119
+ err = _state.sent();
1120
+ return [
1121
+ 2,
1122
+ errorResponse(err)
1123
+ ];
1124
+ case 3:
1125
+ return [
1126
+ 2
1127
+ ];
1128
+ }
1129
+ });
1130
+ })();
1131
+ });
998
1132
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@displaydev/cli",
3
- "version": "0.15.1",
3
+ "version": "0.17.0",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "dsp": "dist/main.js"
@@ -17,14 +17,14 @@
17
17
  "test": "vitest run"
18
18
  },
19
19
  "dependencies": {
20
- "@modelcontextprotocol/sdk": "^1.29.0",
21
- "commander": "^14.0.3",
22
- "zod": "^4.3.6"
20
+ "@modelcontextprotocol/sdk": "1.29.0",
21
+ "commander": "14.0.3",
22
+ "zod": "4.3.6"
23
23
  },
24
24
  "devDependencies": {
25
- "@swc/cli": "^0.7.10",
26
- "@swc/core": "^1.15.24",
27
- "@types/node": "^24.12.2",
28
- "vitest": "^4.1.2"
25
+ "@swc/cli": "0.7.10",
26
+ "@swc/core": "1.15.24",
27
+ "@types/node": "24.12.2",
28
+ "vitest": "4.1.2"
29
29
  }
30
30
  }