@raisenow/tamaro-cli 1.6.0 → 1.7.0-dev.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.
@@ -74,6 +74,7 @@ import { basename, dirname, join, relative, resolve } from "path";
74
74
  import chalk2 from "chalk";
75
75
  import stripIndent2 from "strip-indent";
76
76
  import { getIfUtils } from "webpack-config-utils";
77
+ import { z } from "zod";
77
78
  var require2 = createRequire(import.meta.url);
78
79
  var moduleFileExtensions = ["ts", "tsx", "js", "jsx"];
79
80
  var extensions = moduleFileExtensions.map((v) => `.${v}`);
@@ -139,6 +140,7 @@ var getPaths = (ifCore) => {
139
140
  appTsConfig: resolveApp("tsconfig.json"),
140
141
  appHtml: resolveApp("*.html"),
141
142
  appEnv: resolveApp(".env*"),
143
+ configYml: resolveApp("config.yml"),
142
144
  appTailwindConfig: void 0
143
145
  }
144
146
  );
@@ -185,17 +187,62 @@ var getIfCoreFns = ({
185
187
  );
186
188
  process.exit(1);
187
189
  };
190
+ var resolveAccountUuidFromConfig = (rawConfig, field) => {
191
+ const epmsConfig = z.object({
192
+ [field]: z.record(z.string(), z.unknown())
193
+ }).safeParse(rawConfig);
194
+ if (!epmsConfig.success) {
195
+ return void 0;
196
+ }
197
+ const configContent = epmsConfig.data[field];
198
+ const accountUuid = configContent.account_mapping ?? configContent.account_uuid;
199
+ const accountUuidValidation = z.uuid().safeParse(accountUuid);
200
+ if (!accountUuidValidation.success) {
201
+ halt(
202
+ stripIndent2(
203
+ `Could not extract EPMS account UUID(s) from config.yml. Please ensure that the "${field}" field is correctly formatted. Expected formats:
204
+ 1. ${field}:
205
+ account_uuid: <UUID>
206
+
207
+ 2. ${field}:
208
+ account_mapping: <UUID>
209
+ `
210
+ )
211
+ );
212
+ }
213
+ return accountUuidValidation.data;
214
+ };
215
+ var TAMARO_VERSION_IN_URL_REGEX = /tamaro-core\/(.*)\/index.js/;
216
+ var extractTamaroVersionFromUrl = (url) => {
217
+ const match = url.match(TAMARO_VERSION_IN_URL_REGEX);
218
+ if (match) {
219
+ return match[1].toString();
220
+ }
221
+ };
222
+ var resolveCoreVersion = () => {
223
+ if (process.env.CORE_VERSION) {
224
+ return process.env.CORE_VERSION;
225
+ }
226
+ if (process.env.CORE_URL) {
227
+ return extractTamaroVersionFromUrl(process.env.CORE_URL);
228
+ }
229
+ return void 0;
230
+ };
188
231
 
189
232
  // src/lib/constants.ts
233
+ import envPaths from "env-paths";
190
234
  var DEFAULT_TAG = "latest";
191
235
  var DEFAULT_PORT = 1234;
192
236
  var AWS_S3_BUCKET_TAMARO = "tamaro.raisenow.com";
193
237
  var AWS_S3_BUCKET_TAMARO_EMAIL_CONFIG_STAGE = "rnw-stage-email-service";
194
238
  var AWS_S3_BUCKET_TAMARO_EMAIL_CONFIG_PROD = "rnw-email-service";
239
+ var EPMS_API_BASE_URL_STAGE = "https://api.stage.mesos.raisenow.net";
240
+ var EPMS_API_BASE_URL_PROD = "https://api.raisenow.io";
195
241
  var CORE_CONFIG_NAME = "tamaro-core";
196
242
  var AWS_CLOUDFRONT_DISTRIBUTION_ID = "EHJ1OM458YQ0I";
197
243
  var HTTPS_CRT_FILE = "localhost.crt";
198
244
  var HTTPS_KEY_FILE = "localhost.key";
245
+ var CACHE_DIR = envPaths("tamaro-cli", { suffix: "" }).cache;
199
246
 
200
247
  // src/lib/env.ts
201
248
  import { createRequire as createRequire2 } from "module";
@@ -340,15 +387,20 @@ export {
340
387
  getPaths,
341
388
  getRelativePaths,
342
389
  getIfCoreFns,
390
+ resolveAccountUuidFromConfig,
391
+ resolveCoreVersion,
343
392
  DEFAULT_TAG,
344
393
  DEFAULT_PORT,
345
394
  AWS_S3_BUCKET_TAMARO,
346
395
  AWS_S3_BUCKET_TAMARO_EMAIL_CONFIG_STAGE,
347
396
  AWS_S3_BUCKET_TAMARO_EMAIL_CONFIG_PROD,
397
+ EPMS_API_BASE_URL_STAGE,
398
+ EPMS_API_BASE_URL_PROD,
348
399
  CORE_CONFIG_NAME,
349
400
  AWS_CLOUDFRONT_DISTRIBUTION_ID,
350
401
  HTTPS_CRT_FILE,
351
402
  HTTPS_KEY_FILE,
403
+ CACHE_DIR,
352
404
  getEnvVars,
353
405
  assertEnvValid,
354
406
  applyEnv
package/dist/cli.js CHANGED
@@ -4,9 +4,12 @@ import {
4
4
  AWS_S3_BUCKET_TAMARO,
5
5
  AWS_S3_BUCKET_TAMARO_EMAIL_CONFIG_PROD,
6
6
  AWS_S3_BUCKET_TAMARO_EMAIL_CONFIG_STAGE,
7
+ CACHE_DIR,
7
8
  CORE_CONFIG_NAME,
8
9
  DEFAULT_PORT,
9
10
  DEFAULT_TAG,
11
+ EPMS_API_BASE_URL_PROD,
12
+ EPMS_API_BASE_URL_STAGE,
10
13
  HTTPS_CRT_FILE,
11
14
  HTTPS_KEY_FILE,
12
15
  applyEnv,
@@ -21,10 +24,12 @@ import {
21
24
  logSuccess,
22
25
  logTitle,
23
26
  promptConfirmation,
27
+ resolveAccountUuidFromConfig,
24
28
  resolveBin,
29
+ resolveCoreVersion,
25
30
  resolveOwn,
26
31
  runCommandSync
27
- } from "./chunk-5D6F3T2J.js";
32
+ } from "./chunk-ALQDGTID.js";
28
33
 
29
34
  // src/cli.ts
30
35
  import { createCommand } from "commander";
@@ -402,8 +407,8 @@ var prepareFlags2 = (options) => {
402
407
  };
403
408
 
404
409
  // src/commands/deploy.ts
405
- import { existsSync as existsSync3 } from "fs";
406
- import stripIndent4 from "strip-indent";
410
+ import { existsSync as existsSync5 } from "fs";
411
+ import stripIndent5 from "strip-indent";
407
412
 
408
413
  // src/lib/validators/assertTagValid.ts
409
414
  var assertTagValid = (tag) => {
@@ -415,6 +420,268 @@ var assertTagValid = (tag) => {
415
420
  }
416
421
  };
417
422
 
423
+ // src/commands/update-epms.ts
424
+ import { readFileSync as readFileSync3 } from "fs";
425
+ import { basename as basename2 } from "path";
426
+ import { config as dotenvConfig } from "dotenv";
427
+ import { globSync as globSync2 } from "glob";
428
+ import yaml2 from "js-yaml";
429
+
430
+ // src/lib/epms/assert.ts
431
+ import { existsSync as existsSync3, readFileSync } from "fs";
432
+ import yaml from "js-yaml";
433
+ import stripIndent4 from "strip-indent";
434
+ var assertEpmsCredentials = (configPath) => {
435
+ if (!existsSync3(configPath)) {
436
+ throw new Error(`Config file not found at path: ${configPath}`);
437
+ }
438
+ try {
439
+ const configContent = yaml.load(readFileSync(configPath, "utf8"));
440
+ assertEpmsCredentialsPresentStage(configContent);
441
+ assertEpmsCredentialsPresentProd(configContent);
442
+ } catch (e) {
443
+ throw new Error(
444
+ `Error parsing config file at path: ${configPath}. Details: ${e}`
445
+ );
446
+ }
447
+ };
448
+ var assertEpmsCredentialsPresentStage = (rawConfig) => {
449
+ const accountsUuidsStage = resolveAccountUuidFromConfig(
450
+ rawConfig,
451
+ "epms_stage"
452
+ );
453
+ if (!accountsUuidsStage) {
454
+ return;
455
+ }
456
+ if (!process.env.EPMS_CLIENT_ID_STAGE || !process.env.EPMS_CLIENT_SECRET_STAGE) {
457
+ halt(
458
+ stripIndent4(
459
+ `EPMS credentials for stage environment are missing.
460
+ - Please set EPMS_CLIENT_ID_STAGE and EPMS_CLIENT_SECRET_STAGE in your environment variables.
461
+ - Alternatively, remove the "epms_stage" fields from your config.yml
462
+ `
463
+ )
464
+ );
465
+ }
466
+ };
467
+ var assertEpmsCredentialsPresentProd = (rawConfig) => {
468
+ const accountsUuidsProd = resolveAccountUuidFromConfig(rawConfig, "epms");
469
+ if (!accountsUuidsProd) {
470
+ return;
471
+ }
472
+ if (!process.env.EPMS_CLIENT_ID || !process.env.EPMS_CLIENT_SECRET) {
473
+ halt(
474
+ stripIndent4(
475
+ `EPMS credentials for prod environment are missing.
476
+ - Please set EPMS_CLIENT_ID and EPMS_CLIENT_SECRET in your environment variables.
477
+ - Alternatively, remove the "epms" fields from your config.yml
478
+ `
479
+ )
480
+ );
481
+ }
482
+ };
483
+
484
+ // src/lib/epms/auth.ts
485
+ import { existsSync as existsSync4, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync } from "fs";
486
+ import { dirname as dirname2, join } from "path";
487
+ import ky from "ky";
488
+ var DEFAULT_TIMEOUT = 1e4;
489
+ function getCacheFilePath() {
490
+ return join(CACHE_DIR, "token.json");
491
+ }
492
+ function readCachedToken() {
493
+ try {
494
+ const filePath = getCacheFilePath();
495
+ if (!existsSync4(filePath)) {
496
+ return void 0;
497
+ }
498
+ const data = JSON.parse(readFileSync2(filePath, "utf-8"));
499
+ if (typeof data.token === "string" && typeof data.expirationTime === "number") {
500
+ return data;
501
+ }
502
+ } catch {
503
+ }
504
+ return void 0;
505
+ }
506
+ function writeCachedToken(cached) {
507
+ try {
508
+ const filePath = getCacheFilePath();
509
+ mkdirSync2(dirname2(filePath), { recursive: true });
510
+ writeFileSync(filePath, JSON.stringify(cached), { mode: 384 });
511
+ } catch {
512
+ }
513
+ }
514
+ var createAuthorizer = (baseUrl, clientId, clientSecret) => {
515
+ const apiUnauthorized = ky.extend({
516
+ headers: {
517
+ "Access-Control-Allow-Origin": "*"
518
+ },
519
+ prefixUrl: baseUrl,
520
+ timeout: DEFAULT_TIMEOUT
521
+ });
522
+ let expirationTime = void 0;
523
+ let token = void 0;
524
+ const cached = readCachedToken();
525
+ if (cached) {
526
+ token = cached.token;
527
+ expirationTime = cached.expirationTime;
528
+ }
529
+ const authorize = async () => {
530
+ const isExpired = (expirationTime ?? 0) - Date.now() < 5 * 60 * 1e3;
531
+ if (token && !isExpired) {
532
+ return token;
533
+ }
534
+ const data = await apiUnauthorized.post("oauth2/token", {
535
+ json: {
536
+ client_id: clientId,
537
+ client_secret: clientSecret,
538
+ grant_type: "client_credentials"
539
+ }
540
+ }).json();
541
+ token = `${data.token_type} ${data.access_token}`;
542
+ expirationTime = Date.now() + data.expires_in * 1e3;
543
+ writeCachedToken({ token, expirationTime });
544
+ return token;
545
+ };
546
+ return apiUnauthorized.extend({
547
+ hooks: {
548
+ beforeRequest: [
549
+ async (request) => {
550
+ request.headers.set("Authorization", await authorize());
551
+ }
552
+ ]
553
+ }
554
+ });
555
+ };
556
+
557
+ // src/lib/epms/client.ts
558
+ var EpmsClient = class {
559
+ #epmsClient;
560
+ constructor(baseUrl, clientId, clientSecret) {
561
+ this.#epmsClient = createAuthorizer(baseUrl, clientId, clientSecret);
562
+ }
563
+ async getOrganisationIdByAccountUuid(accountUuid) {
564
+ const query = {
565
+ query: {
566
+ $and: [
567
+ { $term: { object_uuid: accountUuid } },
568
+ { $term: { object: "account" } }
569
+ ]
570
+ },
571
+ size: 1,
572
+ from: 0
573
+ };
574
+ const response = await this.#epmsClient.post("search/events", {
575
+ json: query
576
+ }).json();
577
+ if (response.hits.length === 0) {
578
+ throw new Error(`No events found for account UUID: ${accountUuid}`);
579
+ }
580
+ const organisationId = response.hits[0].organisation_uuid;
581
+ if (!organisationId) {
582
+ throw new Error(
583
+ `Organisation UUID not found for account UUID: ${accountUuid}`
584
+ );
585
+ }
586
+ return organisationId;
587
+ }
588
+ async updateTamaro(configName, tag, json) {
589
+ return this.#epmsClient.put(`products/tamaro/${configName}/tags/${tag}`, {
590
+ json
591
+ }).json();
592
+ }
593
+ };
594
+
595
+ // src/commands/update-epms.ts
596
+ var updateEpms = async (options) => {
597
+ const { ifCore } = getIfCoreFns();
598
+ assertIsNotCore2(ifCore);
599
+ const paths = getPaths(ifCore);
600
+ const { tag, dryrun } = options;
601
+ const dryRunFlag = dryrun ? `--dryrun` : "";
602
+ const configName = getWidgetUuid();
603
+ const appEnvFiles = globSync2(paths.appEnv);
604
+ const filePath = appEnvFiles.find((file) => basename2(file) === ".env");
605
+ if (!filePath) {
606
+ halt(
607
+ 'No ".env" file found. Please make sure to have a ".env" file with EPMS credentials in the root of your widget project.'
608
+ );
609
+ }
610
+ dotenvConfig({ path: filePath, quiet: true });
611
+ if (!("configYml" in paths)) {
612
+ halt("Fatal error, this should never happen");
613
+ throw new Error();
614
+ }
615
+ if (dryRunFlag) {
616
+ logTitle("\u{1F9EA} DRY RUN MODE - No actual changes will be made \u{1F9EA}");
617
+ }
618
+ assertTagValid(tag);
619
+ assertEpmsCredentials(paths.configYml);
620
+ const configContent = yaml2.load(readFileSync3(paths.configYml, "utf8"));
621
+ const accountUuidStage = resolveAccountUuidFromConfig(
622
+ configContent,
623
+ "epms_stage"
624
+ );
625
+ const accountUuidProd = resolveAccountUuidFromConfig(configContent, "epms");
626
+ if (dryrun) {
627
+ logTitle(
628
+ `[DRY RUN] Would update EPMS for "${configName}" with tag "${tag}"`
629
+ );
630
+ } else {
631
+ if (accountUuidStage) {
632
+ const epmsClient = new EpmsClient(
633
+ EPMS_API_BASE_URL_STAGE,
634
+ process.env.EPMS_CLIENT_ID_STAGE,
635
+ process.env.EPMS_CLIENT_SECRET_STAGE
636
+ );
637
+ const organisationUuid = await epmsClient.getOrganisationIdByAccountUuid(accountUuidStage);
638
+ logTitle("Updating EPMS Stage with the following details:");
639
+ const body = {
640
+ account_uuid: accountUuidStage,
641
+ organisation_uuid: organisationUuid,
642
+ configured_version: resolveCoreVersion() ?? "unknown",
643
+ read_only: false,
644
+ // Unix timestamp in seconds
645
+ last_deployment: Math.floor(Date.now() / 1e3)
646
+ };
647
+ logDataTable({
648
+ name: configName,
649
+ tag,
650
+ ...body
651
+ });
652
+ await epmsClient.updateTamaro(configName, tag, body);
653
+ logSuccess("\u2705 EPMS Stage is updated.");
654
+ }
655
+ if (accountUuidProd) {
656
+ const epmsClient = new EpmsClient(
657
+ EPMS_API_BASE_URL_PROD,
658
+ process.env.EPMS_CLIENT_ID,
659
+ process.env.EPMS_CLIENT_SECRET
660
+ );
661
+ const organisationUuid = await epmsClient.getOrganisationIdByAccountUuid(accountUuidProd);
662
+ logTitle("Updating EPMS Prod with the following details:");
663
+ const body = {
664
+ account_uuid: accountUuidProd,
665
+ organisation_uuid: organisationUuid,
666
+ configured_version: resolveCoreVersion() ?? "unknown",
667
+ read_only: false
668
+ };
669
+ logDataTable({
670
+ name: configName,
671
+ tag,
672
+ ...body
673
+ });
674
+ await epmsClient.updateTamaro(configName, tag, body);
675
+ logSuccess("\u2705 EPMS Prod is updated.");
676
+ }
677
+ }
678
+ };
679
+ var assertIsNotCore2 = (ifCore) => {
680
+ if (ifCore()) {
681
+ halt("You cannot update EPMS in the context of Tamaro Core.");
682
+ }
683
+ };
684
+
418
685
  // src/commands/deploy.ts
419
686
  var deploy = async (options) => {
420
687
  const { ifCore } = getIfCoreFns();
@@ -479,6 +746,7 @@ var deploy = async (options) => {
479
746
  halt(error.stderr);
480
747
  }
481
748
  }
749
+ await updateEpms(options);
482
750
  const demoPage = `https://${AWS_S3_BUCKET_TAMARO}/${configName}/${tag}/index.html`;
483
751
  const entryPoint = `https://${AWS_S3_BUCKET_TAMARO}/${configName}/${tag}/${entryFilename}`;
484
752
  logTitle(`
@@ -506,9 +774,9 @@ var assertOptionsValid3 = (options) => {
506
774
  assertTagValid(tag);
507
775
  };
508
776
  var assertDistPathExists = (distPath) => {
509
- if (!existsSync3(distPath)) {
777
+ if (!existsSync5(distPath)) {
510
778
  halt(
511
- stripIndent4(`
779
+ stripIndent5(`
512
780
  Dist folder does not exists.
513
781
  Make sure you have built the bundle before trying to deploy it.
514
782
  `)
@@ -517,13 +785,13 @@ var assertDistPathExists = (distPath) => {
517
785
  };
518
786
 
519
787
  // src/commands/deploy-email-config.ts
520
- import { existsSync as existsSync4 } from "fs";
788
+ import { existsSync as existsSync6 } from "fs";
521
789
  import prompts2 from "prompts";
522
790
  var deployEmailConfig = async (options) => {
523
791
  const { ifCore } = getIfCoreFns();
524
792
  const paths = getPaths(ifCore);
525
793
  const emailConfigPath = `${paths.app}/email-config`;
526
- assertIsNotCore2();
794
+ assertIsNotCore3();
527
795
  assertEmailConfigPathExists(emailConfigPath);
528
796
  if (!options.profile && !options.ci) {
529
797
  assertProfilesPresent();
@@ -579,11 +847,11 @@ var assertOptionsValid4 = (options) => {
579
847
  }
580
848
  };
581
849
  var assertEmailConfigPathExists = (distPath) => {
582
- if (!existsSync4(distPath)) {
850
+ if (!existsSync6(distPath)) {
583
851
  halt("Email config folder does not exists. Nothing to deploy.");
584
852
  }
585
853
  };
586
- var assertIsNotCore2 = () => {
854
+ var assertIsNotCore3 = () => {
587
855
  const { ifCore } = getIfCoreFns();
588
856
  if (ifCore()) {
589
857
  halt("You cannot deploy widget email configuration for Tamaro Core.");
@@ -779,16 +1047,16 @@ var prepareFlags4 = async (options) => {
779
1047
  };
780
1048
 
781
1049
  // src/commands/unarchive.ts
782
- import { existsSync as existsSync5, renameSync as renameSync2 } from "fs";
783
- import { basename as basename2, dirname as dirname2, resolve as resolve4 } from "path";
1050
+ import { existsSync as existsSync7, renameSync as renameSync2 } from "fs";
1051
+ import { basename as basename3, dirname as dirname3, resolve as resolve4 } from "path";
784
1052
  var unarchive = (options) => {
785
1053
  const { ifCore } = getIfCoreFns({ allowArchived: true });
786
- assertIsNotCore3(ifCore);
1054
+ assertIsNotCore4(ifCore);
787
1055
  assertIsArchived();
788
1056
  const configName = getWidgetUuid();
789
1057
  const cwd = process.cwd();
790
- const archivedDir = dirname2(cwd);
791
- const configsDir = dirname2(archivedDir);
1058
+ const archivedDir = dirname3(cwd);
1059
+ const configsDir = dirname3(archivedDir);
792
1060
  const restoreTarget = resolve4(configsDir, configName);
793
1061
  assertRestoreTargetDoesNotExist(restoreTarget);
794
1062
  assertOptionsValid8(options);
@@ -816,20 +1084,20 @@ var assertOptionsValid8 = (options) => {
816
1084
  }
817
1085
  };
818
1086
  var assertIsArchived = () => {
819
- const parentDirName = basename2(dirname2(process.cwd()));
1087
+ const parentDirName = basename3(dirname3(process.cwd()));
820
1088
  if (parentDirName !== "_archived") {
821
1089
  halt(
822
1090
  "This configuration is not archived. Only archived configurations can be unarchived."
823
1091
  );
824
1092
  }
825
1093
  };
826
- var assertIsNotCore3 = (ifCore) => {
1094
+ var assertIsNotCore4 = (ifCore) => {
827
1095
  if (ifCore()) {
828
1096
  halt("You cannot unarchive Tamaro Core.");
829
1097
  }
830
1098
  };
831
1099
  var assertRestoreTargetDoesNotExist = (restoreTarget) => {
832
- if (existsSync5(restoreTarget)) {
1100
+ if (existsSync7(restoreTarget)) {
833
1101
  halt(
834
1102
  `Restore target already exists: ${restoreTarget}. Please remove it first.`
835
1103
  );
@@ -856,7 +1124,7 @@ var undeploy = async (options) => {
856
1124
  }
857
1125
  await promptConfirmation(
858
1126
  `Are you sure you want to undeploy ${description}?`,
859
- options.yes
1127
+ options.ci
860
1128
  );
861
1129
  const cmd = `
862
1130
  aws s3 rm ${deployUrl}
@@ -921,7 +1189,7 @@ var assertOptionsValid9 = (options) => {
921
1189
  import prompts3 from "prompts";
922
1190
  var undeployEmailConfig = async (options) => {
923
1191
  const { ifCore } = getIfCoreFns();
924
- assertIsNotCore4(ifCore);
1192
+ assertIsNotCore5(ifCore);
925
1193
  if (!options.profile && !options.ci) {
926
1194
  assertProfilesPresent();
927
1195
  options.profile = await promptProfile();
@@ -937,7 +1205,7 @@ var undeployEmailConfig = async (options) => {
937
1205
  const deployUrl = `s3://${options.bucket}/${configName}/`;
938
1206
  await promptConfirmation(
939
1207
  `Are you sure you want to undeploy the email configuration for "${configName}" from "${options.bucket}"?`,
940
- options.yes
1208
+ options.ci
941
1209
  );
942
1210
  if (dryRunFlag) {
943
1211
  logTitle("\u{1F9EA} DRY RUN MODE - No actual changes will be made \u{1F9EA}");
@@ -975,7 +1243,7 @@ var assertOptionsValid10 = (options) => {
975
1243
  assertBucketValid2(bucket);
976
1244
  }
977
1245
  };
978
- var assertIsNotCore4 = (ifCore) => {
1246
+ var assertIsNotCore5 = (ifCore) => {
979
1247
  if (ifCore()) {
980
1248
  halt("You cannot undeploy widget email configuration for Tamaro Core.");
981
1249
  }
@@ -1013,7 +1281,7 @@ var promptBucketTamaroEmailConfig2 = async () => {
1013
1281
  // package.json
1014
1282
  var package_default = {
1015
1283
  name: "@raisenow/tamaro-cli",
1016
- version: "1.6.0",
1284
+ version: "1.7.0-dev.0",
1017
1285
  author: {
1018
1286
  name: "RaiseNow",
1019
1287
  email: "development@raisenow.com"
@@ -1076,6 +1344,7 @@ var package_default = {
1076
1344
  "css-loader": "^7.1.3",
1077
1345
  "css-minimizer-webpack-plugin": "^7.0.4",
1078
1346
  dotenv: "^17.2.3",
1347
+ "env-paths": "^4.0.0",
1079
1348
  "escape-string-regexp": "^5.0.0",
1080
1349
  eslint: "^8.57.1",
1081
1350
  "eslint-config-prettier": "^10.1.8",
@@ -1095,7 +1364,9 @@ var package_default = {
1095
1364
  "handlebars-helpers": "^0.10.0",
1096
1365
  "html-loader": "^5.1.0",
1097
1366
  "html-webpack-plugin": "^5.6.6",
1367
+ "js-yaml": "^4.1.1",
1098
1368
  "json-loader": "^0.5.7",
1369
+ ky: "^1.14.3",
1099
1370
  lodash: "^4.17.23",
1100
1371
  "mini-css-extract-plugin": "^2.10.0",
1101
1372
  "node-notifier": "^10.0.1",
@@ -1123,7 +1394,11 @@ var package_default = {
1123
1394
  "webpack-cli": "^6.0.1",
1124
1395
  "webpack-config-utils": "^2.3.1",
1125
1396
  "webpack-dev-server": "^5.2.3",
1126
- "yaml-loader": "^0.9.0"
1397
+ "yaml-loader": "^0.9.0",
1398
+ zod: "^4.3.6"
1399
+ },
1400
+ devDependencies: {
1401
+ "@types/js-yaml": "^4.0.9"
1127
1402
  }
1128
1403
  };
1129
1404
 
@@ -1244,6 +1519,13 @@ cli.command("unarchive").description(
1244
1519
  ).action((options) => {
1245
1520
  unarchive(options);
1246
1521
  });
1522
+ cli.command("update-epms").description("Update EPMS with the currently configured widget version.").option("--tag <tag>", "Tag which should be used for the update", DEFAULT_TAG).option(
1523
+ "--dryrun",
1524
+ "Displays the operations that would be performed without actually running them",
1525
+ false
1526
+ ).action(async (options) => {
1527
+ await updateEpms(options);
1528
+ });
1247
1529
  cli.command("validate").description(
1248
1530
  "Validate the current Tamaro configuration to avoid common errors"
1249
1531
  ).action(async () => {
@@ -10,7 +10,7 @@ import {
10
10
  logTitle,
11
11
  resolveApp,
12
12
  resolveEslintPluginConfig
13
- } from "./chunk-5D6F3T2J.js";
13
+ } from "./chunk-ALQDGTID.js";
14
14
 
15
15
  // src/webpack.config.ts
16
16
  import { existsSync } from "fs";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@raisenow/tamaro-cli",
3
- "version": "1.6.0",
3
+ "version": "1.7.0-dev.0",
4
4
  "author": {
5
5
  "name": "RaiseNow",
6
6
  "email": "development@raisenow.com"
@@ -48,6 +48,7 @@
48
48
  "css-loader": "^7.1.3",
49
49
  "css-minimizer-webpack-plugin": "^7.0.4",
50
50
  "dotenv": "^17.2.3",
51
+ "env-paths": "^4.0.0",
51
52
  "escape-string-regexp": "^5.0.0",
52
53
  "eslint": "^8.57.1",
53
54
  "eslint-config-prettier": "^10.1.8",
@@ -67,7 +68,9 @@
67
68
  "handlebars-helpers": "^0.10.0",
68
69
  "html-loader": "^5.1.0",
69
70
  "html-webpack-plugin": "^5.6.6",
71
+ "js-yaml": "^4.1.1",
70
72
  "json-loader": "^0.5.7",
73
+ "ky": "^1.14.3",
71
74
  "lodash": "^4.17.23",
72
75
  "mini-css-extract-plugin": "^2.10.0",
73
76
  "node-notifier": "^10.0.1",
@@ -95,7 +98,11 @@
95
98
  "webpack-cli": "^6.0.1",
96
99
  "webpack-config-utils": "^2.3.1",
97
100
  "webpack-dev-server": "^5.2.3",
98
- "yaml-loader": "^0.9.0"
101
+ "yaml-loader": "^0.9.0",
102
+ "zod": "^4.3.6"
103
+ },
104
+ "devDependencies": {
105
+ "@types/js-yaml": "^4.0.9"
99
106
  },
100
107
  "scripts": {
101
108
  "typecheck": "tsc --noEmit",
package/.eslintignore DELETED
@@ -1,7 +0,0 @@
1
- .history
2
- .idea
3
- dist
4
- node_modules
5
- pnpm-lock.yaml
6
- tsconfig.eslint.json
7
- tsconfig.json
package/.eslintrc.cjs DELETED
@@ -1,148 +0,0 @@
1
- module.exports = {
2
- root: true,
3
- overrides: [
4
- {
5
- files: ['*.{js,cjs,ts}'],
6
- env: {
7
- node: true,
8
- es2021: true,
9
- },
10
- settings: {
11
- 'import/resolver': {
12
- typescript: {
13
- alwaysTryTypes: true,
14
- project: ['./tsconfig.json'],
15
- },
16
- },
17
- },
18
- parser: '@typescript-eslint/parser',
19
- parserOptions: {
20
- ecmaVersion: 2021,
21
- sourceType: 'module',
22
- tsconfigRootDir: __dirname,
23
- project: ['./tsconfig.json'],
24
- extraFileExtensions: ['.cjs'],
25
- },
26
- extends: [
27
- 'eslint:recommended',
28
- 'plugin:@typescript-eslint/recommended-requiring-type-checking',
29
- 'plugin:@typescript-eslint/strict-type-checked',
30
- 'plugin:@typescript-eslint/stylistic-type-checked',
31
- 'plugin:promise/recommended',
32
- 'plugin:deprecation/recommended',
33
- 'plugin:import/recommended',
34
- 'plugin:import/typescript',
35
- 'prettier',
36
- ],
37
- plugins: ['unused-imports'],
38
- rules: {
39
- curly: 1,
40
- 'prefer-const': 1,
41
- 'no-console': 1,
42
- strict: 1,
43
- 'no-debugger': 1,
44
-
45
- 'no-extra-boolean-cast': 0,
46
- '@typescript-eslint/no-explicit-any': 0,
47
- '@typescript-eslint/no-non-null-assertion': 0,
48
- '@typescript-eslint/no-unsafe-assignment': 0,
49
- '@typescript-eslint/no-unsafe-argument': 0,
50
- '@typescript-eslint/no-unsafe-member-access': 0,
51
- '@typescript-eslint/no-unsafe-return': 0,
52
- // '@typescript-eslint/no-unsafe-enum-comparison': 0,
53
- // '@typescript-eslint/no-unsafe-call': 0,
54
- // '@typescript-eslint/explicit-function-return-type': 0,
55
- '@typescript-eslint/consistent-type-definitions': 0,
56
- // '@typescript-eslint/no-dynamic-delete': 0,
57
- '@typescript-eslint/restrict-template-expressions': 0,
58
-
59
- '@typescript-eslint/ban-ts-comment': [2, {'ts-expect-error': false}],
60
- '@typescript-eslint/no-unused-vars': [1, {varsIgnorePattern: '^_'}],
61
- '@typescript-eslint/prefer-optional-chain': 1,
62
- '@typescript-eslint/member-delimiter-style': [
63
- 1,
64
- {multiline: {delimiter: 'none'}},
65
- ],
66
-
67
- '@typescript-eslint/no-confusing-void-expression': [
68
- 2,
69
- {ignoreArrowShorthand: true},
70
- ],
71
-
72
- 'import/newline-after-import': 2,
73
-
74
- 'unused-imports/no-unused-imports': 1,
75
-
76
- '@typescript-eslint/consistent-type-imports': [
77
- 2,
78
- {
79
- prefer: 'type-imports',
80
- fixStyle: 'inline-type-imports',
81
- },
82
- ],
83
-
84
- 'sort-imports': [2, {ignoreCase: true, ignoreDeclarationSort: true}],
85
- 'import/order': [
86
- 2,
87
- {
88
- groups: [
89
- 'builtin',
90
- 'external',
91
- 'internal',
92
- ['parent', 'sibling', 'index'],
93
- ],
94
- pathGroups: [
95
- {
96
- pattern: '**/*.json',
97
- group: 'unknown',
98
- position: 'after',
99
- },
100
- {
101
- pattern: '**/*.yml',
102
- group: 'unknown',
103
- position: 'after',
104
- },
105
- ],
106
- distinctGroup: false,
107
- alphabetize: {
108
- order: 'asc',
109
- orderImportKind: 'asc',
110
- caseInsensitive: true,
111
- },
112
- 'newlines-between': 'never',
113
-
114
- // Since docs for "pathGroupsExcludedImportTypes" option are confusing,
115
- // see more info about how to correctly use it here:
116
- // https://github.com/import-js/eslint-plugin-import/pull/2156#issuecomment-927559466
117
- pathGroupsExcludedImportTypes: [],
118
- },
119
- ],
120
- },
121
- },
122
- {
123
- files: ['*.{yml,yaml}'],
124
- extends: ['plugin:yml/standard'],
125
- rules: {
126
- // 'yml/no-irregular-whitespace': 0,
127
- 'yml/quotes': [2, {prefer: 'single', avoidEscape: true}],
128
- 'yml/plain-scalar': 0,
129
- 'yml/no-multiple-empty-lines': [2, {max: 1}],
130
- },
131
- },
132
- {
133
- files: ['*.md'],
134
- parser: 'eslint-plugin-markdownlint/parser',
135
- extends: ['plugin:markdownlint/recommended'],
136
- rules: {
137
- // Rules docs:
138
- // https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md
139
-
140
- 'markdownlint/md013': 0, // Line length
141
- 'markdownlint/md024': [2, {siblings_only: true}], // Multiple headings with the same content
142
- 'markdownlint/md025': 0, // Multiple top-level headings in the same document
143
- 'markdownlint/md033': 0, // Inline HTML
144
- 'markdownlint/md041': 0, // First line in a file should be a top-level heading
145
- },
146
- },
147
- ],
148
- }
package/.nvmrc DELETED
@@ -1 +0,0 @@
1
- 22.22.0
package/.prettierignore DELETED
@@ -1,8 +0,0 @@
1
- .history/*
2
- .idea/*
3
- dist/*
4
- node_modules/*
5
- pnpm-lock.yaml
6
- tsconfig.eslint.json
7
- tsconfig.json
8
- *.md
package/.prettierrc.cjs DELETED
@@ -1,19 +0,0 @@
1
- module.exports = {
2
- printWidth: 80,
3
- tabWidth: 2,
4
- useTabs: false,
5
- semi: false,
6
- singleQuote: true,
7
- quoteProps: 'as-needed',
8
- jsxSingleQuote: false,
9
- trailingComma: 'all',
10
- bracketSpacing: false,
11
- bracketSameLine: false,
12
- arrowParens: 'always',
13
- requirePragma: false,
14
- insertPragma: false,
15
- htmlWhitespaceSensitivity: 'strict',
16
- endOfLine: 'lf',
17
- embeddedLanguageFormatting: 'auto',
18
- singleAttributePerLine: false,
19
- }
@@ -1,47 +0,0 @@
1
- image: node:22.22.0
2
-
3
- definitions:
4
- caches:
5
- node:
6
- key:
7
- files:
8
- - pnpm-lock.yaml
9
- - package.json
10
- path: node_modules
11
- pnpm:
12
- key:
13
- files:
14
- - pnpm-lock.yaml
15
- - package.json
16
- path: $BITBUCKET_CLONE_DIR/.pnpm-store
17
- scripts:
18
- initialize: &initialize |-
19
- corepack enable pnpm
20
- corepack prepare --activate
21
- steps:
22
- - step: &install
23
- name: Install dependencies
24
- caches:
25
- - node
26
- - pnpm
27
- script:
28
- - *initialize
29
- - pnpm install --prefer-offline
30
- - step: &check
31
- name: Check
32
- caches:
33
- - node
34
- - pnpm
35
- script:
36
- - *initialize
37
- - pnpm lint
38
- - pnpm typecheck
39
- - pnpm test
40
- # Do not bother for dev deps
41
- # @see https://raisenow.atlassian.net/wiki/spaces/PD/pages/5680037889/TP+RFC+014+-+Unsafe+Outdated+Libraries+Upgrades#Regular-upgrade-of-NPM-libraries-versions
42
- - pnpm audit --audit-level=critical --prod
43
-
44
- pipelines:
45
- default:
46
- - step: *install
47
- - step: *check
package/renovate.json DELETED
@@ -1,3 +0,0 @@
1
- {
2
- "$schema": "https://docs.renovatebot.com/renovate-schema.json"
3
- }
package/vitest.config.ts DELETED
@@ -1,20 +0,0 @@
1
- import {defineConfig} from 'vitest/config'
2
-
3
- export default defineConfig({
4
- test: {
5
- watch: false,
6
- globals: true,
7
- environment: 'node',
8
- include: ['{src,tests}/**/*.{test,spec}.{ts,tsx}'],
9
- reporters: ['default'],
10
- coverage: {
11
- provider: 'v8',
12
- exclude: [
13
- 'dist/**',
14
- '.eslintrc.cjs',
15
- '.prettierrc.cjs',
16
- 'vitest.config.ts',
17
- ],
18
- },
19
- },
20
- })