@trops/dash-core 0.1.250 → 0.1.252

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/dist/index.esm.js CHANGED
@@ -23273,6 +23273,267 @@ var RegistryPackageDetail = function RegistryPackageDetail(_ref) {
23273
23273
  });
23274
23274
  };
23275
23275
 
23276
+ /**
23277
+ * useRegistryAuth — reusable hook for device-code OAuth against the Dash Registry.
23278
+ *
23279
+ * Encapsulates the full auth state machine: check status, initiate login,
23280
+ * poll for token, and cancel. Cleans up the poll interval on unmount.
23281
+ *
23282
+ * @returns {{
23283
+ * isAuthenticated: boolean,
23284
+ * isAuthenticating: boolean,
23285
+ * authFlow: { userCode: string, verificationUrlComplete: string } | null,
23286
+ * authError: string | null,
23287
+ * checkAuth: () => Promise<boolean>,
23288
+ * initiateAuth: () => Promise<void>,
23289
+ * cancelAuth: () => void,
23290
+ * }}
23291
+ */
23292
+ function useRegistryAuth() {
23293
+ var _useState = useState(false),
23294
+ _useState2 = _slicedToArray(_useState, 2),
23295
+ isAuthenticated = _useState2[0],
23296
+ setIsAuthenticated = _useState2[1];
23297
+ var _useState3 = useState(false),
23298
+ _useState4 = _slicedToArray(_useState3, 2),
23299
+ isAuthenticating = _useState4[0],
23300
+ setIsAuthenticating = _useState4[1];
23301
+ var _useState5 = useState(null),
23302
+ _useState6 = _slicedToArray(_useState5, 2),
23303
+ authFlow = _useState6[0],
23304
+ setAuthFlow = _useState6[1];
23305
+ var _useState7 = useState(null),
23306
+ _useState8 = _slicedToArray(_useState7, 2),
23307
+ authError = _useState8[0],
23308
+ setAuthError = _useState8[1];
23309
+ var pollIntervalRef = useRef(null);
23310
+ var onAuthorizedRef = useRef(null);
23311
+
23312
+ // Clean up polling on unmount
23313
+ useEffect(function () {
23314
+ return function () {
23315
+ if (pollIntervalRef.current) clearInterval(pollIntervalRef.current);
23316
+ };
23317
+ }, []);
23318
+ var checkAuth = useCallback(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
23319
+ var status, authed;
23320
+ return _regeneratorRuntime.wrap(function (_context) {
23321
+ while (1) switch (_context.prev = _context.next) {
23322
+ case 0:
23323
+ _context.prev = 0;
23324
+ _context.next = 1;
23325
+ return window.mainApi.registryAuth.getStatus();
23326
+ case 1:
23327
+ status = _context.sent;
23328
+ authed = !!(status !== null && status !== void 0 && status.authenticated);
23329
+ setIsAuthenticated(authed);
23330
+ return _context.abrupt("return", authed);
23331
+ case 2:
23332
+ _context.prev = 2;
23333
+ _context["catch"](0);
23334
+ return _context.abrupt("return", false);
23335
+ case 3:
23336
+ case "end":
23337
+ return _context.stop();
23338
+ }
23339
+ }, _callee, null, [[0, 2]]);
23340
+ })), []);
23341
+ var cancelAuth = useCallback(function () {
23342
+ if (pollIntervalRef.current) {
23343
+ clearInterval(pollIntervalRef.current);
23344
+ pollIntervalRef.current = null;
23345
+ }
23346
+ setIsAuthenticating(false);
23347
+ setAuthFlow(null);
23348
+ }, []);
23349
+ var initiateAuth = useCallback(/*#__PURE__*/function () {
23350
+ var _ref2 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee3(onAuthorized) {
23351
+ var flow, interval;
23352
+ return _regeneratorRuntime.wrap(function (_context3) {
23353
+ while (1) switch (_context3.prev = _context3.next) {
23354
+ case 0:
23355
+ setAuthError(null);
23356
+ onAuthorizedRef.current = onAuthorized || null;
23357
+ _context3.prev = 1;
23358
+ _context3.next = 2;
23359
+ return window.mainApi.registryAuth.initiateLogin();
23360
+ case 2:
23361
+ flow = _context3.sent;
23362
+ setAuthFlow(flow);
23363
+ if (flow.verificationUrlComplete) {
23364
+ window.mainApi.shell.openExternal(flow.verificationUrlComplete);
23365
+ }
23366
+ setIsAuthenticating(true);
23367
+ interval = (flow.interval || 5) * 1000;
23368
+ pollIntervalRef.current = setInterval(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee2() {
23369
+ var pollResult;
23370
+ return _regeneratorRuntime.wrap(function (_context2) {
23371
+ while (1) switch (_context2.prev = _context2.next) {
23372
+ case 0:
23373
+ _context2.prev = 0;
23374
+ _context2.next = 1;
23375
+ return window.mainApi.registryAuth.pollToken(flow.deviceCode);
23376
+ case 1:
23377
+ pollResult = _context2.sent;
23378
+ if (pollResult.status === "authorized") {
23379
+ clearInterval(pollIntervalRef.current);
23380
+ pollIntervalRef.current = null;
23381
+ setIsAuthenticating(false);
23382
+ setAuthFlow(null);
23383
+ setIsAuthenticated(true);
23384
+ if (onAuthorizedRef.current) {
23385
+ onAuthorizedRef.current();
23386
+ }
23387
+ } else if (pollResult.status === "expired") {
23388
+ clearInterval(pollIntervalRef.current);
23389
+ pollIntervalRef.current = null;
23390
+ setIsAuthenticating(false);
23391
+ setAuthFlow(null);
23392
+ setAuthError("Authorization expired. Please try again.");
23393
+ }
23394
+ _context2.next = 3;
23395
+ break;
23396
+ case 2:
23397
+ _context2.prev = 2;
23398
+ _context2["catch"](0);
23399
+ clearInterval(pollIntervalRef.current);
23400
+ pollIntervalRef.current = null;
23401
+ setIsAuthenticating(false);
23402
+ case 3:
23403
+ case "end":
23404
+ return _context2.stop();
23405
+ }
23406
+ }, _callee2, null, [[0, 2]]);
23407
+ })), interval);
23408
+ _context3.next = 4;
23409
+ break;
23410
+ case 3:
23411
+ _context3.prev = 3;
23412
+ _context3["catch"](1);
23413
+ setAuthError("Could not reach the registry. Check your connection and try again.");
23414
+ case 4:
23415
+ case "end":
23416
+ return _context3.stop();
23417
+ }
23418
+ }, _callee3, null, [[1, 3]]);
23419
+ }));
23420
+ return function (_x) {
23421
+ return _ref2.apply(this, arguments);
23422
+ };
23423
+ }(), [cancelAuth]);
23424
+ return {
23425
+ isAuthenticated: isAuthenticated,
23426
+ isAuthenticating: isAuthenticating,
23427
+ authFlow: authFlow,
23428
+ authError: authError,
23429
+ checkAuth: checkAuth,
23430
+ initiateAuth: initiateAuth,
23431
+ cancelAuth: cancelAuth
23432
+ };
23433
+ }
23434
+
23435
+ var RegistryAuthPrompt = function RegistryAuthPrompt(_ref) {
23436
+ var onAuthenticated = _ref.onAuthenticated,
23437
+ _ref$onCancel = _ref.onCancel,
23438
+ onCancel = _ref$onCancel === void 0 ? null : _ref$onCancel,
23439
+ _ref$message = _ref.message,
23440
+ message = _ref$message === void 0 ? "Sign in to install from the Dash Registry." : _ref$message;
23441
+ var _useRegistryAuth = useRegistryAuth(),
23442
+ isAuthenticating = _useRegistryAuth.isAuthenticating,
23443
+ authFlow = _useRegistryAuth.authFlow,
23444
+ authError = _useRegistryAuth.authError,
23445
+ checkAuth = _useRegistryAuth.checkAuth,
23446
+ initiateAuth = _useRegistryAuth.initiateAuth,
23447
+ cancelAuth = _useRegistryAuth.cancelAuth;
23448
+ var checkedRef = useRef(false);
23449
+
23450
+ // Check auth on mount — if already authenticated, short-circuit
23451
+ useEffect(function () {
23452
+ if (checkedRef.current) return;
23453
+ checkedRef.current = true;
23454
+ checkAuth().then(function (authed) {
23455
+ if (authed && onAuthenticated) onAuthenticated();
23456
+ });
23457
+ }, [checkAuth, onAuthenticated]);
23458
+ function handleSignIn() {
23459
+ initiateAuth(function () {
23460
+ if (onAuthenticated) onAuthenticated();
23461
+ });
23462
+ }
23463
+ function handleCancel() {
23464
+ cancelAuth();
23465
+ if (onCancel) onCancel();
23466
+ }
23467
+
23468
+ // Polling state: show user code
23469
+ if (authFlow && isAuthenticating) {
23470
+ return /*#__PURE__*/jsxs("div", {
23471
+ className: "flex flex-col gap-3 p-4",
23472
+ children: [/*#__PURE__*/jsxs("div", {
23473
+ className: "bg-blue-500/10 border border-blue-500/20 rounded-lg p-4 space-y-3",
23474
+ children: [/*#__PURE__*/jsx("p", {
23475
+ className: "text-xs text-blue-300/90",
23476
+ children: "Enter this code in your browser:"
23477
+ }), /*#__PURE__*/jsx("div", {
23478
+ className: "text-center",
23479
+ children: /*#__PURE__*/jsx("span", {
23480
+ className: "text-2xl font-mono font-bold tracking-widest text-white",
23481
+ children: authFlow.userCode
23482
+ })
23483
+ }), /*#__PURE__*/jsx("p", {
23484
+ className: "text-xs text-blue-300/70 text-center",
23485
+ children: "Waiting for authorization \u2014 install will resume automatically..."
23486
+ })]
23487
+ }), onCancel && /*#__PURE__*/jsx("button", {
23488
+ type: "button",
23489
+ onClick: handleCancel,
23490
+ className: "self-center text-xs text-gray-500 hover:text-gray-300 transition-colors",
23491
+ children: "Cancel"
23492
+ })]
23493
+ });
23494
+ }
23495
+
23496
+ // Default: not-started / error state
23497
+ return /*#__PURE__*/jsxs("div", {
23498
+ className: "flex flex-col gap-3 p-4",
23499
+ children: [/*#__PURE__*/jsx("div", {
23500
+ className: "bg-yellow-500/10 border border-yellow-500/20 rounded-lg p-3",
23501
+ children: /*#__PURE__*/jsxs("div", {
23502
+ className: "flex items-start gap-2",
23503
+ children: [/*#__PURE__*/jsx(FontAwesomeIcon, {
23504
+ icon: "lock",
23505
+ className: "h-3.5 w-3.5 text-yellow-400 mt-0.5 flex-shrink-0"
23506
+ }), /*#__PURE__*/jsx("span", {
23507
+ className: "text-sm text-yellow-300/90",
23508
+ children: message
23509
+ })]
23510
+ })
23511
+ }), /*#__PURE__*/jsx("button", {
23512
+ type: "button",
23513
+ onClick: handleSignIn,
23514
+ className: "px-4 py-2 rounded-lg text-sm bg-blue-500/20 border border-blue-500/30 text-blue-300 hover:bg-blue-500/30 transition-colors cursor-pointer",
23515
+ children: "Sign in to Registry"
23516
+ }), authError && /*#__PURE__*/jsx("div", {
23517
+ className: "bg-red-500/10 border border-red-500/20 rounded-lg p-3",
23518
+ children: /*#__PURE__*/jsxs("div", {
23519
+ className: "flex items-start gap-2",
23520
+ children: [/*#__PURE__*/jsx(FontAwesomeIcon, {
23521
+ icon: "circle-xmark",
23522
+ className: "h-3.5 w-3.5 text-red-400 mt-0.5 flex-shrink-0"
23523
+ }), /*#__PURE__*/jsx("span", {
23524
+ className: "text-xs text-red-300/90",
23525
+ children: authError
23526
+ })]
23527
+ })
23528
+ }), onCancel && /*#__PURE__*/jsx("button", {
23529
+ type: "button",
23530
+ onClick: handleCancel,
23531
+ className: "self-center text-xs text-gray-500 hover:text-gray-300 transition-colors",
23532
+ children: "Cancel"
23533
+ })]
23534
+ });
23535
+ };
23536
+
23276
23537
  function getWidgetSearchQuery(componentKey) {
23277
23538
  var parts = componentKey.split(".");
23278
23539
  if (parts.length >= 3) {
@@ -23322,7 +23583,8 @@ function packageToFlatWidget(pkg) {
23322
23583
  *
23323
23584
  * Shows the existing "Widget Not Found" error display and adds a
23324
23585
  * "Find in Registry" button that does an exact registry lookup and
23325
- * opens an install modal.
23586
+ * opens an install modal. When install requires auth, shows an inline
23587
+ * RegistryAuthPrompt and auto-retries after successful sign-in.
23326
23588
  */
23327
23589
  var WidgetNotFound = function WidgetNotFound(_ref) {
23328
23590
  var component = _ref.component;
@@ -23350,6 +23612,12 @@ var WidgetNotFound = function WidgetNotFound(_ref) {
23350
23612
  _useState10 = _slicedToArray(_useState1, 2),
23351
23613
  installError = _useState10[0],
23352
23614
  setInstallError = _useState10[1];
23615
+ var _useState11 = useState(false),
23616
+ _useState12 = _slicedToArray(_useState11, 2),
23617
+ needsAuth = _useState12[0],
23618
+ setNeedsAuth = _useState12[1];
23619
+ var _useRegistryAuth = useRegistryAuth(),
23620
+ checkAuth = _useRegistryAuth.checkAuth;
23353
23621
  var lookupWidget = useCallback(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
23354
23622
  var _getWidgetSearchQuery, packageName, widgetName, pkg, result;
23355
23623
  return _regeneratorRuntime.wrap(function (_context) {
@@ -23360,6 +23628,7 @@ var WidgetNotFound = function WidgetNotFound(_ref) {
23360
23628
  setNotFound(false);
23361
23629
  setRegistryWidget(null);
23362
23630
  setInstallError(null);
23631
+ setNeedsAuth(false);
23363
23632
  _getWidgetSearchQuery = getWidgetSearchQuery(component), packageName = _getWidgetSearchQuery.packageName, widgetName = _getWidgetSearchQuery.widgetName;
23364
23633
  _context.prev = 1;
23365
23634
  pkg = null; // Scoped ID — exact package lookup
@@ -23406,7 +23675,7 @@ var WidgetNotFound = function WidgetNotFound(_ref) {
23406
23675
  }, _callee, null, [[1, 6]]);
23407
23676
  })), [component]);
23408
23677
  var handleInstall = useCallback(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee2() {
23409
- var packageName, packageScope, downloadUrl, packageVersion, scopedId, resolvedUrl, _t2;
23678
+ var authed, packageName, packageScope, downloadUrl, packageVersion, scopedId, resolvedUrl, msg, _t2;
23410
23679
  return _regeneratorRuntime.wrap(function (_context2) {
23411
23680
  while (1) switch (_context2.prev = _context2.next) {
23412
23681
  case 0:
@@ -23418,28 +23687,53 @@ var WidgetNotFound = function WidgetNotFound(_ref) {
23418
23687
  case 1:
23419
23688
  setIsInstalling(true);
23420
23689
  setInstallError(null);
23690
+ setNeedsAuth(false);
23421
23691
  _context2.prev = 2;
23692
+ _context2.next = 3;
23693
+ return checkAuth();
23694
+ case 3:
23695
+ authed = _context2.sent;
23696
+ if (authed) {
23697
+ _context2.next = 4;
23698
+ break;
23699
+ }
23700
+ setNeedsAuth(true);
23701
+ setIsInstalling(false);
23702
+ return _context2.abrupt("return");
23703
+ case 4:
23422
23704
  packageName = registryWidget.packageName, packageScope = registryWidget.packageScope, downloadUrl = registryWidget.downloadUrl, packageVersion = registryWidget.packageVersion;
23423
23705
  scopedId = packageScope ? "@".concat(packageScope.replace(/^@/, ""), "/").concat(packageName) : packageName;
23424
23706
  resolvedUrl = downloadUrl.replace(/\{version\}/g, packageVersion).replace(/\{name\}/g, packageName);
23425
- _context2.next = 3;
23707
+ _context2.next = 5;
23426
23708
  return window.mainApi.widgets.install(scopedId, resolvedUrl);
23427
- case 3:
23709
+ case 5:
23428
23710
  setShowModal(false);
23429
- _context2.next = 5;
23711
+ _context2.next = 7;
23430
23712
  break;
23431
- case 4:
23432
- _context2.prev = 4;
23713
+ case 6:
23714
+ _context2.prev = 6;
23433
23715
  _t2 = _context2["catch"](2);
23434
- setInstallError(_t2.message || "Failed to install package");
23435
- case 5:
23716
+ msg = _t2.message || "Failed to install package";
23717
+ if (msg.toLowerCase().includes("unauthorized")) {
23718
+ setNeedsAuth(true);
23719
+ } else {
23720
+ setInstallError(msg);
23721
+ }
23722
+ case 7:
23436
23723
  setIsInstalling(false);
23437
- case 6:
23724
+ case 8:
23438
23725
  case "end":
23439
23726
  return _context2.stop();
23440
23727
  }
23441
- }, _callee2, null, [[2, 4]]);
23442
- })), [registryWidget]);
23728
+ }, _callee2, null, [[2, 6]]);
23729
+ })), [registryWidget, checkAuth]);
23730
+ var handleAuthSuccess = useCallback(function () {
23731
+ setNeedsAuth(false);
23732
+ handleInstall();
23733
+ }, [handleInstall]);
23734
+ var handleClose = useCallback(function () {
23735
+ setShowModal(false);
23736
+ }, []);
23443
23737
  return /*#__PURE__*/jsxs(Fragment, {
23444
23738
  children: [/*#__PURE__*/jsxs("div", {
23445
23739
  className: "flex flex-col h-full justify-center items-center w-full z-10 gap-2 p-4 text-center",
@@ -23464,41 +23758,56 @@ var WidgetNotFound = function WidgetNotFound(_ref) {
23464
23758
  className: "h-3 w-3"
23465
23759
  }), "Find in Registry"]
23466
23760
  })]
23467
- }), /*#__PURE__*/jsxs(Modal, {
23761
+ }), /*#__PURE__*/jsx(Modal, {
23468
23762
  isOpen: showModal,
23469
23763
  setIsOpen: setShowModal,
23470
23764
  width: "w-1/3",
23471
23765
  height: "auto",
23472
- children: [isLoading && /*#__PURE__*/jsx("div", {
23473
- className: "flex items-center justify-center p-12",
23474
- children: /*#__PURE__*/jsx(FontAwesomeIcon, {
23475
- icon: "spinner",
23476
- className: "h-5 w-5 text-gray-400 animate-spin"
23477
- })
23478
- }), !isLoading && registryWidget && /*#__PURE__*/jsx(RegistryPackageDetail, {
23479
- widget: registryWidget,
23480
- onInstall: handleInstall,
23481
- isInstalling: isInstalling,
23482
- installError: installError
23483
- }), !isLoading && notFound && /*#__PURE__*/jsxs("div", {
23484
- className: "flex flex-col items-center justify-center gap-3 p-12 text-center",
23485
- children: [/*#__PURE__*/jsx(FontAwesomeIcon, {
23486
- icon: "triangle-exclamation",
23487
- className: "h-6 w-6 text-amber-500"
23488
- }), /*#__PURE__*/jsx("div", {
23489
- className: "text-sm text-gray-400",
23490
- children: "This widget is not available in the registry."
23491
- }), /*#__PURE__*/jsx(Button, {
23492
- title: "Close",
23493
- bgColor: "bg-gray-600",
23494
- hoverBackgroundColor: "hover:bg-gray-700",
23495
- textSize: "text-sm",
23496
- padding: "py-1.5 px-4",
23497
- onClick: function onClick() {
23498
- return setShowModal(false);
23499
- }
23766
+ children: /*#__PURE__*/jsxs("div", {
23767
+ className: "relative",
23768
+ children: [/*#__PURE__*/jsx("button", {
23769
+ type: "button",
23770
+ className: "absolute top-3 right-3 z-10 text-gray-500 hover:text-gray-300 transition-colors",
23771
+ onClick: handleClose,
23772
+ children: /*#__PURE__*/jsx(FontAwesomeIcon, {
23773
+ icon: "xmark",
23774
+ className: "h-4 w-4"
23775
+ })
23776
+ }), isLoading && /*#__PURE__*/jsx("div", {
23777
+ className: "flex items-center justify-center p-12",
23778
+ children: /*#__PURE__*/jsx(FontAwesomeIcon, {
23779
+ icon: "spinner",
23780
+ className: "h-5 w-5 text-gray-400 animate-spin"
23781
+ })
23782
+ }), !isLoading && needsAuth && registryWidget && /*#__PURE__*/jsx(RegistryAuthPrompt, {
23783
+ onAuthenticated: handleAuthSuccess,
23784
+ onCancel: function onCancel() {
23785
+ return setNeedsAuth(false);
23786
+ },
23787
+ message: "Sign in to install this widget from the Dash Registry."
23788
+ }), !isLoading && !needsAuth && registryWidget && /*#__PURE__*/jsx(RegistryPackageDetail, {
23789
+ widget: registryWidget,
23790
+ onInstall: handleInstall,
23791
+ isInstalling: isInstalling,
23792
+ installError: installError
23793
+ }), !isLoading && notFound && /*#__PURE__*/jsxs("div", {
23794
+ className: "flex flex-col items-center justify-center gap-3 p-12 text-center",
23795
+ children: [/*#__PURE__*/jsx(FontAwesomeIcon, {
23796
+ icon: "triangle-exclamation",
23797
+ className: "h-6 w-6 text-amber-500"
23798
+ }), /*#__PURE__*/jsx("div", {
23799
+ className: "text-sm text-gray-400",
23800
+ children: "This widget is not available in the registry."
23801
+ }), /*#__PURE__*/jsx(Button, {
23802
+ title: "Close",
23803
+ bgColor: "bg-gray-600",
23804
+ hoverBackgroundColor: "hover:bg-gray-700",
23805
+ textSize: "text-sm",
23806
+ padding: "py-1.5 px-4",
23807
+ onClick: handleClose
23808
+ })]
23500
23809
  })]
23501
- })]
23810
+ })
23502
23811
  })]
23503
23812
  });
23504
23813
  };