rivetkit 2.3.19 → 2.3.21

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 (146) hide show
  1. package/dist/browser/client.d.ts +82 -5
  2. package/dist/browser/client.js +302 -60
  3. package/dist/browser/client.js.map +1 -1
  4. package/dist/browser/inspector/client.js +2 -1
  5. package/dist/browser/inspector/client.js.map +1 -1
  6. package/dist/tsup/actor/errors.cjs.map +1 -1
  7. package/dist/tsup/agent-os/index.cjs +35 -1
  8. package/dist/tsup/agent-os/index.cjs.map +1 -1
  9. package/dist/tsup/agent-os/index.d.cts +71 -4
  10. package/dist/tsup/agent-os/index.d.ts +71 -4
  11. package/dist/tsup/agent-os/index.js +35 -1
  12. package/dist/tsup/agent-os/index.js.map +1 -1
  13. package/dist/tsup/{chunk-X7RMJQGY.js → chunk-2CI2IEVN.js} +2 -2
  14. package/dist/tsup/{chunk-WME6KOXW.js → chunk-5EGLHQJJ.js} +2 -2
  15. package/dist/tsup/{chunk-464WE4RF.js → chunk-5IBUZFLP.js} +2 -2
  16. package/dist/tsup/{chunk-PPEIPCW4.cjs → chunk-6LRPYB4Q.cjs} +4 -4
  17. package/dist/tsup/chunk-6LRPYB4Q.cjs.map +1 -0
  18. package/dist/tsup/{chunk-7BRRGBRY.cjs → chunk-APOANSDG.cjs} +10 -10
  19. package/dist/tsup/chunk-APOANSDG.cjs.map +1 -0
  20. package/dist/tsup/{chunk-G4U5L6AX.cjs → chunk-ARGNQGYG.cjs} +3 -3
  21. package/dist/tsup/chunk-ARGNQGYG.cjs.map +1 -0
  22. package/dist/tsup/{chunk-IJUXBWH4.cjs → chunk-B5SNXPSS.cjs} +448 -199
  23. package/dist/tsup/chunk-B5SNXPSS.cjs.map +1 -0
  24. package/dist/tsup/{chunk-4SC2NSAV.js → chunk-CJXBGTVT.js} +2 -2
  25. package/dist/tsup/{chunk-EB77NZL4.js → chunk-CSOHAAZK.js} +33 -1
  26. package/dist/tsup/chunk-CSOHAAZK.js.map +1 -0
  27. package/dist/tsup/{chunk-Z4RAXFSD.cjs → chunk-GHKQC4PD.cjs} +3 -3
  28. package/dist/tsup/chunk-GHKQC4PD.cjs.map +1 -0
  29. package/dist/tsup/chunk-JX2ITWAV.cjs.map +1 -1
  30. package/dist/tsup/chunk-KVFIONKQ.cjs.map +1 -1
  31. package/dist/tsup/{chunk-RJC5O2SD.cjs → chunk-KWGN2ZBJ.cjs} +3 -2
  32. package/dist/tsup/chunk-KWGN2ZBJ.cjs.map +1 -0
  33. package/dist/tsup/{chunk-OGPFN6BT.cjs → chunk-LWSLKKZ5.cjs} +3 -3
  34. package/dist/tsup/chunk-LWSLKKZ5.cjs.map +1 -0
  35. package/dist/tsup/chunk-MYWZCDML.cjs.map +1 -1
  36. package/dist/tsup/{chunk-7A5EIXJJ.cjs → chunk-NL2EIKK6.cjs} +7 -7
  37. package/dist/tsup/chunk-NL2EIKK6.cjs.map +1 -0
  38. package/dist/tsup/{chunk-EO5UOXXY.cjs → chunk-NWCAIWHL.cjs} +34 -2
  39. package/dist/tsup/chunk-NWCAIWHL.cjs.map +1 -0
  40. package/dist/tsup/{chunk-BKX7UDTA.js → chunk-PYRI75DL.js} +314 -65
  41. package/dist/tsup/chunk-PYRI75DL.js.map +1 -0
  42. package/dist/tsup/{chunk-7HTST3NX.js → chunk-RFN3BG6D.js} +3 -3
  43. package/dist/tsup/chunk-RFN3BG6D.js.map +1 -0
  44. package/dist/tsup/{chunk-DN6MD3KK.js → chunk-RGIZNZYO.js} +3 -2
  45. package/dist/tsup/chunk-RGIZNZYO.js.map +1 -0
  46. package/dist/tsup/{chunk-DK3L22R6.js → chunk-VMMXXVDO.js} +4 -4
  47. package/dist/tsup/client/mod.cjs +5 -5
  48. package/dist/tsup/client/mod.cjs.map +1 -1
  49. package/dist/tsup/client/mod.d.cts +12 -3
  50. package/dist/tsup/client/mod.d.ts +12 -3
  51. package/dist/tsup/client/mod.js +4 -4
  52. package/dist/tsup/common/log.cjs +2 -2
  53. package/dist/tsup/common/log.cjs.map +1 -1
  54. package/dist/tsup/common/log.js +1 -1
  55. package/dist/tsup/common/websocket.cjs +3 -3
  56. package/dist/tsup/common/websocket.cjs.map +1 -1
  57. package/dist/tsup/common/websocket.js +2 -2
  58. package/dist/tsup/{config-DEm0yIVV.d.ts → config-Bc1nnvUl.d.ts} +76 -6
  59. package/dist/tsup/{config-8n2AOhXK.d.cts → config-Do_0guSS.d.cts} +76 -6
  60. package/dist/tsup/{context-DwjOVvlE.d.cts → context-CgNkhjdY.d.cts} +1 -1
  61. package/dist/tsup/{context-DGg2-IOm.d.ts → context-oGQxZDPz.d.ts} +1 -1
  62. package/dist/tsup/db/drizzle.cjs +2 -2
  63. package/dist/tsup/db/drizzle.cjs.map +1 -1
  64. package/dist/tsup/db/drizzle.js +1 -1
  65. package/dist/tsup/db/mod.cjs +3 -3
  66. package/dist/tsup/db/mod.cjs.map +1 -1
  67. package/dist/tsup/db/mod.js +2 -2
  68. package/dist/tsup/dynamic/mod.cjs +2 -2
  69. package/dist/tsup/dynamic/mod.cjs.map +1 -1
  70. package/dist/tsup/dynamic/mod.d.cts +2 -1
  71. package/dist/tsup/dynamic/mod.d.ts +2 -1
  72. package/dist/tsup/dynamic/mod.js +1 -1
  73. package/dist/tsup/inspector/mod.cjs +5 -5
  74. package/dist/tsup/inspector/mod.cjs.map +1 -1
  75. package/dist/tsup/inspector/mod.js +4 -4
  76. package/dist/tsup/inspector/workflow.cjs +4 -4
  77. package/dist/tsup/inspector/workflow.cjs.map +1 -1
  78. package/dist/tsup/inspector/workflow.js +3 -3
  79. package/dist/tsup/inspector-tab/mod.cjs +2 -2
  80. package/dist/tsup/inspector-tab/mod.cjs.map +1 -1
  81. package/dist/tsup/inspector-tab/mod.d.cts +3 -2
  82. package/dist/tsup/inspector-tab/mod.d.ts +3 -2
  83. package/dist/tsup/inspector-tab/mod.js +1 -1
  84. package/dist/tsup/mod.cjs +140 -136
  85. package/dist/tsup/mod.cjs.map +1 -1
  86. package/dist/tsup/mod.d.cts +4 -3
  87. package/dist/tsup/mod.d.ts +4 -3
  88. package/dist/tsup/mod.js +44 -40
  89. package/dist/tsup/mod.js.map +1 -1
  90. package/dist/tsup/test/mod.cjs +6 -6
  91. package/dist/tsup/test/mod.cjs.map +1 -1
  92. package/dist/tsup/test/mod.d.cts +2 -1
  93. package/dist/tsup/test/mod.d.ts +2 -1
  94. package/dist/tsup/test/mod.js +4 -4
  95. package/dist/tsup/unstable/migrations.cjs.map +1 -1
  96. package/dist/tsup/utils.cjs +2 -2
  97. package/dist/tsup/utils.cjs.map +1 -1
  98. package/dist/tsup/utils.js +1 -1
  99. package/dist/tsup/workflow/mod.cjs +10 -10
  100. package/dist/tsup/workflow/mod.cjs.map +1 -1
  101. package/dist/tsup/workflow/mod.d.cts +4 -3
  102. package/dist/tsup/workflow/mod.d.ts +4 -3
  103. package/dist/tsup/workflow/mod.js +5 -5
  104. package/package.json +10 -9
  105. package/src/actor/actions.ts +36 -0
  106. package/src/actor/config.ts +27 -0
  107. package/src/actor/definition.ts +6 -1
  108. package/src/actor/mod.ts +5 -0
  109. package/src/actor/tracing.ts +28 -0
  110. package/src/client/actor-conn.ts +34 -1
  111. package/src/client/actor-handle.ts +29 -1
  112. package/src/client/auth.ts +37 -0
  113. package/src/client/client.ts +10 -2
  114. package/src/client/config.ts +12 -1
  115. package/src/client/mod.ts +9 -0
  116. package/src/client/token-provider.test.ts +86 -0
  117. package/src/client/token-provider.ts +93 -0
  118. package/src/client/utils.ts +1 -0
  119. package/src/engine-client/actor-websocket-client.ts +2 -1
  120. package/src/engine-client/api-endpoints.ts +28 -0
  121. package/src/engine-client/driver.ts +4 -0
  122. package/src/engine-client/mod.ts +201 -64
  123. package/src/registry/config/envoy.ts +1 -17
  124. package/src/registry/config/index.test.ts +2 -2
  125. package/src/registry/config/index.ts +7 -2
  126. package/src/registry/index.ts +28 -0
  127. package/src/registry/native.ts +18 -0
  128. package/src/registry/runtime.ts +8 -0
  129. package/dist/tsup/chunk-7A5EIXJJ.cjs.map +0 -1
  130. package/dist/tsup/chunk-7BRRGBRY.cjs.map +0 -1
  131. package/dist/tsup/chunk-7HTST3NX.js.map +0 -1
  132. package/dist/tsup/chunk-BKX7UDTA.js.map +0 -1
  133. package/dist/tsup/chunk-DN6MD3KK.js.map +0 -1
  134. package/dist/tsup/chunk-EB77NZL4.js.map +0 -1
  135. package/dist/tsup/chunk-EO5UOXXY.cjs.map +0 -1
  136. package/dist/tsup/chunk-G4U5L6AX.cjs.map +0 -1
  137. package/dist/tsup/chunk-IJUXBWH4.cjs.map +0 -1
  138. package/dist/tsup/chunk-OGPFN6BT.cjs.map +0 -1
  139. package/dist/tsup/chunk-PPEIPCW4.cjs.map +0 -1
  140. package/dist/tsup/chunk-RJC5O2SD.cjs.map +0 -1
  141. package/dist/tsup/chunk-Z4RAXFSD.cjs.map +0 -1
  142. /package/dist/tsup/{chunk-X7RMJQGY.js.map → chunk-2CI2IEVN.js.map} +0 -0
  143. /package/dist/tsup/{chunk-WME6KOXW.js.map → chunk-5EGLHQJJ.js.map} +0 -0
  144. /package/dist/tsup/{chunk-464WE4RF.js.map → chunk-5IBUZFLP.js.map} +0 -0
  145. /package/dist/tsup/{chunk-4SC2NSAV.js.map → chunk-CJXBGTVT.js.map} +0 -0
  146. /package/dist/tsup/{chunk-DK3L22R6.js.map → chunk-VMMXXVDO.js.map} +0 -0
@@ -5,7 +5,7 @@ import {
5
5
  import {
6
6
  importWebSocket,
7
7
  logger
8
- } from "./chunk-X7RMJQGY.js";
8
+ } from "./chunk-2CI2IEVN.js";
9
9
  import {
10
10
  AsyncMutex
11
11
  } from "./chunk-JTHHCZCZ.js";
@@ -35,7 +35,7 @@ import {
35
35
  serializeWithEncoding,
36
36
  stringifyError,
37
37
  uint8ArrayToBase64
38
- } from "./chunk-DN6MD3KK.js";
38
+ } from "./chunk-RGIZNZYO.js";
39
39
  import {
40
40
  INTERNAL_ERROR_CODE,
41
41
  RivetError,
@@ -2574,7 +2574,8 @@ async function sendHttpRequest(opts) {
2574
2574
  {
2575
2575
  metadata: responseData.metadata,
2576
2576
  rayId: rayId ?? void 0,
2577
- actor: responseData.actor
2577
+ actor: responseData.actor,
2578
+ statusCode: response.status
2578
2579
  }
2579
2580
  );
2580
2581
  } catch (error) {
@@ -3490,6 +3491,22 @@ var ActorHandleRaw = class {
3490
3491
  "dynamic actor resolution did not produce a direct actor id"
3491
3492
  );
3492
3493
  }
3494
+ /** Issue a token scoped to this actor. Defaults to actor gateway read access. */
3495
+ async issueToken(options = {}) {
3496
+ const actorId = await this.resolve();
3497
+ const permissions = options.permissions ?? {
3498
+ actor_gateway: ["read"]
3499
+ };
3500
+ const grants = Object.keys(permissions).flatMap((resource) => {
3501
+ const operations = permissions[resource];
3502
+ return operations ? [{ resource, target: { id: actorId }, operations }] : [];
3503
+ });
3504
+ return this.#driver.issueToken({
3505
+ subject: options.subject,
3506
+ expiresIn: options.expiresIn,
3507
+ grants
3508
+ });
3509
+ }
3493
3510
  /**
3494
3511
  * Returns the raw URL for routing traffic to the actor.
3495
3512
  */
@@ -3524,6 +3541,8 @@ var ACTOR_CONNS_SYMBOL = /* @__PURE__ */ Symbol("actorConns");
3524
3541
  var CREATE_ACTOR_CONN_PROXY = /* @__PURE__ */ Symbol("createActorConnProxy");
3525
3542
  var ClientRaw = class {
3526
3543
  #disposed = false;
3544
+ /** Issue namespace-scoped tokens with an explicit grant list. */
3545
+ auth;
3527
3546
  [ACTOR_CONNS_SYMBOL] = /* @__PURE__ */ new Set();
3528
3547
  #driver;
3529
3548
  #encodingKind;
@@ -3535,6 +3554,9 @@ var ClientRaw = class {
3535
3554
  */
3536
3555
  constructor(driver, options = {}) {
3537
3556
  this.#driver = driver;
3557
+ this.auth = {
3558
+ issueToken: (issueOptions) => this.#driver.issueToken(issueOptions)
3559
+ };
3538
3560
  this.#encodingKind = options.encoding ?? "bare";
3539
3561
  this.#gatewayOptions = options.gateway ?? {};
3540
3562
  this.#currentActorInvocation = options.currentActorInvocation;
@@ -3827,6 +3849,74 @@ function createActorProxy(handle) {
3827
3849
  });
3828
3850
  }
3829
3851
 
3852
+ // src/client/token-provider.ts
3853
+ function isInvalidToken(group, code) {
3854
+ return group === "auth" && (code === "invalid_token" || code === "token_expired");
3855
+ }
3856
+ function isInvalidTokenResponse(response) {
3857
+ if (response.status !== 401) return false;
3858
+ const error = response.headers.get("x-rivet-error");
3859
+ if (!error) return false;
3860
+ const separator = error.indexOf(".");
3861
+ return separator > 0 && isInvalidToken(error.slice(0, separator), error.slice(separator + 1));
3862
+ }
3863
+ var TokenProvider = class {
3864
+ constructor(getToken) {
3865
+ this.getToken = getToken;
3866
+ }
3867
+ #cached;
3868
+ #pending;
3869
+ #pendingForce = false;
3870
+ async current() {
3871
+ if (this.#cached && (this.#cached.expiresAt === void 0 || Date.now() < this.#cached.expiresAt - 5e3)) {
3872
+ return this.#cached.token;
3873
+ }
3874
+ return this.#load(false);
3875
+ }
3876
+ /** A late rejection for an older token must never erase a newer credential. */
3877
+ async refreshIfCurrent(failedToken) {
3878
+ var _a;
3879
+ if (this.#pending !== void 0) {
3880
+ const wasForced = this.#pendingForce;
3881
+ const refreshed = await this.#pending;
3882
+ if (wasForced || refreshed !== failedToken) return refreshed;
3883
+ }
3884
+ if (((_a = this.#cached) == null ? void 0 : _a.token) !== failedToken) {
3885
+ return this.current();
3886
+ }
3887
+ return this.#load(true);
3888
+ }
3889
+ #load(forceRefresh) {
3890
+ if (this.#pending !== void 0) return this.#pending;
3891
+ const pending = Promise.resolve().then(() => this.getToken({ forceRefresh })).then((token) => {
3892
+ if (typeof token !== "string" || token.length === 0) {
3893
+ throw new Error(
3894
+ "getToken must resolve to a nonempty string"
3895
+ );
3896
+ }
3897
+ this.#cached = { token, expiresAt: jwtExpiration(token) };
3898
+ return token;
3899
+ }).finally(() => {
3900
+ if (this.#pending === pending) this.#pending = void 0;
3901
+ });
3902
+ this.#pending = pending;
3903
+ this.#pendingForce = forceRefresh;
3904
+ return pending;
3905
+ }
3906
+ };
3907
+ function jwtExpiration(token) {
3908
+ try {
3909
+ const payload = token.split(".")[1];
3910
+ if (!payload) return void 0;
3911
+ const claims = JSON.parse(
3912
+ atob(payload.replace(/-/g, "+").replace(/_/g, "/"))
3913
+ );
3914
+ return typeof claims.exp === "number" && Number.isSafeInteger(claims.exp) ? claims.exp * 1e3 : void 0;
3915
+ } catch {
3916
+ return void 0;
3917
+ }
3918
+ }
3919
+
3830
3920
  // src/client/actor-conn.ts
3831
3921
  var CONNECT_SYMBOL = /* @__PURE__ */ Symbol("connect");
3832
3922
  var ActorConnRaw = class {
@@ -3856,6 +3946,7 @@ var ActorConnRaw = class {
3856
3946
  /** Promise used to indicate the socket has connected successfully. This will be rejected if the connection fails. */
3857
3947
  #onOpenPromise;
3858
3948
  #websocket;
3949
+ #authRetryAvailable = true;
3859
3950
  #client;
3860
3951
  #driver;
3861
3952
  #currentActorInvocation;
@@ -4101,6 +4192,10 @@ var ActorConnRaw = class {
4101
4192
  if (error instanceof ActorConnDisposed) {
4102
4193
  return false;
4103
4194
  }
4195
+ if (error instanceof RivetError && isInvalidToken(error.group, error.code) && this.#driver.refreshAuthToken && this.#authRetryAvailable) {
4196
+ this.#authRetryAvailable = false;
4197
+ return true;
4198
+ }
4104
4199
  if (error instanceof RivetError && this.#shouldReconnectForStaleActor(error.group, error.code)) {
4105
4200
  return true;
4106
4201
  }
@@ -4225,6 +4320,7 @@ var ActorConnRaw = class {
4225
4320
  messageQueueLength: this.#messageQueue.length,
4226
4321
  connId: this.#connId
4227
4322
  });
4323
+ this.#authRetryAvailable = true;
4228
4324
  this.#setConnStatus("connected");
4229
4325
  if (this.#onOpenPromise) {
4230
4326
  this.#onOpenPromise.resolve(void 0);
@@ -4367,7 +4463,8 @@ var ActorConnRaw = class {
4367
4463
  }
4368
4464
  /** Called by the onclose event from drivers. */
4369
4465
  async #handleOnClose(event) {
4370
- var _a;
4466
+ var _a, _b, _c;
4467
+ const failedSocket = this.#websocket;
4371
4468
  const closeEvent = event;
4372
4469
  const wasClean = closeEvent.wasClean;
4373
4470
  const wasConnected = this.#connStatus === "connected";
@@ -4389,9 +4486,24 @@ var ActorConnRaw = class {
4389
4486
  const parsed = parseWebSocketCloseReason(reason);
4390
4487
  if (parsed) {
4391
4488
  const { group, code, rayId } = parsed;
4489
+ if (isInvalidToken(group, code) && closeEvent.code === 1008 && failedSocket) {
4490
+ try {
4491
+ if (!await ((_b = (_a = this.#driver).refreshAuthToken) == null ? void 0 : _b.call(
4492
+ _a,
4493
+ failedSocket
4494
+ ))) {
4495
+ this.#authRetryAvailable = false;
4496
+ }
4497
+ } catch {
4498
+ logger().warn("token renewal failed");
4499
+ this.#authRetryAvailable = false;
4500
+ }
4501
+ } else if (isInvalidToken(group, code)) {
4502
+ this.#authRetryAvailable = false;
4503
+ }
4392
4504
  if (this.#shouldReconnectForStaleActor(group, code)) {
4393
4505
  this.#clearResolvedActorIdentity();
4394
- (_a = this.#onOpenPromise) == null ? void 0 : _a.reject(
4506
+ (_c = this.#onOpenPromise) == null ? void 0 : _c.reject(
4395
4507
  new RivetError(
4396
4508
  group,
4397
4509
  code,
@@ -4438,7 +4550,7 @@ var ActorConnRaw = class {
4438
4550
  if (error instanceof RivetError) {
4439
4551
  this.#dispatchActorError(error);
4440
4552
  }
4441
- if (wasConnected) {
4553
+ if (wasConnected && this.#authRetryAvailable) {
4442
4554
  logger().debug({
4443
4555
  msg: "triggering reconnect",
4444
4556
  connId: this.#connId
@@ -4911,6 +5023,25 @@ var ActorConnRaw = class {
4911
5023
  // src/client/config.ts
4912
5024
  import z2 from "zod/v4";
4913
5025
 
5026
+ // src/common/engine.ts
5027
+ var ENGINE_HOST = "127.0.0.1";
5028
+ var ENGINE_PORT = 6420;
5029
+ var ENGINE_ENDPOINT = buildEngineEndpoint(ENGINE_HOST, ENGINE_PORT);
5030
+ function buildEngineEndpoint(host, port) {
5031
+ const urlHost = host.includes(":") && !host.startsWith("[") ? `[${host}]` : host;
5032
+ return `http://${urlHost}:${port}`;
5033
+ }
5034
+ function isLocalEngineEndpoint(endpoint) {
5035
+ let url;
5036
+ try {
5037
+ url = new URL(endpoint);
5038
+ } catch {
5039
+ return false;
5040
+ }
5041
+ const hostname = url.hostname.toLowerCase();
5042
+ return hostname === "localhost" || hostname === "0.0.0.0" || hostname === "::" || hostname === "[::]" || hostname === "::1" || hostname === "[::1]" || /^127(?:\.\d{1,3}){0,3}$/.test(hostname);
5043
+ }
5044
+
4914
5045
  // src/utils/endpoint-parser.ts
4915
5046
  function tryParseEndpoint(ctx, options) {
4916
5047
  const {
@@ -5008,6 +5139,8 @@ var ClientConfigSchemaBase = z2.object({
5008
5139
  }),
5009
5140
  /** Token to use to authenticate with the API. */
5010
5141
  token: z2.string().optional().transform((val) => val ?? getRivetToken()),
5142
+ /** Issue and renew a client token on demand. Overrides the static token when provided. */
5143
+ getToken: z2.custom().optional(),
5011
5144
  /** Namespace to connect to. */
5012
5145
  namespace: z2.string().optional().transform((val) => val ?? getRivetNamespace()),
5013
5146
  /** Name of the envoy pool. This is used to group together envoys in to different pools. */
@@ -5052,7 +5185,7 @@ function transformClientConfig(config, ctx) {
5052
5185
  ...config,
5053
5186
  endpoint: parsedEndpoint == null ? void 0 : parsedEndpoint.endpoint,
5054
5187
  namespace: (parsedEndpoint == null ? void 0 : parsedEndpoint.namespace) ?? config.namespace ?? "default",
5055
- token: (parsedEndpoint == null ? void 0 : parsedEndpoint.token) ?? config.token
5188
+ token: (parsedEndpoint == null ? void 0 : parsedEndpoint.token) ?? config.token ?? (config.endpoint && isLocalEngineEndpoint(config.endpoint) ? "default" : void 0)
5056
5189
  };
5057
5190
  }
5058
5191
  function convertRegistryConfigToClientConfig(config) {
@@ -5060,6 +5193,7 @@ function convertRegistryConfigToClientConfig(config) {
5060
5193
  return {
5061
5194
  endpoint: config.endpoint,
5062
5195
  token: config.token,
5196
+ getToken: void 0,
5063
5197
  namespace: config.namespace,
5064
5198
  poolName: config.envoy.poolName,
5065
5199
  headers: config.headers,
@@ -5404,7 +5538,8 @@ async function openWebSocketToGateway(runConfig, gatewayUrl, encoding, params, o
5404
5538
  const ackHookToken = typeof process !== "undefined" && process.env.VITEST ? crypto.randomUUID() : void 0;
5405
5539
  logger2().debug({
5406
5540
  msg: "opening websocket to actor via guard",
5407
- gatewayUrl
5541
+ // Gateway URLs can embed credentials; never include the path or query in logs.
5542
+ origin: new URL(gatewayUrl).origin
5408
5543
  });
5409
5544
  const ws = new WebSocket2(
5410
5545
  gatewayUrl,
@@ -5499,6 +5634,14 @@ async function apiCall(config, method, path, body) {
5499
5634
  }
5500
5635
 
5501
5636
  // src/engine-client/api-endpoints.ts
5637
+ async function issueToken(config, options) {
5638
+ return apiCall(config, "POST", "/auth/tokens", {
5639
+ namespace: config.namespace,
5640
+ subject: options.subject,
5641
+ duration: options.expiresIn,
5642
+ grants: options.grants
5643
+ });
5644
+ }
5502
5645
  async function getActor(config, _, actorId) {
5503
5646
  return apiCall(
5504
5647
  config,
@@ -5747,6 +5890,8 @@ function closeWebSocketIfOpen(ws, code, reason) {
5747
5890
  var RemoteEngineControlClient = class {
5748
5891
  #config;
5749
5892
  #metadataPromise;
5893
+ #tokenProvider;
5894
+ #webSocketTokens = /* @__PURE__ */ new WeakMap();
5750
5895
  constructor(runConfig) {
5751
5896
  if (getNextPhase() === "phase-production-build") {
5752
5897
  logger2().info(
@@ -5755,6 +5900,8 @@ var RemoteEngineControlClient = class {
5755
5900
  runConfig.disableMetadataLookup = true;
5756
5901
  }
5757
5902
  this.#config = { ...runConfig };
5903
+ if (runConfig.getToken)
5904
+ this.#tokenProvider = new TokenProvider(runConfig.getToken);
5758
5905
  if (!runConfig.disableMetadataLookup) {
5759
5906
  this.#metadataPromise = lookupMetadataCached(this.#config).then(
5760
5907
  (metadataData) => {
@@ -5763,14 +5910,13 @@ var RemoteEngineControlClient = class {
5763
5910
  if (metadataData.clientNamespace) {
5764
5911
  this.#config.namespace = metadataData.clientNamespace;
5765
5912
  }
5766
- if (metadataData.clientToken) {
5913
+ if (metadataData.clientToken && !this.#tokenProvider) {
5767
5914
  this.#config.token = metadataData.clientToken;
5768
5915
  }
5769
5916
  logger2().info({
5770
5917
  msg: "overriding client endpoint",
5771
5918
  endpoint: metadataData.clientEndpoint,
5772
- namespace: metadataData.clientNamespace,
5773
- token: metadataData.clientToken
5919
+ namespace: metadataData.clientNamespace
5774
5920
  });
5775
5921
  }
5776
5922
  logger2().info({
@@ -5783,12 +5929,47 @@ var RemoteEngineControlClient = class {
5783
5929
  );
5784
5930
  }
5785
5931
  }
5932
+ async #authorizedConfig() {
5933
+ if (!this.#tokenProvider) return this.#config;
5934
+ return { ...this.#config, token: await this.#tokenProvider.current() };
5935
+ }
5936
+ async #withCredential(request, readOnly = false) {
5937
+ const config = await this.#authorizedConfig();
5938
+ try {
5939
+ return await request(config);
5940
+ } catch (error) {
5941
+ if (this.#tokenProvider && config.token && error instanceof RivetError && error.statusCode === 401 && isInvalidToken(error.group, error.code)) {
5942
+ if (readOnly) {
5943
+ const token = await this.#tokenProvider.refreshIfCurrent(
5944
+ config.token
5945
+ );
5946
+ return request({ ...this.#config, token });
5947
+ }
5948
+ await this.#tokenProvider.refreshIfCurrent(config.token);
5949
+ }
5950
+ throw error;
5951
+ }
5952
+ }
5953
+ async issueToken(options) {
5954
+ await this.#metadataPromise;
5955
+ const response = await this.#withCredential(
5956
+ (config) => issueToken(config, options)
5957
+ );
5958
+ return {
5959
+ token: response.token,
5960
+ issuedAt: response.issued_ts,
5961
+ expiresAt: response.expires_ts
5962
+ };
5963
+ }
5786
5964
  async getForId({
5787
5965
  name,
5788
5966
  actorId
5789
5967
  }) {
5790
5968
  await this.#metadataPromise;
5791
- const response = await getActor(this.#config, name, actorId);
5969
+ const response = await this.#withCredential(
5970
+ (config) => getActor(config, name, actorId),
5971
+ true
5972
+ );
5792
5973
  const actor = response.actors[0];
5793
5974
  if (!actor) return void 0;
5794
5975
  if (actor.name !== name) {
@@ -5809,7 +5990,10 @@ var RemoteEngineControlClient = class {
5809
5990
  await this.#metadataPromise;
5810
5991
  logger2().debug({ msg: "getWithKey: searching for actor", name, key });
5811
5992
  try {
5812
- const response = await getActorByKey(this.#config, name, key);
5993
+ const response = await this.#withCredential(
5994
+ (config) => getActorByKey(config, name, key),
5995
+ true
5996
+ );
5813
5997
  const actor = response.actors[0];
5814
5998
  if (!actor) return void 0;
5815
5999
  logger2().debug({
@@ -5842,16 +6026,18 @@ var RemoteEngineControlClient = class {
5842
6026
  key
5843
6027
  });
5844
6028
  try {
5845
- const { actor, created } = await getOrCreateActor(this.#config, {
5846
- datacenter: region,
5847
- name,
5848
- key: serializeActorKey(key),
5849
- runner_name_selector: poolName ?? this.#config.poolName,
5850
- input: actorInput ? uint8ArrayToBase64(
5851
- encodeCborCompat(actorInput)
5852
- ) : void 0,
5853
- crash_policy: crashPolicy ?? "sleep"
5854
- });
6029
+ const { actor, created } = await this.#withCredential(
6030
+ (config) => getOrCreateActor(config, {
6031
+ datacenter: region,
6032
+ name,
6033
+ key: serializeActorKey(key),
6034
+ runner_name_selector: poolName ?? this.#config.poolName,
6035
+ input: actorInput ? uint8ArrayToBase64(
6036
+ encodeCborCompat(actorInput)
6037
+ ) : void 0,
6038
+ crash_policy: crashPolicy ?? "sleep"
6039
+ })
6040
+ );
5855
6041
  logger2().info({
5856
6042
  msg: "getOrCreateWithKey: actor ready",
5857
6043
  actorId: actor.actor_id,
@@ -5867,7 +6053,10 @@ var RemoteEngineControlClient = class {
5867
6053
  name,
5868
6054
  key
5869
6055
  });
5870
- const response = await getActorByKey(this.#config, name, key);
6056
+ const response = await this.#withCredential(
6057
+ (config) => getActorByKey(config, name, key),
6058
+ true
6059
+ );
5871
6060
  const existing = response.actors[0];
5872
6061
  if (!existing) throw error;
5873
6062
  logger2().info({
@@ -5891,14 +6080,18 @@ var RemoteEngineControlClient = class {
5891
6080
  }) {
5892
6081
  await this.#metadataPromise;
5893
6082
  logger2().info({ msg: "creating actor via engine api", name, key });
5894
- const result = await createActor(this.#config, {
5895
- datacenter: region,
5896
- name,
5897
- runner_name_selector: poolName ?? this.#config.poolName,
5898
- key: serializeActorKey(key),
5899
- input: input ? uint8ArrayToBase64(encodeCborCompat(input)) : void 0,
5900
- crash_policy: crashPolicy ?? "sleep"
5901
- });
6083
+ const result = await this.#withCredential(
6084
+ (config) => createActor(config, {
6085
+ datacenter: region,
6086
+ name,
6087
+ runner_name_selector: poolName ?? this.#config.poolName,
6088
+ key: serializeActorKey(key),
6089
+ input: input ? uint8ArrayToBase64(
6090
+ encodeCborCompat(input)
6091
+ ) : void 0,
6092
+ crash_policy: crashPolicy ?? "sleep"
6093
+ })
6094
+ );
5902
6095
  logger2().info({
5903
6096
  msg: "actor created",
5904
6097
  actorId: result.actor.actor_id,
@@ -5910,43 +6103,61 @@ var RemoteEngineControlClient = class {
5910
6103
  async listActors({ name }) {
5911
6104
  await this.#metadataPromise;
5912
6105
  logger2().debug({ msg: "listing actors via engine api", name });
5913
- const response = await listActorsByName(this.#config, name);
6106
+ const response = await this.#withCredential(
6107
+ (config) => listActorsByName(config, name),
6108
+ true
6109
+ );
5914
6110
  return response.actors.map(apiActorToOutput);
5915
6111
  }
5916
6112
  async destroyActor(actorId) {
5917
6113
  await this.#metadataPromise;
5918
6114
  logger2().info({ msg: "destroying actor via engine api", actorId });
5919
- await destroyActor(this.#config, actorId);
6115
+ await this.#withCredential((config) => destroyActor(config, actorId));
5920
6116
  logger2().info({ msg: "actor destroyed", actorId });
5921
6117
  }
5922
6118
  async sendRequest(target, actorRequest, options = {}) {
6119
+ var _a;
5923
6120
  await this.#metadataPromise;
5924
- const path = requestPath(actorRequest);
5925
- const gatewayUrl = this.#buildGatewayUrlForTarget(
5926
- target,
5927
- path,
5928
- options
5929
- );
6121
+ const config = await this.#authorizedConfig();
5930
6122
  const httpOptions = {
5931
6123
  ...options,
5932
6124
  directActorId: shouldSkipReadyWait(options) ? directActorIdFromTarget(target) : void 0
5933
6125
  };
5934
- return sendHttpRequestToGateway(
5935
- this.#config,
5936
- gatewayUrl,
6126
+ const send = (current) => sendHttpRequestToGateway(
6127
+ current,
6128
+ this.#buildGatewayUrlForTarget(
6129
+ current,
6130
+ target,
6131
+ requestPath(actorRequest),
6132
+ options
6133
+ ),
5937
6134
  actorRequest,
5938
6135
  httpOptions
5939
6136
  );
6137
+ const response = await send(config);
6138
+ if (!this.#tokenProvider || !config.token || !isInvalidTokenResponse(response))
6139
+ return response;
6140
+ if ((actorRequest.method === "GET" || actorRequest.method === "HEAD") && !("getOrCreateForKey" in target)) {
6141
+ const token = await this.#tokenProvider.refreshIfCurrent(
6142
+ config.token
6143
+ );
6144
+ await ((_a = response.body) == null ? void 0 : _a.cancel());
6145
+ return send({ ...this.#config, token });
6146
+ }
6147
+ await this.#tokenProvider.refreshIfCurrent(config.token);
6148
+ return response;
5940
6149
  }
5941
6150
  async openWebSocket(path, target, encoding, params, options = {}) {
5942
6151
  await this.#metadataPromise;
6152
+ const config = await this.#authorizedConfig();
5943
6153
  const gatewayUrl = this.#buildGatewayUrlForTarget(
6154
+ config,
5944
6155
  target,
5945
6156
  path,
5946
6157
  options
5947
6158
  );
5948
- return openWebSocketToGateway(
5949
- this.#config,
6159
+ const ws = await openWebSocketToGateway(
6160
+ config,
5950
6161
  gatewayUrl,
5951
6162
  encoding,
5952
6163
  params,
@@ -5955,25 +6166,59 @@ var RemoteEngineControlClient = class {
5955
6166
  directActorId: shouldSkipReadyWait(options) ? directActorIdFromTarget(target) : void 0
5956
6167
  }
5957
6168
  );
6169
+ this.#watchWebSocketAuth(ws, config.token);
6170
+ return ws;
6171
+ }
6172
+ async refreshAuthToken(ws) {
6173
+ const context2 = this.#webSocketTokens.get(ws);
6174
+ if (!(context2 == null ? void 0 : context2.refresh)) return false;
6175
+ await context2.refresh;
6176
+ return true;
6177
+ }
6178
+ #watchWebSocketAuth(ws, token) {
6179
+ const tokenProvider = this.#tokenProvider;
6180
+ if (!tokenProvider || !token) return;
6181
+ const context2 = {};
6182
+ this.#webSocketTokens.set(ws, context2);
6183
+ ws.addEventListener(
6184
+ "close",
6185
+ (event) => {
6186
+ if (event.code !== 1008 || !event.reason) return;
6187
+ const separator = event.reason.indexOf(".");
6188
+ if (separator < 0) return;
6189
+ const code = event.reason.slice(separator + 1).split(/[\s:#]/, 1)[0];
6190
+ if (isInvalidToken(event.reason.slice(0, separator), code)) {
6191
+ context2.refresh = tokenProvider.refreshIfCurrent(token).catch((error) => {
6192
+ logger2().warn(
6193
+ "failed to renew authentication token"
6194
+ );
6195
+ throw error;
6196
+ });
6197
+ context2.refresh.catch(() => {
6198
+ });
6199
+ }
6200
+ }
6201
+ );
5958
6202
  }
5959
6203
  async buildGatewayUrl(target, options = {}) {
5960
6204
  await this.#metadataPromise;
5961
- return this.#buildGatewayUrlForTarget(target, "", options);
6205
+ return this.#buildGatewayUrlForTarget(
6206
+ await this.#authorizedConfig(),
6207
+ target,
6208
+ "",
6209
+ options
6210
+ );
5962
6211
  }
5963
6212
  async proxyRequest(_c, actorRequest, actorId) {
5964
- await this.#metadataPromise;
5965
- const gatewayUrl = this.#buildGatewayUrlForTarget(
5966
- { directId: actorId },
5967
- requestPath(actorRequest)
5968
- );
5969
- return sendHttpRequestToGateway(this.#config, gatewayUrl, actorRequest);
6213
+ return this.sendRequest({ directId: actorId }, actorRequest);
5970
6214
  }
5971
6215
  async proxyWebSocket(c, path, actorId, encoding, params) {
5972
- var _a, _b;
6216
+ var _a;
5973
6217
  await this.#metadataPromise;
5974
- const upgradeWebSocket = (_b = (_a = this.#config).getUpgradeWebSocket) == null ? void 0 : _b.call(_a);
6218
+ const config = await this.#authorizedConfig();
6219
+ const upgradeWebSocket = (_a = config.getUpgradeWebSocket) == null ? void 0 : _a.call(config);
5975
6220
  invariant3(upgradeWebSocket, "missing getUpgradeWebSocket");
5976
- const endpoint = getEndpoint(this.#config);
6221
+ const endpoint = getEndpoint(config);
5977
6222
  const guardUrl = combineUrlPath(endpoint, path);
5978
6223
  const wsGuardUrl = guardUrl.replace("http://", "ws://");
5979
6224
  logger2().debug({
@@ -5983,7 +6228,7 @@ var RemoteEngineControlClient = class {
5983
6228
  guardUrl
5984
6229
  });
5985
6230
  const protocols = buildWebSocketProtocols(
5986
- this.#config,
6231
+ config,
5987
6232
  encoding,
5988
6233
  params,
5989
6234
  void 0,
@@ -6001,8 +6246,8 @@ var RemoteEngineControlClient = class {
6001
6246
  setGetUpgradeWebSocket(getUpgradeWebSocket) {
6002
6247
  this.#config.getUpgradeWebSocket = getUpgradeWebSocket;
6003
6248
  }
6004
- #buildGatewayUrlForTarget(target, path, options = {}) {
6005
- const endpoint = getEndpoint(this.#config);
6249
+ #buildGatewayUrlForTarget(config, target, path, options = {}) {
6250
+ const endpoint = getEndpoint(config);
6006
6251
  if (shouldSkipReadyWait(options) && directActorIdFromTarget(target) && canUseDirectSkipReadyWaitPath(path)) {
6007
6252
  return combineUrlPath(endpoint, path);
6008
6253
  }
@@ -6010,7 +6255,7 @@ var RemoteEngineControlClient = class {
6010
6255
  return buildActorGatewayUrl(
6011
6256
  endpoint,
6012
6257
  target.directId,
6013
- this.#config.token,
6258
+ config.token,
6014
6259
  path
6015
6260
  );
6016
6261
  }
@@ -6018,20 +6263,20 @@ var RemoteEngineControlClient = class {
6018
6263
  return buildActorGatewayUrl(
6019
6264
  endpoint,
6020
6265
  target.getForId.actorId,
6021
- this.#config.token,
6266
+ config.token,
6022
6267
  path
6023
6268
  );
6024
6269
  }
6025
6270
  if ("getForKey" in target || "getOrCreateForKey" in target) {
6026
6271
  return buildActorQueryGatewayUrl(
6027
6272
  endpoint,
6028
- this.#config.namespace,
6273
+ config.namespace,
6029
6274
  target,
6030
- this.#config.token,
6275
+ config.token,
6031
6276
  path,
6032
- this.#config.maxInputSize,
6277
+ config.maxInputSize,
6033
6278
  void 0,
6034
- "getOrCreateForKey" in target ? target.getOrCreateForKey.poolName ?? this.#config.poolName : void 0,
6279
+ "getOrCreateForKey" in target ? target.getOrCreateForKey.poolName ?? config.poolName : void 0,
6035
6280
  options
6036
6281
  );
6037
6282
  }
@@ -6094,6 +6339,10 @@ export {
6094
6339
  isResponseLike,
6095
6340
  ActorHandleRaw,
6096
6341
  createClientWithDriver,
6342
+ ENGINE_HOST,
6343
+ ENGINE_PORT,
6344
+ buildEngineEndpoint,
6345
+ isLocalEngineEndpoint,
6097
6346
  tryParseEndpoint,
6098
6347
  ClientConfigSchema,
6099
6348
  convertRegistryConfigToClientConfig,
@@ -6101,4 +6350,4 @@ export {
6101
6350
  updateRunnerConfig,
6102
6351
  RemoteEngineControlClient
6103
6352
  };
6104
- //# sourceMappingURL=chunk-BKX7UDTA.js.map
6353
+ //# sourceMappingURL=chunk-PYRI75DL.js.map