@microsoft/sentinel-cli 0.1.0 → 0.3.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.
Files changed (2) hide show
  1. package/dist/index.js +3536 -612
  2. package/package.json +9 -2
package/dist/index.js CHANGED
@@ -44,7 +44,7 @@ var require_correlationService = __commonJS({
44
44
  Object.defineProperty(exports2, "__esModule", { value: true });
45
45
  exports2.CorrelationService = void 0;
46
46
  var crypto_1 = require("crypto");
47
- var CorrelationService = class {
47
+ var CorrelationService17 = class {
48
48
  /**
49
49
  * Creates a new correlation context with a unique ID for request tracking.
50
50
  * @returns A UUID string to be used as a correlation ID in API requests and telemetry.
@@ -61,7 +61,7 @@ var require_correlationService = __commonJS({
61
61
  return response?.headers?.["x-ms-correlation-request-id"];
62
62
  }
63
63
  };
64
- exports2.CorrelationService = CorrelationService;
64
+ exports2.CorrelationService = CorrelationService17;
65
65
  }
66
66
  });
67
67
 
@@ -159,6 +159,7 @@ var require_requestService = __commonJS({
159
159
  Object.defineProperty(exports2, "__esModule", { value: true });
160
160
  exports2.RequestService = exports2.DEFAULT_RETRY_OPTIONS = void 0;
161
161
  exports2.extractErrorInfo = extractErrorInfo;
162
+ var https_1 = __importDefault(require("https"));
162
163
  var axios_1 = __importDefault(require("axios"));
163
164
  var correlationService_1 = require_correlationService();
164
165
  var httpConstants_1 = require_httpConstants();
@@ -185,13 +186,19 @@ var require_requestService = __commonJS({
185
186
  baseDelayMs: 1e3,
186
187
  maxDelayMs: 3e4,
187
188
  retryableStatusCodes: Object.freeze([429, 500, 502, 503, 504]),
188
- retryableErrors: Object.freeze(["ECONNRESET", "ETIMEDOUT", "ENOTFOUND", "ECONNABORTED"])
189
+ retryableErrors: Object.freeze(["ECONNRESET", "ETIMEDOUT", "ENOTFOUND", "ECONNABORTED"]),
190
+ retryableErrorMessages: Object.freeze([
191
+ "socket disconnected",
192
+ "socket hang up",
193
+ "client network socket disconnected"
194
+ ])
189
195
  });
190
- var RequestService = class {
196
+ var HTTPS_AGENT = new https_1.default.Agent({ keepAlive: false });
197
+ var RequestService5 = class {
191
198
  telemetry;
192
199
  headerBuilder;
193
- constructor(telemetry, headerBuilder) {
194
- this.telemetry = telemetry;
200
+ constructor(telemetry2, headerBuilder) {
201
+ this.telemetry = telemetry2;
195
202
  this.headerBuilder = headerBuilder;
196
203
  }
197
204
  async get(options) {
@@ -273,7 +280,12 @@ var require_requestService = __commonJS({
273
280
  mainSpan.addAttributes({ success: "true" });
274
281
  return result;
275
282
  } catch (error) {
276
- if (attempt < clampedMaxRetries && this.shouldRetry(error, retryOptions ?? {})) {
283
+ const decision = this.shouldRetry(error, retryOptions ?? {});
284
+ if (attempt < clampedMaxRetries && decision.retry) {
285
+ mainSpan.addAttributes({
286
+ [`retry.${attempt}.reason`]: decision.reason ?? "",
287
+ [`retry.${attempt}.detail`]: decision.detail ?? ""
288
+ });
277
289
  await this.sleep(this.calculateRetryDelay(attempt, clampedBaseDelayMs, clampedMaxDelayMs));
278
290
  continue;
279
291
  }
@@ -350,7 +362,8 @@ var require_requestService = __commonJS({
350
362
  url,
351
363
  method: options?.method?.toLowerCase() || "get",
352
364
  headers: { ...options?.headers },
353
- data: options?.body
365
+ data: options?.body,
366
+ httpsAgent: HTTPS_AGENT
354
367
  };
355
368
  if (timeoutMs !== void 0) {
356
369
  axiosConfig.timeout = timeoutMs;
@@ -402,15 +415,24 @@ var require_requestService = __commonJS({
402
415
  shouldRetry(error, retryOptions) {
403
416
  const retryableStatusCodes = retryOptions.retryableStatusCodes ?? exports2.DEFAULT_RETRY_OPTIONS.retryableStatusCodes;
404
417
  const retryableErrors = retryOptions.retryableErrors ?? exports2.DEFAULT_RETRY_OPTIONS.retryableErrors;
418
+ const retryableErrorMessages = retryOptions.retryableErrorMessages ?? exports2.DEFAULT_RETRY_OPTIONS.retryableErrorMessages;
405
419
  const httpError = error;
406
420
  if (typeof httpError?.statusCode === "number") {
407
- return retryableStatusCodes.includes(httpError.statusCode);
421
+ return retryableStatusCodes.includes(httpError.statusCode) ? { retry: true, reason: "statusCode", detail: String(httpError.statusCode) } : { retry: false };
408
422
  }
409
423
  const codedError = error;
410
- if (codedError?.code) {
411
- return retryableErrors.includes(codedError.code);
424
+ if (codedError?.code && retryableErrors.includes(codedError.code)) {
425
+ return { retry: true, reason: "errorCode", detail: codedError.code };
412
426
  }
413
- return false;
427
+ const errorMessage = error?.message;
428
+ if (typeof errorMessage === "string" && errorMessage.length > 0) {
429
+ const lowerMessage = errorMessage.toLowerCase();
430
+ const matchedPattern = retryableErrorMessages.find((pattern) => lowerMessage.includes(pattern.toLowerCase()));
431
+ if (matchedPattern) {
432
+ return { retry: true, reason: "errorMessage", detail: matchedPattern };
433
+ }
434
+ }
435
+ return { retry: false };
414
436
  }
415
437
  /**
416
438
  * Exponential backoff with 10% random jitter.
@@ -423,7 +445,7 @@ var require_requestService = __commonJS({
423
445
  return Math.min(exponentialDelay + jitter, maxDelayMs);
424
446
  }
425
447
  sleep(ms) {
426
- return new Promise((resolve) => setTimeout(resolve, ms));
448
+ return new Promise((resolve2) => setTimeout(resolve2, ms));
427
449
  }
428
450
  // -------------------------------------------------------------------------
429
451
  // URL helpers
@@ -439,7 +461,7 @@ var require_requestService = __commonJS({
439
461
  return urlObj.toString();
440
462
  }
441
463
  };
442
- exports2.RequestService = RequestService;
464
+ exports2.RequestService = RequestService5;
443
465
  function getPathFromUrl(url) {
444
466
  const urlObject = new URL(url);
445
467
  return urlObject.pathname;
@@ -466,20 +488,74 @@ var require_client = __commonJS({
466
488
  o[k2] = m[k];
467
489
  }));
468
490
  var __exportStar = exports2 && exports2.__exportStar || function(m, exports3) {
469
- for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p)) __createBinding(exports3, m, p);
491
+ for (var p4 in m) if (p4 !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p4)) __createBinding(exports3, m, p4);
470
492
  };
471
493
  Object.defineProperty(exports2, "__esModule", { value: true });
472
494
  __exportStar(require_requestService(), exports2);
473
495
  }
474
496
  });
475
497
 
476
- // ../../packages/common/dist/src/constants.js
498
+ // ../../packages/common/dist/src/constants/jobEventNames.js
499
+ var require_jobEventNames = __commonJS({
500
+ "../../packages/common/dist/src/constants/jobEventNames.js"(exports2) {
501
+ "use strict";
502
+ init_cjs_shims();
503
+ Object.defineProperty(exports2, "__esModule", { value: true });
504
+ exports2.JobApiEvents = void 0;
505
+ exports2.JobApiEvents = {
506
+ LOAD_JOBS: "JobsPanel.Load.Jobs",
507
+ CREATE_JOB: "Jobs.Create.Job",
508
+ GET_JOB: "Jobs.Get.Job",
509
+ DELETE_JOB: "Jobs.Delete.Job",
510
+ DISABLE_JOB: "Jobs.Disable.Job",
511
+ ENABLE_JOB: "Jobs.Enable.Job",
512
+ LIST_JOB_RUNS: "Jobs.List.Runs",
513
+ GET_JOB_RUN: "Jobs.Get.Run",
514
+ START_JOB_RUN: "Jobs.Start.Run",
515
+ CANCEL_JOB_RUN: "Jobs.Cancel.Run"
516
+ };
517
+ }
518
+ });
519
+
520
+ // ../../packages/common/dist/src/constants/lakeEventNames.js
521
+ var require_lakeEventNames = __commonJS({
522
+ "../../packages/common/dist/src/constants/lakeEventNames.js"(exports2) {
523
+ "use strict";
524
+ init_cjs_shims();
525
+ Object.defineProperty(exports2, "__esModule", { value: true });
526
+ exports2.LakeApiEvents = void 0;
527
+ exports2.LakeApiEvents = {
528
+ LOAD_TABLES: "LakeTablesPanel.Load.Tables",
529
+ LOAD_DATABASES: "LakeTablesPanel.Load.Databases"
530
+ };
531
+ }
532
+ });
533
+
534
+ // ../../packages/common/dist/src/constants/index.js
477
535
  var require_constants = __commonJS({
478
- "../../packages/common/dist/src/constants.js"(exports2) {
536
+ "../../packages/common/dist/src/constants/index.js"(exports2) {
479
537
  "use strict";
480
538
  init_cjs_shims();
539
+ var __createBinding = exports2 && exports2.__createBinding || (Object.create ? (function(o, m, k, k2) {
540
+ if (k2 === void 0) k2 = k;
541
+ var desc = Object.getOwnPropertyDescriptor(m, k);
542
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
543
+ desc = { enumerable: true, get: function() {
544
+ return m[k];
545
+ } };
546
+ }
547
+ Object.defineProperty(o, k2, desc);
548
+ }) : (function(o, m, k, k2) {
549
+ if (k2 === void 0) k2 = k;
550
+ o[k2] = m[k];
551
+ }));
552
+ var __exportStar = exports2 && exports2.__exportStar || function(m, exports3) {
553
+ for (var p4 in m) if (p4 !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p4)) __createBinding(exports3, m, p4);
554
+ };
481
555
  Object.defineProperty(exports2, "__esModule", { value: true });
482
556
  exports2.FulfillmentStatus = exports2.PackageManifestIdValues = exports2.PackageManifestTypes = exports2.CANCEL_DEPLOYMENT_REQUEST_TYPE = exports2.NEW_DEPLOYMENT_REQUEST_TYPE = void 0;
557
+ __exportStar(require_jobEventNames(), exports2);
558
+ __exportStar(require_lakeEventNames(), exports2);
483
559
  exports2.NEW_DEPLOYMENT_REQUEST_TYPE = "NewDeploymentRequest";
484
560
  exports2.CANCEL_DEPLOYMENT_REQUEST_TYPE = "CancelSubscription";
485
561
  var PackageManifestTypes;
@@ -509,26 +585,26 @@ var require_region = __commonJS({
509
585
  init_cjs_shims();
510
586
  Object.defineProperty(exports2, "__esModule", { value: true });
511
587
  exports2.Region = void 0;
512
- var Region2;
513
- (function(Region3) {
514
- Region3["NorwayEast"] = "norwayeast";
515
- Region3["EastUS2EUAP"] = "eastus2euap";
516
- Region3["AustraliaEast"] = "australiaeast";
517
- Region3["CanadaCentral"] = "canadacentral";
518
- Region3["CentralUS"] = "centralus";
519
- Region3["EastUS"] = "eastus";
520
- Region3["EastUS2"] = "eastus2";
521
- Region3["FranceCentral"] = "francecentral";
522
- Region3["JapanEast"] = "japaneast";
523
- Region3["NorthEurope"] = "northeurope";
524
- Region3["SouthCentralUS"] = "southcentralus";
525
- Region3["UKSouth"] = "uksouth";
526
- Region3["WestEurope"] = "westeurope";
527
- Region3["WestUS"] = "westus";
528
- Region3["WestUS2"] = "westus2";
529
- Region3["Global"] = "global";
530
- Region3["Dev"] = "dev";
531
- })(Region2 || (exports2.Region = Region2 = {}));
588
+ var Region14;
589
+ (function(Region15) {
590
+ Region15["NorwayEast"] = "norwayeast";
591
+ Region15["EastUS2EUAP"] = "eastus2euap";
592
+ Region15["AustraliaEast"] = "australiaeast";
593
+ Region15["CanadaCentral"] = "canadacentral";
594
+ Region15["CentralUS"] = "centralus";
595
+ Region15["EastUS"] = "eastus";
596
+ Region15["EastUS2"] = "eastus2";
597
+ Region15["FranceCentral"] = "francecentral";
598
+ Region15["JapanEast"] = "japaneast";
599
+ Region15["NorthEurope"] = "northeurope";
600
+ Region15["SouthCentralUS"] = "southcentralus";
601
+ Region15["UKSouth"] = "uksouth";
602
+ Region15["WestEurope"] = "westeurope";
603
+ Region15["WestUS"] = "westus";
604
+ Region15["WestUS2"] = "westus2";
605
+ Region15["Global"] = "global";
606
+ Region15["Dev"] = "dev";
607
+ })(Region14 || (exports2.Region = Region14 = {}));
532
608
  }
533
609
  });
534
610
 
@@ -539,10 +615,10 @@ var require_securityPlatformEnvironment = __commonJS({
539
615
  init_cjs_shims();
540
616
  Object.defineProperty(exports2, "__esModule", { value: true });
541
617
  exports2.SecurityPlatformEnvironment = void 0;
542
- var SecurityPlatformEnvironment5;
543
- (function(SecurityPlatformEnvironment6) {
544
- SecurityPlatformEnvironment6["Production"] = "production";
545
- })(SecurityPlatformEnvironment5 || (exports2.SecurityPlatformEnvironment = SecurityPlatformEnvironment5 = {}));
618
+ var SecurityPlatformEnvironment21;
619
+ (function(SecurityPlatformEnvironment22) {
620
+ SecurityPlatformEnvironment22["Production"] = "production";
621
+ })(SecurityPlatformEnvironment21 || (exports2.SecurityPlatformEnvironment = SecurityPlatformEnvironment21 = {}));
546
622
  }
547
623
  });
548
624
 
@@ -563,6 +639,8 @@ var require_production = __commonJS({
563
639
  gatewayAuthResourceUri: "73c2949e-da2d-457a-9607-fcc665198967/.default",
564
640
  gatewayEndpoint: "https://api.securityplatform.microsoft.com/",
565
641
  aadClientId: DeviceCodeApplicationId,
642
+ armEndpoint: "https://management.azure.com",
643
+ armScope: "https://management.azure.com/.default",
566
644
  regions: {
567
645
  [region_1.Region.NorwayEast]: buildRegionConfig(region_1.Region.NorwayEast),
568
646
  [region_1.Region.EastUS2EUAP]: buildRegionConfig(region_1.Region.EastUS2EUAP),
@@ -615,7 +693,7 @@ var require_configs = __commonJS({
615
693
  o[k2] = m[k];
616
694
  }));
617
695
  var __exportStar = exports2 && exports2.__exportStar || function(m, exports3) {
618
- for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p)) __createBinding(exports3, m, p);
696
+ for (var p4 in m) if (p4 !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p4)) __createBinding(exports3, m, p4);
619
697
  };
620
698
  Object.defineProperty(exports2, "__esModule", { value: true });
621
699
  __exportStar(require_production(), exports2);
@@ -644,9 +722,9 @@ var require_api_env = __commonJS({
644
722
  "use strict";
645
723
  init_cjs_shims();
646
724
  Object.defineProperty(exports2, "__esModule", { value: true });
647
- exports2.getApiEnv = getApiEnv5;
725
+ exports2.getApiEnv = getApiEnv21;
648
726
  var helper_1 = require_helper();
649
- function getApiEnv5(env) {
727
+ function getApiEnv21(env) {
650
728
  return (0, helper_1.getEnvironmentConfig)(env);
651
729
  }
652
730
  }
@@ -680,7 +758,7 @@ var require_environments = __commonJS({
680
758
  o[k2] = m[k];
681
759
  }));
682
760
  var __exportStar = exports2 && exports2.__exportStar || function(m, exports3) {
683
- for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p)) __createBinding(exports3, m, p);
761
+ for (var p4 in m) if (p4 !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p4)) __createBinding(exports3, m, p4);
684
762
  };
685
763
  Object.defineProperty(exports2, "__esModule", { value: true });
686
764
  __exportStar(require_configs(), exports2);
@@ -740,11 +818,11 @@ var require_common = __commonJS({
740
818
  init_cjs_shims();
741
819
  var __awaiter = exports2 && exports2.__awaiter || function(thisArg, _arguments, P, generator) {
742
820
  function adopt(value) {
743
- return value instanceof P ? value : new P(function(resolve) {
744
- resolve(value);
821
+ return value instanceof P ? value : new P(function(resolve2) {
822
+ resolve2(value);
745
823
  });
746
824
  }
747
- return new (P || (P = Promise))(function(resolve, reject) {
825
+ return new (P || (P = Promise))(function(resolve2, reject) {
748
826
  function fulfilled(value) {
749
827
  try {
750
828
  step(generator.next(value));
@@ -760,7 +838,7 @@ var require_common = __commonJS({
760
838
  }
761
839
  }
762
840
  function step(result) {
763
- result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected);
841
+ result.done ? resolve2(result.value) : adopt(result.value).then(fulfilled, rejected);
764
842
  }
765
843
  step((generator = generator.apply(thisArg, _arguments || [])).next());
766
844
  });
@@ -859,11 +937,11 @@ var require_api = __commonJS({
859
937
  init_cjs_shims();
860
938
  var __awaiter = exports2 && exports2.__awaiter || function(thisArg, _arguments, P, generator) {
861
939
  function adopt(value) {
862
- return value instanceof P ? value : new P(function(resolve) {
863
- resolve(value);
940
+ return value instanceof P ? value : new P(function(resolve2) {
941
+ resolve2(value);
864
942
  });
865
943
  }
866
- return new (P || (P = Promise))(function(resolve, reject) {
944
+ return new (P || (P = Promise))(function(resolve2, reject) {
867
945
  function fulfilled(value) {
868
946
  try {
869
947
  step(generator.next(value));
@@ -879,7 +957,7 @@ var require_api = __commonJS({
879
957
  }
880
958
  }
881
959
  function step(result) {
882
- result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected);
960
+ result.done ? resolve2(result.value) : adopt(result.value).then(fulfilled, rejected);
883
961
  }
884
962
  step((generator = generator.apply(thisArg, _arguments || [])).next());
885
963
  });
@@ -2324,7 +2402,7 @@ var require_dist = __commonJS({
2324
2402
  o[k2] = m[k];
2325
2403
  }));
2326
2404
  var __exportStar = exports2 && exports2.__exportStar || function(m, exports3) {
2327
- for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p)) __createBinding(exports3, m, p);
2405
+ for (var p4 in m) if (p4 !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p4)) __createBinding(exports3, m, p4);
2328
2406
  };
2329
2407
  Object.defineProperty(exports2, "__esModule", { value: true });
2330
2408
  __exportStar(require_api(), exports2);
@@ -2611,7 +2689,7 @@ var require_factories = __commonJS({
2611
2689
  o[k2] = m[k];
2612
2690
  }));
2613
2691
  var __exportStar = exports2 && exports2.__exportStar || function(m, exports3) {
2614
- for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p)) __createBinding(exports3, m, p);
2692
+ for (var p4 in m) if (p4 !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p4)) __createBinding(exports3, m, p4);
2615
2693
  };
2616
2694
  Object.defineProperty(exports2, "__esModule", { value: true });
2617
2695
  __exportStar(require_jobPayloadFactory(), exports2);
@@ -2690,6 +2768,15 @@ var require_jobResponse = __commonJS({
2690
2768
  }
2691
2769
  });
2692
2770
 
2771
+ // ../../packages/common/dist/src/models/jobs/listJobsResult.js
2772
+ var require_listJobsResult = __commonJS({
2773
+ "../../packages/common/dist/src/models/jobs/listJobsResult.js"(exports2) {
2774
+ "use strict";
2775
+ init_cjs_shims();
2776
+ Object.defineProperty(exports2, "__esModule", { value: true });
2777
+ }
2778
+ });
2779
+
2693
2780
  // ../../packages/common/dist/src/models/jobs/index.js
2694
2781
  var require_jobs = __commonJS({
2695
2782
  "../../packages/common/dist/src/models/jobs/index.js"(exports2) {
@@ -2709,7 +2796,7 @@ var require_jobs = __commonJS({
2709
2796
  o[k2] = m[k];
2710
2797
  }));
2711
2798
  var __exportStar = exports2 && exports2.__exportStar || function(m, exports3) {
2712
- for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p)) __createBinding(exports3, m, p);
2799
+ for (var p4 in m) if (p4 !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p4)) __createBinding(exports3, m, p4);
2713
2800
  };
2714
2801
  Object.defineProperty(exports2, "__esModule", { value: true });
2715
2802
  __exportStar(require_analyticsJobDefinition(), exports2);
@@ -2719,6 +2806,7 @@ var require_jobs = __commonJS({
2719
2806
  __exportStar(require_repeatFrequency(), exports2);
2720
2807
  __exportStar(require_jobTrigger(), exports2);
2721
2808
  __exportStar(require_jobResponse(), exports2);
2809
+ __exportStar(require_listJobsResult(), exports2);
2722
2810
  }
2723
2811
  });
2724
2812
 
@@ -2750,7 +2838,7 @@ var require_lake = __commonJS({
2750
2838
  o[k2] = m[k];
2751
2839
  }));
2752
2840
  var __exportStar = exports2 && exports2.__exportStar || function(m, exports3) {
2753
- for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p)) __createBinding(exports3, m, p);
2841
+ for (var p4 in m) if (p4 !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p4)) __createBinding(exports3, m, p4);
2754
2842
  };
2755
2843
  Object.defineProperty(exports2, "__esModule", { value: true });
2756
2844
  __exportStar(require_database(), exports2);
@@ -2833,7 +2921,7 @@ var require_models = __commonJS({
2833
2921
  o[k2] = m[k];
2834
2922
  }));
2835
2923
  var __exportStar = exports2 && exports2.__exportStar || function(m, exports3) {
2836
- for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p)) __createBinding(exports3, m, p);
2924
+ for (var p4 in m) if (p4 !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p4)) __createBinding(exports3, m, p4);
2837
2925
  };
2838
2926
  Object.defineProperty(exports2, "__esModule", { value: true });
2839
2927
  __exportStar(require_jobs(), exports2);
@@ -2844,6 +2932,460 @@ var require_models = __commonJS({
2844
2932
  }
2845
2933
  });
2846
2934
 
2935
+ // ../../packages/common/dist/src/services/tenant/types.js
2936
+ var require_types = __commonJS({
2937
+ "../../packages/common/dist/src/services/tenant/types.js"(exports2) {
2938
+ "use strict";
2939
+ init_cjs_shims();
2940
+ Object.defineProperty(exports2, "__esModule", { value: true });
2941
+ }
2942
+ });
2943
+
2944
+ // ../../packages/common/dist/src/services/tenant/tenantApiClient.js
2945
+ var require_tenantApiClient = __commonJS({
2946
+ "../../packages/common/dist/src/services/tenant/tenantApiClient.js"(exports2) {
2947
+ "use strict";
2948
+ init_cjs_shims();
2949
+ Object.defineProperty(exports2, "__esModule", { value: true });
2950
+ exports2.TenantApiClient = void 0;
2951
+ var DEFAULT_ARM_ENDPOINT = "https://management.azure.com";
2952
+ var ARM_API_VERSION = "2020-01-01";
2953
+ var MAX_PAGES = 20;
2954
+ var TENANT_LIST_EVENT = "TenantApiClient.fetchAllTenants";
2955
+ var TenantApiClient2 = class {
2956
+ requestService;
2957
+ tenantsUrl;
2958
+ trustedOrigin;
2959
+ constructor(options) {
2960
+ this.requestService = options.requestService;
2961
+ const armEndpoint = options.armEndpoint ?? DEFAULT_ARM_ENDPOINT;
2962
+ this.tenantsUrl = new URL("/tenants", armEndpoint).toString();
2963
+ this.trustedOrigin = new URL(armEndpoint).origin;
2964
+ }
2965
+ /**
2966
+ * Fetches all tenants accessible to the authenticated user from ARM,
2967
+ * following pagination links until exhausted or the page limit is reached.
2968
+ *
2969
+ * @param accessToken - A valid ARM bearer access token.
2970
+ * @returns An array of {@link ArmTenant} objects.
2971
+ */
2972
+ async fetchAllTenants(accessToken) {
2973
+ const allTenants = [];
2974
+ let nextUrl = this.tenantsUrl;
2975
+ let params = { "api-version": ARM_API_VERSION };
2976
+ let pageCount = 0;
2977
+ while (nextUrl && pageCount < MAX_PAGES) {
2978
+ pageCount++;
2979
+ const page = await this.requestService.get({
2980
+ url: nextUrl,
2981
+ eventName: TENANT_LIST_EVENT,
2982
+ params,
2983
+ token: accessToken
2984
+ });
2985
+ if (Array.isArray(page.value)) {
2986
+ allTenants.push(...page.value.map(mapArmTenant));
2987
+ }
2988
+ if (page.nextLink) {
2989
+ this.validateNextLink(page.nextLink);
2990
+ nextUrl = page.nextLink;
2991
+ params = {};
2992
+ } else {
2993
+ nextUrl = void 0;
2994
+ }
2995
+ }
2996
+ if (nextUrl) {
2997
+ throw new Error(`Tenant list is incomplete: maximum page limit of ${MAX_PAGES} reached.`);
2998
+ }
2999
+ return allTenants;
3000
+ }
3001
+ /**
3002
+ * Validates that a pagination URL returned by the ARM API originates from
3003
+ * the trusted ARM endpoint and targets the /tenants path, preventing SSRF
3004
+ * and bearer-token exfiltration to other origins or endpoints.
3005
+ */
3006
+ validateNextLink(nextLink) {
3007
+ let parsedUrl;
3008
+ try {
3009
+ parsedUrl = new URL(nextLink);
3010
+ } catch {
3011
+ throw new Error(`Invalid nextLink URL: ${nextLink}`);
3012
+ }
3013
+ if (parsedUrl.origin !== this.trustedOrigin) {
3014
+ throw new Error(`Untrusted nextLink origin: expected ${this.trustedOrigin}, got ${parsedUrl.origin}`);
3015
+ }
3016
+ if (parsedUrl.pathname !== "/tenants" && !parsedUrl.pathname.startsWith("/tenants/")) {
3017
+ throw new Error(`Untrusted nextLink path detected: ${parsedUrl.pathname}`);
3018
+ }
3019
+ }
3020
+ };
3021
+ exports2.TenantApiClient = TenantApiClient2;
3022
+ function mapArmTenant(raw) {
3023
+ return {
3024
+ id: raw.id,
3025
+ tenantId: raw.tenantId,
3026
+ displayName: raw.displayName ?? "Unknown Tenant",
3027
+ defaultDomain: raw.defaultDomain ?? "",
3028
+ tenantType: raw.tenantType ?? "AAD",
3029
+ tenantCategory: raw.tenantCategory
3030
+ };
3031
+ }
3032
+ }
3033
+ });
3034
+
3035
+ // ../../packages/common/dist/src/services/tenant/index.js
3036
+ var require_tenant = __commonJS({
3037
+ "../../packages/common/dist/src/services/tenant/index.js"(exports2) {
3038
+ "use strict";
3039
+ init_cjs_shims();
3040
+ var __createBinding = exports2 && exports2.__createBinding || (Object.create ? (function(o, m, k, k2) {
3041
+ if (k2 === void 0) k2 = k;
3042
+ var desc = Object.getOwnPropertyDescriptor(m, k);
3043
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
3044
+ desc = { enumerable: true, get: function() {
3045
+ return m[k];
3046
+ } };
3047
+ }
3048
+ Object.defineProperty(o, k2, desc);
3049
+ }) : (function(o, m, k, k2) {
3050
+ if (k2 === void 0) k2 = k;
3051
+ o[k2] = m[k];
3052
+ }));
3053
+ var __exportStar = exports2 && exports2.__exportStar || function(m, exports3) {
3054
+ for (var p4 in m) if (p4 !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p4)) __createBinding(exports3, m, p4);
3055
+ };
3056
+ Object.defineProperty(exports2, "__esModule", { value: true });
3057
+ __exportStar(require_types(), exports2);
3058
+ __exportStar(require_tenantApiClient(), exports2);
3059
+ }
3060
+ });
3061
+
3062
+ // ../../packages/common/dist/src/services/jobs/jobApiClient.js
3063
+ var require_jobApiClient = __commonJS({
3064
+ "../../packages/common/dist/src/services/jobs/jobApiClient.js"(exports2) {
3065
+ "use strict";
3066
+ init_cjs_shims();
3067
+ Object.defineProperty(exports2, "__esModule", { value: true });
3068
+ exports2.JobApiClient = void 0;
3069
+ var sentinel_graph_job_1 = require_dist();
3070
+ var jobEventNames_1 = require_jobEventNames();
3071
+ var API_VERSION = "2023-09-30-preview";
3072
+ var JOB_PATHS = {
3073
+ JOBS: "/jobs"
3074
+ };
3075
+ var JobApiClient2 = class {
3076
+ requestService;
3077
+ baseUrl;
3078
+ constructor(options) {
3079
+ this.requestService = options.requestService;
3080
+ this.baseUrl = options.baseUrl.replace(/\/+$/, "");
3081
+ }
3082
+ get jobsUrl() {
3083
+ return `${this.baseUrl}${JOB_PATHS.JOBS}`;
3084
+ }
3085
+ jobUrl(jobName) {
3086
+ return `${this.jobsUrl}/${encodeURIComponent(jobName)}`;
3087
+ }
3088
+ async createJob(jobName, payload, token, requestId) {
3089
+ if (!jobName?.trim()) {
3090
+ throw new Error("Job name is required");
3091
+ }
3092
+ return this.requestService.put({
3093
+ url: this.jobUrl(jobName),
3094
+ params: { "api-version": API_VERSION },
3095
+ eventName: jobEventNames_1.JobApiEvents.CREATE_JOB,
3096
+ body: JSON.stringify(payload),
3097
+ token,
3098
+ requestId
3099
+ });
3100
+ }
3101
+ async getJob(jobName, token, requestId) {
3102
+ if (!jobName?.trim()) {
3103
+ throw new Error("Job name is required");
3104
+ }
3105
+ return this.requestService.get({
3106
+ url: this.jobUrl(jobName),
3107
+ params: { "api-version": API_VERSION },
3108
+ eventName: jobEventNames_1.JobApiEvents.GET_JOB,
3109
+ token,
3110
+ requestId
3111
+ });
3112
+ }
3113
+ async deleteJob(jobName, token, requestId) {
3114
+ if (!jobName?.trim()) {
3115
+ throw new Error("Job name is required");
3116
+ }
3117
+ return this.requestService.delete({
3118
+ url: this.jobUrl(jobName),
3119
+ params: { "api-version": API_VERSION },
3120
+ eventName: jobEventNames_1.JobApiEvents.DELETE_JOB,
3121
+ token,
3122
+ requestId
3123
+ });
3124
+ }
3125
+ async disableJob(jobName, token, requestId) {
3126
+ if (!jobName?.trim()) {
3127
+ throw new Error("Job name is required");
3128
+ }
3129
+ const current = await this.getJob(jobName, token, requestId);
3130
+ const updated = { ...current, jobDefinition: { ...current.jobDefinition, isDisabled: true } };
3131
+ return this.requestService.put({
3132
+ url: this.jobUrl(jobName),
3133
+ params: { "api-version": API_VERSION },
3134
+ eventName: jobEventNames_1.JobApiEvents.DISABLE_JOB,
3135
+ body: JSON.stringify(updated),
3136
+ token,
3137
+ requestId
3138
+ });
3139
+ }
3140
+ async enableJob(jobName, token, requestId) {
3141
+ if (!jobName?.trim()) {
3142
+ throw new Error("Job name is required");
3143
+ }
3144
+ const current = await this.getJob(jobName, token, requestId);
3145
+ const updated = { ...current, jobDefinition: { ...current.jobDefinition, isDisabled: false } };
3146
+ return this.requestService.put({
3147
+ url: this.jobUrl(jobName),
3148
+ params: { "api-version": API_VERSION },
3149
+ eventName: jobEventNames_1.JobApiEvents.ENABLE_JOB,
3150
+ body: JSON.stringify(updated),
3151
+ token,
3152
+ requestId
3153
+ });
3154
+ }
3155
+ jobRunsUrl(jobName) {
3156
+ return `${this.jobUrl(jobName)}/runs`;
3157
+ }
3158
+ jobRunUrl(jobName, runId) {
3159
+ return `${this.jobRunsUrl(jobName)}/${encodeURIComponent(runId)}`;
3160
+ }
3161
+ async listJobRuns(jobName, token, requestId) {
3162
+ if (!jobName?.trim()) {
3163
+ throw new Error("Job name is required");
3164
+ }
3165
+ const runs = [];
3166
+ let continuationToken = void 0;
3167
+ do {
3168
+ const params = { "api-version": API_VERSION };
3169
+ if (continuationToken !== null && continuationToken !== void 0) {
3170
+ params.continuationToken = continuationToken;
3171
+ }
3172
+ const data = await this.requestService.get({
3173
+ url: this.jobRunsUrl(jobName),
3174
+ params,
3175
+ eventName: jobEventNames_1.JobApiEvents.LIST_JOB_RUNS,
3176
+ token,
3177
+ requestId
3178
+ });
3179
+ if (data?.results) {
3180
+ runs.push(...data.results);
3181
+ }
3182
+ continuationToken = data?.continuationToken ?? null;
3183
+ } while (continuationToken !== null);
3184
+ return runs;
3185
+ }
3186
+ async getJobRun(jobName, runId, token, requestId) {
3187
+ if (!jobName?.trim()) {
3188
+ throw new Error("Job name is required");
3189
+ }
3190
+ if (!runId?.trim()) {
3191
+ throw new Error("Run ID is required");
3192
+ }
3193
+ return this.requestService.get({
3194
+ url: this.jobRunUrl(jobName, runId),
3195
+ params: { "api-version": API_VERSION },
3196
+ eventName: jobEventNames_1.JobApiEvents.GET_JOB_RUN,
3197
+ token,
3198
+ requestId
3199
+ });
3200
+ }
3201
+ async startJobRun(jobName, token, requestId) {
3202
+ if (!jobName?.trim()) {
3203
+ throw new Error("Job name is required");
3204
+ }
3205
+ return this.requestService.post({
3206
+ url: `${this.jobUrl(jobName)}:runNow`,
3207
+ params: { "api-version": API_VERSION },
3208
+ eventName: jobEventNames_1.JobApiEvents.START_JOB_RUN,
3209
+ body: JSON.stringify({}),
3210
+ token,
3211
+ requestId
3212
+ });
3213
+ }
3214
+ async cancelJobRun(jobName, runId, token, requestId) {
3215
+ if (!jobName?.trim()) {
3216
+ throw new Error("Job name is required");
3217
+ }
3218
+ if (!runId?.trim()) {
3219
+ throw new Error("Run ID is required");
3220
+ }
3221
+ return this.requestService.post({
3222
+ url: `${this.jobRunUrl(jobName, runId)}:cancel`,
3223
+ params: { "api-version": API_VERSION },
3224
+ eventName: jobEventNames_1.JobApiEvents.CANCEL_JOB_RUN,
3225
+ body: JSON.stringify({}),
3226
+ token,
3227
+ requestId
3228
+ });
3229
+ }
3230
+ async listJobs(token, requestId) {
3231
+ const jobs = [];
3232
+ let continuationToken = void 0;
3233
+ do {
3234
+ const params = { jobType: sentinel_graph_job_1.JobType.Notebook, "api-version": API_VERSION };
3235
+ if (continuationToken !== null && continuationToken !== void 0) {
3236
+ params.continuationToken = continuationToken;
3237
+ }
3238
+ const data = await this.requestService.get({
3239
+ url: this.jobsUrl,
3240
+ params,
3241
+ eventName: jobEventNames_1.JobApiEvents.LOAD_JOBS,
3242
+ token,
3243
+ requestId
3244
+ });
3245
+ if (data?.results) {
3246
+ const pageJobs = data.results.map((result) => {
3247
+ if (!result.jobDefinition.jobName) {
3248
+ return null;
3249
+ }
3250
+ return {
3251
+ jobName: result.jobDefinition.jobName,
3252
+ id: result.jobDefinition.jobDefinitionId,
3253
+ isDisabled: result.jobDefinition.isDisabled,
3254
+ jobType: result.jobDefinition.jobType
3255
+ };
3256
+ }).filter((job) => job !== null);
3257
+ jobs.push(...pageJobs);
3258
+ }
3259
+ continuationToken = data?.continuationToken ?? null;
3260
+ } while (continuationToken !== null);
3261
+ return jobs;
3262
+ }
3263
+ };
3264
+ exports2.JobApiClient = JobApiClient2;
3265
+ }
3266
+ });
3267
+
3268
+ // ../../packages/common/dist/src/services/jobs/index.js
3269
+ var require_jobs2 = __commonJS({
3270
+ "../../packages/common/dist/src/services/jobs/index.js"(exports2) {
3271
+ "use strict";
3272
+ init_cjs_shims();
3273
+ Object.defineProperty(exports2, "__esModule", { value: true });
3274
+ exports2.JobApiClient = void 0;
3275
+ var jobApiClient_1 = require_jobApiClient();
3276
+ Object.defineProperty(exports2, "JobApiClient", { enumerable: true, get: function() {
3277
+ return jobApiClient_1.JobApiClient;
3278
+ } });
3279
+ }
3280
+ });
3281
+
3282
+ // ../../packages/common/dist/src/services/lake/lakeApiClient.js
3283
+ var require_lakeApiClient = __commonJS({
3284
+ "../../packages/common/dist/src/services/lake/lakeApiClient.js"(exports2) {
3285
+ "use strict";
3286
+ init_cjs_shims();
3287
+ Object.defineProperty(exports2, "__esModule", { value: true });
3288
+ exports2.LakeApiClient = void 0;
3289
+ exports2.isFederatedTable = isFederatedTable;
3290
+ exports2.getFederatedDatasourceKind = getFederatedDatasourceKind;
3291
+ var lakeEventNames_1 = require_lakeEventNames();
3292
+ var FEDERATED_TABLE_TYPE = "Federated";
3293
+ function isFederatedTable(table) {
3294
+ return table.tableType === FEDERATED_TABLE_TYPE;
3295
+ }
3296
+ function getFederatedDatasourceKind(table) {
3297
+ return table.fabricDetails?.federationDetails?.federatedDatasourceKind;
3298
+ }
3299
+ var API_VERSION = {
3300
+ DATABASES_API_VERSION: "2024-07-01",
3301
+ TABLES_API_VERSION: "2024-05-01-preview"
3302
+ };
3303
+ var LAKE_PATHS = {
3304
+ TABLES: "/lake/tables",
3305
+ DATABASES: "/lake/databases"
3306
+ };
3307
+ var LakeApiClient2 = class {
3308
+ requestService;
3309
+ telemetry;
3310
+ baseUrl;
3311
+ constructor(options) {
3312
+ this.requestService = options.requestService;
3313
+ this.telemetry = options.telemetry;
3314
+ this.baseUrl = options.baseUrl.replace(/\/+$/, "");
3315
+ }
3316
+ get tablesUrl() {
3317
+ return `${this.baseUrl}${LAKE_PATHS.TABLES}`;
3318
+ }
3319
+ get databasesUrl() {
3320
+ return `${this.baseUrl}${LAKE_PATHS.DATABASES}`;
3321
+ }
3322
+ /**
3323
+ * Fetches all lake tables. If a database is specified, fetches tables for that database only.
3324
+ */
3325
+ async fetchLakeTables(accessToken, clientRequestId, database) {
3326
+ const span = this.telemetry.span(lakeEventNames_1.LakeApiEvents.LOAD_TABLES, { requestId: clientRequestId ?? "" });
3327
+ try {
3328
+ let url = this.tablesUrl;
3329
+ let params = database ? { databaseName: database.databaseName } : void 0;
3330
+ const tables = [];
3331
+ do {
3332
+ const response = await this.fetchTables(url, accessToken, clientRequestId, params);
3333
+ tables.push(...response.items);
3334
+ url = response.nextLink || null;
3335
+ params = void 0;
3336
+ } while (url);
3337
+ return tables;
3338
+ } finally {
3339
+ span.end();
3340
+ }
3341
+ }
3342
+ async fetchDatabases(accessToken, clientRequestId) {
3343
+ const data = await this.requestService.get({
3344
+ url: this.databasesUrl,
3345
+ params: { "api-version": API_VERSION.DATABASES_API_VERSION },
3346
+ eventName: lakeEventNames_1.LakeApiEvents.LOAD_DATABASES,
3347
+ token: accessToken,
3348
+ requestId: clientRequestId
3349
+ });
3350
+ return data.value;
3351
+ }
3352
+ async fetchTables(url, accessToken, clientRequestId, params) {
3353
+ return this.requestService.get({
3354
+ url,
3355
+ params: {
3356
+ "api-version": API_VERSION.TABLES_API_VERSION,
3357
+ ...params
3358
+ },
3359
+ eventName: lakeEventNames_1.LakeApiEvents.LOAD_TABLES,
3360
+ token: accessToken,
3361
+ requestId: clientRequestId
3362
+ });
3363
+ }
3364
+ };
3365
+ exports2.LakeApiClient = LakeApiClient2;
3366
+ }
3367
+ });
3368
+
3369
+ // ../../packages/common/dist/src/services/lake/index.js
3370
+ var require_lake2 = __commonJS({
3371
+ "../../packages/common/dist/src/services/lake/index.js"(exports2) {
3372
+ "use strict";
3373
+ init_cjs_shims();
3374
+ Object.defineProperty(exports2, "__esModule", { value: true });
3375
+ exports2.getFederatedDatasourceKind = exports2.isFederatedTable = exports2.LakeApiClient = void 0;
3376
+ var lakeApiClient_1 = require_lakeApiClient();
3377
+ Object.defineProperty(exports2, "LakeApiClient", { enumerable: true, get: function() {
3378
+ return lakeApiClient_1.LakeApiClient;
3379
+ } });
3380
+ Object.defineProperty(exports2, "isFederatedTable", { enumerable: true, get: function() {
3381
+ return lakeApiClient_1.isFederatedTable;
3382
+ } });
3383
+ Object.defineProperty(exports2, "getFederatedDatasourceKind", { enumerable: true, get: function() {
3384
+ return lakeApiClient_1.getFederatedDatasourceKind;
3385
+ } });
3386
+ }
3387
+ });
3388
+
2847
3389
  // ../../packages/common/dist/src/services/httpService.js
2848
3390
  var require_httpService = __commonJS({
2849
3391
  "../../packages/common/dist/src/services/httpService.js"(exports2) {
@@ -2855,7 +3397,7 @@ var require_httpService = __commonJS({
2855
3397
  Object.defineProperty(exports2, "__esModule", { value: true });
2856
3398
  exports2.HttpService = void 0;
2857
3399
  var axios_1 = __importDefault(require("axios"));
2858
- var HttpService2 = class {
3400
+ var HttpService = class {
2859
3401
  httpInstance;
2860
3402
  // Implement the interface
2861
3403
  constructor(httpInstance) {
@@ -2920,7 +3462,7 @@ var require_httpService = __commonJS({
2920
3462
  }
2921
3463
  }
2922
3464
  };
2923
- exports2.HttpService = HttpService2;
3465
+ exports2.HttpService = HttpService;
2924
3466
  }
2925
3467
  });
2926
3468
 
@@ -2933,81 +3475,6 @@ var require_httpServiceInterface = __commonJS({
2933
3475
  }
2934
3476
  });
2935
3477
 
2936
- // ../../packages/common/dist/src/services/jobService.js
2937
- var require_jobService = __commonJS({
2938
- "../../packages/common/dist/src/services/jobService.js"(exports2) {
2939
- "use strict";
2940
- init_cjs_shims();
2941
- Object.defineProperty(exports2, "__esModule", { value: true });
2942
- exports2.JobService = void 0;
2943
- var JobService2 = class {
2944
- env;
2945
- region;
2946
- httpInstance;
2947
- API_VERSION = "2023-09-30-preview";
2948
- constructor(env, region, httpInstance) {
2949
- this.env = env;
2950
- this.region = region;
2951
- this.httpInstance = httpInstance;
2952
- if (!env || !region) {
2953
- throw new Error("Environment and region must be provided.");
2954
- }
2955
- if (!env.regions[region]) {
2956
- throw new Error(`Region ${region} is not configured.`);
2957
- }
2958
- if (!httpInstance) {
2959
- throw new Error("HTTP service instance must be provided.");
2960
- }
2961
- this.httpInstance = httpInstance;
2962
- }
2963
- async getHttpInstance() {
2964
- return this.httpInstance;
2965
- }
2966
- getBaseUrl() {
2967
- const regionConfig = this.env.regions[this.region];
2968
- return regionConfig.gatewayEndpoint;
2969
- }
2970
- async createJob(jobName, payload) {
2971
- if (!jobName?.trim()) {
2972
- throw new Error("Job name is required");
2973
- }
2974
- const httpInstance = await this.getHttpInstance();
2975
- const url = `${this.getBaseUrl()}jobs/${encodeURIComponent(jobName)}?api-version=${this.API_VERSION}`;
2976
- const { data } = await httpInstance.put(url, payload);
2977
- return data;
2978
- }
2979
- async getJob(jobName) {
2980
- if (!jobName?.trim()) {
2981
- throw new Error("Job name is required");
2982
- }
2983
- const httpInstance = await this.getHttpInstance();
2984
- const url = `${this.getBaseUrl()}jobs/${encodeURIComponent(jobName)}?api-version=${this.API_VERSION}`;
2985
- const { data } = await httpInstance.get(url);
2986
- return data;
2987
- }
2988
- async deleteJob(jobName) {
2989
- if (!jobName?.trim()) {
2990
- throw new Error("Job name is required");
2991
- }
2992
- const httpInstance = await this.getHttpInstance();
2993
- const url = `${this.getBaseUrl()}jobs/${encodeURIComponent(jobName)}?api-version=${this.API_VERSION}`;
2994
- const { data } = await httpInstance.delete(url);
2995
- return data;
2996
- }
2997
- };
2998
- exports2.JobService = JobService2;
2999
- }
3000
- });
3001
-
3002
- // ../../packages/common/dist/src/services/jobServiceInterface.js
3003
- var require_jobServiceInterface = __commonJS({
3004
- "../../packages/common/dist/src/services/jobServiceInterface.js"(exports2) {
3005
- "use strict";
3006
- init_cjs_shims();
3007
- Object.defineProperty(exports2, "__esModule", { value: true });
3008
- }
3009
- });
3010
-
3011
3478
  // ../../node_modules/.pnpm/js-yaml@4.1.1/node_modules/js-yaml/lib/common.js
3012
3479
  var require_common2 = __commonJS({
3013
3480
  "../../node_modules/.pnpm/js-yaml@4.1.1/node_modules/js-yaml/lib/common.js"(exports2, module2) {
@@ -3016,7 +3483,7 @@ var require_common2 = __commonJS({
3016
3483
  function isNothing(subject) {
3017
3484
  return typeof subject === "undefined" || subject === null;
3018
3485
  }
3019
- function isObject(subject) {
3486
+ function isObject2(subject) {
3020
3487
  return typeof subject === "object" && subject !== null;
3021
3488
  }
3022
3489
  function toArray(sequence) {
@@ -3046,7 +3513,7 @@ var require_common2 = __commonJS({
3046
3513
  return number === 0 && Number.NEGATIVE_INFINITY === 1 / number;
3047
3514
  }
3048
3515
  module2.exports.isNothing = isNothing;
3049
- module2.exports.isObject = isObject;
3516
+ module2.exports.isObject = isObject2;
3050
3517
  module2.exports.toArray = toArray;
3051
3518
  module2.exports.repeat = repeat;
3052
3519
  module2.exports.isNegativeZero = isNegativeZero;
@@ -5874,10 +6341,10 @@ var require_notebookUtils = __commonJS({
5874
6341
  exports2.getJupyterNotebook = getJupyterNotebook;
5875
6342
  exports2.removeCellOutput = removeCellOutput;
5876
6343
  exports2.notebookToBase64 = notebookToBase64;
5877
- var fs3 = __importStar(require("fs/promises"));
6344
+ var fs7 = __importStar(require("fs/promises"));
5878
6345
  async function getJupyterNotebook(filePath) {
5879
6346
  try {
5880
- const notebookFile = await fs3.readFile(filePath, "utf-8");
6347
+ const notebookFile = await fs7.readFile(filePath, "utf-8");
5881
6348
  return JSON.parse(notebookFile);
5882
6349
  } catch (error) {
5883
6350
  throw new Error(`Failed to read or parse the notebook file: ${error}`);
@@ -5955,18 +6422,18 @@ var require_secureExchangeManifestUtils = __commonJS({
5955
6422
  })();
5956
6423
  Object.defineProperty(exports2, "__esModule", { value: true });
5957
6424
  exports2.updateSecureExchangeManifest = updateSecureExchangeManifest;
5958
- var fs3 = __importStar(require("fs-extra"));
6425
+ var fs7 = __importStar(require("fs-extra"));
5959
6426
  var yaml = __importStar(require("yaml"));
5960
6427
  async function updateSecureExchangeManifest(manifestEntries, secureExchangeManifestPath) {
5961
6428
  if (manifestEntries.length > 0) {
5962
- const existingYaml = await fs3.readFile(secureExchangeManifestPath, "utf-8");
6429
+ const existingYaml = await fs7.readFile(secureExchangeManifestPath, "utf-8");
5963
6430
  const parsedYaml = existingYaml ? yaml.parse(existingYaml) || [] : [];
5964
6431
  const newEntries = manifestEntries.filter((newEntry) => !parsedYaml.some((existingEntry) => existingEntry.id === newEntry.id && existingEntry.type === newEntry.type));
5965
6432
  if (newEntries.length === 0) {
5966
6433
  return;
5967
6434
  }
5968
6435
  const updatedYaml = [...parsedYaml, ...newEntries];
5969
- await fs3.writeFile(secureExchangeManifestPath, yaml.stringify(updatedYaml), "utf-8");
6436
+ await fs7.writeFile(secureExchangeManifestPath, yaml.stringify(updatedYaml), "utf-8");
5970
6437
  }
5971
6438
  }
5972
6439
  }
@@ -6582,8 +7049,8 @@ var require_zipDirectory = __commonJS({
6582
7049
  try {
6583
7050
  const output = fs_1.default.createWriteStream(outPath);
6584
7051
  const archive = (0, archiver_1.default)("zip", { zlib: { level: 9 } });
6585
- return new Promise((resolve, reject) => {
6586
- output.on("close", resolve);
7052
+ return new Promise((resolve2, reject) => {
7053
+ output.on("close", resolve2);
6587
7054
  output.on("error", reject);
6588
7055
  archive.on("error", reject);
6589
7056
  archive.pipe(output);
@@ -6660,8 +7127,8 @@ var require_manifestProcessorService = __commonJS({
6660
7127
  Object.defineProperty(exports2, "__esModule", { value: true });
6661
7128
  exports2.ManifestProcessorService = void 0;
6662
7129
  var crypto_1 = require("crypto");
6663
- var fs3 = __importStar(require("fs-extra"));
6664
- var path5 = __importStar(require("path"));
7130
+ var fs7 = __importStar(require("fs-extra"));
7131
+ var path8 = __importStar(require("path"));
6665
7132
  var yaml = __importStar(require("yaml"));
6666
7133
  var constants_1 = require_constants();
6667
7134
  var buildScheduledJobArtifacts_1 = require_buildScheduledJobArtifacts();
@@ -6684,17 +7151,17 @@ var require_manifestProcessorService = __commonJS({
6684
7151
  };
6685
7152
  }
6686
7153
  async buildZipPackage(manifestPath) {
6687
- const manifestDir = path5.dirname(path5.resolve(manifestPath));
6688
- const tempPackageDir = path5.join(manifestDir, ".packaging-temp");
7154
+ const manifestDir = path8.dirname(path8.resolve(manifestPath));
7155
+ const tempPackageDir = path8.join(manifestDir, ".packaging-temp");
6689
7156
  try {
6690
- await fs3.rm(tempPackageDir, { recursive: true, force: true });
6691
- await fs3.mkdir(tempPackageDir, { recursive: true });
7157
+ await fs7.rm(tempPackageDir, { recursive: true, force: true });
7158
+ await fs7.mkdir(tempPackageDir, { recursive: true });
6692
7159
  const manifest = await (0, manifestParser_1.parseManifest)(manifestPath);
6693
- const discoveredFiles = await (0, discoverFiles_1.discoverFiles)(manifest.includePaths, path5.dirname(path5.resolve(manifestPath)));
7160
+ const discoveredFiles = await (0, discoverFiles_1.discoverFiles)(manifest.includePaths, path8.dirname(path8.resolve(manifestPath)));
6694
7161
  console.log("Discovered files:", JSON.stringify(discoveredFiles, null, 2));
6695
7162
  (0, manifestValidator_1.validateSingleScAgent)(discoveredFiles);
6696
- const secureExchangeManifestPath = path5.join(tempPackageDir, "PackageManifest.yaml");
6697
- await fs3.writeFile(secureExchangeManifestPath, "");
7163
+ const secureExchangeManifestPath = path8.join(tempPackageDir, "PackageManifest.yaml");
7164
+ await fs7.writeFile(secureExchangeManifestPath, "");
6698
7165
  console.log("Empty PackageManifest.yaml created at:", secureExchangeManifestPath);
6699
7166
  await (0, processMainTemplate_1.processMainTemplate)(discoveredFiles, tempPackageDir, secureExchangeManifestPath);
6700
7167
  console.log("mainTemplate.json processed and added to PackageManifest.yaml");
@@ -6704,8 +7171,8 @@ var require_manifestProcessorService = __commonJS({
6704
7171
  console.log("SC Agents processed and PackageManifest.yaml updated.");
6705
7172
  await (0, refactorManifest_1.finalizeManifest)(secureExchangeManifestPath, tempPackageDir);
6706
7173
  const zipName = `${manifest.packageName}.zip`;
6707
- const manifestDir2 = path5.dirname(path5.resolve(manifestPath));
6708
- const outputZipPath = path5.join(manifestDir2, zipName);
7174
+ const manifestDir2 = path8.dirname(path8.resolve(manifestPath));
7175
+ const outputZipPath = path8.join(manifestDir2, zipName);
6709
7176
  await (0, zipDirectory_1.zipDirectory)(tempPackageDir, outputZipPath);
6710
7177
  console.log("Package zipped at:", outputZipPath);
6711
7178
  return outputZipPath;
@@ -6717,21 +7184,21 @@ var require_manifestProcessorService = __commonJS({
6717
7184
  }
6718
7185
  } finally {
6719
7186
  try {
6720
- await fs3.rm(tempPackageDir, { recursive: true, force: true });
7187
+ await fs7.rm(tempPackageDir, { recursive: true, force: true });
6721
7188
  } catch (err) {
6722
7189
  console.warn("Please clean the temp directory as Failed to clean up temp directory:", err);
6723
7190
  }
6724
7191
  }
6725
7192
  }
6726
7193
  async validateManifest(manifestPath) {
6727
- const manifestDir = path5.dirname(path5.resolve(manifestPath));
6728
- const tempPackageDir = path5.join(manifestDir, ".packaging-temp");
7194
+ const manifestDir = path8.dirname(path8.resolve(manifestPath));
7195
+ const tempPackageDir = path8.join(manifestDir, ".packaging-temp");
6729
7196
  let parsed;
6730
7197
  try {
6731
- await fs3.rm(tempPackageDir, { recursive: true, force: true });
6732
- const content = await fs3.readFile(manifestPath, "utf8");
7198
+ await fs7.rm(tempPackageDir, { recursive: true, force: true });
7199
+ const content = await fs7.readFile(manifestPath, "utf8");
6733
7200
  parsed = yaml.parse(content);
6734
- const discoveredFiles = await (0, discoverFiles_1.discoverFiles)(parsed.includePaths, path5.dirname(path5.resolve(manifestPath)));
7201
+ const discoveredFiles = await (0, discoverFiles_1.discoverFiles)(parsed.includePaths, path8.dirname(path8.resolve(manifestPath)));
6735
7202
  (0, manifestValidator_1.validateSingleScAgent)(discoveredFiles);
6736
7203
  const yamlType = parsed.yamlType;
6737
7204
  if (!yamlType) {
@@ -6741,8 +7208,8 @@ var require_manifestProcessorService = __commonJS({
6741
7208
  if (!validator) {
6742
7209
  throw new Error(`No validator found for yamlType '${yamlType}'`);
6743
7210
  }
6744
- const absPath = path5.resolve(manifestPath);
6745
- const manifestDir2 = path5.dirname(absPath);
7211
+ const absPath = path8.resolve(manifestPath);
7212
+ const manifestDir2 = path8.dirname(absPath);
6746
7213
  await validator(parsed, manifestDir2);
6747
7214
  } catch (err) {
6748
7215
  if (err instanceof Error) {
@@ -6752,30 +7219,30 @@ var require_manifestProcessorService = __commonJS({
6752
7219
  }
6753
7220
  } finally {
6754
7221
  try {
6755
- await fs3.rm(tempPackageDir, { recursive: true, force: true });
7222
+ await fs7.rm(tempPackageDir, { recursive: true, force: true });
6756
7223
  } catch (err) {
6757
7224
  console.warn("Please clean the temp directory as Failed to clean up temp directory:", err);
6758
7225
  }
6759
7226
  }
6760
7227
  }
6761
7228
  async buildSideLoadRequest(manifestPath) {
6762
- const manifestDir = path5.dirname(path5.resolve(manifestPath));
6763
- const tempPackageDir = path5.join(manifestDir, ".packaging-temp");
6764
- const sentinelLakeDir = path5.join(tempPackageDir, constants_1.PackageManifestIdValues.SentinelLakeId);
7229
+ const manifestDir = path8.dirname(path8.resolve(manifestPath));
7230
+ const tempPackageDir = path8.join(manifestDir, ".packaging-temp");
7231
+ const sentinelLakeDir = path8.join(tempPackageDir, constants_1.PackageManifestIdValues.SentinelLakeId);
6765
7232
  const deploymentId = (0, crypto_1.randomUUID)();
6766
7233
  try {
6767
- await fs3.rm(tempPackageDir, { recursive: true, force: true });
7234
+ await fs7.rm(tempPackageDir, { recursive: true, force: true });
6768
7235
  const manifest = await (0, manifestParser_1.parseManifest)(manifestPath);
6769
- const discoveredFiles = await (0, discoverFiles_1.discoverFiles)(manifest.includePaths, path5.dirname(path5.resolve(manifestPath)));
7236
+ const discoveredFiles = await (0, discoverFiles_1.discoverFiles)(manifest.includePaths, path8.dirname(path8.resolve(manifestPath)));
6770
7237
  console.log("Discovered files:", JSON.stringify(discoveredFiles, null, 2));
6771
- await fs3.mkdir(tempPackageDir, { recursive: true });
7238
+ await fs7.mkdir(tempPackageDir, { recursive: true });
6772
7239
  await (0, buildScheduledJobArtifacts_1.processScheduledJobs)(discoveredFiles, tempPackageDir, "");
6773
- const jobDirs = await fs3.readdir(sentinelLakeDir);
7240
+ const jobDirs = await fs7.readdir(sentinelLakeDir);
6774
7241
  const artifacts = [];
6775
7242
  for (const dir of jobDirs) {
6776
- const deploymentJsonPath = path5.join(sentinelLakeDir, dir, "deployment.json");
6777
- if (await fs3.pathExists(deploymentJsonPath)) {
6778
- const jsonContent = await fs3.readFile(deploymentJsonPath, "utf8");
7243
+ const deploymentJsonPath = path8.join(sentinelLakeDir, dir, "deployment.json");
7244
+ if (await fs7.pathExists(deploymentJsonPath)) {
7245
+ const jsonContent = await fs7.readFile(deploymentJsonPath, "utf8");
6779
7246
  const escapedJson = JSON.stringify(JSON.parse(jsonContent));
6780
7247
  artifacts.push({
6781
7248
  name: "deployment.yaml",
@@ -6798,7 +7265,7 @@ var require_manifestProcessorService = __commonJS({
6798
7265
  console.error("Error building side-load request:", error);
6799
7266
  throw error;
6800
7267
  } finally {
6801
- await fs3.remove(tempPackageDir);
7268
+ await fs7.remove(tempPackageDir);
6802
7269
  }
6803
7270
  }
6804
7271
  };
@@ -7052,14 +7519,15 @@ var require_services = __commonJS({
7052
7519
  o[k2] = m[k];
7053
7520
  }));
7054
7521
  var __exportStar = exports2 && exports2.__exportStar || function(m, exports3) {
7055
- for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p)) __createBinding(exports3, m, p);
7522
+ for (var p4 in m) if (p4 !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p4)) __createBinding(exports3, m, p4);
7056
7523
  };
7057
7524
  Object.defineProperty(exports2, "__esModule", { value: true });
7525
+ __exportStar(require_tenant(), exports2);
7058
7526
  __exportStar(require_httpConstants(), exports2);
7527
+ __exportStar(require_jobs2(), exports2);
7528
+ __exportStar(require_lake2(), exports2);
7059
7529
  __exportStar(require_httpService(), exports2);
7060
7530
  __exportStar(require_httpServiceInterface(), exports2);
7061
- __exportStar(require_jobService(), exports2);
7062
- __exportStar(require_jobServiceInterface(), exports2);
7063
7531
  __exportStar(require_manifestProcessorService(), exports2);
7064
7532
  __exportStar(require_manifestProcessorServiceInterface(), exports2);
7065
7533
  __exportStar(require_packageService(), exports2);
@@ -7086,26 +7554,122 @@ var require_errors = __commonJS({
7086
7554
  o[k2] = m[k];
7087
7555
  }));
7088
7556
  var __exportStar = exports2 && exports2.__exportStar || function(m, exports3) {
7089
- for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p)) __createBinding(exports3, m, p);
7557
+ for (var p4 in m) if (p4 !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p4)) __createBinding(exports3, m, p4);
7090
7558
  };
7091
7559
  Object.defineProperty(exports2, "__esModule", { value: true });
7092
7560
  __exportStar(require_errorTypes(), exports2);
7093
7561
  }
7094
7562
  });
7095
7563
 
7096
- // ../../packages/common/dist/src/utils/pathUtils.js
7097
- var require_pathUtils = __commonJS({
7098
- "../../packages/common/dist/src/utils/pathUtils.js"(exports2) {
7564
+ // ../../packages/common/dist/src/telemetry/types.js
7565
+ var require_types2 = __commonJS({
7566
+ "../../packages/common/dist/src/telemetry/types.js"(exports2) {
7099
7567
  "use strict";
7100
7568
  init_cjs_shims();
7101
- var __importDefault = exports2 && exports2.__importDefault || function(mod) {
7102
- return mod && mod.__esModule ? mod : { "default": mod };
7569
+ Object.defineProperty(exports2, "__esModule", { value: true });
7570
+ }
7571
+ });
7572
+
7573
+ // ../../packages/common/dist/src/telemetry/index.js
7574
+ var require_telemetry = __commonJS({
7575
+ "../../packages/common/dist/src/telemetry/index.js"(exports2) {
7576
+ "use strict";
7577
+ init_cjs_shims();
7578
+ var __createBinding = exports2 && exports2.__createBinding || (Object.create ? (function(o, m, k, k2) {
7579
+ if (k2 === void 0) k2 = k;
7580
+ var desc = Object.getOwnPropertyDescriptor(m, k);
7581
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7582
+ desc = { enumerable: true, get: function() {
7583
+ return m[k];
7584
+ } };
7585
+ }
7586
+ Object.defineProperty(o, k2, desc);
7587
+ }) : (function(o, m, k, k2) {
7588
+ if (k2 === void 0) k2 = k;
7589
+ o[k2] = m[k];
7590
+ }));
7591
+ var __exportStar = exports2 && exports2.__exportStar || function(m, exports3) {
7592
+ for (var p4 in m) if (p4 !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p4)) __createBinding(exports3, m, p4);
7593
+ };
7594
+ Object.defineProperty(exports2, "__esModule", { value: true });
7595
+ __exportStar(require_types2(), exports2);
7596
+ }
7597
+ });
7598
+
7599
+ // ../../packages/common/dist/src/utils/decodeBase64Notebook.js
7600
+ var require_decodeBase64Notebook = __commonJS({
7601
+ "../../packages/common/dist/src/utils/decodeBase64Notebook.js"(exports2) {
7602
+ "use strict";
7603
+ init_cjs_shims();
7604
+ Object.defineProperty(exports2, "__esModule", { value: true });
7605
+ exports2.decodeBase64Notebook = decodeBase64Notebook3;
7606
+ var BASE64_RE = /^[A-Za-z0-9+/\r\n]*={0,2}$/;
7607
+ function decodeBase64Notebook3(encoded, label) {
7608
+ if (!encoded?.trim()) {
7609
+ throw new Error(`${label} has no notebook content to decode.`);
7610
+ }
7611
+ if (!BASE64_RE.test(encoded.trim())) {
7612
+ throw new Error(`${label} has an invalid base64-encoded notebook.`);
7613
+ }
7614
+ return Buffer.from(encoded, "base64").toString("utf-8");
7615
+ }
7616
+ }
7617
+ });
7618
+
7619
+ // ../../packages/common/dist/src/utils/pathUtils.js
7620
+ var require_pathUtils = __commonJS({
7621
+ "../../packages/common/dist/src/utils/pathUtils.js"(exports2) {
7622
+ "use strict";
7623
+ init_cjs_shims();
7624
+ var __importDefault = exports2 && exports2.__importDefault || function(mod) {
7625
+ return mod && mod.__esModule ? mod : { "default": mod };
7103
7626
  };
7104
7627
  Object.defineProperty(exports2, "__esModule", { value: true });
7105
7628
  exports2.resolvePath = resolvePath2;
7106
7629
  var path_1 = __importDefault(require("path"));
7107
- function resolvePath2(p) {
7108
- return path_1.default.resolve(p);
7630
+ function resolvePath2(p4) {
7631
+ return path_1.default.resolve(p4);
7632
+ }
7633
+ }
7634
+ });
7635
+
7636
+ // ../../packages/common/dist/src/utils/tokenUtils.js
7637
+ var require_tokenUtils = __commonJS({
7638
+ "../../packages/common/dist/src/utils/tokenUtils.js"(exports2) {
7639
+ "use strict";
7640
+ init_cjs_shims();
7641
+ Object.defineProperty(exports2, "__esModule", { value: true });
7642
+ exports2.extractTenantId = extractTenantId2;
7643
+ var TOKEN_PARSING = {
7644
+ SEPARATOR: ".",
7645
+ BASE64_HYPHEN_REPLACEMENT: "+",
7646
+ BASE64_UNDERSCORE_REPLACEMENT: "/",
7647
+ BASE64_HYPHEN_PATTERN: /-/g,
7648
+ BASE64_UNDERSCORE_PATTERN: /_/g,
7649
+ BASE64_ENCODING: "base64",
7650
+ TENANT_ID_CLAIM: "tid",
7651
+ TOKEN_PARTS_LENGTH: 3,
7652
+ PAYLOAD_INDEX: 1
7653
+ };
7654
+ function extractTenantId2(accessToken) {
7655
+ try {
7656
+ const tokenParts = accessToken.split(TOKEN_PARSING.SEPARATOR);
7657
+ if (tokenParts.length !== TOKEN_PARSING.TOKEN_PARTS_LENGTH) {
7658
+ return void 0;
7659
+ }
7660
+ let base64Url = tokenParts[TOKEN_PARSING.PAYLOAD_INDEX].replace(TOKEN_PARSING.BASE64_HYPHEN_PATTERN, TOKEN_PARSING.BASE64_HYPHEN_REPLACEMENT).replace(TOKEN_PARSING.BASE64_UNDERSCORE_PATTERN, TOKEN_PARSING.BASE64_UNDERSCORE_REPLACEMENT);
7661
+ while (base64Url.length % 4 !== 0) {
7662
+ base64Url += "=";
7663
+ }
7664
+ const payload = JSON.parse(Buffer.from(base64Url, TOKEN_PARSING.BASE64_ENCODING).toString());
7665
+ if (typeof payload === "object" && payload !== null) {
7666
+ const tenantId = payload[TOKEN_PARSING.TENANT_ID_CLAIM];
7667
+ return typeof tenantId === "string" ? tenantId : void 0;
7668
+ }
7669
+ return void 0;
7670
+ } catch {
7671
+ return void 0;
7672
+ }
7109
7673
  }
7110
7674
  }
7111
7675
  });
@@ -7129,12 +7693,14 @@ var require_utils = __commonJS({
7129
7693
  o[k2] = m[k];
7130
7694
  }));
7131
7695
  var __exportStar = exports2 && exports2.__exportStar || function(m, exports3) {
7132
- for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p)) __createBinding(exports3, m, p);
7696
+ for (var p4 in m) if (p4 !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p4)) __createBinding(exports3, m, p4);
7133
7697
  };
7134
7698
  Object.defineProperty(exports2, "__esModule", { value: true });
7135
7699
  __exportStar(require_correlationService(), exports2);
7700
+ __exportStar(require_decodeBase64Notebook(), exports2);
7136
7701
  __exportStar(require_pathUtils(), exports2);
7137
7702
  __exportStar(require_jobPayloadUtils(), exports2);
7703
+ __exportStar(require_tokenUtils(), exports2);
7138
7704
  }
7139
7705
  });
7140
7706
 
@@ -7157,7 +7723,7 @@ var require_src = __commonJS({
7157
7723
  o[k2] = m[k];
7158
7724
  }));
7159
7725
  var __exportStar = exports2 && exports2.__exportStar || function(m, exports3) {
7160
- for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p)) __createBinding(exports3, m, p);
7726
+ for (var p4 in m) if (p4 !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p4)) __createBinding(exports3, m, p4);
7161
7727
  };
7162
7728
  Object.defineProperty(exports2, "__esModule", { value: true });
7163
7729
  __exportStar(require_client(), exports2);
@@ -7167,6 +7733,7 @@ var require_src = __commonJS({
7167
7733
  __exportStar(require_models(), exports2);
7168
7734
  __exportStar(require_services(), exports2);
7169
7735
  __exportStar(require_errors(), exports2);
7736
+ __exportStar(require_telemetry(), exports2);
7170
7737
  __exportStar(require_utils(), exports2);
7171
7738
  }
7172
7739
  });
@@ -7210,352 +7777,2577 @@ function addCreateZipCommand(packageCommand) {
7210
7777
  });
7211
7778
  }
7212
7779
 
7213
- // src/commands/login.ts
7780
+ // src/commands/jobs/jobDefinitionCreate.ts
7214
7781
  init_cjs_shims();
7215
- var os5 = __toESM(require("os"));
7216
7782
 
7217
- // src/actions/authCodeLogin.ts
7783
+ // src/actions/jobs/index.ts
7784
+ init_cjs_shims();
7785
+
7786
+ // src/actions/jobs/listJobs.ts
7218
7787
  init_cjs_shims();
7219
- var import_child_process = require("child_process");
7220
7788
  var import_common3 = __toESM(require_src());
7789
+ async function listJobs(jobService, accessToken) {
7790
+ const requestId = import_common3.CorrelationService.createCorrelationContext();
7791
+ console.info("Fetching jobs...");
7792
+ return jobService.listJobs(accessToken, requestId);
7793
+ }
7221
7794
 
7222
- // src/auth/msalInstance.ts
7795
+ // src/actions/jobs/getJob.ts
7223
7796
  init_cjs_shims();
7224
- var import_msal_node2 = require("@azure/msal-node");
7797
+ var import_common4 = __toESM(require_src());
7798
+ async function getJob(jobService, accessToken, jobName) {
7799
+ const requestId = import_common4.CorrelationService.createCorrelationContext();
7800
+ console.info(`Fetching job "${jobName}"...`);
7801
+ return jobService.getJob(jobName, accessToken, requestId);
7802
+ }
7225
7803
 
7226
- // src/config/msalConfig.ts
7804
+ // src/actions/jobs/deleteJob.ts
7227
7805
  init_cjs_shims();
7228
- var import_msal_node = require("@azure/msal-node");
7229
- var import_msal_node_extensions2 = require("@azure/msal-node-extensions");
7806
+ var import_common5 = __toESM(require_src());
7807
+ async function deleteJob(jobService, accessToken, jobName) {
7808
+ const requestId = import_common5.CorrelationService.createCorrelationContext();
7809
+ console.info(`Deleting job "${jobName}"...`);
7810
+ return jobService.deleteJob(jobName, accessToken, requestId);
7811
+ }
7230
7812
 
7231
- // src/auth/persistence/persistence.ts
7813
+ // src/actions/jobs/disableJob.ts
7232
7814
  init_cjs_shims();
7233
- var import_msal_node_extensions = require("@azure/msal-node-extensions");
7234
- var import_os = __toESM(require("os"));
7815
+ var import_common6 = __toESM(require_src());
7816
+ async function disableJob(jobService, accessToken, jobName) {
7817
+ const requestId = import_common6.CorrelationService.createCorrelationContext();
7818
+ console.info(`Disabling job "${jobName}"...`);
7819
+ return jobService.disableJob(jobName, accessToken, requestId);
7820
+ }
7821
+
7822
+ // src/actions/jobs/enableJob.ts
7823
+ init_cjs_shims();
7824
+ var import_common7 = __toESM(require_src());
7825
+ async function enableJob(jobService, accessToken, jobName) {
7826
+ const requestId = import_common7.CorrelationService.createCorrelationContext();
7827
+ console.info(`Enabling job "${jobName}"...`);
7828
+ return jobService.enableJob(jobName, accessToken, requestId);
7829
+ }
7830
+
7831
+ // src/actions/jobs/downloadJob.ts
7832
+ init_cjs_shims();
7833
+ var import_fs = __toESM(require("fs"));
7235
7834
  var import_path = __toESM(require("path"));
7236
- var PlatformType = /* @__PURE__ */ ((PlatformType2) => {
7237
- PlatformType2["Windows"] = "win32";
7238
- PlatformType2["MacOS"] = "darwin";
7239
- PlatformType2["Linux"] = "linux";
7240
- return PlatformType2;
7241
- })(PlatformType || {});
7242
- async function createPersistence() {
7243
- const cacheFilePath = import_path.default.join(import_os.default.homedir(), ".nsdcli-cache.json");
7244
- const platform3 = import_os.default.platform();
7245
- switch (platform3) {
7246
- case "win32" /* Windows */:
7247
- return await import_msal_node_extensions.FilePersistenceWithDataProtection.create(cacheFilePath, import_msal_node_extensions.DataProtectionScope.CurrentUser);
7248
- case "darwin" /* MacOS */:
7249
- return await import_msal_node_extensions.KeychainPersistence.create("nsdcli.service", "nsdcli.account", "nsdcli");
7250
- case "linux" /* Linux */:
7251
- return await import_msal_node_extensions.LibSecretPersistence.create("nsdcli.service", "nsdcli.account", "nsdcli");
7252
- default:
7253
- throw new Error(
7254
- `Unsupported platform: ${platform3}. Supported platforms are: ${Object.values(PlatformType).join(", ")}`
7255
- );
7835
+ var import_common8 = __toESM(require_src());
7836
+ async function downloadJob(jobService, accessToken, jobName, outputPath) {
7837
+ const requestId = import_common8.CorrelationService.createCorrelationContext();
7838
+ console.info(`Fetching job "${jobName}"...`);
7839
+ const job = await jobService.getJob(jobName, accessToken, requestId);
7840
+ const inlineScript = job.jobDefinition.inlineScript;
7841
+ const decoded = (0, import_common8.decodeBase64Notebook)(inlineScript, `job "${jobName}"`);
7842
+ const sanitizedJobName = import_path.default.basename(jobName).replace(/[^a-zA-Z0-9_-]/g, "_");
7843
+ const resolvedPath = import_path.default.resolve(outputPath ?? import_path.default.join(process.cwd(), `${sanitizedJobName}.ipynb`));
7844
+ await import_fs.default.promises.mkdir(import_path.default.dirname(resolvedPath), { recursive: true });
7845
+ await import_fs.default.promises.writeFile(resolvedPath, decoded, "utf-8");
7846
+ return resolvedPath;
7847
+ }
7848
+
7849
+ // src/actions/jobs/listJobRuns.ts
7850
+ init_cjs_shims();
7851
+ var import_common9 = __toESM(require_src());
7852
+ async function listJobRuns(jobService, accessToken, jobName) {
7853
+ const requestId = import_common9.CorrelationService.createCorrelationContext();
7854
+ console.info(`Fetching runs for job "${jobName}"...`);
7855
+ return jobService.listJobRuns(jobName, accessToken, requestId);
7856
+ }
7857
+
7858
+ // src/actions/jobs/getJobRun.ts
7859
+ init_cjs_shims();
7860
+ var import_common10 = __toESM(require_src());
7861
+ async function getJobRun(jobService, accessToken, jobName, runId) {
7862
+ const requestId = import_common10.CorrelationService.createCorrelationContext();
7863
+ console.info(`Fetching run "${runId}" for job "${jobName}"...`);
7864
+ return jobService.getJobRun(jobName, runId, accessToken, requestId);
7865
+ }
7866
+
7867
+ // src/actions/jobs/startJobRun.ts
7868
+ init_cjs_shims();
7869
+ var import_common11 = __toESM(require_src());
7870
+ async function startJobRun(jobService, accessToken, jobName) {
7871
+ const requestId = import_common11.CorrelationService.createCorrelationContext();
7872
+ console.info(`Starting run for job "${jobName}"...`);
7873
+ return jobService.startJobRun(jobName, accessToken, requestId);
7874
+ }
7875
+
7876
+ // src/actions/jobs/cancelJobRun.ts
7877
+ init_cjs_shims();
7878
+ var import_common12 = __toESM(require_src());
7879
+ async function cancelJobRun(jobService, accessToken, jobName, runId) {
7880
+ const requestId = import_common12.CorrelationService.createCorrelationContext();
7881
+ console.info(`Cancelling run "${runId}" for job "${jobName}"...`);
7882
+ return jobService.cancelJobRun(jobName, runId, accessToken, requestId);
7883
+ }
7884
+
7885
+ // src/actions/jobs/downloadJobRunNotebook.ts
7886
+ init_cjs_shims();
7887
+ var import_fs2 = __toESM(require("fs"));
7888
+ var import_path2 = __toESM(require("path"));
7889
+ var import_common13 = __toESM(require_src());
7890
+ async function downloadJobRunNotebook(jobService, accessToken, jobName, runId, outputPath) {
7891
+ const requestId = import_common13.CorrelationService.createCorrelationContext();
7892
+ console.info(`Fetching run "${runId}" for job "${jobName}"...`);
7893
+ const run = await jobService.getJobRun(jobName, runId, accessToken, requestId);
7894
+ const scriptSnapshot = run.scriptSnapshot;
7895
+ const decoded = (0, import_common13.decodeBase64Notebook)(scriptSnapshot, `run "${runId}" for job "${jobName}"`);
7896
+ const sanitizedJobName = import_path2.default.basename(jobName).replace(/[^a-zA-Z0-9_-]/g, "_");
7897
+ const sanitizedRunId = import_path2.default.basename(runId).replace(/[^a-zA-Z0-9_-]/g, "_");
7898
+ const defaultFileName = `${sanitizedJobName}_${sanitizedRunId}.ipynb`;
7899
+ const resolvedPath = import_path2.default.resolve(outputPath ?? import_path2.default.join(process.cwd(), defaultFileName));
7900
+ await import_fs2.default.promises.mkdir(import_path2.default.dirname(resolvedPath), { recursive: true });
7901
+ await import_fs2.default.promises.writeFile(resolvedPath, decoded, "utf-8");
7902
+ return resolvedPath;
7903
+ }
7904
+
7905
+ // src/actions/jobs/createJobDefinition.ts
7906
+ init_cjs_shims();
7907
+ var p2 = __toESM(require("@clack/prompts"));
7908
+ var path3 = __toESM(require("path"));
7909
+
7910
+ // src/utils/validator/jobDefinitionValidator.ts
7911
+ init_cjs_shims();
7912
+ var import_zod = require("zod");
7913
+ var ISO_DATE_PATTERN = /^\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}(:\d{2}(\.\d+)?)?(Z|[+-]\d{2}:\d{2})?)?$/;
7914
+ var JOB_TYPES = ["Notebook", "GraphNotebook", "Kql"];
7915
+ var NODE_SIZES = ["small", "medium", "large"];
7916
+ var REPEAT_FREQUENCIES = ["minutes", "hours", "days", "weeks", "months"];
7917
+ var INTERVAL_BOUNDS = {
7918
+ minutes: { min: 15, max: 720 },
7919
+ hours: { min: 1, max: 72 }
7920
+ };
7921
+ var FIXED_INTERVAL_FREQUENCIES = new Set(
7922
+ REPEAT_FREQUENCIES.filter((f) => !(f in INTERVAL_BOUNDS))
7923
+ );
7924
+ var JOB_NAME_PATTERN = /^[a-zA-Z0-9 _-]+$/;
7925
+ var JOB_NAME_PATTERN_MESSAGE = "Job name may only contain letters, numbers, spaces, hyphens, or underscores";
7926
+ var VALID_WEEK_DAYS = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"];
7927
+ function isValidISODate(value) {
7928
+ if (!ISO_DATE_PATTERN.test(value)) {
7929
+ return false;
7256
7930
  }
7931
+ return !isNaN(new Date(value).getTime());
7257
7932
  }
7933
+ var timeTableSchema = import_zod.z.object({
7934
+ weekDays: import_zod.z.array(import_zod.z.enum(VALID_WEEK_DAYS)).optional(),
7935
+ monthDays: import_zod.z.array(import_zod.z.number().int().min(1).max(31)).optional()
7936
+ }).optional();
7937
+ var scheduleConfigSchema = import_zod.z.object({
7938
+ isEnabled: import_zod.z.boolean(),
7939
+ repeatFrequency: import_zod.z.enum(REPEAT_FREQUENCIES).optional(),
7940
+ interval: import_zod.z.number().int().positive().optional(),
7941
+ startTime: import_zod.z.string().optional(),
7942
+ endTime: import_zod.z.string().optional(),
7943
+ timeTable: timeTableSchema
7944
+ });
7945
+ var jobDefinitionValidator = import_zod.z.object({
7946
+ jobName: import_zod.z.string().min(1, "Job name is required").regex(JOB_NAME_PATTERN, JOB_NAME_PATTERN_MESSAGE),
7947
+ jobPath: import_zod.z.string().min(1, "Job path is required"),
7948
+ jobType: import_zod.z.enum(JOB_TYPES).optional(),
7949
+ jobDescription: import_zod.z.string().optional(),
7950
+ computeInfo: import_zod.z.object({
7951
+ nodeSize: import_zod.z.enum(NODE_SIZES)
7952
+ }).optional(),
7953
+ scheduleConfig: scheduleConfigSchema.optional(),
7954
+ inputTables: import_zod.z.array(import_zod.z.string()).optional(),
7955
+ outputTables: import_zod.z.array(import_zod.z.string()).optional(),
7956
+ runtimeArgs: import_zod.z.array(import_zod.z.string()).optional(),
7957
+ isDisabled: import_zod.z.boolean().optional()
7958
+ }).refine(
7959
+ (data) => {
7960
+ const jobType = data.jobType ?? "Notebook";
7961
+ if (jobType === "Kql") {
7962
+ return true;
7963
+ }
7964
+ return data.jobPath.toLowerCase().endsWith(".ipynb");
7965
+ },
7966
+ { message: "Job path must be a Python notebook (.ipynb) file", path: ["jobPath"] }
7967
+ ).refine(
7968
+ (data) => {
7969
+ if (data.scheduleConfig?.isEnabled) {
7970
+ return !!data.scheduleConfig.repeatFrequency;
7971
+ }
7972
+ return true;
7973
+ },
7974
+ { message: "repeatFrequency is required for scheduled jobs", path: ["scheduleConfig", "repeatFrequency"] }
7975
+ ).refine(
7976
+ (data) => {
7977
+ const sc = data.scheduleConfig;
7978
+ if (!sc?.isEnabled || !sc.repeatFrequency) {
7979
+ return true;
7980
+ }
7981
+ return sc.interval !== void 0;
7982
+ },
7983
+ { message: "Interval is required for scheduled jobs", path: ["scheduleConfig", "interval"] }
7984
+ ).refine(
7985
+ (data) => {
7986
+ const sc = data.scheduleConfig;
7987
+ if (!sc?.isEnabled || sc.interval === void 0 || !sc.repeatFrequency) {
7988
+ return true;
7989
+ }
7990
+ const bounds = INTERVAL_BOUNDS[sc.repeatFrequency];
7991
+ if (bounds) {
7992
+ return sc.interval >= bounds.min && sc.interval <= bounds.max;
7993
+ }
7994
+ if (FIXED_INTERVAL_FREQUENCIES.has(sc.repeatFrequency)) {
7995
+ return sc.interval === 1;
7996
+ }
7997
+ return true;
7998
+ },
7999
+ {
8000
+ message: "Schedule interval is out of range for the selected frequency",
8001
+ path: ["scheduleConfig", "interval"]
8002
+ }
8003
+ ).refine(
8004
+ (data) => {
8005
+ const sc = data.scheduleConfig;
8006
+ if (!sc?.isEnabled || !sc.startTime) {
8007
+ return true;
8008
+ }
8009
+ return isValidISODate(sc.startTime);
8010
+ },
8011
+ { message: "Start time must be a valid ISO 8601 date", path: ["scheduleConfig", "startTime"] }
8012
+ ).refine(
8013
+ (data) => {
8014
+ const sc = data.scheduleConfig;
8015
+ if (!sc?.isEnabled || !sc.endTime) {
8016
+ return true;
8017
+ }
8018
+ return isValidISODate(sc.endTime);
8019
+ },
8020
+ { message: "End time must be a valid ISO 8601 date", path: ["scheduleConfig", "endTime"] }
8021
+ ).refine(
8022
+ (data) => {
8023
+ const sc = data.scheduleConfig;
8024
+ if (!sc?.isEnabled || !sc.startTime || !sc.endTime) {
8025
+ return true;
8026
+ }
8027
+ const start = new Date(sc.startTime);
8028
+ const end = new Date(sc.endTime);
8029
+ if (isNaN(start.getTime()) || isNaN(end.getTime())) {
8030
+ return true;
8031
+ }
8032
+ return end > start;
8033
+ },
8034
+ { message: "End time must be after start time", path: ["scheduleConfig", "endTime"] }
8035
+ ).refine(
8036
+ (data) => {
8037
+ const sc = data.scheduleConfig;
8038
+ if (!sc?.isEnabled || sc.repeatFrequency !== "weeks") {
8039
+ return true;
8040
+ }
8041
+ const days = sc.timeTable?.weekDays;
8042
+ return Array.isArray(days) && days.length > 0;
8043
+ },
8044
+ { message: "At least one day of the week is required for weekly schedule", path: ["scheduleConfig", "timeTable"] }
8045
+ ).refine(
8046
+ (data) => {
8047
+ const sc = data.scheduleConfig;
8048
+ if (!sc?.isEnabled || sc.repeatFrequency !== "months") {
8049
+ return true;
8050
+ }
8051
+ const days = sc.timeTable?.monthDays;
8052
+ return Array.isArray(days) && days.length > 0;
8053
+ },
8054
+ {
8055
+ message: "At least one day of the month is required for monthly schedule",
8056
+ path: ["scheduleConfig", "timeTable", "monthDays"]
8057
+ }
8058
+ );
7258
8059
 
7259
- // src/config/msalConfig.ts
7260
- var os2 = __toESM(require("os"));
7261
- async function getMsalConfig(environment, useCachePlugin = true, authorityOverride) {
7262
- let cachePlugin;
7263
- if (useCachePlugin) {
7264
- const persistence = await createPersistence();
7265
- await persistence.verifyPersistence();
7266
- cachePlugin = new import_msal_node_extensions2.PersistenceCachePlugin(persistence);
8060
+ // src/actions/jobs/promptHelpers.ts
8061
+ init_cjs_shims();
8062
+ var fs3 = __toESM(require("fs"));
8063
+ var p = __toESM(require("@clack/prompts"));
8064
+ var DEFAULT_NODE_SIZE = "large";
8065
+ var NODE_SIZE_OPTIONS = NODE_SIZES.map((size) => ({
8066
+ value: size,
8067
+ label: size === DEFAULT_NODE_SIZE ? `${capitalize(size)} (default)` : capitalize(size)
8068
+ }));
8069
+ var FREQUENCY_OPTIONS = REPEAT_FREQUENCIES.map((freq) => ({
8070
+ value: freq,
8071
+ label: capitalize(freq)
8072
+ }));
8073
+ var CONFIGURABLE_INTERVAL_FREQUENCIES = new Set(
8074
+ Object.keys(INTERVAL_BOUNDS)
8075
+ );
8076
+ var WEEKDAY_OPTIONS = [
8077
+ { value: "Monday", label: "Monday" },
8078
+ { value: "Tuesday", label: "Tuesday" },
8079
+ { value: "Wednesday", label: "Wednesday" },
8080
+ { value: "Thursday", label: "Thursday" },
8081
+ { value: "Friday", label: "Friday" },
8082
+ { value: "Saturday", label: "Saturday" },
8083
+ { value: "Sunday", label: "Sunday" }
8084
+ ];
8085
+ function capitalize(s) {
8086
+ return s.charAt(0).toUpperCase() + s.slice(1);
8087
+ }
8088
+ function handleCancel(value) {
8089
+ if (p.isCancel(value)) {
8090
+ p.cancel("Operation cancelled.");
8091
+ process.exit(0);
7267
8092
  }
7268
- const config = {
7269
- auth: {
7270
- clientId: environment.aadClientId,
7271
- authority: authorityOverride ?? environment.aadEndpoint
7272
- },
7273
- cache: cachePlugin ? { cachePlugin } : void 0,
7274
- system: {
7275
- loggerOptions: {
7276
- loggerCallback(_level, message, containsPii) {
7277
- if (!containsPii) {
7278
- console.log(message);
7279
- }
7280
- },
7281
- logLevel: import_msal_node.LogLevel.Info,
7282
- piiLoggingEnabled: false
8093
+ }
8094
+ async function promptIfMissing(flagValue, promptFn) {
8095
+ if (flagValue !== void 0) {
8096
+ return flagValue;
8097
+ }
8098
+ const result = await promptFn();
8099
+ handleCancel(result);
8100
+ return result;
8101
+ }
8102
+ function validateInterval(frequency) {
8103
+ return (v) => {
8104
+ if (!v || v.trim() === "") {
8105
+ return "Interval is required";
8106
+ }
8107
+ const trimmed = v.trim();
8108
+ if (!/^\d+$/.test(trimmed)) {
8109
+ return "Please enter a whole number";
8110
+ }
8111
+ const n = parseInt(trimmed, 10);
8112
+ const bounds = INTERVAL_BOUNDS[frequency];
8113
+ if (bounds) {
8114
+ if (n < bounds.min) {
8115
+ return `Minimum value is ${bounds.min} ${frequency}`;
8116
+ }
8117
+ if (n > bounds.max) {
8118
+ return `Maximum value is ${bounds.max} ${frequency}`;
8119
+ }
8120
+ } else if (FIXED_INTERVAL_FREQUENCIES.has(frequency)) {
8121
+ if (n !== 1) {
8122
+ return `Interval must be 1 for ${frequency}`;
7283
8123
  }
7284
8124
  }
8125
+ return void 0;
7285
8126
  };
7286
- if ("win32" /* Windows */ === os2.platform()) {
7287
- config.broker = {
7288
- nativeBrokerPlugin: new import_msal_node_extensions2.NativeBrokerPlugin()
7289
- };
8127
+ }
8128
+ function validateJobPath(v) {
8129
+ if (!v) {
8130
+ return "Job path is required";
7290
8131
  }
7291
- return config;
8132
+ if (!v.toLowerCase().endsWith(".ipynb")) {
8133
+ return "Job path must be a Python notebook (.ipynb) file";
8134
+ }
8135
+ if (!fs3.existsSync(v)) {
8136
+ return `File not found at "${v}". Please provide a valid path to an existing .ipynb file`;
8137
+ }
8138
+ return void 0;
7292
8139
  }
7293
-
7294
- // src/auth/msalInstance.ts
7295
- var msalInstances = /* @__PURE__ */ new Map();
7296
- var getMsalInstance = async (env, authorityOverride) => {
7297
- const key = authorityOverride ?? env.aadEndpoint;
7298
- if (!msalInstances.has(key)) {
7299
- const config = await getMsalConfig(env, !process.env.CI, authorityOverride);
7300
- msalInstances.set(key, new import_msal_node2.PublicClientApplication(config));
8140
+ function validateISODate(v) {
8141
+ if (!v) {
8142
+ return "Date/time is required";
7301
8143
  }
7302
- return msalInstances.get(key);
7303
- };
7304
-
7305
- // src/actions/authCodeLogin.ts
7306
- var apiEnv = (0, import_common3.getApiEnv)(import_common3.SecurityPlatformEnvironment.Production);
7307
- function openSystemBrowser(url) {
7308
- return new Promise((resolve, reject) => {
7309
- const command = process.platform === "darwin" ? "open" : "xdg-open";
7310
- (0, import_child_process.execFile)(command, [url], (error) => {
7311
- if (error) {
7312
- reject(new Error(`Failed to open browser: ${error.message}`));
7313
- } else {
7314
- resolve();
7315
- }
7316
- });
7317
- });
8144
+ const iso8601Pattern = /^\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}(:\d{2}(\.\d+)?)?(Z|[+-]\d{2}:\d{2})?)?$/;
8145
+ if (!iso8601Pattern.test(v)) {
8146
+ return "Must be a valid ISO 8601 date (e.g. 2026-01-01T09:00:00Z)";
8147
+ }
8148
+ const d = new Date(v);
8149
+ if (isNaN(d.getTime())) {
8150
+ return "Must be a valid ISO 8601 date (e.g. 2026-01-01T09:00:00Z)";
8151
+ }
8152
+ return void 0;
7318
8153
  }
7319
- async function browserAuthLogin(scopes) {
7320
- const msalInstance = await getMsalInstance(apiEnv);
7321
- console.log("\u{1F510} Starting browser login. A browser window will open.");
7322
- const result = await msalInstance.acquireTokenInteractive({
7323
- scopes,
7324
- openBrowser: openSystemBrowser,
7325
- successTemplate: "<h1>Authentication successful</h1><p>You may close this tab and return to the terminal.</p>",
7326
- errorTemplate: "<h1>Authentication failed</h1><p>{error}</p>"
7327
- });
7328
- if (!result?.accessToken) {
7329
- throw new Error("Token acquisition failed: received null or empty token.");
8154
+ function validateEndTimeAfterStart(startTime, endTime) {
8155
+ if (!endTime) {
8156
+ return "End time is required";
7330
8157
  }
7331
- console.log("\u{1F511} Token acquired successfully.");
7332
- return result.accessToken;
8158
+ const start = new Date(startTime);
8159
+ const end = new Date(endTime);
8160
+ if (isNaN(start.getTime()) || isNaN(end.getTime())) {
8161
+ return "Please enter valid date and time values";
8162
+ }
8163
+ if (end <= start) {
8164
+ return "End time must be after start time";
8165
+ }
8166
+ return void 0;
8167
+ }
8168
+ function validateJobName(v) {
8169
+ if (!v) {
8170
+ return "Job name is required";
8171
+ }
8172
+ if (!JOB_NAME_PATTERN.test(v)) {
8173
+ return JOB_NAME_PATTERN_MESSAGE;
8174
+ }
8175
+ return void 0;
8176
+ }
8177
+ function validateEndTime(startTime) {
8178
+ return (v) => {
8179
+ const isoErr = validateISODate(v);
8180
+ if (isoErr) {
8181
+ return isoErr;
8182
+ }
8183
+ return validateEndTimeAfterStart(startTime, v);
8184
+ };
7333
8185
  }
7334
8186
 
7335
- // src/actions/brokerLogin.ts
8187
+ // src/utils/yaml/yamlIO.ts
7336
8188
  init_cjs_shims();
7337
- var import_common4 = __toESM(require_src());
7338
- var import_fs = __toESM(require("fs"));
7339
- var import_os2 = __toESM(require("os"));
7340
- var import_path2 = __toESM(require("path"));
7341
- var apiEnv2 = (0, import_common4.getApiEnv)(import_common4.SecurityPlatformEnvironment.Production);
7342
- var SENTINEL_DIR = import_path2.default.join(import_os2.default.homedir(), ".sentinel");
7343
- var BROKER_ACCOUNT_FILE = import_path2.default.join(SENTINEL_DIR, "broker-account.json");
7344
- function saveBrokerAccount(account, authority) {
7345
- import_fs.default.mkdirSync(SENTINEL_DIR, { recursive: true, mode: 448 });
7346
- const session = { account, authority };
7347
- const tempFile = `${BROKER_ACCOUNT_FILE}.tmp`;
7348
- import_fs.default.writeFileSync(tempFile, JSON.stringify(session, null, 2), { encoding: "utf8", mode: 384 });
7349
- import_fs.default.renameSync(tempFile, BROKER_ACCOUNT_FILE);
7350
- }
7351
- function loadBrokerAccount() {
8189
+ var fs4 = __toESM(require("fs"));
8190
+ var YAML = __toESM(require("yaml"));
8191
+ function readJobDefinitionYaml(filePath) {
8192
+ if (!fs4.existsSync(filePath)) {
8193
+ throw new Error(`File not found: ${filePath}`);
8194
+ }
8195
+ let raw;
7352
8196
  try {
7353
- if (import_fs.default.existsSync(BROKER_ACCOUNT_FILE)) {
7354
- const raw = import_fs.default.readFileSync(BROKER_ACCOUNT_FILE, "utf8");
7355
- const session = JSON.parse(raw);
7356
- if (session.account && typeof session.account === "object" && session.authority && typeof session.authority === "string") {
7357
- return session;
7358
- }
7359
- }
7360
- } catch {
8197
+ const content = fs4.readFileSync(filePath, "utf-8");
8198
+ raw = YAML.parse(content);
8199
+ } catch (err) {
8200
+ const message = err instanceof Error ? err.message : String(err);
8201
+ throw new Error(`Failed to read/parse YAML: ${message}`);
7361
8202
  }
7362
- return null;
8203
+ const result = jobDefinitionValidator.safeParse(raw);
8204
+ if (result.success) {
8205
+ return result.data;
8206
+ }
8207
+ const issues = result.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`);
8208
+ throw new Error(`Validation failed:
8209
+ ${issues.join("\n")}`);
7363
8210
  }
7364
- function deleteBrokerAccount() {
8211
+ function writeJobDefinitionYaml(filePath, config) {
8212
+ const result = jobDefinitionValidator.safeParse(config);
8213
+ if (!result.success) {
8214
+ const issues = result.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`);
8215
+ return { success: false, issues };
8216
+ }
7365
8217
  try {
7366
- if (import_fs.default.existsSync(BROKER_ACCOUNT_FILE)) {
7367
- import_fs.default.unlinkSync(BROKER_ACCOUNT_FILE);
7368
- }
7369
- } catch {
8218
+ const yamlContent = YAML.stringify(result.data, { lineWidth: 0 });
8219
+ fs4.writeFileSync(filePath, yamlContent, "utf-8");
8220
+ return { success: true, issues: [] };
8221
+ } catch (err) {
8222
+ const message = err instanceof Error ? err.message : String(err);
8223
+ return { success: false, issues: [`Failed to write file "${filePath}": ${message}`] };
7370
8224
  }
7371
8225
  }
7372
- async function brokerLogin(scopes, tenant) {
7373
- const authorityOverride = tenant ? `${new URL(apiEnv2.aadEndpoint).origin}/${tenant}` : void 0;
7374
- const authority = authorityOverride ?? apiEnv2.aadEndpoint;
7375
- const msalInstance = await getMsalInstance(apiEnv2, authorityOverride);
7376
- const savedSession = loadBrokerAccount();
7377
- const accounts = await msalInstance.getTokenCache().getAllAccounts();
7378
- if (savedSession) {
7379
- try {
7380
- const silentResult = await msalInstance.acquireTokenSilent({
7381
- account: savedSession.account,
7382
- scopes,
7383
- authority: savedSession.authority
7384
- });
7385
- if (silentResult?.accessToken) {
7386
- console.log("\u2705 Authenticated silently via saved broker session.");
7387
- return silentResult.accessToken;
8226
+
8227
+ // src/actions/jobs/createJobDefinition.ts
8228
+ function sanitizeFileName(fileName) {
8229
+ return fileName.replace(/[<>:"/\\|?*]/g, "_").replace(/\s+/g, "_");
8230
+ }
8231
+ function fail(message) {
8232
+ throw new Error(message);
8233
+ }
8234
+ async function collectJobDetails(jobNameArg, options) {
8235
+ const jobName = await promptIfMissing(
8236
+ jobNameArg,
8237
+ () => p2.text({
8238
+ message: "Job name:",
8239
+ validate: validateJobName
8240
+ })
8241
+ );
8242
+ if (jobNameArg !== void 0) {
8243
+ const nameError = validateJobName(jobName);
8244
+ if (nameError) {
8245
+ fail(nameError);
8246
+ }
8247
+ }
8248
+ const jobDescription = await promptIfMissing(
8249
+ options.description,
8250
+ () => p2.text({ message: "Description (optional):", defaultValue: "" })
8251
+ );
8252
+ const jobPath = await promptIfMissing(
8253
+ options.notebook,
8254
+ () => p2.text({
8255
+ message: "Job path (.ipynb):",
8256
+ placeholder: "path/to/notebook.ipynb",
8257
+ validate: validateJobPath
8258
+ })
8259
+ );
8260
+ if (options.notebook !== void 0) {
8261
+ const pathError = validateJobPath(jobPath);
8262
+ if (pathError) {
8263
+ fail(pathError);
8264
+ }
8265
+ }
8266
+ return { jobName, jobDescription, jobPath };
8267
+ }
8268
+ async function collectCompute(options) {
8269
+ if (options.cluster) {
8270
+ const normalized = options.cluster.toLowerCase();
8271
+ if (!NODE_SIZES.includes(normalized)) {
8272
+ fail(`Invalid cluster size "${options.cluster}". Must be one of: ${NODE_SIZES.join(", ")}`);
8273
+ }
8274
+ return normalized;
8275
+ }
8276
+ const result = await p2.select({
8277
+ message: "Cluster size:",
8278
+ options: NODE_SIZE_OPTIONS,
8279
+ initialValue: DEFAULT_NODE_SIZE
8280
+ });
8281
+ handleCancel(result);
8282
+ return result;
8283
+ }
8284
+ async function collectSchedule(options) {
8285
+ let wantsSchedule = !!options.schedule;
8286
+ if (!wantsSchedule) {
8287
+ const result = await p2.confirm({ message: "Schedule this job?", initialValue: true });
8288
+ handleCancel(result);
8289
+ wantsSchedule = result;
8290
+ }
8291
+ if (!wantsSchedule) {
8292
+ return { isEnabled: false };
8293
+ }
8294
+ const repeatFrequency = await promptIfMissing(
8295
+ options.schedule,
8296
+ () => p2.select({ message: "Repeat frequency:", options: FREQUENCY_OPTIONS })
8297
+ );
8298
+ if (options.schedule && !REPEAT_FREQUENCIES.includes(repeatFrequency)) {
8299
+ fail(`Invalid schedule frequency "${options.schedule}". Must be one of: ${REPEAT_FREQUENCIES.join(", ")}`);
8300
+ }
8301
+ let interval = 1;
8302
+ if (CONFIGURABLE_INTERVAL_FREQUENCIES.has(repeatFrequency)) {
8303
+ const intervalStr = await promptIfMissing(
8304
+ options.interval,
8305
+ () => p2.text({
8306
+ message: `Interval (${repeatFrequency}):`,
8307
+ defaultValue: repeatFrequency === "minutes" ? "15" : "1",
8308
+ validate: validateInterval(repeatFrequency)
8309
+ })
8310
+ );
8311
+ if (options.interval) {
8312
+ const intervalError = validateInterval(repeatFrequency)(intervalStr);
8313
+ if (intervalError) {
8314
+ fail(intervalError);
7388
8315
  }
7389
- } catch {
7390
- console.warn("\u26A0\uFE0F Silent broker authentication with saved session failed. Trying getAllAccounts()...");
7391
8316
  }
8317
+ interval = Number(intervalStr);
7392
8318
  }
7393
- if (accounts.length > 0) {
7394
- try {
7395
- const silentResult = await msalInstance.acquireTokenSilent({
7396
- account: accounts[0],
7397
- scopes
7398
- });
7399
- if (silentResult?.accessToken) {
7400
- saveBrokerAccount(accounts[0], authority);
7401
- console.log("\u2705 Authenticated silently via Windows Native Broker (SSO).");
7402
- return silentResult.accessToken;
8319
+ let timeTable;
8320
+ if (repeatFrequency === "weeks") {
8321
+ const result = await p2.multiselect({
8322
+ message: "Which days of the week?",
8323
+ options: [...WEEKDAY_OPTIONS],
8324
+ required: true
8325
+ });
8326
+ handleCancel(result);
8327
+ timeTable = { weekDays: result };
8328
+ }
8329
+ const startTime = await promptIfMissing(
8330
+ options.startTime,
8331
+ () => p2.text({
8332
+ message: "Start time (ISO 8601):",
8333
+ defaultValue: (/* @__PURE__ */ new Date()).toISOString(),
8334
+ validate: validateISODate
8335
+ })
8336
+ );
8337
+ if (options.startTime) {
8338
+ const startError = validateISODate(startTime);
8339
+ if (startError) {
8340
+ fail(startError);
8341
+ }
8342
+ }
8343
+ if (repeatFrequency === "months") {
8344
+ const dayOfMonth = new Date(startTime).getDate();
8345
+ timeTable = { monthDays: [dayOfMonth] };
8346
+ }
8347
+ let endTime;
8348
+ if (options.endTime) {
8349
+ endTime = options.endTime;
8350
+ } else {
8351
+ let endTimeResolved = false;
8352
+ while (!endTimeResolved) {
8353
+ const setEndTime = await p2.confirm({ message: "Set an end time?", initialValue: false });
8354
+ handleCancel(setEndTime);
8355
+ if (setEndTime) {
8356
+ const result = await p2.text({
8357
+ message: "End time (ISO 8601):",
8358
+ validate: validateEndTime(startTime)
8359
+ });
8360
+ handleCancel(result);
8361
+ endTime = result;
8362
+ endTimeResolved = true;
8363
+ } else {
8364
+ p2.log.warn("This job will run indefinitely until manually stopped or deleted.");
8365
+ const confirmIndefinite = await p2.confirm({ message: "Run indefinitely?", initialValue: true });
8366
+ handleCancel(confirmIndefinite);
8367
+ if (confirmIndefinite) {
8368
+ endTimeResolved = true;
8369
+ }
7403
8370
  }
7404
- } catch {
7405
- console.warn("\u26A0\uFE0F Silent broker authentication failed. Prompting interactively...");
7406
8371
  }
7407
8372
  }
7408
- const result = await msalInstance.acquireTokenInteractive({
7409
- scopes,
7410
- windowHandle: Buffer.alloc(0),
7411
- // headless / console window handle
7412
- openBrowser: async (_url) => {
8373
+ if (options.endTime) {
8374
+ const endError = validateEndTimeAfterStart(startTime, endTime);
8375
+ if (endError) {
8376
+ fail(endError);
7413
8377
  }
7414
- });
7415
- if (!result?.accessToken) {
7416
- throw new Error("Failed to acquire token via Windows Native Broker.");
7417
8378
  }
7418
- if (result.account) {
7419
- saveBrokerAccount(result.account, authority);
8379
+ return { isEnabled: true, repeatFrequency, interval, startTime, endTime, timeTable };
8380
+ }
8381
+ async function createJobDefinition(jobNameArg, options) {
8382
+ p2.intro("Create a job definition");
8383
+ const { jobName, jobDescription, jobPath } = await collectJobDetails(jobNameArg, options);
8384
+ const nodeSize = await collectCompute(options);
8385
+ const schedule = await collectSchedule(options);
8386
+ const config = {
8387
+ jobName,
8388
+ jobPath,
8389
+ jobType: "Notebook",
8390
+ ...jobDescription && { jobDescription },
8391
+ computeInfo: { nodeSize },
8392
+ ...schedule.isEnabled && {
8393
+ scheduleConfig: {
8394
+ isEnabled: true,
8395
+ repeatFrequency: schedule.repeatFrequency,
8396
+ interval: schedule.interval,
8397
+ startTime: schedule.startTime,
8398
+ endTime: schedule.endTime,
8399
+ ...schedule.timeTable && { timeTable: schedule.timeTable }
8400
+ }
8401
+ }
8402
+ };
8403
+ const outputPath = path3.resolve(options.output ?? `${sanitizeFileName(jobName)}.yaml`);
8404
+ const result = writeJobDefinitionYaml(outputPath, config);
8405
+ if (!result.success) {
8406
+ for (const issue of result.issues) {
8407
+ p2.log.error(issue);
8408
+ }
8409
+ throw new Error("Validation failed");
7420
8410
  }
7421
- console.log("\u2705 Authenticated via Windows Native Broker.");
7422
- return result.accessToken;
8411
+ p2.log.success(`Written to ${outputPath}`);
8412
+ p2.outro("Job definition created successfully!");
7423
8413
  }
7424
8414
 
7425
- // src/actions/deviceCodeLogin.ts
7426
- init_cjs_shims();
7427
-
7428
- // src/services/msalAuth.ts
8415
+ // src/actions/jobs/showJobDefinition.ts
7429
8416
  init_cjs_shims();
7430
- var import_common5 = __toESM(require_src());
7431
8417
 
7432
- // src/actions/defaultLogin.ts
8418
+ // src/utils/formatter/outputFormatter.ts
7433
8419
  init_cjs_shims();
7434
- var import_identity = require("@azure/identity");
7435
- var DefaultCredentialProvider = class _DefaultCredentialProvider {
7436
- static instance;
7437
- constructor() {
8420
+ var COLUMN_SEPARATOR = " ";
8421
+ var HEADER_RULE_CHAR = "\u2500";
8422
+ var OutputFormatter = class {
8423
+ format;
8424
+ constructor(options = {}) {
8425
+ this.format = options.output ?? "table";
7438
8426
  }
7439
- static getInstance() {
7440
- if (!_DefaultCredentialProvider.instance) {
7441
- _DefaultCredentialProvider.instance = new _DefaultCredentialProvider();
8427
+ /**
8428
+ * Renders `rows` to stdout using the configured output format.
8429
+ *
8430
+ * @param rows - The data array to render.
8431
+ * @param columns - Column descriptors that define headers and value extractors.
8432
+ */
8433
+ print(rows, columns) {
8434
+ if (this.format === "json") {
8435
+ this.printJson(rows, columns);
8436
+ } else {
8437
+ this.printTable(rows, columns);
7442
8438
  }
7443
- return _DefaultCredentialProvider.instance;
7444
8439
  }
7445
- async getToken(scopes) {
7446
- const credential = new import_identity.DefaultAzureCredential();
7447
- const token = await credential.getToken(scopes);
7448
- if (!token) {
7449
- throw new Error("Failed to acquire token using DefaultAzureCredential.");
8440
+ // ---------------------------------------------------------------------------
8441
+ // Table rendering
8442
+ // ---------------------------------------------------------------------------
8443
+ printTable(rows, columns) {
8444
+ if (rows.length === 0) {
8445
+ console.log("(no results)");
8446
+ return;
7450
8447
  }
7451
- return token;
8448
+ const widths = columns.map((col) => {
8449
+ const cellWidths = rows.map((row) => String(col.key(row) ?? "").length);
8450
+ return Math.max(col.header.length, ...cellWidths);
8451
+ });
8452
+ const header = columns.map((col, i) => col.header.padEnd(widths[i])).join(COLUMN_SEPARATOR);
8453
+ console.log(header);
8454
+ const rule = widths.map((w) => HEADER_RULE_CHAR.repeat(w)).join(COLUMN_SEPARATOR);
8455
+ console.log(rule);
8456
+ for (const row of rows) {
8457
+ const line = columns.map((col, i) => String(col.key(row) ?? "").padEnd(widths[i])).join(COLUMN_SEPARATOR);
8458
+ console.log(line);
8459
+ }
8460
+ }
8461
+ // ---------------------------------------------------------------------------
8462
+ // JSON rendering
8463
+ // ---------------------------------------------------------------------------
8464
+ printJson(rows, columns) {
8465
+ const records = rows.map((row) => {
8466
+ const record = {};
8467
+ for (const col of columns) {
8468
+ const key = col.jsonKey ?? col.header.toLowerCase();
8469
+ const value = col.key(row);
8470
+ record[key] = value ?? null;
8471
+ }
8472
+ return record;
8473
+ });
8474
+ console.log(JSON.stringify(records, null, 2));
7452
8475
  }
7453
8476
  };
7454
8477
 
7455
- // src/services/msalAuth.ts
7456
- var import_os3 = __toESM(require("os"));
7457
- var apiEnv3 = (0, import_common5.getApiEnv)(import_common5.SecurityPlatformEnvironment.Production);
7458
- async function loginAndGetDeviceCodeToken(scopes = [apiEnv3.gatewayAuthResourceUri]) {
7459
- const deviceCodeRequest = {
7460
- scopes,
7461
- deviceCodeCallback: (response) => {
7462
- console.log(response.message);
7463
- }
8478
+ // src/actions/jobs/showJobDefinition.ts
8479
+ var FIELD_COLUMNS = [
8480
+ { header: "FIELD", key: (f) => f.label },
8481
+ { header: "VALUE", key: (f) => f.value }
8482
+ ];
8483
+ function buildJobFields(data) {
8484
+ const fields = [
8485
+ { label: "Name", value: data.jobName },
8486
+ { label: "Description", value: data.jobDescription ?? "" },
8487
+ { label: "Type", value: data.jobType ?? "" },
8488
+ { label: "Job Path", value: data.jobPath },
8489
+ { label: "Cluster", value: data.computeInfo?.nodeSize ? capitalize(data.computeInfo.nodeSize) : "" },
8490
+ { label: "Disabled", value: data.isDisabled ? "Yes" : "No" }
8491
+ ];
8492
+ const schedule = data.scheduleConfig;
8493
+ if (schedule?.isEnabled) {
8494
+ const freq = schedule.repeatFrequency ? capitalize(schedule.repeatFrequency) : "";
8495
+ const interval = schedule.interval ?? 1;
8496
+ fields.push({ label: "Schedule", value: `Every ${interval} ${freq}` });
8497
+ if (schedule.timeTable?.weekDays?.length) {
8498
+ fields.push({ label: "Weekly Days", value: schedule.timeTable.weekDays.join(", ") });
8499
+ }
8500
+ if (schedule.timeTable?.monthDays?.length) {
8501
+ fields.push({ label: "Monthly Days", value: schedule.timeTable.monthDays.join(", ") });
8502
+ }
8503
+ fields.push({ label: "Start Time", value: schedule.startTime ?? "" });
8504
+ fields.push({ label: "End Time", value: schedule.endTime ?? "(indefinite)" });
8505
+ } else {
8506
+ fields.push({ label: "Schedule", value: "On-demand" });
8507
+ }
8508
+ fields.push({ label: "Input Tables", value: data.inputTables?.length ? data.inputTables.join(", ") : "(none)" });
8509
+ fields.push({ label: "Output Tables", value: data.outputTables?.length ? data.outputTables.join(", ") : "(none)" });
8510
+ if (data.runtimeArgs?.length) {
8511
+ fields.push({ label: "Runtime Args", value: data.runtimeArgs.join(", ") });
8512
+ }
8513
+ return fields;
8514
+ }
8515
+ function showJobDefinition(filePath, options) {
8516
+ const data = readJobDefinitionYaml(filePath);
8517
+ const fmt = new OutputFormatter({ output: options.output ?? "table" });
8518
+ const fields = buildJobFields(data);
8519
+ fmt.print(fields, FIELD_COLUMNS);
8520
+ }
8521
+
8522
+ // src/actions/jobs/updateJobDefinition.ts
8523
+ init_cjs_shims();
8524
+ var p3 = __toESM(require("@clack/prompts"));
8525
+ var UPDATABLE_FIELDS = [
8526
+ { value: "description", label: "Description" },
8527
+ { value: "jobPath", label: "Job path" },
8528
+ { value: "cluster", label: "Cluster size" },
8529
+ { value: "schedule", label: "Schedule" },
8530
+ { value: "inputTables", label: "Input tables" },
8531
+ { value: "outputTables", label: "Output tables" },
8532
+ { value: "runtimeArgs", label: "Runtime arguments" }
8533
+ ];
8534
+ async function updateDescription(config) {
8535
+ const result = await p3.text({
8536
+ message: "New description:",
8537
+ defaultValue: config.jobDescription ?? ""
8538
+ });
8539
+ handleCancel(result);
8540
+ config.jobDescription = result;
8541
+ }
8542
+ async function updateJobPath(config) {
8543
+ const result = await p3.text({
8544
+ message: "New job path (.ipynb):",
8545
+ defaultValue: config.jobPath,
8546
+ validate: validateJobPath
8547
+ });
8548
+ handleCancel(result);
8549
+ config.jobPath = result;
8550
+ }
8551
+ async function updateCluster(config) {
8552
+ const result = await p3.select({
8553
+ message: "New cluster size:",
8554
+ options: NODE_SIZE_OPTIONS,
8555
+ initialValue: config.computeInfo?.nodeSize ?? DEFAULT_NODE_SIZE
8556
+ });
8557
+ handleCancel(result);
8558
+ config.computeInfo = { nodeSize: result };
8559
+ }
8560
+ async function updateSchedule(config) {
8561
+ const existing = config.scheduleConfig;
8562
+ const wantsSchedule = await p3.confirm({
8563
+ message: "Enable schedule?",
8564
+ initialValue: existing?.isEnabled ?? true
8565
+ });
8566
+ handleCancel(wantsSchedule);
8567
+ if (!wantsSchedule) {
8568
+ config.scheduleConfig = { isEnabled: false };
8569
+ return;
8570
+ }
8571
+ const frequency = await p3.select({
8572
+ message: "Repeat frequency:",
8573
+ options: FREQUENCY_OPTIONS,
8574
+ initialValue: existing?.repeatFrequency ?? "days"
8575
+ });
8576
+ handleCancel(frequency);
8577
+ const repeatFrequency = frequency;
8578
+ let interval = 1;
8579
+ if (CONFIGURABLE_INTERVAL_FREQUENCIES.has(repeatFrequency)) {
8580
+ const defaultInterval = existing?.interval ?? (repeatFrequency === "minutes" ? 15 : 1);
8581
+ const intervalStr = await p3.text({
8582
+ message: `Interval (${repeatFrequency}):`,
8583
+ defaultValue: String(defaultInterval),
8584
+ validate: validateInterval(repeatFrequency)
8585
+ });
8586
+ handleCancel(intervalStr);
8587
+ interval = Number(intervalStr);
8588
+ }
8589
+ let timeTable;
8590
+ if (repeatFrequency === "weeks") {
8591
+ const existingDays = existing?.timeTable?.weekDays ?? [];
8592
+ const result = await p3.multiselect({
8593
+ message: "Which days of the week?",
8594
+ options: WEEKDAY_OPTIONS.map((opt) => ({
8595
+ ...opt,
8596
+ selected: existingDays.includes(opt.value)
8597
+ })),
8598
+ required: true
8599
+ });
8600
+ handleCancel(result);
8601
+ timeTable = { weekDays: result };
8602
+ }
8603
+ const startTime = await p3.text({
8604
+ message: "Start time (ISO 8601):",
8605
+ defaultValue: existing?.startTime ?? (/* @__PURE__ */ new Date()).toISOString(),
8606
+ validate: validateISODate
8607
+ });
8608
+ handleCancel(startTime);
8609
+ if (repeatFrequency === "months") {
8610
+ const dayOfMonth = new Date(startTime).getDate();
8611
+ timeTable = { monthDays: [dayOfMonth] };
8612
+ }
8613
+ let endTime;
8614
+ const setEndTime = await p3.confirm({
8615
+ message: "Set an end time?",
8616
+ initialValue: !!existing?.endTime
8617
+ });
8618
+ handleCancel(setEndTime);
8619
+ if (setEndTime) {
8620
+ const result = await p3.text({
8621
+ message: "End time (ISO 8601):",
8622
+ defaultValue: existing?.endTime ?? "",
8623
+ validate: validateEndTime(startTime)
8624
+ });
8625
+ handleCancel(result);
8626
+ endTime = result;
8627
+ }
8628
+ config.scheduleConfig = {
8629
+ isEnabled: true,
8630
+ repeatFrequency,
8631
+ interval,
8632
+ startTime,
8633
+ endTime,
8634
+ ...timeTable && { timeTable }
7464
8635
  };
7465
- const msalInstance = await getMsalInstance(apiEnv3);
7466
- const result = await msalInstance.acquireTokenByDeviceCode(deviceCodeRequest);
7467
- if (!result || !result.accessToken) {
7468
- throw new Error("Failed to acquire access token.");
8636
+ }
8637
+ async function updateStringArray(config, field, label) {
8638
+ const current = config[field] ?? [];
8639
+ const result = await p3.text({
8640
+ message: `${label} (comma-separated):`,
8641
+ defaultValue: current.join(", ")
8642
+ });
8643
+ handleCancel(result);
8644
+ const raw = result;
8645
+ config[field] = raw.trim() ? raw.split(",").map((s) => s.trim()) : [];
8646
+ }
8647
+ async function applyFieldUpdate(field, config) {
8648
+ switch (field) {
8649
+ case "description":
8650
+ return updateDescription(config);
8651
+ case "jobPath":
8652
+ return updateJobPath(config);
8653
+ case "cluster":
8654
+ return updateCluster(config);
8655
+ case "schedule":
8656
+ return updateSchedule(config);
8657
+ case "inputTables":
8658
+ return updateStringArray(config, "inputTables", "Input tables");
8659
+ case "outputTables":
8660
+ return updateStringArray(config, "outputTables", "Output tables");
8661
+ case "runtimeArgs":
8662
+ return updateStringArray(config, "runtimeArgs", "Runtime arguments");
7469
8663
  }
7470
- console.log("\u2705 Authenticated using Device Code Flow");
7471
- return result.accessToken;
7472
8664
  }
7473
- async function logout() {
7474
- try {
7475
- const msalInstance = await getMsalInstance(apiEnv3);
7476
- const accounts = await msalInstance.getTokenCache().getAllAccounts();
7477
- if (accounts.length === 0) {
7478
- console.log("\u2139 No cached accounts.");
7479
- return;
7480
- } else {
7481
- await msalInstance.getTokenCache().removeAccount(accounts[0]);
7482
- console.log("\u{1F44B} Logged out successfully.");
8665
+ async function updateJobDefinition(filePath) {
8666
+ p3.intro("Update job definition");
8667
+ const data = readJobDefinitionYaml(filePath);
8668
+ let editing = true;
8669
+ while (editing) {
8670
+ const field = await p3.select({
8671
+ message: "Which field to update?",
8672
+ options: [...UPDATABLE_FIELDS]
8673
+ });
8674
+ handleCancel(field);
8675
+ await applyFieldUpdate(field, data);
8676
+ const again = await p3.confirm({ message: "Update another field?", initialValue: false });
8677
+ handleCancel(again);
8678
+ editing = again;
8679
+ }
8680
+ const result = writeJobDefinitionYaml(filePath, data);
8681
+ if (!result.success) {
8682
+ for (const issue of result.issues) {
8683
+ p3.log.error(issue);
7483
8684
  }
7484
- } catch (error) {
7485
- console.error("\u274C Logout failed:", error instanceof Error ? error.message : "Unknown error");
7486
- } finally {
7487
- deleteBrokerAccount();
8685
+ throw new Error("Validation failed");
7488
8686
  }
8687
+ p3.log.success(`Updated ${filePath}`);
8688
+ p3.outro("Done");
7489
8689
  }
7490
- async function getAccessTokenFromCache(scopes = [apiEnv3.gatewayAuthResourceUri]) {
7491
- if (process.env.CI) {
7492
- const defaultCredentialProvider = DefaultCredentialProvider.getInstance();
7493
- const token = await defaultCredentialProvider.getToken(scopes);
7494
- return token.token;
8690
+
8691
+ // src/utils/error/handleApiError.ts
8692
+ init_cjs_shims();
8693
+ function hasStatusCode(e) {
8694
+ return e instanceof Error && "statusCode" in e && typeof e.statusCode === "number";
8695
+ }
8696
+ function hasResponseStatus(e) {
8697
+ return e instanceof Error && "response" in e && e.response !== null && typeof e.response?.status === "number";
8698
+ }
8699
+ function getStatusInfo(error) {
8700
+ if (hasStatusCode(error)) {
8701
+ return ` (HTTP ${error.statusCode})`;
7495
8702
  }
7496
- const msalInstance = await getMsalInstance(apiEnv3);
7497
- const accounts = await msalInstance.getTokenCache().getAllAccounts();
7498
- console.log("\u{1F510} Checking MSAL cache for tokens...");
7499
- if (accounts.length > 0) {
8703
+ if (hasResponseStatus(error)) {
8704
+ return ` (HTTP ${error.response.status})`;
8705
+ }
8706
+ return "";
8707
+ }
8708
+ function handleApiError(context, error) {
8709
+ if (error instanceof Error) {
8710
+ console.error(`Error ${context}${getStatusInfo(error)}:`, error.message);
8711
+ if (process.env.DEBUG && error.stack) {
8712
+ console.error(error.stack);
8713
+ }
8714
+ process.exitCode = 1;
8715
+ throw error;
8716
+ }
8717
+ const wrapped = new Error(`Unknown error ${context}: ${String(error)}`, { cause: error });
8718
+ console.error(wrapped.message);
8719
+ process.exitCode = 1;
8720
+ throw wrapped;
8721
+ }
8722
+
8723
+ // src/commands/jobs/jobDefinitionCreate.ts
8724
+ function addJobDefinitionCreateCommand(definitionCommand) {
8725
+ definitionCommand.command("create [jobName]").description("Interactively create a job definition YAML file").option("--notebook <path>", "Path to the job file (.ipynb)").option("--description <text>", "Job description").option("--cluster <size>", "Cluster size (small | medium | large)").option("--schedule <frequency>", "Schedule frequency (minutes | hours | days | weeks | months)").option("--interval <number>", "Schedule interval").option("--start-time <datetime>", "Schedule start time (ISO 8601)").option("--end-time <datetime>", "Schedule end time (ISO 8601)").option("--output <path>", "Output YAML file path (default: ./<jobName>.yaml)").action(async (jobName, options) => {
7500
8726
  try {
7501
- const response = await msalInstance.acquireTokenSilent({
7502
- account: accounts[0],
7503
- scopes
7504
- });
7505
- if (response?.accessToken) {
7506
- console.log("\u2705 Authenticated using MSAL cache");
7507
- return response.accessToken;
7508
- }
7509
- console.warn("\u26A0\uFE0F Silent token acquisition returned no access token");
7510
- } catch {
7511
- console.warn("\u26A0\uFE0F Silent token acquisition failed");
8727
+ await createJobDefinition(jobName, options);
8728
+ } catch (error) {
8729
+ handleApiError("creating job definition", error);
8730
+ }
8731
+ });
8732
+ }
8733
+
8734
+ // src/commands/jobs/jobDefinitionShow.ts
8735
+ init_cjs_shims();
8736
+ function addJobDefinitionShowCommand(definitionCommand) {
8737
+ definitionCommand.command("show <path>").description("Display a job definition YAML file").option("--output <format>", "Output format (table | json)", "table").action((filePath, options) => {
8738
+ try {
8739
+ showJobDefinition(filePath, options);
8740
+ } catch (error) {
8741
+ handleApiError("showing job definition", error);
8742
+ }
8743
+ });
8744
+ }
8745
+
8746
+ // src/commands/jobs/jobDefinitionUpdate.ts
8747
+ init_cjs_shims();
8748
+ function addJobDefinitionUpdateCommand(definitionCommand) {
8749
+ definitionCommand.command("update <path>").description("Interactively update a job definition YAML file").action(async (filePath) => {
8750
+ try {
8751
+ await updateJobDefinition(filePath);
8752
+ } catch (error) {
8753
+ handleApiError("updating job definition", error);
7512
8754
  }
8755
+ });
8756
+ }
8757
+
8758
+ // src/commands/jobs/jobDelete.ts
8759
+ init_cjs_shims();
8760
+ var import_common21 = __toESM(require_src());
8761
+
8762
+ // src/services/jobs/index.ts
8763
+ init_cjs_shims();
8764
+
8765
+ // src/services/jobs/jobService.ts
8766
+ init_cjs_shims();
8767
+ var JobService = class {
8768
+ constructor(jobApiClient) {
8769
+ this.jobApiClient = jobApiClient;
8770
+ }
8771
+ async listJobs(accessToken, requestId) {
8772
+ return this.jobApiClient.listJobs(accessToken, requestId);
8773
+ }
8774
+ async getJob(jobName, accessToken, requestId) {
8775
+ return this.jobApiClient.getJob(jobName, accessToken, requestId);
8776
+ }
8777
+ async deleteJob(jobName, accessToken, requestId) {
8778
+ return this.jobApiClient.deleteJob(jobName, accessToken, requestId);
8779
+ }
8780
+ async disableJob(jobName, accessToken, requestId) {
8781
+ return this.jobApiClient.disableJob(jobName, accessToken, requestId);
8782
+ }
8783
+ async enableJob(jobName, accessToken, requestId) {
8784
+ return this.jobApiClient.enableJob(jobName, accessToken, requestId);
8785
+ }
8786
+ async listJobRuns(jobName, accessToken, requestId) {
8787
+ return this.jobApiClient.listJobRuns(jobName, accessToken, requestId);
8788
+ }
8789
+ async getJobRun(jobName, runId, accessToken, requestId) {
8790
+ return this.jobApiClient.getJobRun(jobName, runId, accessToken, requestId);
8791
+ }
8792
+ async startJobRun(jobName, accessToken, requestId) {
8793
+ return this.jobApiClient.startJobRun(jobName, accessToken, requestId);
8794
+ }
8795
+ async cancelJobRun(jobName, runId, accessToken, requestId) {
8796
+ return this.jobApiClient.cancelJobRun(jobName, runId, accessToken, requestId);
8797
+ }
8798
+ };
8799
+
8800
+ // src/services/getToken.ts
8801
+ init_cjs_shims();
8802
+ var import_common17 = __toESM(require_src());
8803
+
8804
+ // src/auth/constants.ts
8805
+ init_cjs_shims();
8806
+
8807
+ // src/auth/provider/TokenProviderFactory.ts
8808
+ init_cjs_shims();
8809
+
8810
+ // src/auth/provider/DeviceCodeTokenProvider.ts
8811
+ init_cjs_shims();
8812
+
8813
+ // src/services/msalAuth.ts
8814
+ init_cjs_shims();
8815
+
8816
+ // src/auth/msalInstance.ts
8817
+ init_cjs_shims();
8818
+ var import_msal_node2 = require("@azure/msal-node");
8819
+
8820
+ // src/config/msalConfig.ts
8821
+ init_cjs_shims();
8822
+ var import_msal_node = require("@azure/msal-node");
8823
+ var import_msal_node_extensions2 = require("@azure/msal-node-extensions");
8824
+
8825
+ // src/auth/persistence/persistence.ts
8826
+ init_cjs_shims();
8827
+ var import_msal_node_extensions = require("@azure/msal-node-extensions");
8828
+ var import_os = __toESM(require("os"));
8829
+ var import_path3 = __toESM(require("path"));
8830
+ var PlatformType = /* @__PURE__ */ ((PlatformType2) => {
8831
+ PlatformType2["Windows"] = "win32";
8832
+ PlatformType2["MacOS"] = "darwin";
8833
+ PlatformType2["Linux"] = "linux";
8834
+ return PlatformType2;
8835
+ })(PlatformType || {});
8836
+ async function createPersistence() {
8837
+ const cacheFilePath = import_path3.default.join(import_os.default.homedir(), ".nsdcli-cache.json");
8838
+ const platform5 = import_os.default.platform();
8839
+ switch (platform5) {
8840
+ case "win32" /* Windows */:
8841
+ return await import_msal_node_extensions.FilePersistenceWithDataProtection.create(cacheFilePath, import_msal_node_extensions.DataProtectionScope.CurrentUser);
8842
+ case "darwin" /* MacOS */:
8843
+ return await import_msal_node_extensions.KeychainPersistence.create("nsdcli.service", "nsdcli.account", "nsdcli");
8844
+ case "linux" /* Linux */:
8845
+ return await import_msal_node_extensions.LibSecretPersistence.create("nsdcli.service", "nsdcli.account", "nsdcli");
8846
+ default:
8847
+ throw new Error(
8848
+ `Unsupported platform: ${platform5}. Supported platforms are: ${Object.values(PlatformType).join(", ")}`
8849
+ );
8850
+ }
8851
+ }
8852
+
8853
+ // src/config/msalConfig.ts
8854
+ var os2 = __toESM(require("os"));
8855
+ async function getMsalConfig(environment, useCachePlugin = true, authorityOverride) {
8856
+ let cachePlugin;
8857
+ if (useCachePlugin) {
8858
+ const persistence = await createPersistence();
8859
+ await persistence.verifyPersistence();
8860
+ cachePlugin = new import_msal_node_extensions2.PersistenceCachePlugin(persistence);
8861
+ }
8862
+ const config = {
8863
+ auth: {
8864
+ clientId: environment.aadClientId,
8865
+ authority: authorityOverride ?? environment.aadEndpoint
8866
+ },
8867
+ cache: cachePlugin ? { cachePlugin } : void 0,
8868
+ system: {
8869
+ loggerOptions: {
8870
+ // Suppress all MSAL internal logs from appearing in CLI output.
8871
+ // MSAL's Info/Verbose messages are library internals not useful to end users.
8872
+ // Only Warning and above are passed to this callback, and we intentionally
8873
+ // discard them to keep the CLI output clean.
8874
+ loggerCallback() {
8875
+ },
8876
+ logLevel: import_msal_node.LogLevel.Warning,
8877
+ piiLoggingEnabled: false
8878
+ }
8879
+ }
8880
+ };
8881
+ if ("win32" /* Windows */ === os2.platform()) {
8882
+ config.broker = {
8883
+ nativeBrokerPlugin: new import_msal_node_extensions2.NativeBrokerPlugin()
8884
+ };
8885
+ }
8886
+ return config;
8887
+ }
8888
+
8889
+ // src/auth/msalInstance.ts
8890
+ var msalInstances = /* @__PURE__ */ new Map();
8891
+ var getMsalInstance = async (env, authorityOverride) => {
8892
+ const key = authorityOverride ?? env.aadEndpoint;
8893
+ if (!msalInstances.has(key)) {
8894
+ const config = await getMsalConfig(env, !process.env.CI, authorityOverride);
8895
+ msalInstances.set(key, new import_msal_node2.PublicClientApplication(config));
8896
+ }
8897
+ return msalInstances.get(key);
8898
+ };
8899
+
8900
+ // src/services/msalAuth.ts
8901
+ var import_common15 = __toESM(require_src());
8902
+
8903
+ // src/actions/defaultLogin.ts
8904
+ init_cjs_shims();
8905
+ var import_identity = require("@azure/identity");
8906
+ var DefaultCredentialProvider = class _DefaultCredentialProvider {
8907
+ static instance;
8908
+ constructor() {
8909
+ }
8910
+ static getInstance() {
8911
+ if (!_DefaultCredentialProvider.instance) {
8912
+ _DefaultCredentialProvider.instance = new _DefaultCredentialProvider();
8913
+ }
8914
+ return _DefaultCredentialProvider.instance;
8915
+ }
8916
+ async getToken(scopes) {
8917
+ const credential = new import_identity.DefaultAzureCredential();
8918
+ const token = await credential.getToken(scopes);
8919
+ if (!token) {
8920
+ throw new Error("Failed to acquire token using DefaultAzureCredential.");
8921
+ }
8922
+ return token;
8923
+ }
8924
+ };
8925
+
8926
+ // src/actions/brokerLogin.ts
8927
+ init_cjs_shims();
8928
+ var import_common14 = __toESM(require_src());
8929
+ var import_fs3 = __toESM(require("fs"));
8930
+ var import_os2 = __toESM(require("os"));
8931
+ var import_path4 = __toESM(require("path"));
8932
+ var apiEnv = (0, import_common14.getApiEnv)(import_common14.SecurityPlatformEnvironment.Production);
8933
+ var SENTINEL_DIR = import_path4.default.join(import_os2.default.homedir(), ".sentinel");
8934
+ var BROKER_ACCOUNT_FILE = import_path4.default.join(SENTINEL_DIR, "broker-account.json");
8935
+ function saveBrokerAccount(account, authority) {
8936
+ import_fs3.default.mkdirSync(SENTINEL_DIR, { recursive: true, mode: 448 });
8937
+ const session = { account, authority };
8938
+ const tempFile = `${BROKER_ACCOUNT_FILE}.tmp`;
8939
+ import_fs3.default.writeFileSync(tempFile, JSON.stringify(session, null, 2), { encoding: "utf8", mode: 384 });
8940
+ import_fs3.default.renameSync(tempFile, BROKER_ACCOUNT_FILE);
8941
+ }
8942
+ function loadBrokerAccount() {
8943
+ try {
8944
+ if (import_fs3.default.existsSync(BROKER_ACCOUNT_FILE)) {
8945
+ const raw = import_fs3.default.readFileSync(BROKER_ACCOUNT_FILE, "utf8");
8946
+ const session = JSON.parse(raw);
8947
+ if (session.account && typeof session.account === "object" && session.authority && typeof session.authority === "string") {
8948
+ return session;
8949
+ }
8950
+ }
8951
+ } catch {
8952
+ }
8953
+ return null;
8954
+ }
8955
+ function deleteBrokerAccount() {
8956
+ try {
8957
+ if (import_fs3.default.existsSync(BROKER_ACCOUNT_FILE)) {
8958
+ import_fs3.default.unlinkSync(BROKER_ACCOUNT_FILE);
8959
+ }
8960
+ } catch {
8961
+ }
8962
+ }
8963
+ async function brokerLogin(scopes, tenant) {
8964
+ const authorityOverride = tenant ? `${new URL(apiEnv.aadEndpoint).origin}/${tenant}` : void 0;
8965
+ const authority = authorityOverride ?? apiEnv.aadEndpoint;
8966
+ const msalInstance = await getMsalInstance(apiEnv, authorityOverride);
8967
+ const savedSession = loadBrokerAccount();
8968
+ const accounts = await msalInstance.getTokenCache().getAllAccounts();
8969
+ if (savedSession) {
8970
+ try {
8971
+ const silentResult = await msalInstance.acquireTokenSilent({
8972
+ account: savedSession.account,
8973
+ scopes,
8974
+ authority: savedSession.authority
8975
+ });
8976
+ if (silentResult?.accessToken) {
8977
+ console.log("\u2705 Authenticated silently via saved broker session.");
8978
+ return silentResult.accessToken;
8979
+ }
8980
+ } catch {
8981
+ console.warn("\u26A0\uFE0F Silent broker authentication with saved session failed. Trying getAllAccounts()...");
8982
+ }
8983
+ }
8984
+ if (accounts.length > 0) {
8985
+ try {
8986
+ const silentResult = await msalInstance.acquireTokenSilent({
8987
+ account: accounts[0],
8988
+ scopes
8989
+ });
8990
+ if (silentResult?.accessToken) {
8991
+ saveBrokerAccount(accounts[0], authority);
8992
+ console.log("\u2705 Authenticated silently via Windows Native Broker (SSO).");
8993
+ return silentResult.accessToken;
8994
+ }
8995
+ } catch {
8996
+ console.warn("\u26A0\uFE0F Silent broker authentication failed. Prompting interactively...");
8997
+ }
8998
+ }
8999
+ const result = await msalInstance.acquireTokenInteractive({
9000
+ scopes,
9001
+ prompt: "select_account",
9002
+ windowHandle: Buffer.alloc(0),
9003
+ // headless / console window handle
9004
+ openBrowser: async (_url) => {
9005
+ }
9006
+ });
9007
+ if (!result?.accessToken) {
9008
+ throw new Error("Failed to acquire token via Windows Native Broker.");
9009
+ }
9010
+ if (result.account) {
9011
+ saveBrokerAccount(result.account, authority);
9012
+ }
9013
+ console.log("\u2705 Authenticated via Windows Native Broker.");
9014
+ return result.accessToken;
9015
+ }
9016
+
9017
+ // src/services/msalAuth.ts
9018
+ var apiEnv2 = (0, import_common15.getApiEnv)(import_common15.SecurityPlatformEnvironment.Production);
9019
+ async function loginAndGetDeviceCodeToken(scopes = [apiEnv2.gatewayAuthResourceUri]) {
9020
+ const deviceCodeRequest = {
9021
+ scopes,
9022
+ deviceCodeCallback: (response) => {
9023
+ console.log(response.message);
9024
+ }
9025
+ };
9026
+ const msalInstance = await getMsalInstance(apiEnv2);
9027
+ const result = await msalInstance.acquireTokenByDeviceCode(deviceCodeRequest);
9028
+ if (!result || !result.accessToken) {
9029
+ throw new Error("Failed to acquire access token.");
9030
+ }
9031
+ console.log("\u2705 Authenticated using Device Code Flow");
9032
+ return result.accessToken;
9033
+ }
9034
+ async function logout() {
9035
+ try {
9036
+ const msalInstance = await getMsalInstance(apiEnv2);
9037
+ const accounts = await msalInstance.getTokenCache().getAllAccounts();
9038
+ if (accounts.length === 0) {
9039
+ console.log("\u2139 No cached accounts.");
9040
+ return;
9041
+ } else {
9042
+ await msalInstance.getTokenCache().removeAccount(accounts[0]);
9043
+ console.log("\u{1F44B} Logged out successfully.");
9044
+ }
9045
+ } catch (error) {
9046
+ console.error("\u274C Logout failed:", error instanceof Error ? error.message : "Unknown error");
9047
+ } finally {
9048
+ deleteBrokerAccount();
9049
+ }
9050
+ }
9051
+ async function getAccessTokenFromCache(scopes = [apiEnv2.gatewayAuthResourceUri]) {
9052
+ if (process.env.CI) {
9053
+ const defaultCredentialProvider = DefaultCredentialProvider.getInstance();
9054
+ const token = await defaultCredentialProvider.getToken(scopes);
9055
+ return token.token;
9056
+ }
9057
+ console.log("\u{1F510} Checking MSAL cache for tokens...");
9058
+ const savedSession = loadBrokerAccount();
9059
+ if (savedSession) {
9060
+ const authoritySegment = (() => {
9061
+ try {
9062
+ return new URL(savedSession.authority).pathname.split("/").filter(Boolean).pop() ?? "";
9063
+ } catch {
9064
+ return "";
9065
+ }
9066
+ })();
9067
+ const expectedTid = authoritySegment && authoritySegment !== "common" && authoritySegment !== "organizations" && authoritySegment !== "consumers" ? authoritySegment : null;
9068
+ try {
9069
+ const sessionMsal = await getMsalInstance(apiEnv2, savedSession.authority);
9070
+ const response = await sessionMsal.acquireTokenSilent({
9071
+ account: savedSession.account,
9072
+ scopes,
9073
+ authority: savedSession.authority
9074
+ });
9075
+ if (response?.accessToken) {
9076
+ if (expectedTid && response.account?.tenantId && response.account.tenantId !== expectedTid) {
9077
+ throw new Error(
9078
+ `Active tenant is ${expectedTid} but silent acquisition returned a token for ${response.account.tenantId}. Run 'sentinel login --tenant ${expectedTid}' (or 'sentinel tenant select') to mint a tenant-bound token.`
9079
+ );
9080
+ }
9081
+ console.log("\u2705 Authenticated using MSAL cache");
9082
+ return response.accessToken;
9083
+ }
9084
+ throw new Error(
9085
+ `Silent token acquisition returned no access token for the active tenant${expectedTid ? ` (${expectedTid})` : ""}. Run 'sentinel login${expectedTid ? ` --tenant ${expectedTid}` : ""}' to refresh credentials.`
9086
+ );
9087
+ } catch (err) {
9088
+ throw err instanceof Error ? err : new Error(`Silent token acquisition failed: ${String(err)}`);
9089
+ }
9090
+ }
9091
+ const msalInstance = await getMsalInstance(apiEnv2);
9092
+ const accounts = await msalInstance.getTokenCache().getAllAccounts();
9093
+ if (accounts.length > 0) {
9094
+ try {
9095
+ const response = await msalInstance.acquireTokenSilent({
9096
+ account: accounts[0],
9097
+ scopes
9098
+ });
9099
+ if (response?.accessToken) {
9100
+ console.log("\u2705 Authenticated using MSAL cache");
9101
+ return response.accessToken;
9102
+ }
9103
+ console.warn("\u26A0\uFE0F Silent token acquisition returned no access token");
9104
+ } catch {
9105
+ console.warn("\u26A0\uFE0F Silent token acquisition failed");
9106
+ }
9107
+ }
9108
+ return "";
9109
+ }
9110
+
9111
+ // src/auth/provider/DeviceCodeTokenProvider.ts
9112
+ var DeviceCodeTokenProvider = class {
9113
+ options;
9114
+ env;
9115
+ constructor(env, options) {
9116
+ if (!env) {
9117
+ throw new Error("Environment cannot be null or undefined");
9118
+ }
9119
+ this.env = env;
9120
+ this.options = {
9121
+ ...options,
9122
+ // overrides defaults if user provided values
9123
+ scopes: options?.scopes ?? [this.env.gatewayAuthResourceUri]
9124
+ };
9125
+ }
9126
+ async getAccessToken() {
9127
+ let token = await getAccessTokenFromCache(this.options?.scopes);
9128
+ if (token) {
9129
+ return token;
9130
+ }
9131
+ token = await loginAndGetDeviceCodeToken(this.options?.scopes);
9132
+ return token;
9133
+ }
9134
+ };
9135
+
9136
+ // src/auth/provider/ManagedIdentityTokenProvider.ts
9137
+ init_cjs_shims();
9138
+ var import_identity2 = require("@azure/identity");
9139
+ var ManagedIdentityTokenProvider = class {
9140
+ options;
9141
+ env;
9142
+ constructor(env, options) {
9143
+ if (!env) {
9144
+ throw new Error("Environment cannot be null or undefined");
9145
+ }
9146
+ if (!options?.uamiClientId) {
9147
+ throw new Error("UAMI clientId required for user-assigned managed identity");
9148
+ }
9149
+ this.env = env;
9150
+ this.options = {
9151
+ ...options,
9152
+ // overrides defaults if user provided values
9153
+ scopes: options?.scopes ?? [env.gatewayAuthResourceUri]
9154
+ };
9155
+ }
9156
+ async getAccessToken() {
9157
+ const scopes = this.options?.scopes && this.options.scopes.length > 0 ? this.options.scopes : [this.env.gatewayAuthResourceUri];
9158
+ const credential = new import_identity2.ManagedIdentityCredential({
9159
+ clientId: this.options?.uamiClientId
9160
+ });
9161
+ const token = await credential.getToken(scopes);
9162
+ if (!token) {
9163
+ throw new Error("Failed to get token from Managed Identity");
9164
+ }
9165
+ return token.token;
9166
+ }
9167
+ };
9168
+
9169
+ // src/auth/provider/MsalCacheTokenProvider.ts
9170
+ init_cjs_shims();
9171
+ var MsalCacheTokenProvider = class {
9172
+ options;
9173
+ env;
9174
+ constructor(env, options) {
9175
+ if (!env) {
9176
+ throw new Error("Environment cannot be null or undefined");
9177
+ }
9178
+ this.env = env;
9179
+ this.options = {
9180
+ ...options,
9181
+ scopes: options?.scopes?.length ? options.scopes : [this.env.gatewayAuthResourceUri]
9182
+ };
9183
+ }
9184
+ async getAccessToken() {
9185
+ const token = await getAccessTokenFromCache(this.options.scopes);
9186
+ if (!token) {
9187
+ throw new Error("No cached authentication token found. Please run `sentinel login` first.");
9188
+ }
9189
+ return token;
9190
+ }
9191
+ };
9192
+
9193
+ // src/auth/provider/TokenProviderFactory.ts
9194
+ var TokenProviderFactory = class {
9195
+ static createProvider(env, method, options) {
9196
+ switch (method) {
9197
+ case "device_code":
9198
+ return new DeviceCodeTokenProvider(env, options);
9199
+ case "managed_identity":
9200
+ if (!options) {
9201
+ throw new Error("UAMI clientId required for user-assigned managed identity");
9202
+ }
9203
+ return new ManagedIdentityTokenProvider(env, options);
9204
+ case "msal_cache":
9205
+ return new MsalCacheTokenProvider(env, options);
9206
+ default:
9207
+ throw new Error(`Unsupported token method: ${method}`);
9208
+ }
9209
+ }
9210
+ };
9211
+
9212
+ // src/telemetry/index.ts
9213
+ init_cjs_shims();
9214
+
9215
+ // src/telemetry/telemetryService.ts
9216
+ init_cjs_shims();
9217
+ var import_common16 = __toESM(require_src());
9218
+ var import_api = require("@opentelemetry/api");
9219
+ var import_monitor_opentelemetry = require("@azure/monitor-opentelemetry");
9220
+
9221
+ // src/telemetry/connectionString.ts
9222
+ init_cjs_shims();
9223
+ var APPLICATION_INSIGHTS_CONNECTION_STRING = "InstrumentationKey=0dadb494-ecd4-44a5-bcc1-baa55b3778be;IngestionEndpoint=https://eastus-8.in.applicationinsights.azure.com/;LiveEndpoint=https://eastus.livediagnostics.monitor.azure.com/;ApplicationId=8bc9c85a-22a3-45f8-b4f5-0bb6cd6ddad2";
9224
+
9225
+ // src/telemetry/types.ts
9226
+ init_cjs_shims();
9227
+ var TELEMETRY_OPT_OUT_ENV_VARS = ["SENTINEL_TELEMETRY_OPTOUT", "DO_NOT_TRACK"];
9228
+
9229
+ // src/telemetry/commonProperties.ts
9230
+ init_cjs_shims();
9231
+ var os4 = __toESM(require("os"));
9232
+ var import_uuid = require("uuid");
9233
+ function readAppVersion() {
9234
+ return true ? "0.3.0" : "unknown";
9235
+ }
9236
+ function detectCiEnvironment(env = process.env) {
9237
+ if (env.TF_BUILD) {
9238
+ return "AzureDevOps";
9239
+ }
9240
+ if (env.GITHUB_ACTIONS) {
9241
+ return "GitHubActions";
9242
+ }
9243
+ if (env.BUILD_BUILDID) {
9244
+ return "AzureDevOps";
9245
+ }
9246
+ if (env.JENKINS_URL) {
9247
+ return "Jenkins";
9248
+ }
9249
+ if (env.CIRCLECI) {
9250
+ return "CircleCI";
9251
+ }
9252
+ if (env.GITLAB_CI) {
9253
+ return "GitLab";
9254
+ }
9255
+ if (env.CI) {
9256
+ return "Generic";
9257
+ }
9258
+ return "unknown";
9259
+ }
9260
+ function buildCommonProperties(sessionId = (0, import_uuid.v4)()) {
9261
+ return {
9262
+ appName: "sentinel-cli",
9263
+ appVersion: readAppVersion(),
9264
+ nodeVersion: process.versions.node,
9265
+ platform: process.platform,
9266
+ arch: process.arch,
9267
+ osRelease: os4.release(),
9268
+ sessionId,
9269
+ ciEnvironment: detectCiEnvironment()
9270
+ };
9271
+ }
9272
+
9273
+ // src/telemetry/redact.ts
9274
+ init_cjs_shims();
9275
+ var EMAIL_RE = /[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}/gi;
9276
+ var GUID_RE = /\b[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\b/gi;
9277
+ var JWT_RE = /(?<![A-Za-z0-9_-])eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}(?![A-Za-z0-9_-])/g;
9278
+ var UNIX_PATH_RE = /(?<![A-Za-z0-9_./\\-])(?:\/[^\s]+\/([^\s/]+)|\/([^\s/]+))/g;
9279
+ var WIN_PATH_RE = /(?<![A-Za-z0-9_./\\-])(?:[a-zA-Z]:\\[^\s]+\\([^\s\\]+)|[a-zA-Z]:\\([^\s\\]+))/g;
9280
+ function redactString(input) {
9281
+ if (!input) {
9282
+ return input;
9283
+ }
9284
+ return input.replace(JWT_RE, "<jwt>").replace(EMAIL_RE, "<email>").replace(GUID_RE, "<guid>").replace(UNIX_PATH_RE, (_m, deepBase, rootBase) => `<redacted>/${deepBase ?? rootBase}`).replace(WIN_PATH_RE, (_m, deepBase, rootBase) => `<redacted>\\${deepBase ?? rootBase}`);
9285
+ }
9286
+ function redactError(error) {
9287
+ const name = error.name || "Error";
9288
+ const message = redactString(error.message ?? "");
9289
+ const stack = error.stack ? error.stack.split("\n").slice(0, 4).map((line) => redactString(line)).join("\n") : "";
9290
+ return {
9291
+ errorName: name,
9292
+ errorMessage: message,
9293
+ errorStack: stack
9294
+ };
9295
+ }
9296
+
9297
+ // src/telemetry/telemetryService.ts
9298
+ var TRACER_NAME = "sentinel-cli";
9299
+ var TRACER_VERSION = "1.0.0";
9300
+ var azureMonitorInitialized = false;
9301
+ var TelemetryService = class _TelemetryService {
9302
+ sharedProperties = {};
9303
+ commonProperties;
9304
+ enabled;
9305
+ initialized = false;
9306
+ disposed = false;
9307
+ tracer;
9308
+ constructor(options = {}) {
9309
+ this.enabled = _TelemetryService.resolveEnabled(options);
9310
+ this.commonProperties = buildCommonProperties(options.sessionId);
9311
+ if (this.enabled) {
9312
+ this.initialize(options.connectionString ?? APPLICATION_INSIGHTS_CONNECTION_STRING);
9313
+ }
9314
+ }
9315
+ /** Determine whether telemetry should be active for this process. */
9316
+ static resolveEnabled(options) {
9317
+ if (options.forceDisabled) {
9318
+ return false;
9319
+ }
9320
+ for (const name of TELEMETRY_OPT_OUT_ENV_VARS) {
9321
+ if (process.env[name] === "1" || process.env[name]?.toLowerCase() === "true") {
9322
+ return false;
9323
+ }
9324
+ }
9325
+ return true;
9326
+ }
9327
+ /**
9328
+ * Initialise the Azure Monitor OpenTelemetry distro exactly once per
9329
+ * process, then acquire this instance's tracer. `useAzureMonitor()`
9330
+ * installs global SDK state (TracerProvider, exporters, processors), so
9331
+ * it is guarded by a module-level flag; `trace.getTracer()` is cheap and
9332
+ * idempotent so it is safe to call for every instance.
9333
+ *
9334
+ * Resource configuration is applied via OpenTelemetry env vars, set
9335
+ * programmatically *before* `useAzureMonitor()` so they're observed by
9336
+ * the SDK's resource-detection bootstrap:
9337
+ *
9338
+ * - `OTEL_NODE_RESOURCE_DETECTORS` — restricted to `env,os,serviceinstance`
9339
+ * so the `HostDetector` is **never** registered. This suppresses
9340
+ * `host.name` (device hostname, PII like `User-MacBook-Pro.local`),
9341
+ * `host.id` (stable hardware fingerprint), and `host.arch`.
9342
+ * - `OTEL_SERVICE_NAME` — populates `service.name`, which Azure Monitor
9343
+ * maps to `cloud_RoleName`. Without this, the backend records the OTel
9344
+ * default `"unknown_service:node"`.
9345
+ * - `OTEL_RESOURCE_ATTRIBUTES` — adds `service.version` (no dedicated env
9346
+ * var exists for it).
9347
+ *
9348
+ * Each variable is set with `??=` so any caller-provided override (e.g.
9349
+ * tests, advanced users) wins.
9350
+ */
9351
+ initialize(connectionString) {
9352
+ if (!azureMonitorInitialized) {
9353
+ process.env.OTEL_NODE_RESOURCE_DETECTORS ??= "env,os,serviceinstance";
9354
+ process.env.OTEL_SERVICE_NAME ??= TRACER_NAME;
9355
+ process.env.OTEL_RESOURCE_ATTRIBUTES ??= `service.version=${TRACER_VERSION}`;
9356
+ (0, import_monitor_opentelemetry.useAzureMonitor)({
9357
+ azureMonitorExporterOptions: { connectionString },
9358
+ tracesPerSecond: 0,
9359
+ samplingRatio: 1
9360
+ });
9361
+ azureMonitorInitialized = true;
9362
+ }
9363
+ this.tracer = import_api.trace.getTracer(TRACER_NAME, TRACER_VERSION);
9364
+ this.initialized = true;
9365
+ }
9366
+ /**
9367
+ * Merge common + shared + caller-supplied properties into a flat
9368
+ * {@link Attributes} bag suitable for an OTel span. Primitive values
9369
+ * (`number`, `boolean`) are passed through unchanged so that downstream
9370
+ * Azure Monitor / Log Analytics queries see their native types instead
9371
+ * of stringified versions (which would break numeric aggregations and
9372
+ * boolean comparisons).
9373
+ */
9374
+ mergeAttributes(extra) {
9375
+ const result = {
9376
+ ...this.commonProperties,
9377
+ ...this.sharedProperties
9378
+ };
9379
+ if (extra) {
9380
+ for (const [key, value] of Object.entries(extra)) {
9381
+ if (value === void 0) {
9382
+ continue;
9383
+ }
9384
+ result[key] = value;
9385
+ }
9386
+ }
9387
+ return result;
9388
+ }
9389
+ event(eventName, data) {
9390
+ if (!this.enabled || this.disposed || !this.tracer) {
9391
+ return;
9392
+ }
9393
+ const span = this.tracer.startSpan(eventName, {
9394
+ attributes: this.mergeAttributes(data?.properties)
9395
+ });
9396
+ if (data?.measurements) {
9397
+ for (const [k, v] of Object.entries(data.measurements)) {
9398
+ span.setAttribute(k, v);
9399
+ }
9400
+ }
9401
+ span.end();
9402
+ }
9403
+ span(eventName, initialAttributes) {
9404
+ if (!this.enabled || this.disposed || !this.tracer) {
9405
+ return new NoopSpanContext(eventName, initialAttributes);
9406
+ }
9407
+ return new TelemetrySpanContext(
9408
+ this.tracer,
9409
+ eventName,
9410
+ initialAttributes,
9411
+ (extras) => this.mergeAttributes(extras)
9412
+ );
9413
+ }
9414
+ setSharedProperty(name, value) {
9415
+ if (value === void 0) {
9416
+ delete this.sharedProperties[name];
9417
+ } else {
9418
+ this.sharedProperties[name] = value;
9419
+ }
9420
+ }
9421
+ getSharedProperties() {
9422
+ return { ...this.sharedProperties };
9423
+ }
9424
+ async dispose() {
9425
+ if (this.disposed) {
9426
+ return;
9427
+ }
9428
+ this.disposed = true;
9429
+ if (!this.enabled || !this.initialized) {
9430
+ return;
9431
+ }
9432
+ try {
9433
+ await (0, import_monitor_opentelemetry.shutdownAzureMonitor)();
9434
+ } catch {
9435
+ } finally {
9436
+ this.tracer = void 0;
9437
+ azureMonitorInitialized = false;
9438
+ }
9439
+ }
9440
+ };
9441
+ var TelemetrySpanContext = class {
9442
+ startTime = Date.now();
9443
+ eventName;
9444
+ attributes;
9445
+ otSpan;
9446
+ requestId;
9447
+ mergeAttributes;
9448
+ ended = false;
9449
+ constructor(tracer, eventName, initialAttributes, mergeAttributes) {
9450
+ this.eventName = eventName;
9451
+ this.attributes = { ...initialAttributes ?? {} };
9452
+ this.requestId = this.attributes.requestId ?? import_common16.CorrelationService.createCorrelationContext();
9453
+ this.attributes.requestId = this.requestId;
9454
+ this.mergeAttributes = mergeAttributes;
9455
+ this.otSpan = tracer.startSpan(eventName, {
9456
+ attributes: this.mergeAttributes(this.attributes)
9457
+ });
9458
+ }
9459
+ getRequestId() {
9460
+ return this.requestId;
9461
+ }
9462
+ addAttributes(extra) {
9463
+ this.applyAttributes(extra);
9464
+ }
9465
+ end(extra) {
9466
+ if (this.ended) {
9467
+ return;
9468
+ }
9469
+ this.applyAttributes(extra);
9470
+ this.finalize();
9471
+ }
9472
+ error(err, extra) {
9473
+ if (this.ended) {
9474
+ return;
9475
+ }
9476
+ const redacted = redactError(err);
9477
+ this.applyAttributes({ ...extra, ...redacted, success: false });
9478
+ const sanitized = new Error(redacted.errorMessage);
9479
+ sanitized.name = redacted.errorName;
9480
+ sanitized.stack = redacted.errorStack;
9481
+ this.otSpan.recordException(sanitized);
9482
+ this.otSpan.setStatus({ code: import_api.SpanStatusCode.ERROR, message: redacted.errorMessage });
9483
+ this.finalize();
9484
+ }
9485
+ /**
9486
+ * Merge non-undefined entries into both the local bag and the OTel span.
9487
+ * Values keep their native primitive type (`string | number | boolean`)
9488
+ * so the backing SDK records typed attributes rather than stringified ones.
9489
+ */
9490
+ applyAttributes(extra) {
9491
+ if (!extra) {
9492
+ return;
9493
+ }
9494
+ for (const [k, v] of Object.entries(extra)) {
9495
+ if (v === void 0) {
9496
+ continue;
9497
+ }
9498
+ this.attributes[k] = v;
9499
+ this.otSpan.setAttribute(k, v);
9500
+ }
9501
+ }
9502
+ /** Stamp duration, close the OTel span, and flip the ended flag. */
9503
+ finalize() {
9504
+ this.ended = true;
9505
+ const finalAttrs = this.mergeAttributes(this.attributes);
9506
+ for (const [k, v] of Object.entries(finalAttrs)) {
9507
+ if (v !== void 0) {
9508
+ this.otSpan.setAttribute(k, v);
9509
+ }
9510
+ }
9511
+ this.otSpan.setAttribute("durationMs", Date.now() - this.startTime);
9512
+ this.otSpan.end();
9513
+ }
9514
+ };
9515
+ var NoopSpanContext = class {
9516
+ startTime = Date.now();
9517
+ eventName;
9518
+ attributes;
9519
+ requestId;
9520
+ constructor(eventName, initialAttributes) {
9521
+ this.eventName = eventName;
9522
+ this.attributes = { ...initialAttributes ?? {} };
9523
+ this.requestId = this.attributes.requestId ?? import_common16.CorrelationService.createCorrelationContext();
9524
+ this.attributes.requestId = this.requestId;
9525
+ }
9526
+ getRequestId() {
9527
+ return this.requestId;
9528
+ }
9529
+ addAttributes(extra) {
9530
+ for (const [k, v] of Object.entries(extra)) {
9531
+ if (v !== void 0) {
9532
+ this.attributes[k] = v;
9533
+ }
9534
+ }
9535
+ }
9536
+ end() {
9537
+ }
9538
+ error() {
9539
+ }
9540
+ };
9541
+
9542
+ // src/telemetry/index.ts
9543
+ var singleton;
9544
+ function getTelemetry(options) {
9545
+ if (!singleton) {
9546
+ singleton = new TelemetryService(options);
9547
+ }
9548
+ return singleton;
9549
+ }
9550
+
9551
+ // src/services/getToken.ts
9552
+ async function getToken(env, scopes, clientId) {
9553
+ let provider = null;
9554
+ const options = {
9555
+ uamiClientId: clientId,
9556
+ scopes
9557
+ };
9558
+ if (clientId) {
9559
+ provider = TokenProviderFactory.createProvider(env, "managed_identity" /* ManagedIdentity */, options);
9560
+ } else {
9561
+ provider = TokenProviderFactory.createProvider(env, "msal_cache" /* MsalCache */, options);
9562
+ }
9563
+ const token = await provider.getAccessToken();
9564
+ stampTenantTelemetry(token);
9565
+ return token;
9566
+ }
9567
+ function stampTenantTelemetry(token) {
9568
+ try {
9569
+ const tenantId = (0, import_common17.extractTenantId)(token);
9570
+ getTelemetry().setSharedProperty("tenantId", tenantId || "");
9571
+ } catch {
9572
+ }
9573
+ }
9574
+
9575
+ // src/client/jobs/index.ts
9576
+ init_cjs_shims();
9577
+ var import_common19 = __toESM(require_src());
9578
+
9579
+ // src/utils/headerBuilder.ts
9580
+ init_cjs_shims();
9581
+ var import_common18 = __toESM(require_src());
9582
+ function buildApiHeaders(token, requestId, extra) {
9583
+ const base = {};
9584
+ if (requestId) {
9585
+ base[import_common18.HTTP_HEADER.REQUEST_ID] = requestId;
9586
+ }
9587
+ if (!extra || !(import_common18.HTTP_HEADER.CONTENT_TYPE in extra)) {
9588
+ base[import_common18.HTTP_HEADER.CONTENT_TYPE] = import_common18.HTTP_HEADER.APPLICATION_JSON;
9589
+ }
9590
+ if (token) {
9591
+ base[import_common18.HTTP_HEADER.AUTHORIZATION] = `${import_common18.HTTP_HEADER.BEARER_PREFIX}${token}`;
9592
+ }
9593
+ const merged = { ...base, ...extra || {} };
9594
+ return Object.fromEntries(
9595
+ Object.entries(merged).filter((entry) => entry[1] !== void 0)
9596
+ );
9597
+ }
9598
+
9599
+ // src/utils/noopTelemetry.ts
9600
+ init_cjs_shims();
9601
+ var noopSpan = {
9602
+ addAttributes: () => {
9603
+ },
9604
+ end: () => {
9605
+ },
9606
+ error: () => {
9607
+ }
9608
+ };
9609
+ var noopTelemetry = {
9610
+ span: () => noopSpan
9611
+ };
9612
+
9613
+ // src/client/jobs/index.ts
9614
+ function createJobApiClient(env, region) {
9615
+ const requestService = new import_common19.RequestService(noopTelemetry, buildApiHeaders);
9616
+ return new import_common19.JobApiClient({
9617
+ requestService,
9618
+ baseUrl: env.regions[region].gatewayEndpoint
9619
+ });
9620
+ }
9621
+
9622
+ // src/utils/parseRegion.ts
9623
+ init_cjs_shims();
9624
+ var import_common20 = __toESM(require_src());
9625
+ function parseRegion(value) {
9626
+ if (Object.values(import_common20.Region).includes(value)) {
9627
+ return value;
9628
+ }
9629
+ throw new Error(`Invalid region "${value}". Valid regions: ${Object.values(import_common20.Region).join(", ")}`);
9630
+ }
9631
+
9632
+ // src/commands/jobs/jobDelete.ts
9633
+ function addJobDeleteCommand(jobCommand) {
9634
+ jobCommand.command("delete <jobName>").description("Delete a scheduled job").option("-r, --region <region>", "Target region (default: global)", import_common21.Region.Global).action(async (jobName, options) => {
9635
+ try {
9636
+ const apiEnv4 = (0, import_common21.getApiEnv)(import_common21.SecurityPlatformEnvironment.Production);
9637
+ const accessToken = await getToken(apiEnv4);
9638
+ const region = parseRegion(options.region);
9639
+ const jobApiClient = createJobApiClient(apiEnv4, region);
9640
+ const jobService = new JobService(jobApiClient);
9641
+ await deleteJob(jobService, accessToken, jobName);
9642
+ console.log(`Job "${jobName}" deleted successfully.`);
9643
+ } catch (error) {
9644
+ handleApiError("deleting job", error);
9645
+ }
9646
+ });
9647
+ }
9648
+
9649
+ // src/commands/jobs/jobDisable.ts
9650
+ init_cjs_shims();
9651
+ var import_common22 = __toESM(require_src());
9652
+ function addJobDisableCommand(jobCommand) {
9653
+ jobCommand.command("disable <jobName>").description("Disable a scheduled job").option("-r, --region <region>", "Target region (default: global)", import_common22.Region.Global).action(async (jobName, options) => {
9654
+ try {
9655
+ const apiEnv4 = (0, import_common22.getApiEnv)(import_common22.SecurityPlatformEnvironment.Production);
9656
+ const accessToken = await getToken(apiEnv4);
9657
+ const region = parseRegion(options.region);
9658
+ const jobApiClient = createJobApiClient(apiEnv4, region);
9659
+ const jobService = new JobService(jobApiClient);
9660
+ await disableJob(jobService, accessToken, jobName);
9661
+ console.log(`Job "${jobName}" disabled successfully.`);
9662
+ } catch (error) {
9663
+ handleApiError("disabling job", error);
9664
+ }
9665
+ });
9666
+ }
9667
+
9668
+ // src/commands/jobs/jobDownload.ts
9669
+ init_cjs_shims();
9670
+ var import_common23 = __toESM(require_src());
9671
+ function addJobDownloadCommand(jobCommand) {
9672
+ jobCommand.command("download <jobName>").description("Download the notebook of a scheduled job").option("-o, --output <path>", "Output file path (defaults to <jobName>.ipynb)").option("-r, --region <region>", "Target region (default: global)", import_common23.Region.Global).action(async (jobName, options) => {
9673
+ try {
9674
+ const apiEnv4 = (0, import_common23.getApiEnv)(import_common23.SecurityPlatformEnvironment.Production);
9675
+ const accessToken = await getToken(apiEnv4);
9676
+ const region = parseRegion(options.region);
9677
+ const jobApiClient = createJobApiClient(apiEnv4, region);
9678
+ const jobService = new JobService(jobApiClient);
9679
+ const writtenPath = await downloadJob(jobService, accessToken, jobName, options.output);
9680
+ console.log(`Notebook downloaded to: ${writtenPath}`);
9681
+ } catch (error) {
9682
+ handleApiError("downloading job notebook", error);
9683
+ }
9684
+ });
9685
+ }
9686
+
9687
+ // src/commands/jobs/jobEnable.ts
9688
+ init_cjs_shims();
9689
+ var import_common24 = __toESM(require_src());
9690
+ function addJobEnableCommand(jobCommand) {
9691
+ jobCommand.command("enable <jobName>").description("Enable a scheduled job").option("-r, --region <region>", "Target region (default: global)", import_common24.Region.Global).action(async (jobName, options) => {
9692
+ try {
9693
+ const apiEnv4 = (0, import_common24.getApiEnv)(import_common24.SecurityPlatformEnvironment.Production);
9694
+ const accessToken = await getToken(apiEnv4);
9695
+ const region = parseRegion(options.region);
9696
+ const jobApiClient = createJobApiClient(apiEnv4, region);
9697
+ const jobService = new JobService(jobApiClient);
9698
+ await enableJob(jobService, accessToken, jobName);
9699
+ console.log(`Job "${jobName}" enabled successfully.`);
9700
+ } catch (error) {
9701
+ handleApiError("enabling job", error);
9702
+ }
9703
+ });
9704
+ }
9705
+
9706
+ // src/commands/jobs/jobList.ts
9707
+ init_cjs_shims();
9708
+ var import_common25 = __toESM(require_src());
9709
+ var JOB_COLUMNS = [
9710
+ { header: "NAME", key: (j) => j.jobName },
9711
+ { header: "TYPE", key: (j) => j.jobType },
9712
+ { header: "DISABLED", key: (j) => String(j.isDisabled) }
9713
+ ];
9714
+ function addJobListCommand(jobCommand) {
9715
+ jobCommand.command("list").description("List all scheduled jobs").option("-r, --region <region>", "Target region (default: global)", import_common25.Region.Global).action(async (options) => {
9716
+ try {
9717
+ const apiEnv4 = (0, import_common25.getApiEnv)(import_common25.SecurityPlatformEnvironment.Production);
9718
+ const accessToken = await getToken(apiEnv4);
9719
+ const region = parseRegion(options.region);
9720
+ const jobApiClient = createJobApiClient(apiEnv4, region);
9721
+ const jobService = new JobService(jobApiClient);
9722
+ const jobs = await listJobs(jobService, accessToken);
9723
+ const fmt = new OutputFormatter();
9724
+ fmt.print(jobs, JOB_COLUMNS);
9725
+ } catch (error) {
9726
+ handleApiError("listing jobs", error);
9727
+ }
9728
+ });
9729
+ }
9730
+
9731
+ // src/commands/jobs/jobRunCancel.ts
9732
+ init_cjs_shims();
9733
+ var import_common26 = __toESM(require_src());
9734
+ function addJobRunCancelCommand(runCommand) {
9735
+ runCommand.command("cancel <jobName> <runId>").description("Cancel a specific job run").option("-r, --region <region>", "Target region (default: global)", import_common26.Region.Global).action(async (jobName, runId, options) => {
9736
+ try {
9737
+ const apiEnv4 = (0, import_common26.getApiEnv)(import_common26.SecurityPlatformEnvironment.Production);
9738
+ const accessToken = await getToken(apiEnv4);
9739
+ const region = parseRegion(options.region);
9740
+ const jobApiClient = createJobApiClient(apiEnv4, region);
9741
+ const jobService = new JobService(jobApiClient);
9742
+ await cancelJobRun(jobService, accessToken, jobName, runId);
9743
+ console.log(`Run "${runId}" for job "${jobName}" cancelled successfully.`);
9744
+ } catch (error) {
9745
+ handleApiError("cancelling job run", error);
9746
+ }
9747
+ });
9748
+ }
9749
+
9750
+ // src/commands/jobs/jobRunList.ts
9751
+ init_cjs_shims();
9752
+ var import_common27 = __toESM(require_src());
9753
+ var RUN_COLUMNS = [
9754
+ { header: "RUN ID", key: (r) => r.jobRunId ?? "" },
9755
+ { header: "STATUS", key: (r) => r.status ?? "" },
9756
+ { header: "STARTED", key: (r) => r.startTime ?? "" },
9757
+ { header: "ENDED", key: (r) => r.endTime ?? "" }
9758
+ ];
9759
+ function addJobRunListCommand(runCommand) {
9760
+ runCommand.command("list <jobName>").description("List all runs for a scheduled job").option("-r, --region <region>", "Target region (default: global)", import_common27.Region.Global).action(async (jobName, options) => {
9761
+ try {
9762
+ const apiEnv4 = (0, import_common27.getApiEnv)(import_common27.SecurityPlatformEnvironment.Production);
9763
+ const accessToken = await getToken(apiEnv4);
9764
+ const region = parseRegion(options.region);
9765
+ const jobApiClient = createJobApiClient(apiEnv4, region);
9766
+ const jobService = new JobService(jobApiClient);
9767
+ const runs = await listJobRuns(jobService, accessToken, jobName);
9768
+ const fmt = new OutputFormatter();
9769
+ fmt.print(runs, RUN_COLUMNS);
9770
+ } catch (error) {
9771
+ handleApiError("listing job runs", error);
9772
+ }
9773
+ });
9774
+ }
9775
+
9776
+ // src/commands/jobs/jobRunNotebookDownload.ts
9777
+ init_cjs_shims();
9778
+ var import_common28 = __toESM(require_src());
9779
+ function addJobRunNotebookDownloadCommand(notebookCommand) {
9780
+ notebookCommand.command("download <jobName> <runId>").description("Download the notebook snapshot of a job run").option("-o, --output <path>", "Output file path (defaults to <jobName>_<runId>.ipynb)").option("-r, --region <region>", "Target region (default: global)", import_common28.Region.Global).action(async (jobName, runId, options) => {
9781
+ try {
9782
+ const apiEnv4 = (0, import_common28.getApiEnv)(import_common28.SecurityPlatformEnvironment.Production);
9783
+ const accessToken = await getToken(apiEnv4);
9784
+ const region = parseRegion(options.region);
9785
+ const jobApiClient = createJobApiClient(apiEnv4, region);
9786
+ const jobService = new JobService(jobApiClient);
9787
+ const writtenPath = await downloadJobRunNotebook(jobService, accessToken, jobName, runId, options.output);
9788
+ console.log(`Notebook downloaded to: ${writtenPath}`);
9789
+ } catch (error) {
9790
+ handleApiError("downloading job run notebook", error);
9791
+ }
9792
+ });
9793
+ }
9794
+
9795
+ // src/commands/jobs/jobRunShow.ts
9796
+ init_cjs_shims();
9797
+ var import_common29 = __toESM(require_src());
9798
+ var RUN_DETAIL_COLUMNS = [
9799
+ { header: "FIELD", key: (f) => f.label },
9800
+ { header: "VALUE", key: (f) => f.value }
9801
+ ];
9802
+ function addJobRunShowCommand(runCommand) {
9803
+ runCommand.command("show <jobName> <runId>").description("Show the details of a job run").option("-r, --region <region>", "Target region (default: global)", import_common29.Region.Global).action(async (jobName, runId, options) => {
9804
+ try {
9805
+ const apiEnv4 = (0, import_common29.getApiEnv)(import_common29.SecurityPlatformEnvironment.Production);
9806
+ const accessToken = await getToken(apiEnv4);
9807
+ const region = parseRegion(options.region);
9808
+ const jobApiClient = createJobApiClient(apiEnv4, region);
9809
+ const jobService = new JobService(jobApiClient);
9810
+ const run = await getJobRun(jobService, accessToken, jobName, runId);
9811
+ printRunDetails(run);
9812
+ } catch (error) {
9813
+ handleApiError("showing job run", error);
9814
+ }
9815
+ });
9816
+ }
9817
+ function printRunDetails(run) {
9818
+ const fields = [
9819
+ { label: "Run ID", value: run.jobRunId ?? "" },
9820
+ { label: "Status", value: run.status ?? "" },
9821
+ { label: "Schedule", value: run.scheduleName ?? "" },
9822
+ { label: "Started", value: run.startTime ?? "" },
9823
+ { label: "Ended", value: run.endTime ?? "" },
9824
+ { label: "Error", value: run.error?.errorMessage ?? "" }
9825
+ ];
9826
+ const fmt = new OutputFormatter();
9827
+ fmt.print(fields, RUN_DETAIL_COLUMNS);
9828
+ }
9829
+
9830
+ // src/commands/jobs/jobRunStart.ts
9831
+ init_cjs_shims();
9832
+ var import_common30 = __toESM(require_src());
9833
+ function addJobRunStartCommand(runCommand) {
9834
+ runCommand.command("start <jobName>").description("Start an ad-hoc run of a scheduled job").option("-r, --region <region>", "Target region (default: global)", import_common30.Region.Global).action(async (jobName, options) => {
9835
+ try {
9836
+ const apiEnv4 = (0, import_common30.getApiEnv)(import_common30.SecurityPlatformEnvironment.Production);
9837
+ const accessToken = await getToken(apiEnv4);
9838
+ const region = parseRegion(options.region);
9839
+ const jobApiClient = createJobApiClient(apiEnv4, region);
9840
+ const jobService = new JobService(jobApiClient);
9841
+ const run = await startJobRun(jobService, accessToken, jobName);
9842
+ console.log(`Job run started. Run ID: ${run.jobRunId ?? "(unknown)"}`);
9843
+ } catch (error) {
9844
+ handleApiError("starting job run", error);
9845
+ }
9846
+ });
9847
+ }
9848
+
9849
+ // src/commands/jobs/jobShow.ts
9850
+ init_cjs_shims();
9851
+ var import_common31 = __toESM(require_src());
9852
+ var JOB_DETAIL_COLUMNS = [
9853
+ { header: "FIELD", key: (f) => f.label },
9854
+ { header: "VALUE", key: (f) => f.value }
9855
+ ];
9856
+ function addJobShowCommand(jobCommand) {
9857
+ jobCommand.command("show <jobName>").description("Show the details of a scheduled job").option("-r, --region <region>", "Target region (default: global)", import_common31.Region.Global).action(async (jobName, options) => {
9858
+ try {
9859
+ const apiEnv4 = (0, import_common31.getApiEnv)(import_common31.SecurityPlatformEnvironment.Production);
9860
+ const accessToken = await getToken(apiEnv4);
9861
+ const region = parseRegion(options.region);
9862
+ const jobApiClient = createJobApiClient(apiEnv4, region);
9863
+ const jobService = new JobService(jobApiClient);
9864
+ const job = await getJob(jobService, accessToken, jobName);
9865
+ printJobDetails(job);
9866
+ } catch (error) {
9867
+ handleApiError("showing job", error);
9868
+ }
9869
+ });
9870
+ }
9871
+ function printJobDetails(job) {
9872
+ const def = job.jobDefinition;
9873
+ const fields = [
9874
+ { label: "Name", value: def.jobName ?? "" },
9875
+ { label: "Type", value: def.jobType ?? "" },
9876
+ { label: "Disabled", value: String(def.isDisabled ?? false) },
9877
+ { label: "Description", value: def.description ?? "" },
9878
+ { label: "Spark Pool", value: def.computeInfo?.friendlyName ?? "" },
9879
+ { label: "Created At", value: def.createdAt ?? "" },
9880
+ { label: "Last Updated At", value: def.lastUpdatedAt ?? "" }
9881
+ ];
9882
+ const fmt = new OutputFormatter();
9883
+ fmt.print(fields, JOB_DETAIL_COLUMNS);
9884
+ }
9885
+
9886
+ // src/commands/lake/database.ts
9887
+ init_cjs_shims();
9888
+ var import_common36 = __toESM(require_src());
9889
+
9890
+ // src/actions/lake/index.ts
9891
+ init_cjs_shims();
9892
+
9893
+ // src/actions/lake/listDatabases.ts
9894
+ init_cjs_shims();
9895
+ var import_common32 = __toESM(require_src());
9896
+ async function listDatabases(databaseService, accessToken) {
9897
+ const requestId = import_common32.CorrelationService.createCorrelationContext();
9898
+ console.info("Fetching databases...");
9899
+ return databaseService.listDatabases(accessToken, requestId);
9900
+ }
9901
+
9902
+ // src/actions/lake/listTables.ts
9903
+ init_cjs_shims();
9904
+ var import_common33 = __toESM(require_src());
9905
+ async function listTables(tableService, accessToken, database) {
9906
+ const requestId = import_common33.CorrelationService.createCorrelationContext();
9907
+ const scope = database ? ` for database "${database.databaseName}"` : "";
9908
+ console.info(`Fetching lake tables${scope}...`);
9909
+ return tableService.listTables(accessToken, requestId, database);
9910
+ }
9911
+
9912
+ // src/services/lake/index.ts
9913
+ init_cjs_shims();
9914
+
9915
+ // src/services/lake/databaseService.ts
9916
+ init_cjs_shims();
9917
+ var DatabaseService = class {
9918
+ constructor(lakeApiClient) {
9919
+ this.lakeApiClient = lakeApiClient;
9920
+ }
9921
+ async listDatabases(accessToken, requestId) {
9922
+ return this.lakeApiClient.fetchDatabases(accessToken, requestId);
9923
+ }
9924
+ };
9925
+
9926
+ // src/services/lake/tableService.ts
9927
+ init_cjs_shims();
9928
+ var TableService = class {
9929
+ constructor(lakeApiClient) {
9930
+ this.lakeApiClient = lakeApiClient;
9931
+ }
9932
+ async listTables(accessToken, requestId, database) {
9933
+ return this.lakeApiClient.fetchLakeTables(accessToken, requestId, database);
9934
+ }
9935
+ };
9936
+
9937
+ // src/services/lake/databaseLookup.ts
9938
+ init_cjs_shims();
9939
+ var SYSTEM_TABLES_DISPLAY_NAME = "System tables";
9940
+ var DEFAULT_DATABASE = { databaseName: "default" };
9941
+ async function lookupDatabase(options, lakeApiClient, accessToken) {
9942
+ if (options.databaseId) {
9943
+ if (options.databaseId === SYSTEM_TABLES_DISPLAY_NAME) {
9944
+ return DEFAULT_DATABASE;
9945
+ }
9946
+ return lookupDatabaseById(options.databaseId, lakeApiClient, accessToken);
9947
+ }
9948
+ if (options.databaseName) {
9949
+ if (options.databaseName === SYSTEM_TABLES_DISPLAY_NAME) {
9950
+ return DEFAULT_DATABASE;
9951
+ }
9952
+ return lookupDatabaseByName(options.databaseName, lakeApiClient, accessToken);
9953
+ }
9954
+ return void 0;
9955
+ }
9956
+ async function lookupDatabaseById(databaseId, lakeApiClient, accessToken) {
9957
+ const databaseService = new DatabaseService(lakeApiClient);
9958
+ const databases = await listDatabases(databaseService, accessToken);
9959
+ const match = databases.find((db) => db.databaseName === databaseId);
9960
+ if (!match) {
9961
+ console.error(
9962
+ `Error: database "${databaseId}" not found. Run "sentinel database list" to see available databases.`
9963
+ );
9964
+ process.exit(1);
9965
+ }
9966
+ return match;
9967
+ }
9968
+ async function lookupDatabaseByName(databaseName, lakeApiClient, accessToken) {
9969
+ const databaseService = new DatabaseService(lakeApiClient);
9970
+ const databases = await listDatabases(databaseService, accessToken);
9971
+ const match = databases.find((db) => db.sentinelWorkspace?.name === databaseName);
9972
+ if (!match) {
9973
+ console.error(
9974
+ `Error: database "${databaseName}" not found. Run "sentinel database list" to see available databases.`
9975
+ );
9976
+ process.exit(1);
9977
+ }
9978
+ return match;
9979
+ }
9980
+
9981
+ // src/client/lake/index.ts
9982
+ init_cjs_shims();
9983
+ var import_common34 = __toESM(require_src());
9984
+ function createLakeApiClient(env) {
9985
+ const requestService = new import_common34.RequestService(noopTelemetry, buildApiHeaders);
9986
+ return new import_common34.LakeApiClient({
9987
+ requestService,
9988
+ telemetry: noopTelemetry,
9989
+ baseUrl: env.gatewayEndpoint
9990
+ });
9991
+ }
9992
+
9993
+ // src/telemetry/events.ts
9994
+ init_cjs_shims();
9995
+ var CliEvents = {
9996
+ /** Fired exactly once per CLI process, before Commander parses argv. */
9997
+ Invoked: "cli.invoked",
9998
+ // Top-level commands
9999
+ Login: "cli.login",
10000
+ Logout: "cli.logout",
10001
+ Token: "cli.token",
10002
+ Update: "cli.update",
10003
+ // `package` group
10004
+ PackageCreateZip: "cli.package.createzip",
10005
+ PackageValidate: "cli.package.validate",
10006
+ // `job` group
10007
+ JobPublish: "cli.job.publish",
10008
+ // `database` group
10009
+ DatabaseList: "cli.database.list",
10010
+ // `table` group
10011
+ TableList: "cli.table.list",
10012
+ TableShow: "cli.table.show"
10013
+ };
10014
+
10015
+ // src/telemetry/withCommandSpan.ts
10016
+ init_cjs_shims();
10017
+
10018
+ // src/telemetry/commandInterceptor.ts
10019
+ init_cjs_shims();
10020
+ var ATTACHED_FLAG = /* @__PURE__ */ Symbol.for("sentinel.cli.commandTelemetryAttached");
10021
+ function buildCommandPath(cmd) {
10022
+ const segments = [];
10023
+ let cursor = cmd;
10024
+ while (cursor) {
10025
+ segments.unshift(cursor.name());
10026
+ cursor = cursor.parent ?? null;
10027
+ }
10028
+ segments.shift();
10029
+ return segments.join(".");
10030
+ }
10031
+ function buildCommandInvokedAttributes(cmd) {
10032
+ const path8 = buildCommandPath(cmd);
10033
+ const segments = path8.split(".");
10034
+ const command = segments[0];
10035
+ const subcommand = segments.length > 1 ? segments[segments.length - 1] : "";
10036
+ return {
10037
+ command,
10038
+ subcommand,
10039
+ commandPath: path8
10040
+ };
10041
+ }
10042
+ function attachCommandTelemetry(program2, telemetry2) {
10043
+ const flagged = program2;
10044
+ if (flagged[ATTACHED_FLAG]) {
10045
+ return;
10046
+ }
10047
+ flagged[ATTACHED_FLAG] = true;
10048
+ program2.hook("preAction", (_thisCommand, actionCommand) => {
10049
+ try {
10050
+ const attrs = buildCommandInvokedAttributes(actionCommand);
10051
+ telemetry2.event("Command.Invoked", { properties: attrs });
10052
+ } catch {
10053
+ }
10054
+ });
10055
+ }
10056
+
10057
+ // src/telemetry/errorContext.ts
10058
+ init_cjs_shims();
10059
+ var import_common35 = __toESM(require_src());
10060
+ function isObject(v) {
10061
+ return typeof v === "object" && v !== null;
10062
+ }
10063
+ function extractErrorProperties(error) {
10064
+ const err = error instanceof Error ? error : new Error(String(error));
10065
+ const redacted = redactError(err);
10066
+ const props = {
10067
+ errorName: redacted.errorName,
10068
+ errorMessage: redacted.errorMessage,
10069
+ errorStack: redacted.errorStack,
10070
+ isException: "true"
10071
+ };
10072
+ if (!isObject(error)) {
10073
+ return props;
10074
+ }
10075
+ const axiosErr = error;
10076
+ if (!axiosErr.response) {
10077
+ return props;
10078
+ }
10079
+ props.status = axiosErr.response.status !== void 0 ? String(axiosErr.response.status) : "unknown";
10080
+ const method = axiosErr.config?.method;
10081
+ props.method = typeof method === "string" ? method.toUpperCase() : "unknown";
10082
+ const url = axiosErr.config?.url;
10083
+ props.url = typeof url === "string" ? url : "unknown";
10084
+ const correlationId = import_common35.CorrelationService.extractCorrelationId(axiosErr.response);
10085
+ if (correlationId) {
10086
+ props.correlationId = correlationId;
10087
+ }
10088
+ return props;
10089
+ }
10090
+ function toTelemetryProperties(props) {
10091
+ const out = {
10092
+ errorName: props.errorName,
10093
+ errorMessage: props.errorMessage,
10094
+ errorStack: props.errorStack,
10095
+ isException: props.isException
10096
+ };
10097
+ if (props.status !== void 0) {
10098
+ out.status = props.status;
10099
+ }
10100
+ if (props.method !== void 0) {
10101
+ out.method = props.method;
10102
+ }
10103
+ if (props.url !== void 0) {
10104
+ out.url = props.url;
10105
+ }
10106
+ if (props.correlationId !== void 0) {
10107
+ out.correlationId = props.correlationId;
10108
+ }
10109
+ return out;
10110
+ }
10111
+
10112
+ // src/telemetry/withCommandSpan.ts
10113
+ function withCommandSpan(eventName, handler, telemetry2) {
10114
+ return async (...args) => {
10115
+ let span;
10116
+ try {
10117
+ const command = extractCommand(args);
10118
+ const initialAttributes = command ? buildCommandInvokedAttributes(command) : void 0;
10119
+ const svc = telemetry2 ?? getTelemetry();
10120
+ span = svc.span(eventName, initialAttributes);
10121
+ } catch {
10122
+ span = void 0;
10123
+ }
10124
+ let success = true;
10125
+ try {
10126
+ await handler(...args);
10127
+ } catch (err) {
10128
+ success = false;
10129
+ const props = extractErrorProperties(err);
10130
+ safeError(span, err, toTelemetryProperties(props));
10131
+ throw err;
10132
+ } finally {
10133
+ safeAddAttributes(span, { success });
10134
+ safeEnd(span);
10135
+ }
10136
+ };
10137
+ }
10138
+ function extractCommand(args) {
10139
+ const last = args[args.length - 1];
10140
+ if (last && typeof last === "object" && typeof last.name === "function") {
10141
+ return last;
10142
+ }
10143
+ return void 0;
10144
+ }
10145
+ function safeAddAttributes(span, extra) {
10146
+ if (!span) {
10147
+ return;
10148
+ }
10149
+ try {
10150
+ span.addAttributes(extra);
10151
+ } catch {
10152
+ }
10153
+ }
10154
+ function safeEnd(span, extra) {
10155
+ if (!span) {
10156
+ return;
10157
+ }
10158
+ try {
10159
+ span.end(extra);
10160
+ } catch {
10161
+ }
10162
+ }
10163
+ function safeError(span, err, extra) {
10164
+ if (!span) {
10165
+ return;
10166
+ }
10167
+ try {
10168
+ span.error(err instanceof Error ? err : new Error(String(err)), extra);
10169
+ } catch {
10170
+ }
10171
+ }
10172
+
10173
+ // src/commands/lake/database.ts
10174
+ function addDatabaseCommand(databaseCommand) {
10175
+ databaseCommand.command("list").description("List all available databases").action(
10176
+ withCommandSpan(CliEvents.DatabaseList, async () => {
10177
+ try {
10178
+ const apiEnv4 = (0, import_common36.getApiEnv)(import_common36.SecurityPlatformEnvironment.Production);
10179
+ const accessToken = await getToken(apiEnv4);
10180
+ const lakeApiClient = createLakeApiClient(apiEnv4);
10181
+ const databaseService = new DatabaseService(lakeApiClient);
10182
+ const databases = await listDatabases(databaseService, accessToken);
10183
+ const fmt = new OutputFormatter();
10184
+ fmt.print(databases, [
10185
+ { header: "ID", key: (db) => db.databaseName === "default" ? "System tables" : db.databaseName },
10186
+ {
10187
+ header: "NAME",
10188
+ key: (db) => db.databaseName === "default" ? "System tables" : db.sentinelWorkspace?.name ?? ""
10189
+ }
10190
+ ]);
10191
+ } catch (error) {
10192
+ handleApiError("listing databases", error);
10193
+ }
10194
+ })
10195
+ );
10196
+ }
10197
+
10198
+ // src/commands/lake/lakeTables.ts
10199
+ init_cjs_shims();
10200
+ var import_common37 = __toESM(require_src());
10201
+ var TABLE_COLUMNS = [
10202
+ { header: "TABLE", key: (t) => t.name ?? "" },
10203
+ {
10204
+ header: "DATABASE NAME",
10205
+ key: (t) => t.sgWorkspaceName === "default" ? SYSTEM_TABLES_DISPLAY_NAME : t.sgWorkspaceName ?? ""
10206
+ },
10207
+ { header: "CATEGORY", key: (t) => t.category ?? "" }
10208
+ ];
10209
+ function addLakeTableListCommand(tableCommand) {
10210
+ tableCommand.command("list").description("List lake tables").option("--database-id <databaseId>", "Database ID to fetch tables").option("--database-name <databaseName>", "Database name to fetch tables").action(
10211
+ withCommandSpan(CliEvents.TableList, async (options) => {
10212
+ try {
10213
+ validateOptions(options);
10214
+ const apiEnv4 = (0, import_common37.getApiEnv)(import_common37.SecurityPlatformEnvironment.Production);
10215
+ const accessToken = await getToken(apiEnv4);
10216
+ const lakeApiClient = createLakeApiClient(apiEnv4);
10217
+ const database = await lookupDatabase(options, lakeApiClient, accessToken);
10218
+ const tableService = new TableService(lakeApiClient);
10219
+ const tables = await listTables(tableService, accessToken, database);
10220
+ printTables(tables);
10221
+ } catch (error) {
10222
+ handleApiError("listing lake tables", error);
10223
+ }
10224
+ })
10225
+ );
10226
+ }
10227
+ function validateOptions(options) {
10228
+ if (options.databaseId && options.databaseName) {
10229
+ throw new Error("--database-id and --database-name are mutually exclusive. Provide only one.");
7513
10230
  }
7514
- if (import_os3.default.platform() === "win32" /* Windows */) {
7515
- const session = loadBrokerAccount();
7516
- if (session) {
10231
+ }
10232
+ function printTables(tables) {
10233
+ const fmt = new OutputFormatter();
10234
+ fmt.print(tables, TABLE_COLUMNS);
10235
+ }
10236
+
10237
+ // src/commands/lake/lakeTableSchema.ts
10238
+ init_cjs_shims();
10239
+ var import_common38 = __toESM(require_src());
10240
+ var SCHEMA_COLUMNS = [
10241
+ { header: "COLUMN", key: (col) => col.name },
10242
+ { header: "TYPE", key: (col) => col.type }
10243
+ ];
10244
+ function addLakeTableShowCommand(tableCommand) {
10245
+ tableCommand.command("show <tableName>").description("Show the schema of a lake table").option("--database-id <databaseId>", "Database ID to look up the table in").option("--database-name <databaseName>", "Database name to look up the table in").action(
10246
+ withCommandSpan(CliEvents.TableShow, async (tableName, options) => {
7517
10247
  try {
7518
- const brokerInstance = await getMsalInstance(apiEnv3, session.authority);
7519
- const response = await brokerInstance.acquireTokenSilent({
7520
- account: session.account,
7521
- scopes
7522
- });
7523
- if (response?.accessToken) {
7524
- console.log("\u2705 Authenticated using Windows Native Broker (WAM) cache");
7525
- return response.accessToken;
10248
+ validateOptions2(options);
10249
+ const apiEnv4 = (0, import_common38.getApiEnv)(import_common38.SecurityPlatformEnvironment.Production);
10250
+ const accessToken = await getToken(apiEnv4);
10251
+ const lakeApiClient = createLakeApiClient(apiEnv4);
10252
+ const database = await lookupDatabase(options, lakeApiClient, accessToken) ?? DEFAULT_DATABASE;
10253
+ const tableService = new TableService(lakeApiClient);
10254
+ const tables = await listTables(tableService, accessToken, database);
10255
+ const table = findTable(tables, tableName);
10256
+ if (!table) {
10257
+ console.error(
10258
+ `Error: table "${tableName}" not found. Run "sentinel table list" to see available tables.`
10259
+ );
10260
+ throw new Error(`Table not found: ${tableName}`);
7526
10261
  }
7527
- } catch {
7528
- console.warn("\u26A0\uFE0F Silent WAM token acquisition failed");
10262
+ printSchema(table);
10263
+ } catch (error) {
10264
+ handleApiError("showing lake table schema", error);
7529
10265
  }
7530
- }
10266
+ })
10267
+ );
10268
+ }
10269
+ function validateOptions2(options) {
10270
+ if (options.databaseId && options.databaseName) {
10271
+ throw new Error("--database-id and --database-name are mutually exclusive. Provide only one.");
7531
10272
  }
7532
- return "";
10273
+ }
10274
+ function findTable(tables, tableName) {
10275
+ const lowerName = tableName.toLowerCase();
10276
+ return tables.find((t) => t.name?.toLowerCase() === lowerName);
10277
+ }
10278
+ function printSchema(table) {
10279
+ const fmt = new OutputFormatter();
10280
+ fmt.print(table.schema, SCHEMA_COLUMNS);
10281
+ }
10282
+
10283
+ // src/commands/login.ts
10284
+ init_cjs_shims();
10285
+ var os5 = __toESM(require("os"));
10286
+
10287
+ // src/actions/authCodeLogin.ts
10288
+ init_cjs_shims();
10289
+ var import_child_process = require("child_process");
10290
+ var import_common39 = __toESM(require_src());
10291
+ var apiEnv3 = (0, import_common39.getApiEnv)(import_common39.SecurityPlatformEnvironment.Production);
10292
+ function openSystemBrowser(url) {
10293
+ return new Promise((resolve2, reject) => {
10294
+ const command = process.platform === "darwin" ? "open" : "xdg-open";
10295
+ (0, import_child_process.execFile)(command, [url], (error) => {
10296
+ if (error) {
10297
+ reject(new Error(`Failed to open browser: ${error.message}`));
10298
+ } else {
10299
+ resolve2();
10300
+ }
10301
+ });
10302
+ });
10303
+ }
10304
+ async function browserAuthLogin(scopes, tenant) {
10305
+ const authorityOverride = tenant ? `${new URL(apiEnv3.aadEndpoint).origin}/${encodeURIComponent(tenant)}` : void 0;
10306
+ const authority = authorityOverride ?? apiEnv3.aadEndpoint;
10307
+ const msalInstance = await getMsalInstance(apiEnv3, authorityOverride);
10308
+ console.log("\u{1F510} Starting browser login. A browser window will open.");
10309
+ const result = await msalInstance.acquireTokenInteractive({
10310
+ scopes,
10311
+ prompt: "select_account",
10312
+ openBrowser: openSystemBrowser,
10313
+ successTemplate: "<h1>Authentication successful</h1><p>You may close this tab and return to the terminal.</p>",
10314
+ errorTemplate: "<h1>Authentication failed</h1><p>{error}</p>"
10315
+ });
10316
+ if (!result?.accessToken) {
10317
+ throw new Error("Token acquisition failed: received null or empty token.");
10318
+ }
10319
+ if (result.account) {
10320
+ saveBrokerAccount(result.account, authority);
10321
+ }
10322
+ console.log("\u{1F511} Token acquired successfully.");
10323
+ return result.accessToken;
7533
10324
  }
7534
10325
 
7535
10326
  // src/actions/deviceCodeLogin.ts
10327
+ init_cjs_shims();
7536
10328
  async function login(scopes) {
7537
10329
  await loginAndGetDeviceCodeToken(scopes);
7538
10330
  }
7539
10331
 
7540
10332
  // src/actions/managedIdentityLogin.ts
7541
10333
  init_cjs_shims();
7542
- var import_identity2 = require("@azure/identity");
10334
+ var import_identity3 = require("@azure/identity");
7543
10335
  async function getTokenManagedIdentity(options) {
7544
10336
  const { scope, clientId, objectId, resourceId, workload } = options;
7545
10337
  let credential;
7546
10338
  try {
7547
10339
  if (workload) {
7548
10340
  console.log("\u{1F510} Using WorkloadIdentityCredential...");
7549
- credential = new import_identity2.WorkloadIdentityCredential();
10341
+ credential = new import_identity3.WorkloadIdentityCredential();
7550
10342
  } else if (clientId) {
7551
10343
  console.log("\u{1F510} Using ManagedIdentityCredential with Client ID...");
7552
- credential = new import_identity2.ManagedIdentityCredential(clientId);
10344
+ credential = new import_identity3.ManagedIdentityCredential(clientId);
7553
10345
  } else if (objectId) {
7554
10346
  console.log("\u{1F510} Using ManagedIdentityCredential with Object ID...");
7555
- credential = new import_identity2.ManagedIdentityCredential({ objectId });
10347
+ credential = new import_identity3.ManagedIdentityCredential({ objectId });
7556
10348
  } else if (resourceId) {
7557
10349
  console.log("\u{1F510} Using ManagedIdentityCredential with Resource ID...");
7558
- credential = new import_identity2.ManagedIdentityCredential({ resourceId });
10350
+ credential = new import_identity3.ManagedIdentityCredential({ resourceId });
7559
10351
  } else {
7560
10352
  throw new Error("No managed identity parameters provided.");
7561
10353
  }
@@ -7627,7 +10419,7 @@ function loginCommand(program2) {
7627
10419
  console.log("\u2705 Logged in via Windows Native Broker.");
7628
10420
  } else {
7629
10421
  console.log("\u{1F310} Launching Browser Authentication (Auth Code Flow)...");
7630
- await browserAuthLogin(scope);
10422
+ await browserAuthLogin(scope, tenant);
7631
10423
  console.log("\u2705 Logged in using Browser Authentication.");
7632
10424
  }
7633
10425
  } catch (error) {
@@ -7657,215 +10449,244 @@ function logoutCommand(program2) {
7657
10449
 
7658
10450
  // src/commands/publishJob.ts
7659
10451
  init_cjs_shims();
7660
- var import_common8 = __toESM(require_src());
7661
- var import_path4 = __toESM(require("path"));
10452
+ var import_common41 = __toESM(require_src());
10453
+ var import_path6 = __toESM(require("path"));
7662
10454
 
7663
10455
  // src/actions/publishJob.ts
7664
10456
  init_cjs_shims();
7665
- var import_common6 = __toESM(require_src());
7666
- var fs2 = __toESM(require("fs"));
7667
- var import_path3 = __toESM(require("path"));
7668
- var YAML = __toESM(require("yaml"));
10457
+ var import_common40 = __toESM(require_src());
10458
+ var fs6 = __toESM(require("fs"));
10459
+ var import_path5 = __toESM(require("path"));
10460
+ var YAML2 = __toESM(require("yaml"));
7669
10461
  function parseJobConfig(jobConfigPath) {
7670
- const jobConfigContent = fs2.readFileSync(jobConfigPath, "utf-8");
7671
- const ext = import_path3.default.extname(jobConfigPath);
10462
+ const jobConfigContent = fs6.readFileSync(jobConfigPath, "utf-8");
10463
+ const ext = import_path5.default.extname(jobConfigPath);
7672
10464
  switch (ext) {
7673
10465
  case ".json":
7674
10466
  return JSON.parse(jobConfigContent);
7675
10467
  case ".yaml":
7676
10468
  case ".yml":
7677
- return YAML.parse(jobConfigContent);
10469
+ return YAML2.parse(jobConfigContent);
7678
10470
  default:
7679
10471
  throw new Error(`Unsupported file extension: ${ext}`);
7680
10472
  }
7681
10473
  }
7682
- async function publish(notebookPath, jobConfigPath, jobService) {
7683
- if (!fs2.existsSync(notebookPath)) {
10474
+ async function publish(notebookPath, jobConfigPath, jobClient, accessToken) {
10475
+ if (!fs6.existsSync(notebookPath)) {
7684
10476
  console.error(`File not found: ${notebookPath}`);
7685
10477
  throw new Error(`File not found: ${notebookPath}`);
7686
10478
  }
7687
- if (!fs2.existsSync(jobConfigPath)) {
10479
+ if (!fs6.existsSync(jobConfigPath)) {
7688
10480
  console.error(`File not found: ${jobConfigPath}`);
7689
10481
  throw new Error(`File not found: ${jobConfigPath}`);
7690
10482
  }
7691
- const notebookBase64 = fs2.readFileSync(notebookPath).toString("base64");
10483
+ const requestId = import_common40.CorrelationService.createCorrelationContext();
10484
+ const notebookBase64 = fs6.readFileSync(notebookPath).toString("base64");
7692
10485
  const jobConfig = parseJobConfig(jobConfigPath);
7693
- const payload = (0, import_common6.buildCompleteJobPayload)(jobConfig, notebookBase64);
10486
+ const payload = (0, import_common40.buildCompleteJobPayload)(jobConfig, notebookBase64);
7694
10487
  const jobName = jobConfig.jobName;
7695
- await jobService.createJob(jobName, payload);
10488
+ await jobClient.createJob(jobName, payload, accessToken, requestId);
7696
10489
  return jobName;
7697
10490
  }
7698
10491
 
7699
- // src/utils/httpServiceUtils.ts
7700
- init_cjs_shims();
7701
- var import_common7 = __toESM(require_src());
7702
- var import_axios = __toESM(require("axios"));
7703
-
7704
- // src/services/getToken.ts
7705
- init_cjs_shims();
10492
+ // src/commands/publishJob.ts
10493
+ function addPublishCommand(jobCommand) {
10494
+ jobCommand.command("publish <notebookPath>").description("Publish a scheduled job.").option("-c, --config <path>", "Path to job YAML config").option("-r, --region <region>", "Target region (e.g. eastus2)", import_common41.Region.Global).action(async (notebookPath, options) => {
10495
+ try {
10496
+ const resolvedNotebookPath = import_path6.default.resolve(notebookPath);
10497
+ const resolvedConfigPath = import_path6.default.resolve(options.config);
10498
+ const apiEnv4 = (0, import_common41.getApiEnv)(import_common41.SecurityPlatformEnvironment.Production);
10499
+ const region = options.region;
10500
+ const accessToken = await getToken(apiEnv4);
10501
+ const jobApiClient = createJobApiClient(apiEnv4, region);
10502
+ const result = await publish(resolvedNotebookPath, resolvedConfigPath, jobApiClient, accessToken);
10503
+ console.log("Published job:", result);
10504
+ } catch (error) {
10505
+ handleApiError("publishing job", error);
10506
+ }
10507
+ });
10508
+ }
7706
10509
 
7707
- // src/auth/constants.ts
10510
+ // src/commands/tenant/tenantList.ts
7708
10511
  init_cjs_shims();
10512
+ var import_common43 = __toESM(require_src());
7709
10513
 
7710
- // src/auth/provider/TokenProviderFactory.ts
10514
+ // src/services/tenant/index.ts
7711
10515
  init_cjs_shims();
7712
10516
 
7713
- // src/auth/provider/DeviceCodeTokenProvider.ts
10517
+ // src/services/tenant/tenantService.ts
7714
10518
  init_cjs_shims();
7715
- var DeviceCodeTokenProvider = class {
7716
- options;
7717
- env;
7718
- constructor(env, options) {
7719
- if (!env) {
7720
- throw new Error("Environment cannot be null or undefined");
7721
- }
7722
- this.env = env;
7723
- this.options = {
7724
- ...options,
7725
- // overrides defaults if user provided values
7726
- scopes: options?.scopes ?? [this.env.gatewayAuthResourceUri]
7727
- };
10519
+ var import_common42 = __toESM(require_src());
10520
+ var TenantService = class {
10521
+ constructor(requestService, armEndpoint) {
10522
+ this.requestService = requestService;
10523
+ this.armEndpoint = armEndpoint;
7728
10524
  }
7729
- async getAccessToken() {
7730
- let token = await getAccessTokenFromCache(this.options?.scopes);
7731
- if (token) {
7732
- return token;
7733
- }
7734
- token = await loginAndGetDeviceCodeToken(this.options?.scopes);
7735
- return token;
10525
+ /**
10526
+ * Fetches all tenants accessible to the authenticated user from ARM.
10527
+ *
10528
+ * @param accessToken - A valid ARM bearer access token.
10529
+ * @returns An array of {@link ArmTenant} objects.
10530
+ */
10531
+ async fetchAllTenants(accessToken) {
10532
+ const client = new import_common42.TenantApiClient({ requestService: this.requestService, armEndpoint: this.armEndpoint });
10533
+ return client.fetchAllTenants(accessToken);
7736
10534
  }
7737
10535
  };
7738
10536
 
7739
- // src/auth/provider/ManagedIdentityTokenProvider.ts
7740
- init_cjs_shims();
7741
- var import_identity3 = require("@azure/identity");
7742
- var ManagedIdentityTokenProvider = class {
7743
- options;
7744
- env;
7745
- constructor(env, options) {
7746
- if (!env) {
7747
- throw new Error("Environment cannot be null or undefined");
7748
- }
7749
- if (!options?.uamiClientId) {
7750
- throw new Error("UAMI clientId required for user-assigned managed identity");
7751
- }
7752
- this.env = env;
7753
- this.options = {
7754
- ...options,
7755
- // overrides defaults if user provided values
7756
- scopes: options?.scopes ?? [env.gatewayAuthResourceUri]
7757
- };
7758
- }
7759
- async getAccessToken() {
7760
- const scopes = this.options?.scopes && this.options.scopes.length > 0 ? this.options.scopes : [this.env.gatewayAuthResourceUri];
7761
- const credential = new import_identity3.ManagedIdentityCredential({
7762
- clientId: this.options?.uamiClientId
7763
- });
7764
- const token = await credential.getToken(scopes);
7765
- if (!token) {
7766
- throw new Error("Failed to get token from Managed Identity");
10537
+ // src/commands/tenant/tenantList.ts
10538
+ var TENANT_COLUMNS = [
10539
+ { header: "DISPLAY NAME", key: (t) => t.displayName },
10540
+ { header: "TENANT ID", key: (t) => t.tenantId },
10541
+ { header: "DEFAULT DOMAIN", key: (t) => t.defaultDomain }
10542
+ ];
10543
+ function addTenantListCommand(tenantCommand) {
10544
+ tenantCommand.command("list").description("List accessible tenants for the signed-in user").action(async () => {
10545
+ try {
10546
+ const apiEnv4 = (0, import_common43.getApiEnv)(import_common43.SecurityPlatformEnvironment.Production);
10547
+ const accessToken = await getToken(apiEnv4, [apiEnv4.armScope]);
10548
+ const requestService = new import_common43.RequestService(noopTelemetry, buildApiHeaders);
10549
+ const tenantService = new TenantService(requestService, apiEnv4.armEndpoint);
10550
+ const tenants = await tenantService.fetchAllTenants(accessToken);
10551
+ printTenants(tenants);
10552
+ } catch (error) {
10553
+ handleApiError("listing tenants", error);
7767
10554
  }
7768
- return token.token;
7769
- }
7770
- };
10555
+ });
10556
+ }
10557
+ function printTenants(tenants) {
10558
+ const fmt = new OutputFormatter();
10559
+ fmt.print(tenants, TENANT_COLUMNS);
10560
+ }
7771
10561
 
7772
- // src/auth/provider/MsalCacheTokenProvider.ts
10562
+ // src/commands/tenant/tenantSelect.ts
7773
10563
  init_cjs_shims();
7774
- var MsalCacheTokenProvider = class {
7775
- options;
7776
- env;
7777
- constructor(env, options) {
7778
- if (!env) {
7779
- throw new Error("Environment cannot be null or undefined");
10564
+ var import_common44 = __toESM(require_src());
10565
+ var os6 = __toESM(require("os"));
10566
+ var readline = __toESM(require("readline"));
10567
+ var MAX_PROMPT_ATTEMPTS = 3;
10568
+ function addTenantSelectCommand(tenantCommand) {
10569
+ tenantCommand.command("select").description(
10570
+ "Select an active tenant for this account from an interactive numbered prompt. Subsequent commands will acquire tokens for the selected tenant."
10571
+ ).action(async () => {
10572
+ try {
10573
+ const apiEnv4 = (0, import_common44.getApiEnv)(import_common44.SecurityPlatformEnvironment.Production);
10574
+ const armToken = await getToken(apiEnv4, [apiEnv4.armScope]);
10575
+ const requestService = new import_common44.RequestService(noopTelemetry, buildApiHeaders);
10576
+ const tenantService = new TenantService(requestService, apiEnv4.armEndpoint);
10577
+ const tenants = await tenantService.fetchAllTenants(armToken);
10578
+ if (tenants.length === 0) {
10579
+ console.error("\u274C No tenants accessible for the signed-in account.");
10580
+ process.exit(1);
10581
+ }
10582
+ const activeTenantId = getActiveTenantId();
10583
+ const activeIndex = activeTenantId ? tenants.findIndex((t) => t.tenantId === activeTenantId) : -1;
10584
+ const chosen = await promptForTenant(tenants, activeIndex);
10585
+ if (!chosen) {
10586
+ console.log("\u2139 Active tenant unchanged.");
10587
+ return;
10588
+ }
10589
+ await switchActiveTenant(apiEnv4, chosen);
10590
+ console.log(`\u2705 Active tenant set to ${chosen.tenantId} (${chosen.displayName}).`);
10591
+ } catch (error) {
10592
+ handleApiError("selecting tenant", error);
7780
10593
  }
7781
- this.env = env;
7782
- this.options = {
7783
- ...options,
7784
- scopes: options?.scopes?.length ? options.scopes : [this.env.gatewayAuthResourceUri]
7785
- };
10594
+ });
10595
+ }
10596
+ function getActiveTenantId() {
10597
+ const session = loadBrokerAccount();
10598
+ if (!session) {
10599
+ return null;
7786
10600
  }
7787
- async getAccessToken() {
7788
- const token = await getAccessTokenFromCache(this.options.scopes);
7789
- if (!token) {
7790
- throw new Error("No cached authentication token found. Please run `sentinel login` first.");
10601
+ try {
10602
+ const url = new URL(session.authority);
10603
+ const segment = url.pathname.split("/").filter(Boolean).pop();
10604
+ if (!segment || segment === "common" || segment === "organizations" || segment === "consumers") {
10605
+ return null;
7791
10606
  }
7792
- return token;
10607
+ return segment;
10608
+ } catch {
10609
+ return null;
7793
10610
  }
7794
- };
7795
-
7796
- // src/auth/provider/TokenProviderFactory.ts
7797
- var TokenProviderFactory = class {
7798
- static createProvider(env, method, options) {
7799
- switch (method) {
7800
- case "device_code":
7801
- return new DeviceCodeTokenProvider(env, options);
7802
- case "managed_identity":
7803
- if (!options) {
7804
- throw new Error("UAMI clientId required for user-assigned managed identity");
10611
+ }
10612
+ async function promptForTenant(tenants, activeIndex) {
10613
+ const defaultIdx = activeIndex >= 0 ? activeIndex + 1 : 1;
10614
+ console.log("");
10615
+ console.log(formatTenantTable(tenants, activeIndex));
10616
+ console.log("");
10617
+ if (activeIndex >= 0) {
10618
+ console.log(`The default is marked with an *; the default tenant is '${tenants[activeIndex].tenantId}'.`);
10619
+ console.log("");
10620
+ }
10621
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
10622
+ try {
10623
+ for (let attempt = 0; attempt < MAX_PROMPT_ATTEMPTS; attempt++) {
10624
+ const answer = await new Promise((resolve2) => {
10625
+ rl.question(`Select a tenant by number [${defaultIdx}]: `, (a) => resolve2(a));
10626
+ });
10627
+ const trimmed = answer.trim();
10628
+ if (trimmed === "") {
10629
+ if (activeIndex >= 0) {
10630
+ return null;
7805
10631
  }
7806
- return new ManagedIdentityTokenProvider(env, options);
7807
- case "msal_cache":
7808
- return new MsalCacheTokenProvider(env, options);
7809
- default:
7810
- throw new Error(`Unsupported token method: ${method}`);
10632
+ return tenants[defaultIdx - 1];
10633
+ }
10634
+ if (/^\d+$/.test(trimmed)) {
10635
+ const idx = Number.parseInt(trimmed, 10);
10636
+ if (idx >= 1 && idx <= tenants.length) {
10637
+ const chosen = tenants[idx - 1];
10638
+ if (activeIndex >= 0 && idx - 1 === activeIndex) {
10639
+ return null;
10640
+ }
10641
+ return chosen;
10642
+ }
10643
+ }
10644
+ console.error(`Invalid selection. Enter a number between 1 and ${tenants.length}.`);
7811
10645
  }
10646
+ throw new Error("Too many invalid attempts. Aborting.");
10647
+ } finally {
10648
+ rl.close();
7812
10649
  }
7813
- };
7814
-
7815
- // src/services/getToken.ts
7816
- async function getToken(env, scopes, clientId) {
7817
- let provider = null;
7818
- const options = {
7819
- uamiClientId: clientId,
7820
- scopes
7821
- };
7822
- if (clientId) {
7823
- provider = TokenProviderFactory.createProvider(env, "managed_identity" /* ManagedIdentity */, options);
7824
- } else {
7825
- provider = TokenProviderFactory.createProvider(env, "msal_cache" /* MsalCache */, options);
7826
- }
7827
- const token = await provider.getAccessToken();
7828
- return token;
7829
10650
  }
7830
-
7831
- // src/utils/httpServiceUtils.ts
7832
- async function getHttpService(env) {
7833
- try {
7834
- const accessToken = await getToken(env);
7835
- return new import_common7.HttpService(
7836
- import_axios.default.create({
7837
- headers: {
7838
- "Content-Type": "application/json",
7839
- Authorization: `Bearer ${accessToken}`
7840
- }
7841
- })
10651
+ function formatTenantTable(tenants, activeIndex) {
10652
+ const headers = ["No.", "", "Tenant ID", "Tenant Name", "Default Domain"];
10653
+ const rows = tenants.map((t, i) => {
10654
+ const marker = i === activeIndex ? "*" : "";
10655
+ return [`[${i + 1}]`, marker, t.tenantId, t.displayName, t.defaultDomain ?? ""];
10656
+ });
10657
+ const widths = headers.map((h, col) => Math.max(h.length, ...rows.map((r) => r[col].length)));
10658
+ const pad = (s, w) => s + " ".repeat(Math.max(0, w - s.length));
10659
+ const formatRow = (cells) => cells.map((c, i) => pad(c, widths[i])).join(" ");
10660
+ return [formatRow(headers), ...rows.map(formatRow)].join("\n");
10661
+ }
10662
+ async function switchActiveTenant(apiEnv4, chosen) {
10663
+ const newAuthority = `${new URL(apiEnv4.aadEndpoint).origin}/${chosen.tenantId}`;
10664
+ const session = loadBrokerAccount();
10665
+ if (!session) {
10666
+ throw new Error(
10667
+ "No active session found. Run 'sentinel login' first. Note: tenant switching is not supported for managed-identity / workload-identity sign-ins."
7842
10668
  );
7843
- } catch {
7844
- throw new Error("Failed to retrieve access token");
7845
10669
  }
7846
- }
7847
-
7848
- // src/commands/publishJob.ts
7849
- function addPublishCommand(jobCommand) {
7850
- jobCommand.command("publish <notebookPath>").description("Publish a scheduled job.").option("-c, --config <path>", "Path to job YAML config").option("-r, --region <region>", "Target region (e.g. eastus2)", import_common8.Region.Global).action(async (notebookPath, options) => {
7851
- try {
7852
- const resolvedNotebookPath = import_path4.default.resolve(notebookPath);
7853
- const resolvedConfigPath = import_path4.default.resolve(options.config);
7854
- const apiEnv4 = (0, import_common8.getApiEnv)(import_common8.SecurityPlatformEnvironment.Production);
7855
- const region = options.region;
7856
- const httpService = await getHttpService(apiEnv4);
7857
- const jobService = new import_common8.JobService(apiEnv4, region, httpService);
7858
- const result = await publish(resolvedNotebookPath, resolvedConfigPath, jobService);
7859
- console.log("Published job:", result);
7860
- } catch (error) {
7861
- if (error instanceof Error) {
7862
- console.error("Publish Error:", error.message);
7863
- } else {
7864
- console.error("Unknown error in publish:", error);
7865
- }
7866
- process.exit(1);
10670
+ const msalInstance = await getMsalInstance(apiEnv4, newAuthority);
10671
+ try {
10672
+ const result = await msalInstance.acquireTokenSilent({
10673
+ account: session.account,
10674
+ scopes: [apiEnv4.gatewayAuthResourceUri],
10675
+ authority: newAuthority
10676
+ });
10677
+ const acquiredTid = result?.account?.tenantId;
10678
+ if (result?.accessToken && acquiredTid === chosen.tenantId) {
10679
+ saveBrokerAccount(result.account, newAuthority);
10680
+ return;
7867
10681
  }
7868
- });
10682
+ } catch {
10683
+ }
10684
+ console.log(`\u2139 Silent sign-in to tenant ${chosen.tenantId} not possible \u2014 prompting interactively\u2026`);
10685
+ if (os6.platform() === "win32") {
10686
+ await brokerLogin([apiEnv4.gatewayAuthResourceUri], chosen.tenantId);
10687
+ } else {
10688
+ await browserAuthLogin([apiEnv4.gatewayAuthResourceUri], chosen.tenantId);
10689
+ }
7869
10690
  }
7870
10691
 
7871
10692
  // src/commands/token.ts
@@ -7876,17 +10697,79 @@ function addTokenCommand(program2) {
7876
10697
  });
7877
10698
  }
7878
10699
 
10700
+ // src/commands/updateCLI.ts
10701
+ init_cjs_shims();
10702
+
10703
+ // src/actions/updateCLI.ts
10704
+ init_cjs_shims();
10705
+ var import_axios = __toESM(require("axios"));
10706
+ var import_child_process2 = require("child_process");
10707
+ var os7 = __toESM(require("os"));
10708
+ var import_semver = __toESM(require("semver"));
10709
+ var PACKAGE_NAME = "@microsoft/sentinel-cli";
10710
+ var NPM_REGISTRY_URL = `https://registry.npmjs.org/${PACKAGE_NAME}/latest`;
10711
+ async function fetchLatestVersion() {
10712
+ const response = await import_axios.default.get(NPM_REGISTRY_URL, { timeout: 5e3 });
10713
+ return response.data.version;
10714
+ }
10715
+ function isNewerVersion(current, latest) {
10716
+ const c = import_semver.default.coerce(current);
10717
+ const l = import_semver.default.coerce(latest);
10718
+ if (!c || !l) {
10719
+ return false;
10720
+ }
10721
+ return import_semver.default.gt(l, c);
10722
+ }
10723
+ function runUpdateCommand(version) {
10724
+ if (!import_semver.default.valid(version)) {
10725
+ throw new Error(`Invalid version: ${version}`);
10726
+ }
10727
+ const args = ["install", "-g", `${PACKAGE_NAME}@${version}`];
10728
+ (0, import_child_process2.execFileSync)("npm", args, { stdio: "inherit", shell: true });
10729
+ }
10730
+ async function checkAndUpdate(currentVersion) {
10731
+ console.log(`\u{1F50D} Current version: ${currentVersion}`);
10732
+ console.log("\u{1F310} Checking for latest version on npm...");
10733
+ const latestVersion = await fetchLatestVersion();
10734
+ if (!isNewerVersion(currentVersion, latestVersion)) {
10735
+ console.log(`\u2705 You are already on the latest version (${currentVersion}).`);
10736
+ return;
10737
+ }
10738
+ console.log(`\u{1F4E6} New version available: ${latestVersion}`);
10739
+ console.log(`\u2B06\uFE0F Updating from ${currentVersion} to ${latestVersion}...`);
10740
+ if (os7.platform() !== "win32") {
10741
+ console.log(
10742
+ "\u2139\uFE0F On macOS/Linux, you may need administrator privileges. If the update fails, try running with sudo."
10743
+ );
10744
+ }
10745
+ runUpdateCommand(latestVersion);
10746
+ console.log(`\u2705 Successfully updated to version ${latestVersion}.`);
10747
+ }
10748
+
10749
+ // src/commands/updateCLI.ts
10750
+ function addUpdateCliCommand(program2) {
10751
+ program2.command("update").description("Update the Sentinel CLI to the latest version").action(async () => {
10752
+ try {
10753
+ await checkAndUpdate("0.3.0");
10754
+ } catch (error) {
10755
+ console.error(`\u274C Update failed: ${error instanceof Error ? error.message : error}`);
10756
+ process.exitCode = 1;
10757
+ return;
10758
+ }
10759
+ });
10760
+ }
10761
+
7879
10762
  // src/commands/validate.ts
7880
10763
  init_cjs_shims();
7881
10764
 
7882
10765
  // src/actions/validate.ts
7883
10766
  init_cjs_shims();
7884
- var import_common9 = __toESM(require_src());
10767
+ var import_common45 = __toESM(require_src());
7885
10768
  async function validateFromFile(filePath) {
7886
10769
  if (!filePath || typeof filePath !== "string" || filePath.trim().length === 0) {
7887
10770
  throw new Error("Invalid file path provided.");
7888
10771
  }
7889
- const manifestProcessorService = new import_common9.ManifestProcessorService();
10772
+ const manifestProcessorService = new import_common45.ManifestProcessorService();
7890
10773
  console.info("Starting validate process...");
7891
10774
  await manifestProcessorService.validateManifest(filePath);
7892
10775
  }
@@ -7913,15 +10796,56 @@ function addValidateCommand(packageCommand) {
7913
10796
  function registerCommands(program2) {
7914
10797
  const jobCommand = program2.command("job").description("Manage scheduled jobs");
7915
10798
  addPublishCommand(jobCommand);
10799
+ addJobListCommand(jobCommand);
10800
+ addJobShowCommand(jobCommand);
10801
+ addJobDeleteCommand(jobCommand);
10802
+ addJobDisableCommand(jobCommand);
10803
+ addJobEnableCommand(jobCommand);
10804
+ addJobDownloadCommand(jobCommand);
10805
+ const runCommand = jobCommand.command("run").description("Manage job runs");
10806
+ addJobRunListCommand(runCommand);
10807
+ addJobRunShowCommand(runCommand);
10808
+ addJobRunStartCommand(runCommand);
10809
+ addJobRunCancelCommand(runCommand);
10810
+ const notebookCommand = runCommand.command("notebook").description("Manage job run notebooks");
10811
+ addJobRunNotebookDownloadCommand(notebookCommand);
10812
+ const definitionCommand = jobCommand.command("definition").description("Manage job definition YAML files");
10813
+ addJobDefinitionCreateCommand(definitionCommand);
10814
+ addJobDefinitionShowCommand(definitionCommand);
10815
+ addJobDefinitionUpdateCommand(definitionCommand);
7916
10816
  const packageCommand = program2.command("package").description("Manage packages");
7917
10817
  addCreateZipCommand(packageCommand);
7918
10818
  addValidateCommand(packageCommand);
10819
+ const databaseCommand = program2.command("database").description("Manage sentinel lake databases");
10820
+ addDatabaseCommand(databaseCommand);
10821
+ const tableCommand = program2.command("table").description("Manage sentinel lake tables");
10822
+ addLakeTableListCommand(tableCommand);
10823
+ addLakeTableShowCommand(tableCommand);
10824
+ const tenantCommand = program2.command("tenant").description("Manage tenants");
10825
+ addTenantListCommand(tenantCommand);
10826
+ addTenantSelectCommand(tenantCommand);
7919
10827
  loginCommand(program2);
7920
10828
  logoutCommand(program2);
7921
10829
  addTokenCommand(program2);
10830
+ addUpdateCliCommand(program2);
7922
10831
  }
7923
10832
 
7924
10833
  // src/index.ts
7925
- import_commander.program.name("sentinel").description("CLI for MSAL login").version("1.0.0");
10834
+ import_commander.program.name("sentinel").description("Sentinel CLI \u2014 manage lake tables, databases, scheduled jobs, packages, and authentication").version("0.3.0");
7926
10835
  registerCommands(import_commander.program);
7927
- import_commander.program.parse(process.argv);
10836
+ var telemetry = getTelemetry();
10837
+ telemetry.event("cli.invoked", {
10838
+ properties: { command: process.argv[2] ?? "<none>" }
10839
+ });
10840
+ attachCommandTelemetry(import_commander.program, telemetry);
10841
+ (async () => {
10842
+ let exitCode = 0;
10843
+ try {
10844
+ await import_commander.program.parseAsync(process.argv);
10845
+ } catch {
10846
+ exitCode = 1;
10847
+ } finally {
10848
+ await telemetry.dispose();
10849
+ }
10850
+ process.exit(exitCode);
10851
+ })();