@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/CHANGELOG.md +8 -0
- package/dist/index.cjs +517 -113
- package/dist/index.d.cts +16 -6
- package/dist/index.d.ts +16 -6
- package/dist/index.js +517 -113
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -275,7 +275,7 @@ function isRenderKind(kind) {
|
|
|
275
275
|
}
|
|
276
276
|
}
|
|
277
277
|
}
|
|
278
|
-
async function forEachWithConcurrency(items,
|
|
278
|
+
async function forEachWithConcurrency(items, limit2, fn) {
|
|
279
279
|
let next = 0;
|
|
280
280
|
let failed = false;
|
|
281
281
|
let firstError;
|
|
@@ -293,7 +293,7 @@ async function forEachWithConcurrency(items, limit, fn) {
|
|
|
293
293
|
}
|
|
294
294
|
}
|
|
295
295
|
}
|
|
296
|
-
await Promise.all(Array.from({ length: Math.min(
|
|
296
|
+
await Promise.all(Array.from({ length: Math.min(limit2, items.length) }, () => worker()));
|
|
297
297
|
if (failed) throw firstError;
|
|
298
298
|
}
|
|
299
299
|
function createAssetsApi(http) {
|
|
@@ -442,7 +442,7 @@ function createAssetsApi(http) {
|
|
|
442
442
|
};
|
|
443
443
|
}
|
|
444
444
|
|
|
445
|
-
// node_modules/.pnpm/@fleetless+contracts@6.0.
|
|
445
|
+
// node_modules/.pnpm/@fleetless+contracts@6.2.0-next.2/node_modules/@fleetless/contracts/dist/common.js
|
|
446
446
|
var import_zod = require("zod");
|
|
447
447
|
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.";
|
|
448
448
|
var slug = import_zod.z.string().min(2).max(63).regex(/^[a-z][a-z0-9]*(?:_[a-z0-9]+)*$/, SLUG_RULE);
|
|
@@ -473,7 +473,7 @@ var applyError = import_zod.z.object({
|
|
|
473
473
|
details: import_zod.z.record(import_zod.z.string(), import_zod.z.unknown()).optional()
|
|
474
474
|
});
|
|
475
475
|
|
|
476
|
-
// node_modules/.pnpm/@fleetless+contracts@6.0.
|
|
476
|
+
// node_modules/.pnpm/@fleetless+contracts@6.2.0-next.2/node_modules/@fleetless/contracts/dist/mcp.js
|
|
477
477
|
var import_zod2 = require("zod");
|
|
478
478
|
function mcpAppEndpointPath(appIdentifier2) {
|
|
479
479
|
return `/mcp/${appIdentifier2}`;
|
|
@@ -522,10 +522,10 @@ var mcpRolePreviewResponse = import_zod2.z.object({
|
|
|
522
522
|
});
|
|
523
523
|
var MCP_ASSET_LINK_TTL_MS = 15 * 60 * 1e3;
|
|
524
524
|
|
|
525
|
-
// node_modules/.pnpm/@fleetless+contracts@6.0.
|
|
525
|
+
// node_modules/.pnpm/@fleetless+contracts@6.2.0-next.2/node_modules/@fleetless/contracts/dist/protocol.js
|
|
526
526
|
var import_zod8 = require("zod");
|
|
527
527
|
|
|
528
|
-
// node_modules/.pnpm/@fleetless+contracts@6.0.
|
|
528
|
+
// node_modules/.pnpm/@fleetless+contracts@6.2.0-next.2/node_modules/@fleetless/contracts/dist/assets.js
|
|
529
529
|
var import_zod3 = require("zod");
|
|
530
530
|
var assetKind = import_zod3.z.enum(["urdf", "mesh", "texture"]);
|
|
531
531
|
var asset = import_zod3.z.object({
|
|
@@ -845,10 +845,10 @@ var assetSyncBusyDetails = import_zod3.z.object({
|
|
|
845
845
|
started_at_ms: import_zod3.z.number().int().nonnegative()
|
|
846
846
|
});
|
|
847
847
|
|
|
848
|
-
// node_modules/.pnpm/@fleetless+contracts@6.0.
|
|
848
|
+
// node_modules/.pnpm/@fleetless+contracts@6.2.0-next.2/node_modules/@fleetless/contracts/dist/config.js
|
|
849
849
|
var import_zod5 = require("zod");
|
|
850
850
|
|
|
851
|
-
// node_modules/.pnpm/@fleetless+contracts@6.0.
|
|
851
|
+
// node_modules/.pnpm/@fleetless+contracts@6.2.0-next.2/node_modules/@fleetless/contracts/dist/alerts.js
|
|
852
852
|
var import_zod4 = require("zod");
|
|
853
853
|
var alertRowCondition = import_zod4.z.discriminatedUnion("kind", [
|
|
854
854
|
import_zod4.z.strictObject({
|
|
@@ -918,7 +918,7 @@ var putDatapointDisplayRequest = import_zod4.z.object({
|
|
|
918
918
|
y_max: import_zod4.z.number().finite().nullable()
|
|
919
919
|
}).strict();
|
|
920
920
|
|
|
921
|
-
// node_modules/.pnpm/@fleetless+contracts@6.0.
|
|
921
|
+
// node_modules/.pnpm/@fleetless+contracts@6.2.0-next.2/node_modules/@fleetless/contracts/dist/config.js
|
|
922
922
|
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:`.";
|
|
923
923
|
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:`.";
|
|
924
924
|
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.";
|
|
@@ -2010,7 +2010,7 @@ var configState = import_zod5.z.object({
|
|
|
2010
2010
|
applied_errors: import_zod5.z.array(applyError).nullable()
|
|
2011
2011
|
});
|
|
2012
2012
|
|
|
2013
|
-
// node_modules/.pnpm/@fleetless+contracts@6.0.
|
|
2013
|
+
// node_modules/.pnpm/@fleetless+contracts@6.2.0-next.2/node_modules/@fleetless/contracts/dist/introspection.js
|
|
2014
2014
|
var import_zod6 = require("zod");
|
|
2015
2015
|
var rosGraphEntry = import_zod6.z.object({
|
|
2016
2016
|
name: rosName,
|
|
@@ -2049,7 +2049,7 @@ var typeDefinition = import_zod6.z.discriminatedUnion("kind", [
|
|
|
2049
2049
|
})
|
|
2050
2050
|
]);
|
|
2051
2051
|
|
|
2052
|
-
// node_modules/.pnpm/@fleetless+contracts@6.0.
|
|
2052
|
+
// node_modules/.pnpm/@fleetless+contracts@6.2.0-next.2/node_modules/@fleetless/contracts/dist/jobs.js
|
|
2053
2053
|
var import_zod7 = require("zod");
|
|
2054
2054
|
var jobState = import_zod7.z.enum(["running", "unknown", "succeeded", "failed", "cancelled", "lost"]);
|
|
2055
2055
|
var reportedJobState = jobState.exclude(["unknown"]);
|
|
@@ -2286,7 +2286,7 @@ var jobRunSummary = import_zod7.z.object({
|
|
|
2286
2286
|
since_ms: import_zod7.z.number().int().nonnegative()
|
|
2287
2287
|
});
|
|
2288
2288
|
|
|
2289
|
-
// node_modules/.pnpm/@fleetless+contracts@6.0.
|
|
2289
|
+
// node_modules/.pnpm/@fleetless+contracts@6.2.0-next.2/node_modules/@fleetless/contracts/dist/protocol.js
|
|
2290
2290
|
var DAY_MS = 24 * 60 * 60 * 1e3;
|
|
2291
2291
|
var MAX_PATIENCE_MS = 12e4;
|
|
2292
2292
|
var MIN_PATIENCE_MS = 1e3;
|
|
@@ -2684,11 +2684,11 @@ var bridgeCameraState = import_zod8.z.object({
|
|
|
2684
2684
|
request_id: import_zod8.z.string().min(1).max(64).nullable()
|
|
2685
2685
|
});
|
|
2686
2686
|
|
|
2687
|
-
// node_modules/.pnpm/@fleetless+contracts@6.0.
|
|
2687
|
+
// node_modules/.pnpm/@fleetless+contracts@6.2.0-next.2/node_modules/@fleetless/contracts/dist/config-issues.js
|
|
2688
2688
|
var EXPOSURE_SECTIONS = ["datapoints", "actions", "services", "publishers", "cameras"];
|
|
2689
2689
|
var EXPOSURE_SECTION_NAMES = new Set(EXPOSURE_SECTIONS);
|
|
2690
2690
|
|
|
2691
|
-
// node_modules/.pnpm/@fleetless+contracts@6.0.
|
|
2691
|
+
// node_modules/.pnpm/@fleetless+contracts@6.2.0-next.2/node_modules/@fleetless/contracts/dist/rest.js
|
|
2692
2692
|
var import_zod9 = require("zod");
|
|
2693
2693
|
var robot = import_zod9.z.object({
|
|
2694
2694
|
id: import_zod9.z.uuid().meta({
|
|
@@ -3453,13 +3453,13 @@ var slugUsageResponse = import_zod9.z.object({
|
|
|
3453
3453
|
alert_count: import_zod9.z.number().int().nonnegative()
|
|
3454
3454
|
});
|
|
3455
3455
|
|
|
3456
|
-
// node_modules/.pnpm/@fleetless+contracts@6.0.
|
|
3456
|
+
// node_modules/.pnpm/@fleetless+contracts@6.2.0-next.2/node_modules/@fleetless/contracts/dist/realtime.js
|
|
3457
3457
|
var import_zod14 = require("zod");
|
|
3458
3458
|
|
|
3459
|
-
// node_modules/.pnpm/@fleetless+contracts@6.0.
|
|
3459
|
+
// node_modules/.pnpm/@fleetless+contracts@6.2.0-next.2/node_modules/@fleetless/contracts/dist/client-auth.js
|
|
3460
3460
|
var import_zod13 = require("zod");
|
|
3461
3461
|
|
|
3462
|
-
// node_modules/.pnpm/@fleetless+contracts@6.0.
|
|
3462
|
+
// node_modules/.pnpm/@fleetless+contracts@6.2.0-next.2/node_modules/@fleetless/contracts/dist/apps.js
|
|
3463
3463
|
var import_zod10 = require("zod");
|
|
3464
3464
|
var appIdentifier = slug;
|
|
3465
3465
|
var app = import_zod10.z.object({
|
|
@@ -3682,10 +3682,10 @@ var rolePermissions = import_zod10.z.object({
|
|
|
3682
3682
|
})
|
|
3683
3683
|
});
|
|
3684
3684
|
|
|
3685
|
-
// node_modules/.pnpm/@fleetless+contracts@6.0.
|
|
3685
|
+
// node_modules/.pnpm/@fleetless+contracts@6.2.0-next.2/node_modules/@fleetless/contracts/dist/app-users.js
|
|
3686
3686
|
var import_zod12 = require("zod");
|
|
3687
3687
|
|
|
3688
|
-
// node_modules/.pnpm/@fleetless+contracts@6.0.
|
|
3688
|
+
// node_modules/.pnpm/@fleetless+contracts@6.2.0-next.2/node_modules/@fleetless/contracts/dist/identity.js
|
|
3689
3689
|
var import_zod11 = require("zod");
|
|
3690
3690
|
var password = import_zod11.z.string().min(12).max(256);
|
|
3691
3691
|
var USER_DISPLAY_NAME_MAX = 120;
|
|
@@ -3903,7 +3903,7 @@ var recoveryCodesResponse = import_zod11.z.object({
|
|
|
3903
3903
|
recovery_codes: recoveryCodesList.meta({ description: "The ten new recovery codes, lowercase, shown once. Every earlier code is void." })
|
|
3904
3904
|
});
|
|
3905
3905
|
|
|
3906
|
-
// node_modules/.pnpm/@fleetless+contracts@6.0.
|
|
3906
|
+
// node_modules/.pnpm/@fleetless+contracts@6.2.0-next.2/node_modules/@fleetless/contracts/dist/app-users.js
|
|
3907
3907
|
var APP_USER_DISPLAY_NAME_MAX = 120;
|
|
3908
3908
|
var providerSlug = import_zod12.z.string().max(40).regex(/^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/, "must be lowercase and hyphen-separated, starting with a letter");
|
|
3909
3909
|
var appUserStatus = import_zod12.z.enum(["pending_verification", "active", "blocked"]);
|
|
@@ -4214,7 +4214,7 @@ var mailOutcome = import_zod12.z.object({
|
|
|
4214
4214
|
})
|
|
4215
4215
|
});
|
|
4216
4216
|
|
|
4217
|
-
// node_modules/.pnpm/@fleetless+contracts@6.0.
|
|
4217
|
+
// node_modules/.pnpm/@fleetless+contracts@6.2.0-next.2/node_modules/@fleetless/contracts/dist/client-auth.js
|
|
4218
4218
|
var clientLoginRequest = import_zod13.z.object({
|
|
4219
4219
|
app_identifier: appIdentifier.meta({
|
|
4220
4220
|
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."
|
|
@@ -4390,7 +4390,8 @@ var clientOidcErrorCode = import_zod13.z.enum([
|
|
|
4390
4390
|
"provider_misconfigured",
|
|
4391
4391
|
"provider_disabled",
|
|
4392
4392
|
"invalid_request",
|
|
4393
|
-
"quota_exceeded"
|
|
4393
|
+
"quota_exceeded",
|
|
4394
|
+
"plan_limit"
|
|
4394
4395
|
]);
|
|
4395
4396
|
var clientMcpInteraction = import_zod13.z.object({
|
|
4396
4397
|
id: import_zod13.z.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." }),
|
|
@@ -4454,7 +4455,7 @@ var clientIdentity = import_zod13.z.object({
|
|
|
4454
4455
|
})
|
|
4455
4456
|
});
|
|
4456
4457
|
|
|
4457
|
-
// node_modules/.pnpm/@fleetless+contracts@6.0.
|
|
4458
|
+
// node_modules/.pnpm/@fleetless+contracts@6.2.0-next.2/node_modules/@fleetless/contracts/dist/realtime.js
|
|
4458
4459
|
var clientAuth = import_zod14.z.object({
|
|
4459
4460
|
type: import_zod14.z.literal("auth"),
|
|
4460
4461
|
token: import_zod14.z.string().min(1)
|
|
@@ -4622,6 +4623,12 @@ var liveSessionEndReason = import_zod14.z.enum([
|
|
|
4622
4623
|
"expired",
|
|
4623
4624
|
/** The robot was deleted out from under the session. */
|
|
4624
4625
|
"robot_deleted",
|
|
4626
|
+
/**
|
|
4627
|
+
* The organization's live video for app users reached its plan's monthly
|
|
4628
|
+
* limit (2026-10-02, fleetless/fleetless#103); `detail` carries the
|
|
4629
|
+
* sentence the viewer shows.
|
|
4630
|
+
*/
|
|
4631
|
+
"plan_limit",
|
|
4625
4632
|
/**
|
|
4626
4633
|
* The cloud ended it and cannot say which of the above applied. **Kept
|
|
4627
4634
|
* deliberately**: a channel that cannot say "I do not know" will say
|
|
@@ -4732,7 +4739,7 @@ var orgEventDropped = import_zod14.z.object({
|
|
|
4732
4739
|
dropped: import_zod14.z.number().int().positive()
|
|
4733
4740
|
}).strict();
|
|
4734
4741
|
|
|
4735
|
-
// node_modules/.pnpm/@fleetless+contracts@6.0.
|
|
4742
|
+
// node_modules/.pnpm/@fleetless+contracts@6.2.0-next.2/node_modules/@fleetless/contracts/dist/feedback.js
|
|
4736
4743
|
var import_zod15 = require("zod");
|
|
4737
4744
|
var FEEDBACK_KINDS = ["idea", "problem", "question", "other"];
|
|
4738
4745
|
var feedbackKind = import_zod15.z.enum(FEEDBACK_KINDS);
|
|
@@ -4757,7 +4764,7 @@ var feedbackResponse = import_zod15.z.object({
|
|
|
4757
4764
|
})
|
|
4758
4765
|
}).strict();
|
|
4759
4766
|
|
|
4760
|
-
// node_modules/.pnpm/@fleetless+contracts@6.0.
|
|
4767
|
+
// node_modules/.pnpm/@fleetless+contracts@6.2.0-next.2/node_modules/@fleetless/contracts/dist/client-robots.js
|
|
4761
4768
|
var import_zod16 = require("zod");
|
|
4762
4769
|
var clientRobotListItem = import_zod16.z.object({
|
|
4763
4770
|
...robot.shape,
|
|
@@ -4774,10 +4781,10 @@ var clientRobotListResponse = import_zod16.z.object({
|
|
|
4774
4781
|
})
|
|
4775
4782
|
});
|
|
4776
4783
|
|
|
4777
|
-
// node_modules/.pnpm/@fleetless+contracts@6.0.
|
|
4784
|
+
// node_modules/.pnpm/@fleetless+contracts@6.2.0-next.2/node_modules/@fleetless/contracts/dist/audit.js
|
|
4778
4785
|
var import_zod17 = require("zod");
|
|
4779
4786
|
var auditActor = import_zod17.z.object({
|
|
4780
|
-
kind: import_zod17.z.enum(["developer", "end_user", "app_user", "server_key", "bridge"]),
|
|
4787
|
+
kind: import_zod17.z.enum(["developer", "end_user", "app_user", "server_key", "bridge", "fleetless"]),
|
|
4781
4788
|
id: import_zod17.z.uuid(),
|
|
4782
4789
|
label: import_zod17.z.string().min(1).max(200)
|
|
4783
4790
|
});
|
|
@@ -4916,34 +4923,358 @@ var auditListResponse = import_zod17.z.object({
|
|
|
4916
4923
|
next_cursor: import_zod17.z.number().int().positive().nullable()
|
|
4917
4924
|
});
|
|
4918
4925
|
|
|
4919
|
-
// node_modules/.pnpm/@fleetless+contracts@6.0.
|
|
4926
|
+
// node_modules/.pnpm/@fleetless+contracts@6.2.0-next.2/node_modules/@fleetless/contracts/dist/errors.js
|
|
4927
|
+
var import_zod19 = require("zod");
|
|
4928
|
+
|
|
4929
|
+
// node_modules/.pnpm/@fleetless+contracts@6.2.0-next.2/node_modules/@fleetless/contracts/dist/plans.js
|
|
4920
4930
|
var import_zod18 = require("zod");
|
|
4921
|
-
var
|
|
4922
|
-
|
|
4923
|
-
|
|
4924
|
-
|
|
4931
|
+
var planId = import_zod18.z.enum(["basic", "plus", "pro", "enterprise"]);
|
|
4932
|
+
var planLimitKey = import_zod18.z.enum([
|
|
4933
|
+
"seats",
|
|
4934
|
+
"robots",
|
|
4935
|
+
"apps",
|
|
4936
|
+
"app_users",
|
|
4937
|
+
"live_video_ms_per_month",
|
|
4938
|
+
"asset_bytes_per_robot",
|
|
4939
|
+
"history_days",
|
|
4940
|
+
"audit_days"
|
|
4941
|
+
]);
|
|
4942
|
+
var limit = import_zod18.z.number().int().positive().nullable();
|
|
4943
|
+
var planLimits = import_zod18.z.object({
|
|
4944
|
+
seats: limit.meta({ description: "Developers, owners included, plus pending team invitations." }),
|
|
4945
|
+
robots: limit.meta({ description: "Robots in the org." }),
|
|
4946
|
+
apps: limit.meta({ description: "Apps in the org." }),
|
|
4947
|
+
app_users: limit.meta({ description: "App users across every app of the org, plus pending app-user invitations." }),
|
|
4948
|
+
live_video_ms_per_month: limit.meta({
|
|
4949
|
+
description: "Live video watched by app users in one UTC calendar month, in milliseconds, across the org. Console sessions do not count."
|
|
4950
|
+
}),
|
|
4951
|
+
asset_bytes_per_robot: limit.meta({
|
|
4952
|
+
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."
|
|
4953
|
+
}),
|
|
4954
|
+
history_days: limit.meta({ description: "Days the org's robot history is kept." }),
|
|
4955
|
+
audit_days: limit.meta({ description: "Days the org's audit log is kept." })
|
|
4956
|
+
});
|
|
4957
|
+
var planFeature = import_zod18.z.enum(["app_mcp", "two_factor", "require_two_factor", "app_oidc", "hosted_logo", "audit_export", "addons"]);
|
|
4958
|
+
var FEATURE_DESCRIPTIONS = {
|
|
4959
|
+
app_mcp: "An app's own MCP endpoint, for its app users.",
|
|
4960
|
+
two_factor: "Two-factor sign-in for developers.",
|
|
4961
|
+
require_two_factor: "An owner may require two-factor sign-in for every developer of the org.",
|
|
4962
|
+
app_oidc: "An app may let its users sign in through an OpenID Connect identity provider.",
|
|
4963
|
+
hosted_logo: "An app's hosted pages show its logo and accent colour, not only its name.",
|
|
4964
|
+
audit_export: "The audit log can be exported as CSV.",
|
|
4965
|
+
addons: "Add-ons can be bought on top of the plan."
|
|
4966
|
+
};
|
|
4967
|
+
var planFeatures = import_zod18.z.object(Object.fromEntries(planFeature.options.map((f) => [f, import_zod18.z.boolean().meta({ description: FEATURE_DESCRIPTIONS[f] })])));
|
|
4968
|
+
var cents = import_zod18.z.number().int().nonnegative();
|
|
4969
|
+
var planPrices = import_zod18.z.object({
|
|
4970
|
+
eur_month: cents.meta({ description: "Per month in euro cents, excluding VAT." }),
|
|
4971
|
+
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." }),
|
|
4972
|
+
eur_year: cents.meta({ description: "Per year in euro cents, excluding VAT: twelve months less 15 %." }),
|
|
4973
|
+
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." })
|
|
4974
|
+
});
|
|
4975
|
+
var planSupport = import_zod18.z.enum(["community", "email", "priority", "named_contact"]);
|
|
4976
|
+
var planCatalogueEntry = import_zod18.z.object({
|
|
4977
|
+
id: planId.meta({ description: "The plan." }),
|
|
4978
|
+
name: import_zod18.z.string().min(1).meta({ description: "The plan's display name: Basic, Plus, Pro or Enterprise." }),
|
|
4979
|
+
limits: planLimits.meta({ description: "What the plan allows. `null` means by contract." }),
|
|
4980
|
+
features: planFeatures.meta({ description: "What the plan unlocks." }),
|
|
4981
|
+
prices: planPrices.nullable().meta({ description: "`null` for Enterprise: sold by contract, on request." }),
|
|
4982
|
+
support: planSupport.meta({ description: "The support that comes with the plan." })
|
|
4983
|
+
});
|
|
4984
|
+
var addonKey = import_zod18.z.enum(["seats", "robots", "apps", "app_user_packs", "live_video_packs"]);
|
|
4985
|
+
var addonCatalogueEntry = import_zod18.z.object({
|
|
4986
|
+
key: addonKey.meta({ description: "The add-on." }),
|
|
4987
|
+
raises: planLimitKey.meta({ description: "The plan limit this add-on raises." }),
|
|
4988
|
+
per_unit: import_zod18.z.number().int().positive().meta({ description: "How much one unit of this add-on raises `raises` by." }),
|
|
4989
|
+
prices: planPrices.meta({ description: "The price of one unit." })
|
|
4990
|
+
});
|
|
4991
|
+
function usdCentsFromEurCents(eurCents) {
|
|
4992
|
+
return Math.floor((eurCents * 115 + 9999) / 1e4) * 100;
|
|
4993
|
+
}
|
|
4994
|
+
function yearlyEurCents(monthEurCents) {
|
|
4995
|
+
return Math.round(monthEurCents * 12 * 85 / 100);
|
|
4996
|
+
}
|
|
4997
|
+
function pricesFromEurMonth(eurMonthCents) {
|
|
4998
|
+
const eurYear = yearlyEurCents(eurMonthCents);
|
|
4999
|
+
return {
|
|
5000
|
+
eur_month: eurMonthCents,
|
|
5001
|
+
usd_month: usdCentsFromEurCents(eurMonthCents),
|
|
5002
|
+
eur_year: eurYear,
|
|
5003
|
+
usd_year: usdCentsFromEurCents(eurYear)
|
|
5004
|
+
};
|
|
5005
|
+
}
|
|
5006
|
+
var PLANS = {
|
|
5007
|
+
basic: {
|
|
5008
|
+
id: "basic",
|
|
5009
|
+
name: "Basic",
|
|
5010
|
+
limits: {
|
|
5011
|
+
seats: 1,
|
|
5012
|
+
robots: 1,
|
|
5013
|
+
apps: 1,
|
|
5014
|
+
app_users: 10,
|
|
5015
|
+
live_video_ms_per_month: 36e6,
|
|
5016
|
+
asset_bytes_per_robot: 1e9,
|
|
5017
|
+
history_days: 7,
|
|
5018
|
+
audit_days: 7
|
|
5019
|
+
},
|
|
5020
|
+
features: {
|
|
5021
|
+
app_mcp: false,
|
|
5022
|
+
two_factor: false,
|
|
5023
|
+
require_two_factor: false,
|
|
5024
|
+
app_oidc: false,
|
|
5025
|
+
hosted_logo: false,
|
|
5026
|
+
audit_export: false,
|
|
5027
|
+
addons: false
|
|
5028
|
+
},
|
|
5029
|
+
prices: pricesFromEurMonth(0),
|
|
5030
|
+
support: "community"
|
|
5031
|
+
},
|
|
5032
|
+
plus: {
|
|
5033
|
+
id: "plus",
|
|
5034
|
+
name: "Plus",
|
|
5035
|
+
limits: {
|
|
5036
|
+
seats: 3,
|
|
5037
|
+
robots: 3,
|
|
5038
|
+
apps: 3,
|
|
5039
|
+
app_users: 25,
|
|
5040
|
+
live_video_ms_per_month: 36e7,
|
|
5041
|
+
asset_bytes_per_robot: 2e9,
|
|
5042
|
+
history_days: 30,
|
|
5043
|
+
audit_days: 30
|
|
5044
|
+
},
|
|
5045
|
+
features: {
|
|
5046
|
+
app_mcp: true,
|
|
5047
|
+
two_factor: true,
|
|
5048
|
+
require_two_factor: false,
|
|
5049
|
+
app_oidc: true,
|
|
5050
|
+
hosted_logo: true,
|
|
5051
|
+
audit_export: false,
|
|
5052
|
+
addons: false
|
|
5053
|
+
},
|
|
5054
|
+
prices: pricesFromEurMonth(2900),
|
|
5055
|
+
support: "email"
|
|
5056
|
+
},
|
|
5057
|
+
pro: {
|
|
5058
|
+
id: "pro",
|
|
5059
|
+
name: "Pro",
|
|
5060
|
+
limits: {
|
|
5061
|
+
seats: 5,
|
|
5062
|
+
robots: 5,
|
|
5063
|
+
apps: 5,
|
|
5064
|
+
app_users: 50,
|
|
5065
|
+
live_video_ms_per_month: 9e8,
|
|
5066
|
+
asset_bytes_per_robot: 3e9,
|
|
5067
|
+
history_days: 90,
|
|
5068
|
+
audit_days: 90
|
|
5069
|
+
},
|
|
5070
|
+
features: {
|
|
5071
|
+
app_mcp: true,
|
|
5072
|
+
two_factor: true,
|
|
5073
|
+
require_two_factor: true,
|
|
5074
|
+
app_oidc: true,
|
|
5075
|
+
hosted_logo: true,
|
|
5076
|
+
audit_export: true,
|
|
5077
|
+
addons: true
|
|
5078
|
+
},
|
|
5079
|
+
prices: pricesFromEurMonth(14900),
|
|
5080
|
+
support: "priority"
|
|
5081
|
+
},
|
|
5082
|
+
enterprise: {
|
|
5083
|
+
id: "enterprise",
|
|
5084
|
+
name: "Enterprise",
|
|
5085
|
+
limits: {
|
|
5086
|
+
seats: null,
|
|
5087
|
+
robots: null,
|
|
5088
|
+
apps: null,
|
|
5089
|
+
app_users: null,
|
|
5090
|
+
live_video_ms_per_month: null,
|
|
5091
|
+
asset_bytes_per_robot: null,
|
|
5092
|
+
history_days: null,
|
|
5093
|
+
audit_days: null
|
|
5094
|
+
},
|
|
5095
|
+
features: {
|
|
5096
|
+
app_mcp: true,
|
|
5097
|
+
two_factor: true,
|
|
5098
|
+
require_two_factor: true,
|
|
5099
|
+
app_oidc: true,
|
|
5100
|
+
hosted_logo: true,
|
|
5101
|
+
audit_export: true,
|
|
5102
|
+
addons: true
|
|
5103
|
+
},
|
|
5104
|
+
prices: null,
|
|
5105
|
+
support: "named_contact"
|
|
5106
|
+
}
|
|
5107
|
+
};
|
|
5108
|
+
var ADDONS = {
|
|
5109
|
+
seats: { key: "seats", raises: "seats", per_unit: 1, prices: pricesFromEurMonth(900) },
|
|
5110
|
+
robots: { key: "robots", raises: "robots", per_unit: 1, prices: pricesFromEurMonth(1900) },
|
|
5111
|
+
apps: { key: "apps", raises: "apps", per_unit: 1, prices: pricesFromEurMonth(900) },
|
|
5112
|
+
app_user_packs: { key: "app_user_packs", raises: "app_users", per_unit: 5, prices: pricesFromEurMonth(1e3) },
|
|
5113
|
+
live_video_packs: { key: "live_video_packs", raises: "live_video_ms_per_month", per_unit: 9e8, prices: pricesFromEurMonth(900) }
|
|
5114
|
+
};
|
|
5115
|
+
var planCurrency = import_zod18.z.enum(["eur", "usd"]);
|
|
5116
|
+
var addonCount = import_zod18.z.number().int().nonnegative();
|
|
5117
|
+
var orgAddons = import_zod18.z.object({
|
|
5118
|
+
seats: addonCount.meta({ description: "Extra developer seats, one each." }),
|
|
5119
|
+
robots: addonCount.meta({ description: "Extra robots, one each." }),
|
|
5120
|
+
apps: addonCount.meta({ description: "Extra apps, one each." }),
|
|
5121
|
+
app_user_packs: addonCount.meta({ description: "Packs of five extra app users." }),
|
|
5122
|
+
live_video_packs: addonCount.meta({ description: "Packs of 250 extra hours of app-user live video per month." })
|
|
5123
|
+
});
|
|
5124
|
+
var usageCount = import_zod18.z.number().int().nonnegative();
|
|
5125
|
+
var orgPlanUsage = import_zod18.z.object({
|
|
5126
|
+
seats: usageCount.meta({ description: "Developers, owners included, plus pending team invitations." }),
|
|
5127
|
+
robots: usageCount.meta({ description: "Robots in the org." }),
|
|
5128
|
+
apps: usageCount.meta({ description: "Apps in the org." }),
|
|
5129
|
+
app_users: usageCount.meta({ description: "App users across every app, plus pending app-user invitations." }),
|
|
5130
|
+
live_video_ms_this_month: usageCount.meta({
|
|
5131
|
+
description: "Live video watched by app users in the current UTC calendar month, in milliseconds. Console sessions do not count."
|
|
5132
|
+
}),
|
|
5133
|
+
asset_bytes: usageCount.meta({ description: "Bytes the assets of every robot of the org occupy, together." })
|
|
5134
|
+
});
|
|
5135
|
+
var planChangeKeep = import_zod18.z.object({
|
|
5136
|
+
robots: import_zod18.z.array(import_zod18.z.uuid()).meta({ description: "The robots that stay, by id. Every other robot is deleted when the change takes effect." }),
|
|
5137
|
+
apps: import_zod18.z.array(import_zod18.z.uuid()).meta({ description: "The apps that stay, by id. Every other app is deleted when the change takes effect." }),
|
|
5138
|
+
app_users: import_zod18.z.array(import_zod18.z.uuid()).meta({
|
|
5139
|
+
description: "The app users that stay, by id, across every app. Every other app user is deleted when the change takes effect."
|
|
5140
|
+
}),
|
|
5141
|
+
developers: import_zod18.z.array(import_zod18.z.uuid()).meta({
|
|
5142
|
+
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."
|
|
5143
|
+
})
|
|
5144
|
+
}).strict();
|
|
5145
|
+
var planChangeReason = import_zod18.z.enum(["downgrade", "cancel", "migration", "lock"]);
|
|
5146
|
+
var pendingPlanChange = import_zod18.z.object({
|
|
5147
|
+
target_plan: planId.meta({ description: "The plan the org moves to." }),
|
|
5148
|
+
reason: planChangeReason.meta({ description: "Why the change is pending: `downgrade`, `cancel`, `migration` or `lock`." }),
|
|
5149
|
+
effective_at: import_zod18.z.iso.datetime().nullable().meta({
|
|
5150
|
+
description: "When the change takes effect. `null` only for a move off the beta whose date is not set yet."
|
|
5151
|
+
}),
|
|
5152
|
+
keep: planChangeKeep.nullable().meta({
|
|
5153
|
+
description: "What stays. `null` when the org already fits the target plan and nothing is deleted."
|
|
5154
|
+
}),
|
|
5155
|
+
history_days_after: import_zod18.z.number().int().positive().meta({
|
|
5156
|
+
description: "Days of history and audit log the org keeps on the target plan."
|
|
5157
|
+
}),
|
|
5158
|
+
chosen_by: import_zod18.z.uuid().meta({ description: "The user id of the owner who chose the change, or the nil UUID when Fleetless queued it." }),
|
|
5159
|
+
chosen_at: import_zod18.z.iso.datetime().meta({ description: "When the change was chosen." })
|
|
5160
|
+
});
|
|
5161
|
+
var orgLock = import_zod18.z.object({
|
|
5162
|
+
reason: import_zod18.z.enum(["payment", "migration"]).meta({
|
|
5163
|
+
description: "`payment`: a payment is missing. `migration`: the org did not choose what stays when the beta ended."
|
|
5164
|
+
}),
|
|
5165
|
+
since: import_zod18.z.iso.datetime().meta({ description: "When the org was locked." })
|
|
5166
|
+
});
|
|
5167
|
+
var orgPlan = import_zod18.z.object({
|
|
5168
|
+
plan: planId.meta({ description: "The org's current plan." }),
|
|
5169
|
+
currency: planCurrency.meta({ description: "The currency the org's prices are shown and billed in." }),
|
|
5170
|
+
period_ends_at: import_zod18.z.iso.datetime().meta({
|
|
5171
|
+
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."
|
|
5172
|
+
}),
|
|
5173
|
+
addons: orgAddons.meta({ description: "The add-ons the org has bought. All zero on a plan without the `addons` feature." }),
|
|
5174
|
+
limits: planLimits.meta({
|
|
5175
|
+
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`."
|
|
5176
|
+
}),
|
|
5177
|
+
features: planFeatures.meta({ description: "What the org's plan unlocks." }),
|
|
5178
|
+
usage: orgPlanUsage.meta({ description: "What the org uses now, counted the way each limit counts it." }),
|
|
5179
|
+
pending_change: pendingPlanChange.nullable().meta({ description: "A move to a lower plan that has not taken effect yet, or `null`." }),
|
|
5180
|
+
lock: orgLock.nullable().meta({ description: "Why and since when the org is locked, or `null` when it is not." }),
|
|
5181
|
+
switch: import_zod18.z.object({
|
|
5182
|
+
at: import_zod18.z.iso.datetime().nullable().meta({
|
|
5183
|
+
description: "When the org moves from the beta onto its plan. `null` while the date is not set."
|
|
5184
|
+
}),
|
|
5185
|
+
needs_choice: import_zod18.z.boolean().meta({
|
|
5186
|
+
description: "Whether the org uses more than Basic allows, so an owner has to choose what stays before `at`."
|
|
5187
|
+
})
|
|
5188
|
+
}).nullable().meta({ description: "Set only while the org is still on the beta; `null` for every other org." })
|
|
4925
5189
|
});
|
|
4926
|
-
var
|
|
4927
|
-
|
|
5190
|
+
var planChangeRequest = import_zod18.z.object({
|
|
5191
|
+
target_plan: planId.meta({ description: "The lower plan to move to; `basic` cancels." }),
|
|
5192
|
+
keep: planChangeKeep.nullable().meta({
|
|
5193
|
+
description: "What stays. `null` when the org already fits the target plan, so nothing is deleted."
|
|
5194
|
+
})
|
|
5195
|
+
}).strict();
|
|
5196
|
+
var planOverrides = import_zod18.z.object(Object.fromEntries(planLimitKey.options.map((k) => [
|
|
5197
|
+
k,
|
|
5198
|
+
limit.optional().meta({ description: `Replaces the plan's \`${k}\`. \`null\` clears the override.` })
|
|
5199
|
+
]))).strict();
|
|
5200
|
+
var adminPlanChangeRequest = import_zod18.z.object({
|
|
5201
|
+
plan: planId.meta({ description: "The plan the org is on after this request." }),
|
|
5202
|
+
addons: orgAddons.partial().strict().optional().meta({ description: "Add-on counts to set. Counts not named stay as they are." }),
|
|
5203
|
+
overrides: planOverrides.optional().meta({ description: "Limits to override. `null` clears an override." }),
|
|
5204
|
+
currency: planCurrency.optional().meta({ description: "The currency the org is billed in." }),
|
|
5205
|
+
period_ends_at: import_zod18.z.iso.datetime().nullable().optional().meta({
|
|
5206
|
+
description: "The end of the org's billing period. `null` falls back to the end of the current UTC month."
|
|
5207
|
+
})
|
|
5208
|
+
}).strict();
|
|
5209
|
+
|
|
5210
|
+
// node_modules/.pnpm/@fleetless+contracts@6.2.0-next.2/node_modules/@fleetless/contracts/dist/errors.js
|
|
5211
|
+
var apiError = import_zod19.z.object({
|
|
5212
|
+
code: import_zod19.z.string().min(1),
|
|
5213
|
+
message: import_zod19.z.string().min(1),
|
|
5214
|
+
details: import_zod19.z.unknown().optional()
|
|
5215
|
+
});
|
|
5216
|
+
var parameterViolation = import_zod19.z.object({
|
|
5217
|
+
field: import_zod19.z.string().min(1),
|
|
4928
5218
|
/** Which rule failed — `min`, `max`, `enum`, `pattern`, `required`, `undeclared`. */
|
|
4929
|
-
rule:
|
|
4930
|
-
message:
|
|
5219
|
+
rule: import_zod19.z.string().min(1),
|
|
5220
|
+
message: import_zod19.z.string().min(1)
|
|
4931
5221
|
});
|
|
4932
|
-
var parameterInvalidDetails =
|
|
4933
|
-
violations:
|
|
5222
|
+
var parameterInvalidDetails = import_zod19.z.object({
|
|
5223
|
+
violations: import_zod19.z.array(parameterViolation).min(1)
|
|
4934
5224
|
});
|
|
4935
|
-
var cancelRejectedDetails =
|
|
4936
|
-
goals:
|
|
5225
|
+
var cancelRejectedDetails = import_zod19.z.object({
|
|
5226
|
+
goals: import_zod19.z.array(bridgeCancelResultEntry).min(1)
|
|
4937
5227
|
});
|
|
4938
|
-
var invalidCodeDetails =
|
|
4939
|
-
attempts_left:
|
|
5228
|
+
var invalidCodeDetails = import_zod19.z.object({
|
|
5229
|
+
attempts_left: import_zod19.z.number().int().min(0).meta({
|
|
4940
5230
|
description: "How many more wrong codes this code or challenge takes before it is spent. `0` means the next attempt answers `410 token_spent`."
|
|
4941
5231
|
})
|
|
4942
5232
|
});
|
|
5233
|
+
var planLimitDetails = import_zod19.z.object({
|
|
5234
|
+
limit: planLimitKey.exclude(["history_days", "audit_days"]).meta({ description: "The limit the action would exceed." }),
|
|
5235
|
+
used: import_zod19.z.number().int().nonnegative().meta({ description: "How much of the limit the org uses now." }),
|
|
5236
|
+
max: import_zod19.z.number().int().nonnegative().meta({
|
|
5237
|
+
description: "The limit. For `asset_bytes_per_robot`, the org's whole pool: robots \xD7 the plan's bytes per robot."
|
|
5238
|
+
}),
|
|
5239
|
+
plan: planId.meta({ description: "The plan whose limit refused: the target plan while a move to a lower plan is pending." }),
|
|
5240
|
+
lifted_by: import_zod19.z.object({
|
|
5241
|
+
plan: planId.nullable().meta({ description: "The cheapest higher plan that raises this limit, or `null` when none does." }),
|
|
5242
|
+
addon: addonKey.nullable().meta({
|
|
5243
|
+
description: "The add-on that raises this limit, when the org's plan can buy add-ons; otherwise `null`."
|
|
5244
|
+
})
|
|
5245
|
+
}).meta({ description: "What would lift the limit." })
|
|
5246
|
+
});
|
|
5247
|
+
var assetPlanLimitDetails = planLimitDetails.extend({
|
|
5248
|
+
...assetStoreRefusedDetails.shape,
|
|
5249
|
+
store_bytes: assetStoreRefusedDetails.shape.store_bytes.meta({
|
|
5250
|
+
description: "The org's asset pool, in bytes: `robots \xD7 asset_bytes_per_robot`."
|
|
5251
|
+
}),
|
|
5252
|
+
used_bytes: assetStoreRefusedDetails.shape.used_bytes.meta({
|
|
5253
|
+
description: "Bytes the org's assets occupy, across every robot, before this upload."
|
|
5254
|
+
})
|
|
5255
|
+
});
|
|
5256
|
+
var planRequiredDetails = import_zod19.z.object({
|
|
5257
|
+
feature: planFeature.meta({ description: "The feature the action needs." }),
|
|
5258
|
+
plan: planId.meta({ description: "The org's current plan." }),
|
|
5259
|
+
required_plan: planId.meta({ description: "The cheapest plan that has the feature." })
|
|
5260
|
+
});
|
|
5261
|
+
var orgLockedDetails = import_zod19.z.object({
|
|
5262
|
+
reason: import_zod19.z.enum(["payment", "migration"]).meta({
|
|
5263
|
+
description: "`payment`: a payment is missing. `migration`: the org did not choose what stays when the beta ended."
|
|
5264
|
+
})
|
|
5265
|
+
});
|
|
5266
|
+
var fileTooLargeDetails = import_zod19.z.object({
|
|
5267
|
+
max_bytes: import_zod19.z.number().int().positive().meta({
|
|
5268
|
+
description: "The most one asset file can be, in bytes: `ASSET_FILE_MAX_BYTES`, the same on every plan."
|
|
5269
|
+
}),
|
|
5270
|
+
size_bytes: import_zod19.z.number().int().positive().nullable().meta({
|
|
5271
|
+
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."
|
|
5272
|
+
})
|
|
5273
|
+
});
|
|
4943
5274
|
|
|
4944
|
-
// node_modules/.pnpm/@fleetless+contracts@6.0.
|
|
4945
|
-
var
|
|
4946
|
-
var oauthErrorCode =
|
|
5275
|
+
// node_modules/.pnpm/@fleetless+contracts@6.2.0-next.2/node_modules/@fleetless/contracts/dist/oauth.js
|
|
5276
|
+
var import_zod20 = require("zod");
|
|
5277
|
+
var oauthErrorCode = import_zod20.z.enum([
|
|
4947
5278
|
"invalid_request",
|
|
4948
5279
|
"invalid_client",
|
|
4949
5280
|
"invalid_grant",
|
|
@@ -4956,11 +5287,11 @@ var oauthErrorCode = import_zod19.z.enum([
|
|
|
4956
5287
|
/** RFC 8707: the `resource` named is not one this server issues tokens for. */
|
|
4957
5288
|
"invalid_target"
|
|
4958
5289
|
]);
|
|
4959
|
-
var oauthError =
|
|
5290
|
+
var oauthError = import_zod20.z.object({
|
|
4960
5291
|
error: oauthErrorCode,
|
|
4961
|
-
error_description:
|
|
5292
|
+
error_description: import_zod20.z.string().min(1).max(500).optional(),
|
|
4962
5293
|
/** Echoed back per RFC 6749 §4.1.2.1 so a client can match the response. */
|
|
4963
|
-
state:
|
|
5294
|
+
state: import_zod20.z.string().min(1).max(500).optional(),
|
|
4964
5295
|
/**
|
|
4965
5296
|
* **A Fleetless reason carried inside a standard envelope, and it exists
|
|
4966
5297
|
* because the alternative lost a distinction.**
|
|
@@ -4978,9 +5309,9 @@ var oauthError = import_zod19.z.object({
|
|
|
4978
5309
|
* our own tooling switches on. RFC 6749 §5.2 permits additional members, and
|
|
4979
5310
|
* a client that ignores this one still behaves correctly.
|
|
4980
5311
|
*/
|
|
4981
|
-
fleetless_code:
|
|
5312
|
+
fleetless_code: import_zod20.z.string().min(1).max(60).optional()
|
|
4982
5313
|
});
|
|
4983
|
-
var redirectUri =
|
|
5314
|
+
var redirectUri = import_zod20.z.string().min(1).max(2e3).refine((v) => {
|
|
4984
5315
|
let url;
|
|
4985
5316
|
try {
|
|
4986
5317
|
url = new URL(v);
|
|
@@ -4995,180 +5326,180 @@ var redirectUri = import_zod19.z.string().min(1).max(2e3).refine((v) => {
|
|
|
4995
5326
|
return ["localhost", "127.0.0.1", "[::1]"].includes(url.hostname);
|
|
4996
5327
|
return false;
|
|
4997
5328
|
}, { message: "redirect_uri must be an https URL, or http on an explicit loopback address, and carry no fragment" });
|
|
4998
|
-
var codeChallengeMethod =
|
|
5329
|
+
var codeChallengeMethod = import_zod20.z.enum(["S256"]);
|
|
4999
5330
|
var MCP_DCR_MAX_REDIRECT_URIS = 5;
|
|
5000
|
-
var dynamicClientRegistrationRequest =
|
|
5001
|
-
redirect_uris:
|
|
5331
|
+
var dynamicClientRegistrationRequest = import_zod20.z.object({
|
|
5332
|
+
redirect_uris: import_zod20.z.array(redirectUri).min(1).max(MCP_DCR_MAX_REDIRECT_URIS).meta({
|
|
5002
5333
|
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.`
|
|
5003
5334
|
}),
|
|
5004
|
-
client_name:
|
|
5335
|
+
client_name: import_zod20.z.string().min(1).max(200).optional().meta({
|
|
5005
5336
|
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"*.'
|
|
5006
5337
|
}),
|
|
5007
|
-
token_endpoint_auth_method:
|
|
5338
|
+
token_endpoint_auth_method: import_zod20.z.enum(["none"]).optional().meta({
|
|
5008
5339
|
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."
|
|
5009
5340
|
}),
|
|
5010
|
-
grant_types:
|
|
5341
|
+
grant_types: import_zod20.z.array(import_zod20.z.enum(["authorization_code", "refresh_token"])).optional().meta({
|
|
5011
5342
|
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."
|
|
5012
5343
|
}),
|
|
5013
|
-
response_types:
|
|
5344
|
+
response_types: import_zod20.z.array(import_zod20.z.enum(["code"])).optional().meta({
|
|
5014
5345
|
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."
|
|
5015
5346
|
}),
|
|
5016
|
-
scope:
|
|
5347
|
+
scope: import_zod20.z.string().max(500).optional().meta({
|
|
5017
5348
|
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."
|
|
5018
5349
|
})
|
|
5019
5350
|
}).meta({
|
|
5020
5351
|
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)."
|
|
5021
5352
|
});
|
|
5022
|
-
var dynamicClientRegistrationResponse =
|
|
5023
|
-
client_id:
|
|
5353
|
+
var dynamicClientRegistrationResponse = import_zod20.z.object({
|
|
5354
|
+
client_id: import_zod20.z.string().min(1).max(200).meta({
|
|
5024
5355
|
description: "The identifier this client sends at the authorize and token endpoints. Opaque, and not the app identifier."
|
|
5025
5356
|
}),
|
|
5026
|
-
client_name:
|
|
5357
|
+
client_name: import_zod20.z.string().min(1).max(200).meta({
|
|
5027
5358
|
description: "The name the client registered under, echoed back. Chosen by the client and not vouched for by Fleetless."
|
|
5028
5359
|
}),
|
|
5029
|
-
redirect_uris:
|
|
5360
|
+
redirect_uris: import_zod20.z.array(redirectUri).meta({
|
|
5030
5361
|
description: "The redirect URIs this registration was accepted for. A code is returned to one of these and nowhere else."
|
|
5031
5362
|
}),
|
|
5032
|
-
grant_types:
|
|
5363
|
+
grant_types: import_zod20.z.array(import_zod20.z.string()).meta({
|
|
5033
5364
|
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.'
|
|
5034
5365
|
}),
|
|
5035
|
-
response_types:
|
|
5366
|
+
response_types: import_zod20.z.array(import_zod20.z.string()).meta({
|
|
5036
5367
|
description: "The response types this client may ask for: `code`."
|
|
5037
5368
|
}),
|
|
5038
|
-
token_endpoint_auth_method:
|
|
5369
|
+
token_endpoint_auth_method: import_zod20.z.literal("none").meta({
|
|
5039
5370
|
description: "`none` \u2014 this server registers public clients only, and PKCE rather than a secret is what protects the exchange."
|
|
5040
5371
|
}),
|
|
5041
|
-
client_id_issued_at:
|
|
5372
|
+
client_id_issued_at: import_zod20.z.number().int().nonnegative().meta({
|
|
5042
5373
|
description: "When the registration was created, in seconds since the epoch, per RFC 7591."
|
|
5043
5374
|
}),
|
|
5044
|
-
client_secret_expires_at:
|
|
5375
|
+
client_secret_expires_at: import_zod20.z.literal(0).meta({
|
|
5045
5376
|
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."
|
|
5046
5377
|
})
|
|
5047
5378
|
});
|
|
5048
|
-
var oauthCodeTokenRequest =
|
|
5049
|
-
grant_type:
|
|
5379
|
+
var oauthCodeTokenRequest = import_zod20.z.object({
|
|
5380
|
+
grant_type: import_zod20.z.literal("authorization_code").meta({
|
|
5050
5381
|
description: "`authorization_code`: this request exchanges the code from the authorize redirect for an access token and a refresh token."
|
|
5051
5382
|
}),
|
|
5052
|
-
code:
|
|
5383
|
+
code: import_zod20.z.string().min(1).max(500).meta({
|
|
5053
5384
|
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."
|
|
5054
5385
|
}),
|
|
5055
5386
|
redirect_uri: redirectUri.meta({
|
|
5056
5387
|
description: "The same redirect URI the authorize request used. It is compared, not merely recorded."
|
|
5057
5388
|
}),
|
|
5058
|
-
client_id:
|
|
5389
|
+
client_id: import_zod20.z.string().min(1).max(200).meta({
|
|
5059
5390
|
description: "The client making the exchange, as registered."
|
|
5060
5391
|
}),
|
|
5061
|
-
code_verifier:
|
|
5392
|
+
code_verifier: import_zod20.z.string().regex(/^[A-Za-z0-9\-._~]{43,128}$/, "code_verifier must be 43-128 unreserved characters (RFC 7636 \xA74.1)").meta({
|
|
5062
5393
|
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."
|
|
5063
5394
|
}),
|
|
5064
|
-
resource:
|
|
5395
|
+
resource: import_zod20.z.url().optional().meta({
|
|
5065
5396
|
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."
|
|
5066
5397
|
})
|
|
5067
5398
|
}).meta({
|
|
5068
5399
|
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."
|
|
5069
5400
|
});
|
|
5070
|
-
var oauthRefreshTokenRequest =
|
|
5071
|
-
grant_type:
|
|
5401
|
+
var oauthRefreshTokenRequest = import_zod20.z.object({
|
|
5402
|
+
grant_type: import_zod20.z.literal("refresh_token").meta({
|
|
5072
5403
|
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."
|
|
5073
5404
|
}),
|
|
5074
|
-
refresh_token:
|
|
5405
|
+
refresh_token: import_zod20.z.string().min(1).max(500).meta({
|
|
5075
5406
|
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."
|
|
5076
5407
|
}),
|
|
5077
|
-
client_id:
|
|
5408
|
+
client_id: import_zod20.z.string().min(1).max(200).meta({
|
|
5078
5409
|
description: "The client the refresh token was issued to, as registered. A refresh token is not transferable between clients."
|
|
5079
5410
|
}),
|
|
5080
|
-
resource:
|
|
5411
|
+
resource: import_zod20.z.url().optional().meta({
|
|
5081
5412
|
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."
|
|
5082
5413
|
})
|
|
5083
5414
|
}).meta({
|
|
5084
5415
|
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."
|
|
5085
5416
|
});
|
|
5086
|
-
var oauthTokenRequest =
|
|
5417
|
+
var oauthTokenRequest = import_zod20.z.discriminatedUnion("grant_type", [oauthCodeTokenRequest, oauthRefreshTokenRequest]).meta({
|
|
5087
5418
|
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."
|
|
5088
5419
|
});
|
|
5089
|
-
var oauthTokenResponse =
|
|
5090
|
-
access_token:
|
|
5420
|
+
var oauthTokenResponse = import_zod20.z.object({
|
|
5421
|
+
access_token: import_zod20.z.string().min(1).meta({
|
|
5091
5422
|
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."
|
|
5092
5423
|
}),
|
|
5093
|
-
token_type:
|
|
5424
|
+
token_type: import_zod20.z.literal("Bearer").meta({
|
|
5094
5425
|
description: "`Bearer`. RFC 6749 \xA75.1 makes the value case-insensitive for a client reading it; this is the spelling this server emits."
|
|
5095
5426
|
}),
|
|
5096
|
-
expires_in:
|
|
5427
|
+
expires_in: import_zod20.z.number().int().positive().meta({
|
|
5097
5428
|
description: "How long the access token is valid, in **seconds**, per RFC 6749 \xA75.1. Not a timestamp, and not milliseconds."
|
|
5098
5429
|
}),
|
|
5099
|
-
refresh_token:
|
|
5430
|
+
refresh_token: import_zod20.z.string().min(1).optional().meta({
|
|
5100
5431
|
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."
|
|
5101
5432
|
}),
|
|
5102
|
-
scope:
|
|
5433
|
+
scope: import_zod20.z.string().max(500).optional().meta({
|
|
5103
5434
|
description: "The scopes the issued token actually carries, space-separated."
|
|
5104
5435
|
})
|
|
5105
5436
|
});
|
|
5106
|
-
var authorizationServerMetadata =
|
|
5107
|
-
issuer:
|
|
5437
|
+
var authorizationServerMetadata = import_zod20.z.object({
|
|
5438
|
+
issuer: import_zod20.z.url().meta({
|
|
5108
5439
|
description: "The issuer identifier of this authorization server, per RFC 8414 \xA72. It is what a client checks a token's `iss` against."
|
|
5109
5440
|
}),
|
|
5110
|
-
authorization_endpoint:
|
|
5441
|
+
authorization_endpoint: import_zod20.z.url().meta({
|
|
5111
5442
|
description: "Where a client sends the user to authorize."
|
|
5112
5443
|
}),
|
|
5113
|
-
token_endpoint:
|
|
5444
|
+
token_endpoint: import_zod20.z.url().meta({
|
|
5114
5445
|
description: "The URL where a client exchanges an authorization code, or a refresh token, for tokens."
|
|
5115
5446
|
}),
|
|
5116
|
-
registration_endpoint:
|
|
5447
|
+
registration_endpoint: import_zod20.z.url().optional().meta({
|
|
5117
5448
|
description: "The URL where a client may register itself, per RFC 7591. Absent when the app does not accept dynamic clients."
|
|
5118
5449
|
}),
|
|
5119
|
-
response_types_supported:
|
|
5450
|
+
response_types_supported: import_zod20.z.array(import_zod20.z.literal("code")).meta({
|
|
5120
5451
|
description: "The response types this server offers: `code` only, the implicit grant being gone with OAuth 2.1."
|
|
5121
5452
|
}),
|
|
5122
|
-
grant_types_supported:
|
|
5453
|
+
grant_types_supported: import_zod20.z.array(import_zod20.z.enum(["authorization_code", "refresh_token"])).meta({
|
|
5123
5454
|
description: "The grants this server offers: `authorization_code` and `refresh_token`. OAuth 2.1 removes the implicit and password grants, so neither appears here."
|
|
5124
5455
|
}),
|
|
5125
|
-
code_challenge_methods_supported:
|
|
5456
|
+
code_challenge_methods_supported: import_zod20.z.array(codeChallengeMethod).meta({
|
|
5126
5457
|
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."
|
|
5127
5458
|
}),
|
|
5128
|
-
token_endpoint_auth_methods_supported:
|
|
5459
|
+
token_endpoint_auth_methods_supported: import_zod20.z.array(import_zod20.z.literal("none")).meta({
|
|
5129
5460
|
description: "How a client authenticates at the token endpoint: `none`, the public-client method, with PKCE protecting the exchange."
|
|
5130
5461
|
}),
|
|
5131
|
-
scopes_supported:
|
|
5462
|
+
scopes_supported: import_zod20.z.array(import_zod20.z.string()).optional().meta({
|
|
5132
5463
|
description: "The scopes this server knows about, where it publishes a list."
|
|
5133
5464
|
})
|
|
5134
5465
|
});
|
|
5135
|
-
var protectedResourceMetadata =
|
|
5136
|
-
resource:
|
|
5466
|
+
var protectedResourceMetadata = import_zod20.z.object({
|
|
5467
|
+
resource: import_zod20.z.url().meta({
|
|
5137
5468
|
description: "The resource identifier this document describes, per RFC 9728. A token whose audience names something else is rejected here rather than merely noted."
|
|
5138
5469
|
}),
|
|
5139
|
-
authorization_servers:
|
|
5470
|
+
authorization_servers: import_zod20.z.array(import_zod20.z.url()).min(1).meta({
|
|
5140
5471
|
description: "The authorization servers that may issue tokens for this resource. There is always at least one."
|
|
5141
5472
|
}),
|
|
5142
|
-
bearer_methods_supported:
|
|
5473
|
+
bearer_methods_supported: import_zod20.z.array(import_zod20.z.literal("header")).meta({
|
|
5143
5474
|
description: "How a token may be presented: in the `Authorization` header only, never in a query parameter or a form field."
|
|
5144
5475
|
}),
|
|
5145
|
-
scopes_supported:
|
|
5476
|
+
scopes_supported: import_zod20.z.array(import_zod20.z.string()).optional().meta({
|
|
5146
5477
|
description: "The scopes this resource understands, where it publishes a list."
|
|
5147
5478
|
})
|
|
5148
5479
|
});
|
|
5149
|
-
var oauthRedirectResponse =
|
|
5150
|
-
redirect_to:
|
|
5480
|
+
var oauthRedirectResponse = import_zod20.z.object({
|
|
5481
|
+
redirect_to: import_zod20.z.string().min(1).max(2e3)
|
|
5151
5482
|
});
|
|
5152
|
-
var oauthAuthorizeQuery =
|
|
5153
|
-
response_type:
|
|
5483
|
+
var oauthAuthorizeQuery = import_zod20.z.object({
|
|
5484
|
+
response_type: import_zod20.z.literal("code").meta({
|
|
5154
5485
|
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`."
|
|
5155
5486
|
}),
|
|
5156
|
-
client_id:
|
|
5487
|
+
client_id: import_zod20.z.string().min(1).meta({
|
|
5157
5488
|
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."
|
|
5158
5489
|
}),
|
|
5159
|
-
redirect_uri:
|
|
5490
|
+
redirect_uri: import_zod20.z.string().min(1).meta({
|
|
5160
5491
|
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."
|
|
5161
5492
|
}),
|
|
5162
|
-
code_challenge:
|
|
5493
|
+
code_challenge: import_zod20.z.string().min(1).meta({
|
|
5163
5494
|
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."
|
|
5164
5495
|
}),
|
|
5165
|
-
code_challenge_method:
|
|
5496
|
+
code_challenge_method: import_zod20.z.literal("S256").meta({
|
|
5166
5497
|
description: "Only `S256`. `plain` is refused: a challenge equal to its verifier defends against nothing."
|
|
5167
5498
|
}),
|
|
5168
|
-
state:
|
|
5499
|
+
state: import_zod20.z.string().optional().meta({
|
|
5169
5500
|
description: "Returned unchanged on the callback, and on the error redirect too, so a client can bind either answer to its own request."
|
|
5170
5501
|
}),
|
|
5171
|
-
resource:
|
|
5502
|
+
resource: import_zod20.z.string().optional().meta({
|
|
5172
5503
|
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."
|
|
5173
5504
|
})
|
|
5174
5505
|
// **No `scope`, because this authorization server issues none.** The field
|
|
@@ -5181,7 +5512,7 @@ var oauthAuthorizeQuery = import_zod19.z.object({
|
|
|
5181
5512
|
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."
|
|
5182
5513
|
});
|
|
5183
5514
|
|
|
5184
|
-
// node_modules/.pnpm/@fleetless+contracts@6.0.
|
|
5515
|
+
// node_modules/.pnpm/@fleetless+contracts@6.2.0-next.2/node_modules/@fleetless/contracts/dist/routes.js
|
|
5185
5516
|
var MCP_APP = MCP_APP_PATHS(":appIdentifier");
|
|
5186
5517
|
var APP_IDENTIFIER = {
|
|
5187
5518
|
name: "appIdentifier",
|
|
@@ -8818,6 +9149,79 @@ var ROUTES = [
|
|
|
8818
9149
|
transport: "http",
|
|
8819
9150
|
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."
|
|
8820
9151
|
},
|
|
9152
|
+
/* ----------------------------------------------------------- org (plan) */
|
|
9153
|
+
{
|
|
9154
|
+
method: "GET",
|
|
9155
|
+
path: "/api/org/plan",
|
|
9156
|
+
section: "org",
|
|
9157
|
+
summary: "Reads the org's plan: its limits, its usage against them, its add-ons and any change already queued.",
|
|
9158
|
+
audience: "developer",
|
|
9159
|
+
auth: "developer",
|
|
9160
|
+
rateLimited: false,
|
|
9161
|
+
ownerTier: false,
|
|
9162
|
+
status: 200,
|
|
9163
|
+
params: [],
|
|
9164
|
+
query: null,
|
|
9165
|
+
request: null,
|
|
9166
|
+
response: orgPlan,
|
|
9167
|
+
errors: [...DEVELOPER_GUARD],
|
|
9168
|
+
transport: "http",
|
|
9169
|
+
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."
|
|
9170
|
+
},
|
|
9171
|
+
{
|
|
9172
|
+
method: "PUT",
|
|
9173
|
+
path: "/api/org/plan/change",
|
|
9174
|
+
section: "org",
|
|
9175
|
+
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.",
|
|
9176
|
+
audience: "developer",
|
|
9177
|
+
auth: "developer",
|
|
9178
|
+
rateLimited: false,
|
|
9179
|
+
ownerTier: true,
|
|
9180
|
+
status: 200,
|
|
9181
|
+
params: [],
|
|
9182
|
+
query: null,
|
|
9183
|
+
request: planChangeRequest,
|
|
9184
|
+
response: orgPlan,
|
|
9185
|
+
errors: [...DEVELOPER_GUARD, "tier_required", "validation_error", "plan_limit", "target_state_conflict"],
|
|
9186
|
+
transport: "http",
|
|
9187
|
+
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."
|
|
9188
|
+
},
|
|
9189
|
+
{
|
|
9190
|
+
method: "DELETE",
|
|
9191
|
+
path: "/api/org/plan/change",
|
|
9192
|
+
section: "org",
|
|
9193
|
+
summary: "Withdraws a plan change that was queued but has not taken effect yet.",
|
|
9194
|
+
audience: "developer",
|
|
9195
|
+
auth: "developer",
|
|
9196
|
+
rateLimited: false,
|
|
9197
|
+
ownerTier: true,
|
|
9198
|
+
status: 204,
|
|
9199
|
+
params: [],
|
|
9200
|
+
query: null,
|
|
9201
|
+
request: null,
|
|
9202
|
+
response: null,
|
|
9203
|
+
errors: [...DEVELOPER_GUARD, "tier_required", "not_found"],
|
|
9204
|
+
transport: "http",
|
|
9205
|
+
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."
|
|
9206
|
+
},
|
|
9207
|
+
{
|
|
9208
|
+
method: "PATCH",
|
|
9209
|
+
path: "/api/admin/orgs/:id/plan",
|
|
9210
|
+
section: "org",
|
|
9211
|
+
summary: "Changes an org's plan, add-ons, limit overrides, currency or billing period as the operator.",
|
|
9212
|
+
audience: "internal",
|
|
9213
|
+
auth: "ops",
|
|
9214
|
+
rateLimited: true,
|
|
9215
|
+
ownerTier: false,
|
|
9216
|
+
status: 200,
|
|
9217
|
+
params: [{ name: "id", description: "The org's uuid, whose plan, add-ons or overrides the operator is changing." }],
|
|
9218
|
+
query: null,
|
|
9219
|
+
request: adminPlanChangeRequest,
|
|
9220
|
+
response: orgPlan,
|
|
9221
|
+
errors: ["unauthorized", "not_found", "validation_error", "plan_limit", "rate_limited"],
|
|
9222
|
+
transport: "http",
|
|
9223
|
+
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."
|
|
9224
|
+
},
|
|
8821
9225
|
/* ------------------------------------------------- assets (robot upload) */
|
|
8822
9226
|
{
|
|
8823
9227
|
method: "POST",
|
|
@@ -8833,9 +9237,9 @@ var ROUTES = [
|
|
|
8833
9237
|
query: null,
|
|
8834
9238
|
request: null,
|
|
8835
9239
|
response: asset,
|
|
8836
|
-
errors: ["unauthorized", "rate_limited", "validation_error", "not_found", "quota_exceeded", "bad_request"],
|
|
9240
|
+
errors: ["unauthorized", "rate_limited", "validation_error", "not_found", "file_too_large", "plan_limit", "quota_exceeded", "bad_request"],
|
|
8837
9241
|
transport: "http",
|
|
8838
|
-
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. **
|
|
9242
|
+
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."
|
|
8839
9243
|
},
|
|
8840
9244
|
/* ------------------------------------ realtime and bridge transports */
|
|
8841
9245
|
{
|