@fleetless/sdk 4.3.0 → 4.4.0-next.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -243,7 +243,7 @@ function isRenderKind(kind) {
243
243
  }
244
244
  }
245
245
  }
246
- async function forEachWithConcurrency(items, limit, fn) {
246
+ async function forEachWithConcurrency(items, limit2, fn) {
247
247
  let next = 0;
248
248
  let failed = false;
249
249
  let firstError;
@@ -261,7 +261,7 @@ async function forEachWithConcurrency(items, limit, fn) {
261
261
  }
262
262
  }
263
263
  }
264
- await Promise.all(Array.from({ length: Math.min(limit, items.length) }, () => worker()));
264
+ await Promise.all(Array.from({ length: Math.min(limit2, items.length) }, () => worker()));
265
265
  if (failed) throw firstError;
266
266
  }
267
267
  function createAssetsApi(http) {
@@ -410,7 +410,7 @@ function createAssetsApi(http) {
410
410
  };
411
411
  }
412
412
 
413
- // node_modules/.pnpm/@fleetless+contracts@6.0.0/node_modules/@fleetless/contracts/dist/common.js
413
+ // node_modules/.pnpm/@fleetless+contracts@6.2.0-next.2/node_modules/@fleetless/contracts/dist/common.js
414
414
  import { z } from "zod";
415
415
  var SLUG_RULE = "A name is lower-case: it starts with a letter, continues with letters and digits, and joins further words with a single underscore \u2014 `battery_voltage`. Capitals, dashes, dots, spaces, a leading digit and a doubled or trailing underscore are all refused.";
416
416
  var slug = z.string().min(2).max(63).regex(/^[a-z][a-z0-9]*(?:_[a-z0-9]+)*$/, SLUG_RULE);
@@ -441,7 +441,7 @@ var applyError = z.object({
441
441
  details: z.record(z.string(), z.unknown()).optional()
442
442
  });
443
443
 
444
- // node_modules/.pnpm/@fleetless+contracts@6.0.0/node_modules/@fleetless/contracts/dist/mcp.js
444
+ // node_modules/.pnpm/@fleetless+contracts@6.2.0-next.2/node_modules/@fleetless/contracts/dist/mcp.js
445
445
  import { z as z2 } from "zod";
446
446
  function mcpAppEndpointPath(appIdentifier2) {
447
447
  return `/mcp/${appIdentifier2}`;
@@ -490,10 +490,10 @@ var mcpRolePreviewResponse = z2.object({
490
490
  });
491
491
  var MCP_ASSET_LINK_TTL_MS = 15 * 60 * 1e3;
492
492
 
493
- // node_modules/.pnpm/@fleetless+contracts@6.0.0/node_modules/@fleetless/contracts/dist/protocol.js
493
+ // node_modules/.pnpm/@fleetless+contracts@6.2.0-next.2/node_modules/@fleetless/contracts/dist/protocol.js
494
494
  import { z as z8 } from "zod";
495
495
 
496
- // node_modules/.pnpm/@fleetless+contracts@6.0.0/node_modules/@fleetless/contracts/dist/assets.js
496
+ // node_modules/.pnpm/@fleetless+contracts@6.2.0-next.2/node_modules/@fleetless/contracts/dist/assets.js
497
497
  import { z as z3 } from "zod";
498
498
  var assetKind = z3.enum(["urdf", "mesh", "texture"]);
499
499
  var asset = z3.object({
@@ -813,10 +813,10 @@ var assetSyncBusyDetails = z3.object({
813
813
  started_at_ms: z3.number().int().nonnegative()
814
814
  });
815
815
 
816
- // node_modules/.pnpm/@fleetless+contracts@6.0.0/node_modules/@fleetless/contracts/dist/config.js
816
+ // node_modules/.pnpm/@fleetless+contracts@6.2.0-next.2/node_modules/@fleetless/contracts/dist/config.js
817
817
  import { z as z5 } from "zod";
818
818
 
819
- // node_modules/.pnpm/@fleetless+contracts@6.0.0/node_modules/@fleetless/contracts/dist/alerts.js
819
+ // node_modules/.pnpm/@fleetless+contracts@6.2.0-next.2/node_modules/@fleetless/contracts/dist/alerts.js
820
820
  import { z as z4 } from "zod";
821
821
  var alertRowCondition = z4.discriminatedUnion("kind", [
822
822
  z4.strictObject({
@@ -886,7 +886,7 @@ var putDatapointDisplayRequest = z4.object({
886
886
  y_max: z4.number().finite().nullable()
887
887
  }).strict();
888
888
 
889
- // node_modules/.pnpm/@fleetless+contracts@6.0.0/node_modules/@fleetless/contracts/dist/config.js
889
+ // node_modules/.pnpm/@fleetless+contracts@6.2.0-next.2/node_modules/@fleetless/contracts/dist/config.js
890
890
  var RTSP_URL_RULE = "The URL has to begin with `rtsp://` or `rtsps://` \u2014 `rtsp://cam-1.plant.local/stream1`. No other scheme is accepted: the bridge opens this with a library that would equally honour `file:`.";
891
891
  var MJPEG_URL_RULE = "The URL has to begin with `http://` or `https://` \u2014 `http://cam-1.plant.local/video.mjpg`. No other scheme is accepted: the bridge opens this with a library that would equally serve `file:`.";
892
892
  var DEVICE_PATH_RULE = "A capture device is a path under `/dev/`, and the character straight after it is a letter or a digit \u2014 `/dev/video0`, or a stable `/dev/v4l/by-id/...` symlink. Nothing outside `/dev/` is accepted: the string reaches OpenCV, which would as happily open an ordinary file.";
@@ -1978,7 +1978,7 @@ var configState = z5.object({
1978
1978
  applied_errors: z5.array(applyError).nullable()
1979
1979
  });
1980
1980
 
1981
- // node_modules/.pnpm/@fleetless+contracts@6.0.0/node_modules/@fleetless/contracts/dist/introspection.js
1981
+ // node_modules/.pnpm/@fleetless+contracts@6.2.0-next.2/node_modules/@fleetless/contracts/dist/introspection.js
1982
1982
  import { z as z6 } from "zod";
1983
1983
  var rosGraphEntry = z6.object({
1984
1984
  name: rosName,
@@ -2017,7 +2017,7 @@ var typeDefinition = z6.discriminatedUnion("kind", [
2017
2017
  })
2018
2018
  ]);
2019
2019
 
2020
- // node_modules/.pnpm/@fleetless+contracts@6.0.0/node_modules/@fleetless/contracts/dist/jobs.js
2020
+ // node_modules/.pnpm/@fleetless+contracts@6.2.0-next.2/node_modules/@fleetless/contracts/dist/jobs.js
2021
2021
  import { z as z7 } from "zod";
2022
2022
  var jobState = z7.enum(["running", "unknown", "succeeded", "failed", "cancelled", "lost"]);
2023
2023
  var reportedJobState = jobState.exclude(["unknown"]);
@@ -2254,7 +2254,7 @@ var jobRunSummary = z7.object({
2254
2254
  since_ms: z7.number().int().nonnegative()
2255
2255
  });
2256
2256
 
2257
- // node_modules/.pnpm/@fleetless+contracts@6.0.0/node_modules/@fleetless/contracts/dist/protocol.js
2257
+ // node_modules/.pnpm/@fleetless+contracts@6.2.0-next.2/node_modules/@fleetless/contracts/dist/protocol.js
2258
2258
  var DAY_MS = 24 * 60 * 60 * 1e3;
2259
2259
  var MAX_PATIENCE_MS = 12e4;
2260
2260
  var MIN_PATIENCE_MS = 1e3;
@@ -2652,11 +2652,11 @@ var bridgeCameraState = z8.object({
2652
2652
  request_id: z8.string().min(1).max(64).nullable()
2653
2653
  });
2654
2654
 
2655
- // node_modules/.pnpm/@fleetless+contracts@6.0.0/node_modules/@fleetless/contracts/dist/config-issues.js
2655
+ // node_modules/.pnpm/@fleetless+contracts@6.2.0-next.2/node_modules/@fleetless/contracts/dist/config-issues.js
2656
2656
  var EXPOSURE_SECTIONS = ["datapoints", "actions", "services", "publishers", "cameras"];
2657
2657
  var EXPOSURE_SECTION_NAMES = new Set(EXPOSURE_SECTIONS);
2658
2658
 
2659
- // node_modules/.pnpm/@fleetless+contracts@6.0.0/node_modules/@fleetless/contracts/dist/rest.js
2659
+ // node_modules/.pnpm/@fleetless+contracts@6.2.0-next.2/node_modules/@fleetless/contracts/dist/rest.js
2660
2660
  import { z as z9 } from "zod";
2661
2661
  var robot = z9.object({
2662
2662
  id: z9.uuid().meta({
@@ -3421,13 +3421,13 @@ var slugUsageResponse = z9.object({
3421
3421
  alert_count: z9.number().int().nonnegative()
3422
3422
  });
3423
3423
 
3424
- // node_modules/.pnpm/@fleetless+contracts@6.0.0/node_modules/@fleetless/contracts/dist/realtime.js
3424
+ // node_modules/.pnpm/@fleetless+contracts@6.2.0-next.2/node_modules/@fleetless/contracts/dist/realtime.js
3425
3425
  import { z as z14 } from "zod";
3426
3426
 
3427
- // node_modules/.pnpm/@fleetless+contracts@6.0.0/node_modules/@fleetless/contracts/dist/client-auth.js
3427
+ // node_modules/.pnpm/@fleetless+contracts@6.2.0-next.2/node_modules/@fleetless/contracts/dist/client-auth.js
3428
3428
  import { z as z13 } from "zod";
3429
3429
 
3430
- // node_modules/.pnpm/@fleetless+contracts@6.0.0/node_modules/@fleetless/contracts/dist/apps.js
3430
+ // node_modules/.pnpm/@fleetless+contracts@6.2.0-next.2/node_modules/@fleetless/contracts/dist/apps.js
3431
3431
  import { z as z10 } from "zod";
3432
3432
  var appIdentifier = slug;
3433
3433
  var app = z10.object({
@@ -3650,10 +3650,10 @@ var rolePermissions = z10.object({
3650
3650
  })
3651
3651
  });
3652
3652
 
3653
- // node_modules/.pnpm/@fleetless+contracts@6.0.0/node_modules/@fleetless/contracts/dist/app-users.js
3653
+ // node_modules/.pnpm/@fleetless+contracts@6.2.0-next.2/node_modules/@fleetless/contracts/dist/app-users.js
3654
3654
  import { z as z12 } from "zod";
3655
3655
 
3656
- // node_modules/.pnpm/@fleetless+contracts@6.0.0/node_modules/@fleetless/contracts/dist/identity.js
3656
+ // node_modules/.pnpm/@fleetless+contracts@6.2.0-next.2/node_modules/@fleetless/contracts/dist/identity.js
3657
3657
  import { z as z11 } from "zod";
3658
3658
  var password = z11.string().min(12).max(256);
3659
3659
  var USER_DISPLAY_NAME_MAX = 120;
@@ -3871,7 +3871,7 @@ var recoveryCodesResponse = z11.object({
3871
3871
  recovery_codes: recoveryCodesList.meta({ description: "The ten new recovery codes, lowercase, shown once. Every earlier code is void." })
3872
3872
  });
3873
3873
 
3874
- // node_modules/.pnpm/@fleetless+contracts@6.0.0/node_modules/@fleetless/contracts/dist/app-users.js
3874
+ // node_modules/.pnpm/@fleetless+contracts@6.2.0-next.2/node_modules/@fleetless/contracts/dist/app-users.js
3875
3875
  var APP_USER_DISPLAY_NAME_MAX = 120;
3876
3876
  var providerSlug = z12.string().max(40).regex(/^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/, "must be lowercase and hyphen-separated, starting with a letter");
3877
3877
  var appUserStatus = z12.enum(["pending_verification", "active", "blocked"]);
@@ -4182,7 +4182,7 @@ var mailOutcome = z12.object({
4182
4182
  })
4183
4183
  });
4184
4184
 
4185
- // node_modules/.pnpm/@fleetless+contracts@6.0.0/node_modules/@fleetless/contracts/dist/client-auth.js
4185
+ // node_modules/.pnpm/@fleetless+contracts@6.2.0-next.2/node_modules/@fleetless/contracts/dist/client-auth.js
4186
4186
  var clientLoginRequest = z13.object({
4187
4187
  app_identifier: appIdentifier.meta({
4188
4188
  description: "The app being logged in to: its globally unique, lowercase, underscore-separated identifier, chosen by the developer at creation. There is no organisation context at login, so this is what decides which app the credentials are checked for."
@@ -4358,7 +4358,8 @@ var clientOidcErrorCode = z13.enum([
4358
4358
  "provider_misconfigured",
4359
4359
  "provider_disabled",
4360
4360
  "invalid_request",
4361
- "quota_exceeded"
4361
+ "quota_exceeded",
4362
+ "plan_limit"
4362
4363
  ]);
4363
4364
  var clientMcpInteraction = z13.object({
4364
4365
  id: z13.string().meta({ description: "The interaction, as it arrived in the app's `mcp_login_url`. Not a credential: it names a pending request the server already holds, and approving it needs the app user's own access token." }),
@@ -4422,7 +4423,7 @@ var clientIdentity = z13.object({
4422
4423
  })
4423
4424
  });
4424
4425
 
4425
- // node_modules/.pnpm/@fleetless+contracts@6.0.0/node_modules/@fleetless/contracts/dist/realtime.js
4426
+ // node_modules/.pnpm/@fleetless+contracts@6.2.0-next.2/node_modules/@fleetless/contracts/dist/realtime.js
4426
4427
  var clientAuth = z14.object({
4427
4428
  type: z14.literal("auth"),
4428
4429
  token: z14.string().min(1)
@@ -4590,6 +4591,12 @@ var liveSessionEndReason = z14.enum([
4590
4591
  "expired",
4591
4592
  /** The robot was deleted out from under the session. */
4592
4593
  "robot_deleted",
4594
+ /**
4595
+ * The organization's live video for app users reached its plan's monthly
4596
+ * limit (2026-10-02, fleetless/fleetless#103); `detail` carries the
4597
+ * sentence the viewer shows.
4598
+ */
4599
+ "plan_limit",
4593
4600
  /**
4594
4601
  * The cloud ended it and cannot say which of the above applied. **Kept
4595
4602
  * deliberately**: a channel that cannot say "I do not know" will say
@@ -4700,7 +4707,7 @@ var orgEventDropped = z14.object({
4700
4707
  dropped: z14.number().int().positive()
4701
4708
  }).strict();
4702
4709
 
4703
- // node_modules/.pnpm/@fleetless+contracts@6.0.0/node_modules/@fleetless/contracts/dist/feedback.js
4710
+ // node_modules/.pnpm/@fleetless+contracts@6.2.0-next.2/node_modules/@fleetless/contracts/dist/feedback.js
4704
4711
  import { z as z15 } from "zod";
4705
4712
  var FEEDBACK_KINDS = ["idea", "problem", "question", "other"];
4706
4713
  var feedbackKind = z15.enum(FEEDBACK_KINDS);
@@ -4725,7 +4732,7 @@ var feedbackResponse = z15.object({
4725
4732
  })
4726
4733
  }).strict();
4727
4734
 
4728
- // node_modules/.pnpm/@fleetless+contracts@6.0.0/node_modules/@fleetless/contracts/dist/client-robots.js
4735
+ // node_modules/.pnpm/@fleetless+contracts@6.2.0-next.2/node_modules/@fleetless/contracts/dist/client-robots.js
4729
4736
  import { z as z16 } from "zod";
4730
4737
  var clientRobotListItem = z16.object({
4731
4738
  ...robot.shape,
@@ -4742,10 +4749,10 @@ var clientRobotListResponse = z16.object({
4742
4749
  })
4743
4750
  });
4744
4751
 
4745
- // node_modules/.pnpm/@fleetless+contracts@6.0.0/node_modules/@fleetless/contracts/dist/audit.js
4752
+ // node_modules/.pnpm/@fleetless+contracts@6.2.0-next.2/node_modules/@fleetless/contracts/dist/audit.js
4746
4753
  import { z as z17 } from "zod";
4747
4754
  var auditActor = z17.object({
4748
- kind: z17.enum(["developer", "end_user", "app_user", "server_key", "bridge"]),
4755
+ kind: z17.enum(["developer", "end_user", "app_user", "server_key", "bridge", "fleetless"]),
4749
4756
  id: z17.uuid(),
4750
4757
  label: z17.string().min(1).max(200)
4751
4758
  });
@@ -4884,34 +4891,358 @@ var auditListResponse = z17.object({
4884
4891
  next_cursor: z17.number().int().positive().nullable()
4885
4892
  });
4886
4893
 
4887
- // node_modules/.pnpm/@fleetless+contracts@6.0.0/node_modules/@fleetless/contracts/dist/errors.js
4894
+ // node_modules/.pnpm/@fleetless+contracts@6.2.0-next.2/node_modules/@fleetless/contracts/dist/errors.js
4895
+ import { z as z19 } from "zod";
4896
+
4897
+ // node_modules/.pnpm/@fleetless+contracts@6.2.0-next.2/node_modules/@fleetless/contracts/dist/plans.js
4888
4898
  import { z as z18 } from "zod";
4889
- var apiError = z18.object({
4890
- code: z18.string().min(1),
4891
- message: z18.string().min(1),
4892
- details: z18.unknown().optional()
4899
+ var planId = z18.enum(["basic", "plus", "pro", "enterprise"]);
4900
+ var planLimitKey = z18.enum([
4901
+ "seats",
4902
+ "robots",
4903
+ "apps",
4904
+ "app_users",
4905
+ "live_video_ms_per_month",
4906
+ "asset_bytes_per_robot",
4907
+ "history_days",
4908
+ "audit_days"
4909
+ ]);
4910
+ var limit = z18.number().int().positive().nullable();
4911
+ var planLimits = z18.object({
4912
+ seats: limit.meta({ description: "Developers, owners included, plus pending team invitations." }),
4913
+ robots: limit.meta({ description: "Robots in the org." }),
4914
+ apps: limit.meta({ description: "Apps in the org." }),
4915
+ app_users: limit.meta({ description: "App users across every app of the org, plus pending app-user invitations." }),
4916
+ live_video_ms_per_month: limit.meta({
4917
+ description: "Live video watched by app users in one UTC calendar month, in milliseconds, across the org. Console sessions do not count."
4918
+ }),
4919
+ asset_bytes_per_robot: limit.meta({
4920
+ description: "Asset storage per robot, in bytes (decimal: 1 GB = 1,000,000,000). The org stores up to robots \xD7 this value in total."
4921
+ }),
4922
+ history_days: limit.meta({ description: "Days the org's robot history is kept." }),
4923
+ audit_days: limit.meta({ description: "Days the org's audit log is kept." })
4924
+ });
4925
+ var planFeature = z18.enum(["app_mcp", "two_factor", "require_two_factor", "app_oidc", "hosted_logo", "audit_export", "addons"]);
4926
+ var FEATURE_DESCRIPTIONS = {
4927
+ app_mcp: "An app's own MCP endpoint, for its app users.",
4928
+ two_factor: "Two-factor sign-in for developers.",
4929
+ require_two_factor: "An owner may require two-factor sign-in for every developer of the org.",
4930
+ app_oidc: "An app may let its users sign in through an OpenID Connect identity provider.",
4931
+ hosted_logo: "An app's hosted pages show its logo and accent colour, not only its name.",
4932
+ audit_export: "The audit log can be exported as CSV.",
4933
+ addons: "Add-ons can be bought on top of the plan."
4934
+ };
4935
+ var planFeatures = z18.object(Object.fromEntries(planFeature.options.map((f) => [f, z18.boolean().meta({ description: FEATURE_DESCRIPTIONS[f] })])));
4936
+ var cents = z18.number().int().nonnegative();
4937
+ var planPrices = z18.object({
4938
+ eur_month: cents.meta({ description: "Per month in euro cents, excluding VAT." }),
4939
+ usd_month: cents.meta({ description: "Per month in US dollar cents, excluding VAT: the euro price \xD7 1.15, rounded up to a whole dollar." }),
4940
+ eur_year: cents.meta({ description: "Per year in euro cents, excluding VAT: twelve months less 15 %." }),
4941
+ usd_year: cents.meta({ description: "Per year in US dollar cents, excluding VAT: the yearly euro price \xD7 1.15, rounded up to a whole dollar." })
4942
+ });
4943
+ var planSupport = z18.enum(["community", "email", "priority", "named_contact"]);
4944
+ var planCatalogueEntry = z18.object({
4945
+ id: planId.meta({ description: "The plan." }),
4946
+ name: z18.string().min(1).meta({ description: "The plan's display name: Basic, Plus, Pro or Enterprise." }),
4947
+ limits: planLimits.meta({ description: "What the plan allows. `null` means by contract." }),
4948
+ features: planFeatures.meta({ description: "What the plan unlocks." }),
4949
+ prices: planPrices.nullable().meta({ description: "`null` for Enterprise: sold by contract, on request." }),
4950
+ support: planSupport.meta({ description: "The support that comes with the plan." })
4951
+ });
4952
+ var addonKey = z18.enum(["seats", "robots", "apps", "app_user_packs", "live_video_packs"]);
4953
+ var addonCatalogueEntry = z18.object({
4954
+ key: addonKey.meta({ description: "The add-on." }),
4955
+ raises: planLimitKey.meta({ description: "The plan limit this add-on raises." }),
4956
+ per_unit: z18.number().int().positive().meta({ description: "How much one unit of this add-on raises `raises` by." }),
4957
+ prices: planPrices.meta({ description: "The price of one unit." })
4958
+ });
4959
+ function usdCentsFromEurCents(eurCents) {
4960
+ return Math.floor((eurCents * 115 + 9999) / 1e4) * 100;
4961
+ }
4962
+ function yearlyEurCents(monthEurCents) {
4963
+ return Math.round(monthEurCents * 12 * 85 / 100);
4964
+ }
4965
+ function pricesFromEurMonth(eurMonthCents) {
4966
+ const eurYear = yearlyEurCents(eurMonthCents);
4967
+ return {
4968
+ eur_month: eurMonthCents,
4969
+ usd_month: usdCentsFromEurCents(eurMonthCents),
4970
+ eur_year: eurYear,
4971
+ usd_year: usdCentsFromEurCents(eurYear)
4972
+ };
4973
+ }
4974
+ var PLANS = {
4975
+ basic: {
4976
+ id: "basic",
4977
+ name: "Basic",
4978
+ limits: {
4979
+ seats: 1,
4980
+ robots: 1,
4981
+ apps: 1,
4982
+ app_users: 10,
4983
+ live_video_ms_per_month: 36e6,
4984
+ asset_bytes_per_robot: 1e9,
4985
+ history_days: 7,
4986
+ audit_days: 7
4987
+ },
4988
+ features: {
4989
+ app_mcp: false,
4990
+ two_factor: false,
4991
+ require_two_factor: false,
4992
+ app_oidc: false,
4993
+ hosted_logo: false,
4994
+ audit_export: false,
4995
+ addons: false
4996
+ },
4997
+ prices: pricesFromEurMonth(0),
4998
+ support: "community"
4999
+ },
5000
+ plus: {
5001
+ id: "plus",
5002
+ name: "Plus",
5003
+ limits: {
5004
+ seats: 3,
5005
+ robots: 3,
5006
+ apps: 3,
5007
+ app_users: 25,
5008
+ live_video_ms_per_month: 36e7,
5009
+ asset_bytes_per_robot: 2e9,
5010
+ history_days: 30,
5011
+ audit_days: 30
5012
+ },
5013
+ features: {
5014
+ app_mcp: true,
5015
+ two_factor: true,
5016
+ require_two_factor: false,
5017
+ app_oidc: true,
5018
+ hosted_logo: true,
5019
+ audit_export: false,
5020
+ addons: false
5021
+ },
5022
+ prices: pricesFromEurMonth(2900),
5023
+ support: "email"
5024
+ },
5025
+ pro: {
5026
+ id: "pro",
5027
+ name: "Pro",
5028
+ limits: {
5029
+ seats: 5,
5030
+ robots: 5,
5031
+ apps: 5,
5032
+ app_users: 50,
5033
+ live_video_ms_per_month: 9e8,
5034
+ asset_bytes_per_robot: 3e9,
5035
+ history_days: 90,
5036
+ audit_days: 90
5037
+ },
5038
+ features: {
5039
+ app_mcp: true,
5040
+ two_factor: true,
5041
+ require_two_factor: true,
5042
+ app_oidc: true,
5043
+ hosted_logo: true,
5044
+ audit_export: true,
5045
+ addons: true
5046
+ },
5047
+ prices: pricesFromEurMonth(14900),
5048
+ support: "priority"
5049
+ },
5050
+ enterprise: {
5051
+ id: "enterprise",
5052
+ name: "Enterprise",
5053
+ limits: {
5054
+ seats: null,
5055
+ robots: null,
5056
+ apps: null,
5057
+ app_users: null,
5058
+ live_video_ms_per_month: null,
5059
+ asset_bytes_per_robot: null,
5060
+ history_days: null,
5061
+ audit_days: null
5062
+ },
5063
+ features: {
5064
+ app_mcp: true,
5065
+ two_factor: true,
5066
+ require_two_factor: true,
5067
+ app_oidc: true,
5068
+ hosted_logo: true,
5069
+ audit_export: true,
5070
+ addons: true
5071
+ },
5072
+ prices: null,
5073
+ support: "named_contact"
5074
+ }
5075
+ };
5076
+ var ADDONS = {
5077
+ seats: { key: "seats", raises: "seats", per_unit: 1, prices: pricesFromEurMonth(900) },
5078
+ robots: { key: "robots", raises: "robots", per_unit: 1, prices: pricesFromEurMonth(1900) },
5079
+ apps: { key: "apps", raises: "apps", per_unit: 1, prices: pricesFromEurMonth(900) },
5080
+ app_user_packs: { key: "app_user_packs", raises: "app_users", per_unit: 5, prices: pricesFromEurMonth(1e3) },
5081
+ live_video_packs: { key: "live_video_packs", raises: "live_video_ms_per_month", per_unit: 9e8, prices: pricesFromEurMonth(900) }
5082
+ };
5083
+ var planCurrency = z18.enum(["eur", "usd"]);
5084
+ var addonCount = z18.number().int().nonnegative();
5085
+ var orgAddons = z18.object({
5086
+ seats: addonCount.meta({ description: "Extra developer seats, one each." }),
5087
+ robots: addonCount.meta({ description: "Extra robots, one each." }),
5088
+ apps: addonCount.meta({ description: "Extra apps, one each." }),
5089
+ app_user_packs: addonCount.meta({ description: "Packs of five extra app users." }),
5090
+ live_video_packs: addonCount.meta({ description: "Packs of 250 extra hours of app-user live video per month." })
5091
+ });
5092
+ var usageCount = z18.number().int().nonnegative();
5093
+ var orgPlanUsage = z18.object({
5094
+ seats: usageCount.meta({ description: "Developers, owners included, plus pending team invitations." }),
5095
+ robots: usageCount.meta({ description: "Robots in the org." }),
5096
+ apps: usageCount.meta({ description: "Apps in the org." }),
5097
+ app_users: usageCount.meta({ description: "App users across every app, plus pending app-user invitations." }),
5098
+ live_video_ms_this_month: usageCount.meta({
5099
+ description: "Live video watched by app users in the current UTC calendar month, in milliseconds. Console sessions do not count."
5100
+ }),
5101
+ asset_bytes: usageCount.meta({ description: "Bytes the assets of every robot of the org occupy, together." })
5102
+ });
5103
+ var planChangeKeep = z18.object({
5104
+ robots: z18.array(z18.uuid()).meta({ description: "The robots that stay, by id. Every other robot is deleted when the change takes effect." }),
5105
+ apps: z18.array(z18.uuid()).meta({ description: "The apps that stay, by id. Every other app is deleted when the change takes effect." }),
5106
+ app_users: z18.array(z18.uuid()).meta({
5107
+ description: "The app users that stay, by id, across every app. Every other app user is deleted when the change takes effect."
5108
+ }),
5109
+ developers: z18.array(z18.uuid()).meta({
5110
+ description: "The developers that stay, by user id, owners never among them: every owner stays. Every other developer is removed from the org when the change takes effect."
5111
+ })
5112
+ }).strict();
5113
+ var planChangeReason = z18.enum(["downgrade", "cancel", "migration", "lock"]);
5114
+ var pendingPlanChange = z18.object({
5115
+ target_plan: planId.meta({ description: "The plan the org moves to." }),
5116
+ reason: planChangeReason.meta({ description: "Why the change is pending: `downgrade`, `cancel`, `migration` or `lock`." }),
5117
+ effective_at: z18.iso.datetime().nullable().meta({
5118
+ description: "When the change takes effect. `null` only for a move off the beta whose date is not set yet."
5119
+ }),
5120
+ keep: planChangeKeep.nullable().meta({
5121
+ description: "What stays. `null` when the org already fits the target plan and nothing is deleted."
5122
+ }),
5123
+ history_days_after: z18.number().int().positive().meta({
5124
+ description: "Days of history and audit log the org keeps on the target plan."
5125
+ }),
5126
+ chosen_by: z18.uuid().meta({ description: "The user id of the owner who chose the change, or the nil UUID when Fleetless queued it." }),
5127
+ chosen_at: z18.iso.datetime().meta({ description: "When the change was chosen." })
5128
+ });
5129
+ var orgLock = z18.object({
5130
+ reason: z18.enum(["payment", "migration"]).meta({
5131
+ description: "`payment`: a payment is missing. `migration`: the org did not choose what stays when the beta ended."
5132
+ }),
5133
+ since: z18.iso.datetime().meta({ description: "When the org was locked." })
5134
+ });
5135
+ var orgPlan = z18.object({
5136
+ plan: planId.meta({ description: "The org's current plan." }),
5137
+ currency: planCurrency.meta({ description: "The currency the org's prices are shown and billed in." }),
5138
+ period_ends_at: z18.iso.datetime().meta({
5139
+ description: "The end of the organization's current billing period; while no payment period exists yet, the end of the current UTC calendar month. A pending downward plan change normally takes effect at this exact instant \u2014 except one chosen while the org was locked, which lands at once, and the platform's own move off the beta, which lands at its switch date instead."
5140
+ }),
5141
+ addons: orgAddons.meta({ description: "The add-ons the org has bought. All zero on a plan without the `addons` feature." }),
5142
+ limits: planLimits.meta({
5143
+ description: "The org's effective limits: the plan's, raised by its add-ons, or an operator's override in their place. `null` means unlimited for a count, and 90 days for `history_days` and `audit_days`."
5144
+ }),
5145
+ features: planFeatures.meta({ description: "What the org's plan unlocks." }),
5146
+ usage: orgPlanUsage.meta({ description: "What the org uses now, counted the way each limit counts it." }),
5147
+ pending_change: pendingPlanChange.nullable().meta({ description: "A move to a lower plan that has not taken effect yet, or `null`." }),
5148
+ lock: orgLock.nullable().meta({ description: "Why and since when the org is locked, or `null` when it is not." }),
5149
+ switch: z18.object({
5150
+ at: z18.iso.datetime().nullable().meta({
5151
+ description: "When the org moves from the beta onto its plan. `null` while the date is not set."
5152
+ }),
5153
+ needs_choice: z18.boolean().meta({
5154
+ description: "Whether the org uses more than Basic allows, so an owner has to choose what stays before `at`."
5155
+ })
5156
+ }).nullable().meta({ description: "Set only while the org is still on the beta; `null` for every other org." })
4893
5157
  });
4894
- var parameterViolation = z18.object({
4895
- field: z18.string().min(1),
5158
+ var planChangeRequest = z18.object({
5159
+ target_plan: planId.meta({ description: "The lower plan to move to; `basic` cancels." }),
5160
+ keep: planChangeKeep.nullable().meta({
5161
+ description: "What stays. `null` when the org already fits the target plan, so nothing is deleted."
5162
+ })
5163
+ }).strict();
5164
+ var planOverrides = z18.object(Object.fromEntries(planLimitKey.options.map((k) => [
5165
+ k,
5166
+ limit.optional().meta({ description: `Replaces the plan's \`${k}\`. \`null\` clears the override.` })
5167
+ ]))).strict();
5168
+ var adminPlanChangeRequest = z18.object({
5169
+ plan: planId.meta({ description: "The plan the org is on after this request." }),
5170
+ addons: orgAddons.partial().strict().optional().meta({ description: "Add-on counts to set. Counts not named stay as they are." }),
5171
+ overrides: planOverrides.optional().meta({ description: "Limits to override. `null` clears an override." }),
5172
+ currency: planCurrency.optional().meta({ description: "The currency the org is billed in." }),
5173
+ period_ends_at: z18.iso.datetime().nullable().optional().meta({
5174
+ description: "The end of the org's billing period. `null` falls back to the end of the current UTC month."
5175
+ })
5176
+ }).strict();
5177
+
5178
+ // node_modules/.pnpm/@fleetless+contracts@6.2.0-next.2/node_modules/@fleetless/contracts/dist/errors.js
5179
+ var apiError = z19.object({
5180
+ code: z19.string().min(1),
5181
+ message: z19.string().min(1),
5182
+ details: z19.unknown().optional()
5183
+ });
5184
+ var parameterViolation = z19.object({
5185
+ field: z19.string().min(1),
4896
5186
  /** Which rule failed — `min`, `max`, `enum`, `pattern`, `required`, `undeclared`. */
4897
- rule: z18.string().min(1),
4898
- message: z18.string().min(1)
5187
+ rule: z19.string().min(1),
5188
+ message: z19.string().min(1)
4899
5189
  });
4900
- var parameterInvalidDetails = z18.object({
4901
- violations: z18.array(parameterViolation).min(1)
5190
+ var parameterInvalidDetails = z19.object({
5191
+ violations: z19.array(parameterViolation).min(1)
4902
5192
  });
4903
- var cancelRejectedDetails = z18.object({
4904
- goals: z18.array(bridgeCancelResultEntry).min(1)
5193
+ var cancelRejectedDetails = z19.object({
5194
+ goals: z19.array(bridgeCancelResultEntry).min(1)
4905
5195
  });
4906
- var invalidCodeDetails = z18.object({
4907
- attempts_left: z18.number().int().min(0).meta({
5196
+ var invalidCodeDetails = z19.object({
5197
+ attempts_left: z19.number().int().min(0).meta({
4908
5198
  description: "How many more wrong codes this code or challenge takes before it is spent. `0` means the next attempt answers `410 token_spent`."
4909
5199
  })
4910
5200
  });
5201
+ var planLimitDetails = z19.object({
5202
+ limit: planLimitKey.exclude(["history_days", "audit_days"]).meta({ description: "The limit the action would exceed." }),
5203
+ used: z19.number().int().nonnegative().meta({ description: "How much of the limit the org uses now." }),
5204
+ max: z19.number().int().nonnegative().meta({
5205
+ description: "The limit. For `asset_bytes_per_robot`, the org's whole pool: robots \xD7 the plan's bytes per robot."
5206
+ }),
5207
+ plan: planId.meta({ description: "The plan whose limit refused: the target plan while a move to a lower plan is pending." }),
5208
+ lifted_by: z19.object({
5209
+ plan: planId.nullable().meta({ description: "The cheapest higher plan that raises this limit, or `null` when none does." }),
5210
+ addon: addonKey.nullable().meta({
5211
+ description: "The add-on that raises this limit, when the org's plan can buy add-ons; otherwise `null`."
5212
+ })
5213
+ }).meta({ description: "What would lift the limit." })
5214
+ });
5215
+ var assetPlanLimitDetails = planLimitDetails.extend({
5216
+ ...assetStoreRefusedDetails.shape,
5217
+ store_bytes: assetStoreRefusedDetails.shape.store_bytes.meta({
5218
+ description: "The org's asset pool, in bytes: `robots \xD7 asset_bytes_per_robot`."
5219
+ }),
5220
+ used_bytes: assetStoreRefusedDetails.shape.used_bytes.meta({
5221
+ description: "Bytes the org's assets occupy, across every robot, before this upload."
5222
+ })
5223
+ });
5224
+ var planRequiredDetails = z19.object({
5225
+ feature: planFeature.meta({ description: "The feature the action needs." }),
5226
+ plan: planId.meta({ description: "The org's current plan." }),
5227
+ required_plan: planId.meta({ description: "The cheapest plan that has the feature." })
5228
+ });
5229
+ var orgLockedDetails = z19.object({
5230
+ reason: z19.enum(["payment", "migration"]).meta({
5231
+ description: "`payment`: a payment is missing. `migration`: the org did not choose what stays when the beta ended."
5232
+ })
5233
+ });
5234
+ var fileTooLargeDetails = z19.object({
5235
+ max_bytes: z19.number().int().positive().meta({
5236
+ description: "The most one asset file can be, in bytes: `ASSET_FILE_MAX_BYTES`, the same on every plan."
5237
+ }),
5238
+ size_bytes: z19.number().int().positive().nullable().meta({
5239
+ description: "The refused file's size, in bytes: the announced size, or the bytes that arrived when none (or a false one) was announced; `null` only when the body limit stopped the upload and nobody counted the bytes."
5240
+ })
5241
+ });
4911
5242
 
4912
- // node_modules/.pnpm/@fleetless+contracts@6.0.0/node_modules/@fleetless/contracts/dist/oauth.js
4913
- import { z as z19 } from "zod";
4914
- var oauthErrorCode = z19.enum([
5243
+ // node_modules/.pnpm/@fleetless+contracts@6.2.0-next.2/node_modules/@fleetless/contracts/dist/oauth.js
5244
+ import { z as z20 } from "zod";
5245
+ var oauthErrorCode = z20.enum([
4915
5246
  "invalid_request",
4916
5247
  "invalid_client",
4917
5248
  "invalid_grant",
@@ -4924,11 +5255,11 @@ var oauthErrorCode = z19.enum([
4924
5255
  /** RFC 8707: the `resource` named is not one this server issues tokens for. */
4925
5256
  "invalid_target"
4926
5257
  ]);
4927
- var oauthError = z19.object({
5258
+ var oauthError = z20.object({
4928
5259
  error: oauthErrorCode,
4929
- error_description: z19.string().min(1).max(500).optional(),
5260
+ error_description: z20.string().min(1).max(500).optional(),
4930
5261
  /** Echoed back per RFC 6749 §4.1.2.1 so a client can match the response. */
4931
- state: z19.string().min(1).max(500).optional(),
5262
+ state: z20.string().min(1).max(500).optional(),
4932
5263
  /**
4933
5264
  * **A Fleetless reason carried inside a standard envelope, and it exists
4934
5265
  * because the alternative lost a distinction.**
@@ -4946,9 +5277,9 @@ var oauthError = z19.object({
4946
5277
  * our own tooling switches on. RFC 6749 §5.2 permits additional members, and
4947
5278
  * a client that ignores this one still behaves correctly.
4948
5279
  */
4949
- fleetless_code: z19.string().min(1).max(60).optional()
5280
+ fleetless_code: z20.string().min(1).max(60).optional()
4950
5281
  });
4951
- var redirectUri = z19.string().min(1).max(2e3).refine((v) => {
5282
+ var redirectUri = z20.string().min(1).max(2e3).refine((v) => {
4952
5283
  let url;
4953
5284
  try {
4954
5285
  url = new URL(v);
@@ -4963,180 +5294,180 @@ var redirectUri = z19.string().min(1).max(2e3).refine((v) => {
4963
5294
  return ["localhost", "127.0.0.1", "[::1]"].includes(url.hostname);
4964
5295
  return false;
4965
5296
  }, { message: "redirect_uri must be an https URL, or http on an explicit loopback address, and carry no fragment" });
4966
- var codeChallengeMethod = z19.enum(["S256"]);
5297
+ var codeChallengeMethod = z20.enum(["S256"]);
4967
5298
  var MCP_DCR_MAX_REDIRECT_URIS = 5;
4968
- var dynamicClientRegistrationRequest = z19.object({
4969
- redirect_uris: z19.array(redirectUri).min(1).max(MCP_DCR_MAX_REDIRECT_URIS).meta({
5299
+ var dynamicClientRegistrationRequest = z20.object({
5300
+ redirect_uris: z20.array(redirectUri).min(1).max(MCP_DCR_MAX_REDIRECT_URIS).meta({
4970
5301
  description: `Where the authorization code may be returned, and the one field a registration cannot omit. Each must be an \`https\` URL, or \`http\` on an explicit loopback address for a native app that cannot hold a certificate, and none may carry a fragment. Between \`1\` and \`${MCP_DCR_MAX_REDIRECT_URIS}\` of them; duplicates are collapsed rather than counted twice. Matched **exactly** at the authorize step against what was registered here.`
4971
5302
  }),
4972
- client_name: z19.string().min(1).max(200).optional().meta({
5303
+ client_name: z20.string().min(1).max(200).optional().meta({
4973
5304
  description: 'The name the client calls itself. Optional: RFC 7591 makes every metadata field optional, so a registration without one is recorded under a default name. It is **not** vouched for by Fleetless and must never be rendered as if it were: a self-registered client chooses this string, and one has called itself *"Fleetless Official Helper"*.'
4974
5305
  }),
4975
- token_endpoint_auth_method: z19.enum(["none"]).optional().meta({
5306
+ token_endpoint_auth_method: z20.enum(["none"]).optional().meta({
4976
5307
  description: "`none`, RFC 7591's value for a public client, and the only value either server registers. Any other value is **refused rather than silently downgraded**: a client that believes it holds a secret and does not has a wrong mental model of its own security. There is no client secret to hold \u2014 mandatory PKCE (`S256`) is the defence."
4977
5308
  }),
4978
- grant_types: z19.array(z19.enum(["authorization_code", "refresh_token"])).optional().meta({
5309
+ grant_types: z20.array(z20.enum(["authorization_code", "refresh_token"])).optional().meta({
4979
5310
  description: "Accepted for conformance with RFC 7591 and then **ignored**: both MCP authorization servers grant `authorization_code` and `refresh_token` to every registration, and the answer states what was granted (\xA73.2.1) rather than what was asked."
4980
5311
  }),
4981
- response_types: z19.array(z19.enum(["code"])).optional().meta({
5312
+ response_types: z20.array(z20.enum(["code"])).optional().meta({
4982
5313
  description: "Accepted for conformance and then **ignored**; the response names `code`, which is the only response type OAuth 2.1 leaves, the implicit grant having been removed."
4983
5314
  }),
4984
- scope: z19.string().max(500).optional().meta({
5315
+ scope: z20.string().max(500).optional().meta({
4985
5316
  description: "Accepted for conformance and then **ignored**. This authorization server issues no scopes at all, which is why the registration answer carries no `scope` field to echo one back in."
4986
5317
  })
4987
5318
  }).meta({
4988
5319
  description: "What an MCP client sends to register itself, per RFC 7591. Unknown metadata is ignored rather than refused (\xA73.1), and the answer states what was actually granted rather than what was asked for (\xA73.2.1)."
4989
5320
  });
4990
- var dynamicClientRegistrationResponse = z19.object({
4991
- client_id: z19.string().min(1).max(200).meta({
5321
+ var dynamicClientRegistrationResponse = z20.object({
5322
+ client_id: z20.string().min(1).max(200).meta({
4992
5323
  description: "The identifier this client sends at the authorize and token endpoints. Opaque, and not the app identifier."
4993
5324
  }),
4994
- client_name: z19.string().min(1).max(200).meta({
5325
+ client_name: z20.string().min(1).max(200).meta({
4995
5326
  description: "The name the client registered under, echoed back. Chosen by the client and not vouched for by Fleetless."
4996
5327
  }),
4997
- redirect_uris: z19.array(redirectUri).meta({
5328
+ redirect_uris: z20.array(redirectUri).meta({
4998
5329
  description: "The redirect URIs this registration was accepted for. A code is returned to one of these and nowhere else."
4999
5330
  }),
5000
- grant_types: z19.array(z19.string()).meta({
5331
+ grant_types: z20.array(z20.string()).meta({
5001
5332
  description: 'The grants this client may use. Always exactly `["authorization_code", "refresh_token"]` \u2014 an exchange mints a refresh token and the token endpoint rotates it.'
5002
5333
  }),
5003
- response_types: z19.array(z19.string()).meta({
5334
+ response_types: z20.array(z20.string()).meta({
5004
5335
  description: "The response types this client may ask for: `code`."
5005
5336
  }),
5006
- token_endpoint_auth_method: z19.literal("none").meta({
5337
+ token_endpoint_auth_method: z20.literal("none").meta({
5007
5338
  description: "`none` \u2014 this server registers public clients only, and PKCE rather than a secret is what protects the exchange."
5008
5339
  }),
5009
- client_id_issued_at: z19.number().int().nonnegative().meta({
5340
+ client_id_issued_at: z20.number().int().nonnegative().meta({
5010
5341
  description: "When the registration was created, in seconds since the epoch, per RFC 7591."
5011
5342
  }),
5012
- client_secret_expires_at: z19.literal(0).meta({
5343
+ client_secret_expires_at: z20.literal(0).meta({
5013
5344
  description: "Always `0`, which is RFC 7591's way of saying the client secret never expires \u2014 there is none. The **registration** itself does expire: a self-registered client that never completes a flow is an unauthenticated write somebody left behind."
5014
5345
  })
5015
5346
  });
5016
- var oauthCodeTokenRequest = z19.object({
5017
- grant_type: z19.literal("authorization_code").meta({
5347
+ var oauthCodeTokenRequest = z20.object({
5348
+ grant_type: z20.literal("authorization_code").meta({
5018
5349
  description: "`authorization_code`: this request exchanges the code from the authorize redirect for an access token and a refresh token."
5019
5350
  }),
5020
- code: z19.string().min(1).max(500).meta({
5351
+ code: z20.string().min(1).max(500).meta({
5021
5352
  description: "The authorization code from the redirect. It may be exchanged once; a second presentation is `invalid_grant`, the same answer a fabricated code gets."
5022
5353
  }),
5023
5354
  redirect_uri: redirectUri.meta({
5024
5355
  description: "The same redirect URI the authorize request used. It is compared, not merely recorded."
5025
5356
  }),
5026
- client_id: z19.string().min(1).max(200).meta({
5357
+ client_id: z20.string().min(1).max(200).meta({
5027
5358
  description: "The client making the exchange, as registered."
5028
5359
  }),
5029
- code_verifier: z19.string().regex(/^[A-Za-z0-9\-._~]{43,128}$/, "code_verifier must be 43-128 unreserved characters (RFC 7636 \xA74.1)").meta({
5360
+ code_verifier: z20.string().regex(/^[A-Za-z0-9\-._~]{43,128}$/, "code_verifier must be 43-128 unreserved characters (RFC 7636 \xA74.1)").meta({
5030
5361
  description: "The PKCE verifier whose `S256` hash was sent as the challenge at the authorize step. Between `43` and `128` unreserved characters, per RFC 7636 \xA74.1 \u2014 it is compared rather than parsed, so a length nobody checks is a length an attacker chooses. PKCE is mandatory for every client under OAuth 2.1."
5031
5362
  }),
5032
- resource: z19.url().optional().meta({
5363
+ resource: z20.url().optional().meta({
5033
5364
  description: "The resource the token is requested for, per RFC 8707. It must match the audience the code was authorized for, or the answer is `invalid_target`; omitted, the code's own audience stands. It becomes the token's `aud`, and a resource refuses a token whose audience names something else \u2014 which is what keeps a token minted for one app out of another app's endpoint."
5034
5365
  })
5035
5366
  }).meta({
5036
5367
  description: "RFC 6749 \xA74.1.3's authorization-code exchange with PKCE, as either MCP authorization server reads it. Sent as `application/x-www-form-urlencoded`, per \xA74.1.3, though the server accepts a JSON body too."
5037
5368
  });
5038
- var oauthRefreshTokenRequest = z19.object({
5039
- grant_type: z19.literal("refresh_token").meta({
5369
+ var oauthRefreshTokenRequest = z20.object({
5370
+ grant_type: z20.literal("refresh_token").meta({
5040
5371
  description: "`refresh_token`: this request rotates a refresh token into a new access token and a new refresh token. The presented token is consumed; presenting it again revokes the whole session."
5041
5372
  }),
5042
- refresh_token: z19.string().min(1).max(500).meta({
5373
+ refresh_token: z20.string().min(1).max(500).meta({
5043
5374
  description: "The refresh token from the last token response. Bound to the client that received it and to one identity space: presented by another client, or at the other MCP server, it is `invalid_grant` and stays unconsumed."
5044
5375
  }),
5045
- client_id: z19.string().min(1).max(200).meta({
5376
+ client_id: z20.string().min(1).max(200).meta({
5046
5377
  description: "The client the refresh token was issued to, as registered. A refresh token is not transferable between clients."
5047
5378
  }),
5048
- resource: z19.url().optional().meta({
5379
+ resource: z20.url().optional().meta({
5049
5380
  description: "The resource the new token is for, per RFC 8707. Optional; when named it must be the audience the session was issued for, or the answer is `invalid_target` and the refresh token is left untouched. The successor carries the same audience either way."
5050
5381
  })
5051
5382
  }).meta({
5052
5383
  description: "RFC 6749 \xA76's refresh, as either MCP authorization server reads it. Every use rotates: the answer carries a new refresh token and the presented one is dead."
5053
5384
  });
5054
- var oauthTokenRequest = z19.discriminatedUnion("grant_type", [oauthCodeTokenRequest, oauthRefreshTokenRequest]).meta({
5385
+ var oauthTokenRequest = z20.discriminatedUnion("grant_type", [oauthCodeTokenRequest, oauthRefreshTokenRequest]).meta({
5055
5386
  description: "What an MCP token endpoint accepts: the authorization-code exchange, or a refresh. Any other `grant_type` is `unsupported_grant_type`, refused before a lookup happens."
5056
5387
  });
5057
- var oauthTokenResponse = z19.object({
5058
- access_token: z19.string().min(1).meta({
5388
+ var oauthTokenResponse = z20.object({
5389
+ access_token: z20.string().min(1).meta({
5059
5390
  description: "The bearer token. It is the same token the client login mints \u2014 only the envelope differs, because an RFC-compliant client parses this one and knows nothing about Fleetless."
5060
5391
  }),
5061
- token_type: z19.literal("Bearer").meta({
5392
+ token_type: z20.literal("Bearer").meta({
5062
5393
  description: "`Bearer`. RFC 6749 \xA75.1 makes the value case-insensitive for a client reading it; this is the spelling this server emits."
5063
5394
  }),
5064
- expires_in: z19.number().int().positive().meta({
5395
+ expires_in: z20.number().int().positive().meta({
5065
5396
  description: "How long the access token is valid, in **seconds**, per RFC 6749 \xA75.1. Not a timestamp, and not milliseconds."
5066
5397
  }),
5067
- refresh_token: z19.string().min(1).optional().meta({
5398
+ refresh_token: z20.string().min(1).optional().meta({
5068
5399
  description: "The refresh token. Both MCP token endpoints issue one on every exchange and every refresh; it rotates on every use, lives ninety days from its last use, and dies with the account's sessions \u2014 a block, a password change, a withdrawn consent. The console's own OAuth portal issues none."
5069
5400
  }),
5070
- scope: z19.string().max(500).optional().meta({
5401
+ scope: z20.string().max(500).optional().meta({
5071
5402
  description: "The scopes the issued token actually carries, space-separated."
5072
5403
  })
5073
5404
  });
5074
- var authorizationServerMetadata = z19.object({
5075
- issuer: z19.url().meta({
5405
+ var authorizationServerMetadata = z20.object({
5406
+ issuer: z20.url().meta({
5076
5407
  description: "The issuer identifier of this authorization server, per RFC 8414 \xA72. It is what a client checks a token's `iss` against."
5077
5408
  }),
5078
- authorization_endpoint: z19.url().meta({
5409
+ authorization_endpoint: z20.url().meta({
5079
5410
  description: "Where a client sends the user to authorize."
5080
5411
  }),
5081
- token_endpoint: z19.url().meta({
5412
+ token_endpoint: z20.url().meta({
5082
5413
  description: "The URL where a client exchanges an authorization code, or a refresh token, for tokens."
5083
5414
  }),
5084
- registration_endpoint: z19.url().optional().meta({
5415
+ registration_endpoint: z20.url().optional().meta({
5085
5416
  description: "The URL where a client may register itself, per RFC 7591. Absent when the app does not accept dynamic clients."
5086
5417
  }),
5087
- response_types_supported: z19.array(z19.literal("code")).meta({
5418
+ response_types_supported: z20.array(z20.literal("code")).meta({
5088
5419
  description: "The response types this server offers: `code` only, the implicit grant being gone with OAuth 2.1."
5089
5420
  }),
5090
- grant_types_supported: z19.array(z19.enum(["authorization_code", "refresh_token"])).meta({
5421
+ grant_types_supported: z20.array(z20.enum(["authorization_code", "refresh_token"])).meta({
5091
5422
  description: "The grants this server offers: `authorization_code` and `refresh_token`. OAuth 2.1 removes the implicit and password grants, so neither appears here."
5092
5423
  }),
5093
- code_challenge_methods_supported: z19.array(codeChallengeMethod).meta({
5424
+ code_challenge_methods_supported: z20.array(codeChallengeMethod).meta({
5094
5425
  description: "The PKCE challenge methods accepted: `S256` only. `plain` is not offered \u2014 a challenge equal to its verifier defends against nothing, and offering it would make a downgrade negotiable."
5095
5426
  }),
5096
- token_endpoint_auth_methods_supported: z19.array(z19.literal("none")).meta({
5427
+ token_endpoint_auth_methods_supported: z20.array(z20.literal("none")).meta({
5097
5428
  description: "How a client authenticates at the token endpoint: `none`, the public-client method, with PKCE protecting the exchange."
5098
5429
  }),
5099
- scopes_supported: z19.array(z19.string()).optional().meta({
5430
+ scopes_supported: z20.array(z20.string()).optional().meta({
5100
5431
  description: "The scopes this server knows about, where it publishes a list."
5101
5432
  })
5102
5433
  });
5103
- var protectedResourceMetadata = z19.object({
5104
- resource: z19.url().meta({
5434
+ var protectedResourceMetadata = z20.object({
5435
+ resource: z20.url().meta({
5105
5436
  description: "The resource identifier this document describes, per RFC 9728. A token whose audience names something else is rejected here rather than merely noted."
5106
5437
  }),
5107
- authorization_servers: z19.array(z19.url()).min(1).meta({
5438
+ authorization_servers: z20.array(z20.url()).min(1).meta({
5108
5439
  description: "The authorization servers that may issue tokens for this resource. There is always at least one."
5109
5440
  }),
5110
- bearer_methods_supported: z19.array(z19.literal("header")).meta({
5441
+ bearer_methods_supported: z20.array(z20.literal("header")).meta({
5111
5442
  description: "How a token may be presented: in the `Authorization` header only, never in a query parameter or a form field."
5112
5443
  }),
5113
- scopes_supported: z19.array(z19.string()).optional().meta({
5444
+ scopes_supported: z20.array(z20.string()).optional().meta({
5114
5445
  description: "The scopes this resource understands, where it publishes a list."
5115
5446
  })
5116
5447
  });
5117
- var oauthRedirectResponse = z19.object({
5118
- redirect_to: z19.string().min(1).max(2e3)
5448
+ var oauthRedirectResponse = z20.object({
5449
+ redirect_to: z20.string().min(1).max(2e3)
5119
5450
  });
5120
- var oauthAuthorizeQuery = z19.object({
5121
- response_type: z19.literal("code").meta({
5451
+ var oauthAuthorizeQuery = z20.object({
5452
+ response_type: z20.literal("code").meta({
5122
5453
  description: "Always `code`. RFC 6749 \xA74.1.2.1 names `unsupported_response_type` for any other value, but `oauthErrorCode` has no such member \u2014 this server issues no other grant from this endpoint \u2014 so an unsupported value comes back on the callback as `invalid_request`."
5123
5454
  }),
5124
- client_id: z19.string().min(1).meta({
5455
+ client_id: z20.string().min(1).meta({
5125
5456
  description: "The OAuth client, self-registered or the one well-known central client \u2014 **not** the app identifier. Unknown, expired-dynamic and mismatched clients all collapse into the same `400 invalid_client`, answered without a redirect."
5126
5457
  }),
5127
- redirect_uri: z19.string().min(1).meta({
5458
+ redirect_uri: z20.string().min(1).meta({
5128
5459
  description: "One of the client's registered redirect URIs, compared **exactly** \u2014 string equality against the registered list, never a prefix or a host match. Both the shape (`redirectUri`) and the registration are checked, and a failure of either is a `400 invalid_request` with no redirect."
5129
5460
  }),
5130
- code_challenge: z19.string().min(1).meta({
5461
+ code_challenge: z20.string().min(1).meta({
5131
5462
  description: "The PKCE challenge; the verifier is presented at the token endpoint. Only non-emptiness is checked here \u2014 length and alphabet are not \u2014 since the verifier is what has to match."
5132
5463
  }),
5133
- code_challenge_method: z19.literal("S256").meta({
5464
+ code_challenge_method: z20.literal("S256").meta({
5134
5465
  description: "Only `S256`. `plain` is refused: a challenge equal to its verifier defends against nothing."
5135
5466
  }),
5136
- state: z19.string().optional().meta({
5467
+ state: z20.string().optional().meta({
5137
5468
  description: "Returned unchanged on the callback, and on the error redirect too, so a client can bind either answer to its own request."
5138
5469
  }),
5139
- resource: z19.string().optional().meta({
5470
+ resource: z20.string().optional().meta({
5140
5471
  description: "RFC 8707 resource indicator: the API origin or the MCP endpoint the token is for. Checked against the resources this server issues tokens for **on behalf of this client's app**; a mismatch is `invalid_target` on the callback."
5141
5472
  })
5142
5473
  // **No `scope`, because this authorization server issues none.** The field
@@ -5149,7 +5480,7 @@ var oauthAuthorizeQuery = z19.object({
5149
5480
  description: "The authorization request an MCP client sends, per RFC 6749 \xA74.1.1 with mandatory PKCE. The handler reads it parameter by parameter rather than through one parse, because the answers differ: `client_id` and `redirect_uri` are refused flat, with no redirect, since until both are confirmed there is no trusted target to bounce a browser to, and everything after them is reported to the client's own callback as query parameters."
5150
5481
  });
5151
5482
 
5152
- // node_modules/.pnpm/@fleetless+contracts@6.0.0/node_modules/@fleetless/contracts/dist/routes.js
5483
+ // node_modules/.pnpm/@fleetless+contracts@6.2.0-next.2/node_modules/@fleetless/contracts/dist/routes.js
5153
5484
  var MCP_APP = MCP_APP_PATHS(":appIdentifier");
5154
5485
  var APP_IDENTIFIER = {
5155
5486
  name: "appIdentifier",
@@ -8786,6 +9117,79 @@ var ROUTES = [
8786
9117
  transport: "http",
8787
9118
  notes: "The message is stored before any mail is tried, so `202` means it is kept whatever `mail` says: `sent`, `failed`, or `not_configured` when this cloud has no feedback address. At most 10 messages per developer per hour; the 11th answers `429 rate_limited` with `retry_after_ms`. Replies come by mail, to the sender's address."
8788
9119
  },
9120
+ /* ----------------------------------------------------------- org (plan) */
9121
+ {
9122
+ method: "GET",
9123
+ path: "/api/org/plan",
9124
+ section: "org",
9125
+ summary: "Reads the org's plan: its limits, its usage against them, its add-ons and any change already queued.",
9126
+ audience: "developer",
9127
+ auth: "developer",
9128
+ rateLimited: false,
9129
+ ownerTier: false,
9130
+ status: 200,
9131
+ params: [],
9132
+ query: null,
9133
+ request: null,
9134
+ response: orgPlan,
9135
+ errors: [...DEVELOPER_GUARD],
9136
+ transport: "http",
9137
+ notes: "The one read the console's Plan & billing page, its usage and limit gauges, and every upgrade prompt and feature gate draw from \u2014 nothing else computes `limits` or `usage` on its own. `limits` is already the effective ceiling, the catalogue row raised by `addons` or replaced by an operator's override, so a consumer never recomputes it from the catalogue. `usage` is counted fresh on every call, never cached. `switch` is present only for an organization still on the beta that has not yet landed on a priced plan."
9138
+ },
9139
+ {
9140
+ method: "PUT",
9141
+ path: "/api/org/plan/change",
9142
+ section: "org",
9143
+ summary: "Moves the org's plan down \u2014 a lower plan or a cancellation to Basic \u2014 queuing the change rather than applying it at once.",
9144
+ audience: "developer",
9145
+ auth: "developer",
9146
+ rateLimited: false,
9147
+ ownerTier: true,
9148
+ status: 200,
9149
+ params: [],
9150
+ query: null,
9151
+ request: planChangeRequest,
9152
+ response: orgPlan,
9153
+ errors: [...DEVELOPER_GUARD, "tier_required", "validation_error", "plan_limit", "target_state_conflict"],
9154
+ transport: "http",
9155
+ notes: "Owner tier, and **downward only**: this route moves the org to a lower plan or cancels it outright to Basic. It never moves the org up \u2014 until payment exists, an upgrade or an add-on is not this route's job at all, and is handled today as a Feedback request that Fleetless then applies through the admin route. `409 target_state_conflict` names `target_plan` with rule `not_lower` when the chosen plan is not below the org's current one; with rule `locked_basic_only` when the org is locked (`orgLock`) and the chosen plan is anything but Basic; and with rule `migration_basic_only` when the org is still on the beta, awaiting the switch to priced plans, and the chosen plan is anything but Basic \u2014 that choice is exactly what the org lands on at the switch. An owner is never named in `keep` and always stays, but still counts against the target plan's `seats`; `409 plan_limit` names `seats` when the owners alone already exceed it, and names whichever other limit `keep` still exceeds otherwise. `keep` is `null` when the org's current usage already fits the target plan outright and nothing is deleted; named, it lists exactly the robots, apps, app users and developers that stay. The choice is stored as `pending_change` and takes effect at `period_ends_at` \u2014 **everything of the chosen kind not named in `keep` is deleted at that instant, never before** \u2014 except a choice made while the org is locked, which takes effect at once, and a beta org's choice, which takes effect at the switch date instead. Anything created while the choice is pending is checked against the target plan too and, when it passes, is folded into `keep`, so exactly what the confirmation counted is what is actually deleted. A later `PUT` replaces a still-pending choice outright."
9156
+ },
9157
+ {
9158
+ method: "DELETE",
9159
+ path: "/api/org/plan/change",
9160
+ section: "org",
9161
+ summary: "Withdraws a plan change that was queued but has not taken effect yet.",
9162
+ audience: "developer",
9163
+ auth: "developer",
9164
+ rateLimited: false,
9165
+ ownerTier: true,
9166
+ status: 204,
9167
+ params: [],
9168
+ query: null,
9169
+ request: null,
9170
+ response: null,
9171
+ errors: [...DEVELOPER_GUARD, "tier_required", "not_found"],
9172
+ transport: "http",
9173
+ notes: "Owner tier. `404 not_found` when the org has no `pending_change` to withdraw. The org stays on its current plan, unchanged, as if the choice had never been made; a developer who wants a different one sends a new `PUT`, which would have replaced this one outright anyway."
9174
+ },
9175
+ {
9176
+ method: "PATCH",
9177
+ path: "/api/admin/orgs/:id/plan",
9178
+ section: "org",
9179
+ summary: "Changes an org's plan, add-ons, limit overrides, currency or billing period as the operator.",
9180
+ audience: "internal",
9181
+ auth: "ops",
9182
+ rateLimited: true,
9183
+ ownerTier: false,
9184
+ status: 200,
9185
+ params: [{ name: "id", description: "The org's uuid, whose plan, add-ons or overrides the operator is changing." }],
9186
+ query: null,
9187
+ request: adminPlanChangeRequest,
9188
+ response: orgPlan,
9189
+ errors: ["unauthorized", "not_found", "validation_error", "plan_limit", "rate_limited"],
9190
+ transport: "http",
9191
+ notes: "Every public host answers `404 not_found` for every `/api/admin/*` path \u2014 this route is reachable only on the cloud's private address \u2014 and that same address answers `404` here too while `OPS_API_TOKEN` is not configured, so a door with no key behind it reads exactly like one nobody opened. An unknown `:id` is the same `404`. Applies at once, never queued as a `pending_change`, and only when the org's current usage fits the result: `409 plan_limit` when a lower plan, a lowered override or a removed add-on would leave the org over a limit \u2014 the operator never deletes an org's things, only the owner's own choice does. On success it also withdraws any `pending_change`, ends a beta org's wait for the switch and lifts a lock. Audited as `org.plan_changed` with the `fleetless` actor, never a developer's \u2014 the row names what an operator did, not who in the org asked for it."
9192
+ },
8789
9193
  /* ------------------------------------------------- assets (robot upload) */
8790
9194
  {
8791
9195
  method: "POST",
@@ -8801,9 +9205,9 @@ var ROUTES = [
8801
9205
  query: null,
8802
9206
  request: null,
8803
9207
  response: asset,
8804
- errors: ["unauthorized", "rate_limited", "validation_error", "not_found", "quota_exceeded", "bad_request"],
9208
+ errors: ["unauthorized", "rate_limited", "validation_error", "not_found", "file_too_large", "plan_limit", "quota_exceeded", "bad_request"],
8805
9209
  transport: "http",
8806
- notes: "The body is the **raw file bytes**, not JSON, so it has no request schema; everything about the file \u2014 its kind, its name, its sync id and its announced size \u2014 rides in the `x-fleetless-asset-*` headers `ASSET_UPLOAD_HEADERS` names. The credential is a short-lived upload token minted by `POST /api/robots/:id/assets/sync`, verified in a `preParsing` hook so a refusal precedes the work rather than following it: a `preHandler` would already have buffered the whole file. **Nothing is refused for its own size** \u2014 the robot's asset store is the only limit, so the announced size is checked there against `ROBOT_ASSET_STORE_BYTES` and a file with no room left answers `409 quota_exceeded` carrying `store_bytes`, `used_bytes` and `size_bytes`, while the sync carries on with the next file. Past that, the server's own body limit answers a bare `413 bad_request` with none of those numbers in it. Rate limited per robot inside that same hook, which is why `rateLimited` is `false`: there is no rate-limiting preHandler registered on this route. The URDF itself is never refused for the store; only meshes and textures are charged against it."
9210
+ notes: "The body is the **raw file bytes**, not JSON, so it has no request schema; everything about the file \u2014 its kind, its name, its sync id and its announced size \u2014 rides in the `x-fleetless-asset-*` headers `ASSET_UPLOAD_HEADERS` names. The credential is a short-lived upload token minted by `POST /api/robots/:id/assets/sync`, verified in a `preParsing` hook so a refusal precedes the work rather than following it: a `preHandler` would already have buffered the whole file. **One file can be at most `ASSET_FILE_MAX_BYTES`**, on every plan and for every kind, the URDF included: an announced size over it answers `413 file_too_large` with `max_bytes` and `size_bytes` before a byte is buffered; without a truthful size, a body over the limit answers the same code with the bytes that arrived as `size_bytes`, or with `size_bytes: null` when it ran past the server's body limit and nobody counted the bytes. Retrying does not help. A file that fits but finds the store full answers `409 plan_limit` (or `409 quota_exceeded` for an organisation still on the beta) carrying `store_bytes`, `used_bytes` and `size_bytes`, while the sync carries on with the next file. Rate limited per robot inside that same hook, which is why `rateLimited` is `false`: there is no rate-limiting preHandler registered on this route. The URDF itself is never refused for the store; only meshes and textures are charged against it."
8807
9211
  },
8808
9212
  /* ------------------------------------ realtime and bridge transports */
8809
9213
  {