@camstack/system 1.2.396 → 1.2.397

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.
@@ -1,5 +1,5 @@
1
1
  import { Ln as storageOccupancyCapability, Vr as nodePin, X as backupCapability, dr as BaseAddon, ei as toNodeId, ri as EventCategory, rn as mayWriteToLocation } from "../../dist-0P1gm4Gd.mjs";
2
- import { a as BackupSnapshotRefusedError, c as BackupKeyFormatError, d as generateBackupKeyPair, f as parseBackupPublicKey, i as BackupCancelledError, n as precheckRestoreKey, o as SystemBackupService, p as parseBackupSecretKey, r as prepareRestoreArchive, u as ENCRYPTED_BACKUP_SUFFIX } from "../../restore-archive-0g91qMVF.mjs";
2
+ import { a as BackupSnapshotRefusedError, c as BackupKeyFormatError, d as generateBackupKeyPair, f as parseBackupPublicKey, i as BackupCancelledError, n as precheckRestoreKey, o as SystemBackupService, p as parseBackupSecretKey, r as prepareRestoreArchive, u as ENCRYPTED_BACKUP_SUFFIX } from "../../restore-archive-DQ2NuwD1.mjs";
3
3
  import { randomUUID } from "node:crypto";
4
4
  import * as fsp from "node:fs/promises";
5
5
  import * as path$1 from "node:path";
@@ -5,7 +5,7 @@ Object.defineProperties(exports, {
5
5
  const require_chunk = require("../../chunk-Cek0wNdY.js");
6
6
  const require_dist = require("../../dist-CME5sVBJ.js");
7
7
  const require_jwt_signing_key = require("../../jwt-signing-key-CyoJaT3C.js");
8
- const require_constants = require("../../constants-Bz9gKWe8.js");
8
+ const require_constants = require("../../constants-Dcecs0Ks.js");
9
9
  const require_platform_key_source = require("../../platform-key-source-Di7HrlGR.js");
10
10
  let node_crypto = require("node:crypto");
11
11
  let node_path = require("node:path");
@@ -1,6 +1,6 @@
1
1
  import { E as KEYCHAIN_RESET_TRIGGER_ACTOR, Gr as parseSecretRef, Gt as keychainAdminCapability, Hr as normalizeSecretOwner, Kt as keychainCapability, Mr as formatSecretScope, dr as BaseAddon, ri as EventCategory } from "../../dist-0P1gm4Gd.mjs";
2
2
  import { r as SYSTEM_SECRET_OWNER, t as JWT_SIGNING_KEY_REF } from "../../jwt-signing-key-DK-IFI9j.mjs";
3
- import { m as CLUSTER_SECRET_SETTINGS_KEY, o as MESH_CA_KEY_REF } from "../../constants-C1WoQ0E8.mjs";
3
+ import { a as MESH_CA_KEY_REF, p as CLUSTER_SECRET_SETTINGS_KEY } from "../../constants-5vADty9I.mjs";
4
4
  import { n as getPlatformKeychainKey } from "../../platform-key-source-BWlq0jjn.mjs";
5
5
  import { createCipheriv, createDecipheriv, createHmac, randomBytes, randomUUID, timingSafeEqual } from "node:crypto";
6
6
  import * as path$1 from "node:path";
@@ -7,17 +7,9 @@ export declare class SystemConfigAddon extends BaseAddon {
7
7
  readonly id = "system-config";
8
8
  private clusterSecretKeeper;
9
9
  private meshCaKeeper;
10
- /** One warn per process when a retired cutover key is posted with a cluster save. */
11
- private retiredClusterCutoverPatchWarned;
12
10
  constructor();
13
11
  protected onInitialize(): Promise<AddonInitResult<typeof systemConfigMeshActions>>;
14
12
  protected onShutdown(): Promise<void>;
15
- /**
16
- * Boot: a stored `meshClearPort: off` is the operator's standing choice, so it
17
- * is applied WITHOUT the agents gate (nobody is connected yet to be checked).
18
- * Default `on` changes nothing.
19
- */
20
- private applyStoredClearPort;
21
13
  private onMeshCaReady;
22
14
  private mintJoinToken;
23
15
  /** D821 — short-lived ticket for the agent's `:4444` unlock session. */
@@ -45,8 +37,6 @@ export declare class SystemConfigAddon extends BaseAddon {
45
37
  * enforced (D821) — a legacy `meshAuth` in the patch is ignored.
46
38
  */
47
39
  private writeClusterSection;
48
- /** Cutover keys were removed from the Cluster form; ignore stray posts from stale clients. */
49
- private warnRetiredClusterCutoverPatch;
50
40
  /** Persist + publish mesh auth mode (always `enforced` after D821). */
51
41
  private writeMeshAuthMode;
52
42
  /**
@@ -5,7 +5,7 @@ Object.defineProperties(exports, {
5
5
  const require_chunk = require("../../chunk-Cek0wNdY.js");
6
6
  const require_dist = require("../../dist-CME5sVBJ.js");
7
7
  const require_ms$1 = require("../../ms-t68_FaqE.js");
8
- const require_constants$8 = require("../../constants-Bz9gKWe8.js");
8
+ const require_constants$8 = require("../../constants-Dcecs0Ks.js");
9
9
  const require_x509_es = require("../../x509.es-BhTzcFhZ.js");
10
10
  let zod = require("zod");
11
11
  let node_crypto = require("node:crypto");
@@ -607,67 +607,23 @@ function processMeshCrl() {
607
607
  return crl;
608
608
  }
609
609
  //#endregion
610
- //#region src/kernel/moleculer/mesh-mtls/mesh-clear-port.ts
611
- /** The field key inside the `cluster` section. */
612
- var MESH_CLEAR_PORT_FIELD = "meshClearPort";
613
- function isMeshClearPortMode(value) {
614
- return value === "on" || value === "off";
615
- }
616
- /** A stored value that is not a mode reads as `on`: never cut the mesh on a typo. */
617
- function parseMeshClearPortMode(value) {
618
- return isMeshClearPortMode(value) ? value : "on";
619
- }
620
- /** Pure: may the clear port be switched off right now? */
621
- function decideMeshClearPortOff(control) {
622
- if (control === null) return {
623
- allowed: false,
624
- blocking: [],
625
- error: "The clear mesh port can only be switched off on the hub (no mesh transport here)."
626
- };
627
- if (!control.isTlsListening()) return {
628
- allowed: false,
629
- blocking: [],
630
- error: "Refusing to close the clear mesh port: the TLS listener (:6443) is not up yet, so no node could reach the hub."
631
- };
632
- const blocking = control.listOnlineAgents().filter((agent) => agent.transport !== "tls").map((agent) => agent.nodeId).toSorted();
633
- if (blocking.length > 0) return {
634
- allowed: false,
635
- blocking,
636
- error: `Refusing to close the clear mesh port: ${blocking.join(", ")} still ${blocking.length === 1 ? "connects" : "connect"} in clear. Enroll ${blocking.length === 1 ? "it" : "each"} with a join token first (System → Cluster → Add agent).`
637
- };
638
- return { allowed: true };
610
+ //#region src/kernel/moleculer/mesh-mtls/mesh-peer-transport.ts
611
+ var LOOKUP_SLOT = Symbol.for("camstack.cluster.mesh-peer-transport-lookup");
612
+ /** Published by the hub broker owner; cleared on shutdown. */
613
+ function setProcessMeshPeerTransportLookup(lookup) {
614
+ if (lookup === null) Reflect.deleteProperty(globalThis, LOOKUP_SLOT);
615
+ else Reflect.set(globalThis, LOOKUP_SLOT, lookup);
639
616
  }
640
- var CONTROL_SLOT = Symbol.for("camstack.cluster.mesh-clear-port-control");
641
- /** Published by the hub's broker owner; cleared on shutdown. */
642
- function setProcessMeshClearPortControl(control) {
643
- if (control === null) Reflect.deleteProperty(globalThis, CONTROL_SLOT);
644
- else Reflect.set(globalThis, CONTROL_SLOT, control);
617
+ function isMeshPeerTransportLookup(value) {
618
+ return value !== null && typeof value === "object" && typeof Reflect.get(value, "transportOf") === "function";
645
619
  }
646
- function isMeshClearPortControl(value) {
647
- return value !== null && typeof value === "object" && typeof Reflect.get(value, "listOnlineAgents") === "function" && typeof Reflect.get(value, "isTlsListening") === "function" && typeof Reflect.get(value, "apply") === "function" && typeof Reflect.get(value, "transportOf") === "function";
648
- }
649
- function getProcessMeshClearPortControl() {
650
- const value = Reflect.get(globalThis, CONTROL_SLOT);
651
- return isMeshClearPortControl(value) ? value : null;
620
+ function getProcessMeshPeerTransportLookup() {
621
+ const value = Reflect.get(globalThis, LOOKUP_SLOT);
622
+ return isMeshPeerTransportLookup(value) ? value : null;
652
623
  }
653
624
  /** `tls` / `clear` for an agent as the hub sees it; `undefined` off the hub. */
654
625
  function getProcessNodeMeshTransport(nodeId) {
655
- return getProcessMeshClearPortControl()?.transportOf(nodeId);
656
- }
657
- /**
658
- * Validate a requested mode against the live mesh. `on` is always allowed; `off`
659
- * only when {@link decideMeshClearPortOff} allows. Does NOT apply it.
660
- */
661
- function checkProcessMeshClearPort(mode) {
662
- if (mode === "on") return { allowed: true };
663
- return decideMeshClearPortOff(getProcessMeshClearPortControl());
664
- }
665
- /** Apply a mode that {@link checkProcessMeshClearPort} allowed. No-op where nobody can. */
666
- async function applyProcessMeshClearPort(mode) {
667
- const control = getProcessMeshClearPortControl();
668
- if (control === null) return false;
669
- await control.apply(mode);
670
- return true;
626
+ return getProcessMeshPeerTransportLookup()?.transportOf(nodeId);
671
627
  }
672
628
  //#endregion
673
629
  //#region ../../node_modules/jose/dist/webapi/lib/buffer_utils.js
@@ -87469,11 +87425,12 @@ import_moleculer.default.Validators;
87469
87425
  //#endregion
87470
87426
  //#region src/kernel/moleculer/mesh-mtls/tls-tcp-transporter.ts
87471
87427
  /**
87472
- * Moleculer TCP transporter with a second mTLS listener (Release A).
87428
+ * Moleculer TCP transporter with a mutual-TLS listener (D826).
87473
87429
  *
87474
- * Hub rollout: clear TCP stays on `port` (default 6000); TLS 1.3 mutual auth
87475
- * listens on `tlsPort` (default 6443). Agents without a certificate keep using
87476
- * 6000. On a TLS socket, any packet whose `sender` ≠ the peer certificate CN
87430
+ * Hub: `hubTlsOnly` — no clear TCP reader and no UDP discovery; TLS 1.3 on
87431
+ * `tlsPort` (default 6443) once mesh material is ready. Agents without mesh
87432
+ * material use clear TCP on their own listen port and dial the hub on TLS when
87433
+ * enrolled. On a TLS socket, any packet whose `sender` ≠ the peer certificate CN
87477
87434
  * is dropped.
87478
87435
  */
87479
87436
  var TcpTransporterBase = Transporters.TCP;
@@ -87517,6 +87474,7 @@ var TlsTcpTransporter = class extends TcpTransporterBase {
87517
87474
  /** Node id (certificate CN) → serial of every peer that completed a mutual-TLS handshake. */
87518
87475
  tlsPeers = /* @__PURE__ */ new Map();
87519
87476
  clearDisabled = false;
87477
+ hubTlsOnly;
87520
87478
  /** Clear-text `TcpWriter.connect` captured once before the TLS wrap (A→B). */
87521
87479
  clearWriterConnect = null;
87522
87480
  writerTlsPatched = false;
@@ -87524,6 +87482,7 @@ var TlsTcpTransporter = class extends TcpTransporterBase {
87524
87482
  super({ ...opts });
87525
87483
  this.meshTls = opts.meshTls ?? null;
87526
87484
  this.crl = opts.crl ?? processMeshCrl();
87485
+ this.hubTlsOnly = opts.hubTlsOnly === true;
87527
87486
  if (this.opts.tlsPort === void 0) this.opts.tlsPort = require_constants$8.DEFAULT_HUB_TLS_TCP_PORT;
87528
87487
  }
87529
87488
  startTcpServer() {
@@ -87534,7 +87493,9 @@ var TlsTcpTransporter = class extends TcpTransporterBase {
87534
87493
  connect() {
87535
87494
  return this.Promise.resolve().then(() => {
87536
87495
  if (this.opts.urls) return this.loadUrls();
87537
- }).then(() => this.startTcpServer()).then(() => this.startTlsServerIfReady()).then(() => this.startUdpServer()).then(() => this.startTimers()).then(() => {
87496
+ }).then(() => this.startTcpServer()).then(() => {
87497
+ if (this.hubTlsOnly) this.disableClearTransport();
87498
+ }).then(() => this.startTlsServerIfReady()).then(() => this.hubTlsOnly ? this.Promise.resolve() : this.startUdpServer()).then(() => this.startTimers()).then(() => {
87538
87499
  this.logger.info("TCP Transporter started.");
87539
87500
  this.connected = true;
87540
87501
  this.nodes.localNode.port = this.opts.port;
@@ -87684,6 +87645,7 @@ var TlsTcpTransporter = class extends TcpTransporterBase {
87684
87645
  }
87685
87646
  /** The switch back: listen on the clear port again and restart UDP discovery. Idempotent. */
87686
87647
  async enableClearTransport() {
87648
+ if (this.hubTlsOnly) return;
87687
87649
  if (!this.clearDisabled) return;
87688
87650
  this.clearDisabled = false;
87689
87651
  if (this.reader !== null && this.reader.server?.listening !== true) await this.reader.listen();
@@ -87971,7 +87933,7 @@ var mintJoinTokenInputSchema = zod.z.object({
87971
87933
  nodeId: zod.z.string().min(1).optional(),
87972
87934
  /** Override hub HTTPS base (default: local-network publicEndpoint). */
87973
87935
  hubUrl: zod.z.string().url().optional(),
87974
- /** Override `host:6000` clear mesh address carried in the token. */
87936
+ /** Override `host:6443` TLS mesh address carried in the token. */
87975
87937
  hubMeshAddress: zod.z.string().min(3).optional(),
87976
87938
  /** Seconds until expiry; capped at 1 h. */
87977
87939
  ttlSec: zod.z.number().int().positive().max(3600).optional()
@@ -88072,9 +88034,7 @@ var KEY_TO_SECTION = {
88072
88034
  trustedProxies: "auth",
88073
88035
  trustedNetworks: "auth",
88074
88036
  [CLUSTER_SECRET_FIELD]: "cluster",
88075
- [MESH_AUTH_MODE_FIELD]: "cluster",
88076
- [MESH_CLEAR_PORT_FIELD]: "cluster",
88077
- [AGENT_DASHBOARD_ORIGINS_FIELD]: "cluster"
88037
+ [MESH_AUTH_MODE_FIELD]: "cluster"
88078
88038
  };
88079
88039
  /** Bytes of a generated cluster secret (D802) — 256 bits, base64url (43 chars). */
88080
88040
  var GENERATED_SECRET_BYTES = 32;
@@ -88102,8 +88062,6 @@ var SystemConfigAddon = class extends require_dist.BaseAddon {
88102
88062
  id = "system-config";
88103
88063
  clusterSecretKeeper = null;
88104
88064
  meshCaKeeper = null;
88105
- /** One warn per process when a retired cutover key is posted with a cluster save. */
88106
- retiredClusterCutoverPatchWarned = false;
88107
88065
  constructor() {
88108
88066
  super({});
88109
88067
  }
@@ -88132,7 +88090,6 @@ var SystemConfigAddon = class extends require_dist.BaseAddon {
88132
88090
  onReady: (ca) => this.onMeshCaReady(ca)
88133
88091
  });
88134
88092
  await this.meshCaKeeper.start();
88135
- await this.applyStoredClearPort();
88136
88093
  this.ctx.logger.info("Initialized — exposes yml-backed sections via getGlobalSettings");
88137
88094
  return {
88138
88095
  customActions: systemConfigMeshActions,
@@ -88149,20 +88106,6 @@ var SystemConfigAddon = class extends require_dist.BaseAddon {
88149
88106
  this.clusterSecretKeeper?.stop();
88150
88107
  this.clusterSecretKeeper = null;
88151
88108
  }
88152
- /**
88153
- * Boot: a stored `meshClearPort: off` is the operator's standing choice, so it
88154
- * is applied WITHOUT the agents gate (nobody is connected yet to be checked).
88155
- * Default `on` changes nothing.
88156
- */
88157
- async applyStoredClearPort() {
88158
- try {
88159
- const stored = (await this.ctx.settings?.getSection("cluster"))?.[MESH_CLEAR_PORT_FIELD];
88160
- if (parseMeshClearPortMode(stored) !== "off") return;
88161
- if (await applyProcessMeshClearPort("off")) this.ctx.logger.info("Mesh clear port is OFF (cluster.meshClearPort)");
88162
- } catch (err) {
88163
- this.ctx.logger.warn("could not apply cluster.meshClearPort at boot", { meta: { error: require_dist.errMsg(err) } });
88164
- }
88165
- }
88166
88109
  async onMeshCaReady(ca) {
88167
88110
  const hubLeaf = await issueMeshLeafForNode(ca, "hub");
88168
88111
  await requestProcessMeshTlsEnable({
@@ -88240,10 +88183,10 @@ var SystemConfigAddon = class extends require_dist.BaseAddon {
88240
88183
  async resolveHubMeshAddress() {
88241
88184
  try {
88242
88185
  const base = (await this.ctx.api?.localNetwork?.getAddresses?.query({}))?.roles?.internal?.resolved;
88243
- if (typeof base === "string" && base.length > 0) return `${new URL(base).hostname}:${require_constants$8.DEFAULT_HUB_TCP_PORT}`;
88186
+ if (typeof base === "string" && base.length > 0) return `${new URL(base).hostname}:${require_constants$8.DEFAULT_HUB_TLS_TCP_PORT}`;
88244
88187
  } catch {}
88245
88188
  const host = (await this.ctx.settings?.getSection("server"))?.["host"];
88246
- return `${typeof host === "string" && host.length > 0 && host !== "0.0.0.0" ? host : "127.0.0.1"}:${require_constants$8.DEFAULT_HUB_TCP_PORT}`;
88189
+ return `${typeof host === "string" && host.length > 0 && host !== "0.0.0.0" ? host : "127.0.0.1"}:${require_constants$8.DEFAULT_HUB_TLS_TCP_PORT}`;
88247
88190
  }
88248
88191
  /** The keychain handle for owner `system`; `null` where there is no door. */
88249
88192
  systemSecrets() {
@@ -88384,6 +88327,14 @@ var SystemConfigAddon = class extends require_dist.BaseAddon {
88384
88327
  if (!this.ctx.settings) throw new Error("system-config: ctx.settings not available — cannot write sections");
88385
88328
  const perSection = /* @__PURE__ */ new Map();
88386
88329
  for (const [key, value] of Object.entries(patch)) {
88330
+ if (key === "meshClearPort") {
88331
+ this.ctx.logger.warn("cluster.meshClearPort is retired (D826) — the hub mesh is TLS-only; ignoring this patch");
88332
+ continue;
88333
+ }
88334
+ if (key === "agentDashboardOrigins") {
88335
+ this.ctx.logger.warn("cluster.agentDashboardOrigins is no longer writable from settings — ignoring this patch");
88336
+ continue;
88337
+ }
88387
88338
  const section = KEY_TO_SECTION[key];
88388
88339
  if (section === void 0) {
88389
88340
  this.ctx.logger.warn("update ignored unknown key (not mapped to any section)", { meta: { key } });
@@ -88424,8 +88375,7 @@ var SystemConfigAddon = class extends require_dist.BaseAddon {
88424
88375
  * enforced (D821) — a legacy `meshAuth` in the patch is ignored.
88425
88376
  */
88426
88377
  async writeClusterSection(patch) {
88427
- const { [MESH_AUTH_MODE_FIELD]: _legacyMode, [MESH_CLEAR_PORT_FIELD]: clearPort, [AGENT_DASHBOARD_ORIGINS_FIELD]: dashboardOrigins, ...secretPatch } = patch;
88428
- if (clearPort !== void 0 || dashboardOrigins !== void 0) this.warnRetiredClusterCutoverPatch(clearPort !== void 0, dashboardOrigins !== void 0);
88378
+ const { [MESH_AUTH_MODE_FIELD]: _legacyMode, ...secretPatch } = patch;
88429
88379
  await this.writeMeshAuthMode("enforced");
88430
88380
  if (Object.keys(secretPatch).length === 0) return;
88431
88381
  if (require_dist.isSecretClear(secretPatch["clusterSecret"])) throw new Error("The cluster secret is mandatory and cannot be cleared — save a new value to rotate it");
@@ -88433,15 +88383,6 @@ var SystemConfigAddon = class extends require_dist.BaseAddon {
88433
88383
  this.ctx.logger.info("Cluster secret updated");
88434
88384
  await this.clusterSecretKeeper?.reload();
88435
88385
  }
88436
- /** Cutover keys were removed from the Cluster form; ignore stray posts from stale clients. */
88437
- warnRetiredClusterCutoverPatch(hadMeshClearPort, hadAgentDashboardOrigins) {
88438
- if (this.retiredClusterCutoverPatchWarned) return;
88439
- this.retiredClusterCutoverPatchWarned = true;
88440
- this.ctx.logger.warn("cluster save ignored retired cutover field(s) — use Pipeline → Cluster / Nodes", { meta: {
88441
- meshClearPort: hadMeshClearPort,
88442
- agentDashboardOrigins: hadAgentDashboardOrigins
88443
- } });
88444
- }
88445
88386
  /** Persist + publish mesh auth mode (always `enforced` after D821). */
88446
88387
  async writeMeshAuthMode(mode) {
88447
88388
  await this.ctx.settings.setSection("cluster", { [MESH_AUTH_MODE_FIELD]: mode });
@@ -88527,7 +88468,6 @@ exports.AGENT_UI_UNLOCK_VERSION = AGENT_UI_UNLOCK_VERSION;
88527
88468
  exports.Errors = Errors;
88528
88469
  exports.JoinTokenJtiStore = JoinTokenJtiStore;
88529
88470
  exports.MESH_AUTH_MODE_FIELD = MESH_AUTH_MODE_FIELD;
88530
- exports.MESH_CLEAR_PORT_FIELD = MESH_CLEAR_PORT_FIELD;
88531
88471
  exports.MeshCaKeeper = MeshCaKeeper;
88532
88472
  exports.MeshCrl = MeshCrl;
88533
88473
  exports.SYSTEM_CONFIG_CLUSTER_SECTION_ID = SYSTEM_CONFIG_CLUSTER_SECTION_ID;
@@ -88536,13 +88476,10 @@ exports.SystemConfigAddon = SystemConfigAddon;
88536
88476
  exports.default = SystemConfigAddon;
88537
88477
  exports.TlsTcpTransporter = TlsTcpTransporter;
88538
88478
  exports.UnlockTicketJtiStore = UnlockTicketJtiStore;
88539
- exports.applyProcessMeshClearPort = applyProcessMeshClearPort;
88540
88479
  exports.caFingerprint = caFingerprint;
88541
88480
  exports.caFingerprintCompact = caFingerprintCompact;
88542
- exports.checkProcessMeshClearPort = checkProcessMeshClearPort;
88543
88481
  exports.createCidrMatcher = createCidrMatcher;
88544
88482
  exports.createMeshCsrPem = createMeshCsrPem;
88545
- exports.decideMeshClearPortOff = decideMeshClearPortOff;
88546
88483
  exports.enrollMeshNode = enrollMeshNode;
88547
88484
  exports.exportMeshPrivateKeyPem = exportMeshPrivateKeyPem;
88548
88485
  exports.generateMeshCa = generateMeshCa;
@@ -88569,8 +88506,8 @@ exports.requestProcessMeshEnforcement = requestProcessMeshEnforcement;
88569
88506
  exports.requireProcessMeshCa = requireProcessMeshCa;
88570
88507
  exports.setProcessMeshAuthMode = setProcessMeshAuthMode;
88571
88508
  exports.setProcessMeshAuthStatusSource = setProcessMeshAuthStatusSource;
88572
- exports.setProcessMeshClearPortControl = setProcessMeshClearPortControl;
88573
88509
  exports.setProcessMeshEnforcer = setProcessMeshEnforcer;
88510
+ exports.setProcessMeshPeerTransportLookup = setProcessMeshPeerTransportLookup;
88574
88511
  exports.setProcessMeshTlsEnabler = setProcessMeshTlsEnabler;
88575
88512
  exports.systemConfigMeshActions = systemConfigMeshActions;
88576
88513
  exports.verifyAgentUiUnlockTicket = verifyAgentUiUnlockTicket;