@fleetless/sdk 4.0.0 → 4.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +17 -1
- package/CONTRIBUTING.md +3 -2
- package/dist/index.cjs +208 -55
- package/dist/index.d.cts +76 -9
- package/dist/index.d.ts +76 -9
- package/dist/index.js +208 -55
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -410,7 +410,7 @@ function createAssetsApi(http) {
|
|
|
410
410
|
};
|
|
411
411
|
}
|
|
412
412
|
|
|
413
|
-
// node_modules/.pnpm/@fleetless+contracts@
|
|
413
|
+
// node_modules/.pnpm/@fleetless+contracts@5.0.0/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@
|
|
444
|
+
// node_modules/.pnpm/@fleetless+contracts@5.0.0/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@
|
|
493
|
+
// node_modules/.pnpm/@fleetless+contracts@5.0.0/node_modules/@fleetless/contracts/dist/protocol.js
|
|
494
494
|
import { z as z8 } from "zod";
|
|
495
495
|
|
|
496
|
-
// node_modules/.pnpm/@fleetless+contracts@
|
|
496
|
+
// node_modules/.pnpm/@fleetless+contracts@5.0.0/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@
|
|
816
|
+
// node_modules/.pnpm/@fleetless+contracts@5.0.0/node_modules/@fleetless/contracts/dist/config.js
|
|
817
817
|
import { z as z5 } from "zod";
|
|
818
818
|
|
|
819
|
-
// node_modules/.pnpm/@fleetless+contracts@
|
|
819
|
+
// node_modules/.pnpm/@fleetless+contracts@5.0.0/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@
|
|
889
|
+
// node_modules/.pnpm/@fleetless+contracts@5.0.0/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@
|
|
1981
|
+
// node_modules/.pnpm/@fleetless+contracts@5.0.0/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,9 +2017,11 @@ var typeDefinition = z6.discriminatedUnion("kind", [
|
|
|
2017
2017
|
})
|
|
2018
2018
|
]);
|
|
2019
2019
|
|
|
2020
|
-
// node_modules/.pnpm/@fleetless+contracts@
|
|
2020
|
+
// node_modules/.pnpm/@fleetless+contracts@5.0.0/node_modules/@fleetless/contracts/dist/jobs.js
|
|
2021
2021
|
import { z as z7 } from "zod";
|
|
2022
|
-
var jobState = z7.enum(["running", "succeeded", "failed", "cancelled", "lost"]);
|
|
2022
|
+
var jobState = z7.enum(["running", "unknown", "succeeded", "failed", "cancelled", "lost"]);
|
|
2023
|
+
var reportedJobState = jobState.exclude(["unknown"]);
|
|
2024
|
+
var jobOrigin = z7.enum(["fleetless", "external"]);
|
|
2023
2025
|
var job = z7.object({
|
|
2024
2026
|
id: z7.uuid().meta({
|
|
2025
2027
|
description: "The job's id, minted by the cloud when the invocation is accepted. Informative \u2014 state is observed by slug; a cancel names this id to stop one specific job rather than whatever is running."
|
|
@@ -2029,7 +2031,10 @@ var job = z7.object({
|
|
|
2029
2031
|
description: "The action or service this job is running, as the published configuration exposes it. One slug carries one job at a time, so every observer of that slug sees the same one."
|
|
2030
2032
|
}),
|
|
2031
2033
|
state: jobState.meta({
|
|
2032
|
-
description: "Where the job stands: `running`, `succeeded`, `failed`, `cancelled` or `lost`. `
|
|
2034
|
+
description: "Where the job stands: `running`, `unknown`, `succeeded`, `failed`, `cancelled` or `lost`. `unknown` is not an outcome \u2014 the robot went offline or silent and the cloud does not know yet; the slug stays occupied and the bridge's next statement resolves it, `error` naming why the cloud lost sight of it. `lost` is final: the bridge stated it does not know the job and nothing else runs on its action, or the action server vanished mid-goal."
|
|
2035
|
+
}),
|
|
2036
|
+
origin: jobOrigin.meta({
|
|
2037
|
+
description: "Who started this job. `fleetless` for everything minted by the cloud; `external` for a goal the bridge found active on a published action without having sent it \u2014 no parameters, no starter, never written to `job_runs`."
|
|
2033
2038
|
}),
|
|
2034
2039
|
started_at: z7.iso.datetime().meta({
|
|
2035
2040
|
description: "When the cloud minted this job, as an ISO 8601 timestamp. For a job adopted from a reconnecting bridge, this is **adoption time**, not the real start \u2014 the cloud never minted it."
|
|
@@ -2048,7 +2053,7 @@ var job = z7.object({
|
|
|
2048
2053
|
* exists for the same reason on the audit log.
|
|
2049
2054
|
*
|
|
2050
2055
|
* **Scoped honestly: per cloud process, per run.** Job state lives in memory
|
|
2051
|
-
* — that is why `lost`
|
|
2056
|
+
* — that is why `unknown` and `lost` exist at all — so this counter restarts when
|
|
2052
2057
|
* the cloud does, alongside the jobs it orders. Sound, because it only ever
|
|
2053
2058
|
* orders jobs that coexist in one registry — and stated, because a reader
|
|
2054
2059
|
* who assumed `auditEvent.seq`'s durable semantics would be wrong.
|
|
@@ -2083,7 +2088,7 @@ var job = z7.object({
|
|
|
2083
2088
|
description: "The structured payload belonging to `code`, for the codes that document one \u2014 `job_queue_full` carries its `limit` and its `queued` count here. Absent for a failure with nothing structured to add, which is most of them."
|
|
2084
2089
|
})
|
|
2085
2090
|
}).nullable().meta({
|
|
2086
|
-
description: "Why the job failed: a human `message`, a `code` where one exists, and `details` for the codes that carry a documented payload. `
|
|
2091
|
+
description: "Why the job failed, or why the cloud does not know how it stands: a human `message`, a `code` where one exists, and `details` for the codes that carry a documented payload. Set on `failed` and `lost`, and on `unknown` \u2014 where `code` is `bridge_disconnected` or `bridge_timeout`, the cloud's own reason for not knowing, cleared when the bridge reports the job running again."
|
|
2087
2092
|
})
|
|
2088
2093
|
});
|
|
2089
2094
|
var jobEvent = z7.object({
|
|
@@ -2142,16 +2147,16 @@ var jobRun = z7.object({
|
|
|
2142
2147
|
description: "Whether the slug was an `action` or a `service`."
|
|
2143
2148
|
}),
|
|
2144
2149
|
state: jobState.meta({
|
|
2145
|
-
description: "How the run ended, or `running` while it is still going. `lost`
|
|
2150
|
+
description: "How the run ended, or `running` while it is still going. `unknown` while the robot has not accounted for it \u2014 offline or silent \u2014 and updated once the bridge says how it stands. `lost` is final: the bridge did not know the run and nothing else ran on its action, so the outcome is unknowable rather than unknown."
|
|
2146
2151
|
}),
|
|
2147
2152
|
started_at: z7.iso.datetime().meta({
|
|
2148
2153
|
description: "When the run started, as an ISO 8601 timestamp. Runs are listed and filtered by this instant."
|
|
2149
2154
|
}),
|
|
2150
2155
|
ended_at: z7.iso.datetime().nullable().meta({
|
|
2151
|
-
description: "When the run finished, as an ISO 8601 timestamp. `null` while it is still `running` \u2014 a run has an end only once it has one."
|
|
2156
|
+
description: "When the run finished, as an ISO 8601 timestamp. `null` while it is still `running` or `unknown` \u2014 a run has an end only once it has one."
|
|
2152
2157
|
}),
|
|
2153
2158
|
duration_ms: z7.number().int().nonnegative().nullable().meta({
|
|
2154
|
-
description: 'How long the run took, in milliseconds. `null` while it is still `running`, never `0` standing in for "nothing so far".'
|
|
2159
|
+
description: 'How long the run took, in milliseconds. `null` while it is still `running` or `unknown`, never `0` standing in for "nothing so far".'
|
|
2155
2160
|
}),
|
|
2156
2161
|
result: z7.unknown().nullable().meta({
|
|
2157
2162
|
description: "What the action or service returned once it succeeded, shaped by ROS itself. `null` otherwise."
|
|
@@ -2201,7 +2206,7 @@ var jobRunQuery = z7.object({
|
|
|
2201
2206
|
description: "Only runs of this action or service."
|
|
2202
2207
|
}),
|
|
2203
2208
|
state: jobState.optional().meta({
|
|
2204
|
-
description: "Only runs in this state \u2014 `running`, `succeeded`, `failed`, `cancelled` or `lost`."
|
|
2209
|
+
description: "Only runs in this state \u2014 `running`, `unknown`, `succeeded`, `failed`, `cancelled` or `lost`."
|
|
2205
2210
|
}),
|
|
2206
2211
|
kind: jobRunKind.optional().meta({
|
|
2207
2212
|
description: "Only `action` runs, or only `service` runs."
|
|
@@ -2235,14 +2240,14 @@ var jobRunSummary = z7.object({
|
|
|
2235
2240
|
since_ms: z7.number().int().nonnegative()
|
|
2236
2241
|
});
|
|
2237
2242
|
|
|
2238
|
-
// node_modules/.pnpm/@fleetless+contracts@
|
|
2243
|
+
// node_modules/.pnpm/@fleetless+contracts@5.0.0/node_modules/@fleetless/contracts/dist/protocol.js
|
|
2239
2244
|
var DAY_MS = 24 * 60 * 60 * 1e3;
|
|
2240
2245
|
var MAX_PATIENCE_MS = 12e4;
|
|
2241
2246
|
var MIN_PATIENCE_MS = 1e3;
|
|
2242
2247
|
var activeJob = z8.object({
|
|
2243
2248
|
job_id: z8.uuid(),
|
|
2244
2249
|
slug,
|
|
2245
|
-
state:
|
|
2250
|
+
state: reportedJobState
|
|
2246
2251
|
});
|
|
2247
2252
|
var bridgeHello = z8.object({
|
|
2248
2253
|
type: z8.literal("hello"),
|
|
@@ -2253,16 +2258,14 @@ var bridgeHello = z8.object({
|
|
|
2253
2258
|
* Every job this bridge still knows about, right now.
|
|
2254
2259
|
*
|
|
2255
2260
|
* A reconnect and a restart look **identical** on the wire — same token,
|
|
2256
|
-
* same version, same frame —
|
|
2257
|
-
*
|
|
2258
|
-
*
|
|
2259
|
-
*
|
|
2260
|
-
*
|
|
2261
|
-
*
|
|
2262
|
-
*
|
|
2263
|
-
*
|
|
2264
|
-
* the cloud needs. A breadcrumb file would only add a window in which the
|
|
2265
|
-
* crash beat the write.
|
|
2261
|
+
* same version, same frame — so the bridge enumerates what it still has:
|
|
2262
|
+
* its live jobs, and after a restart every job whose goal it recognised
|
|
2263
|
+
* again from its persisted job-to-goal mapping. A job the cloud holds
|
|
2264
|
+
* `running` or `unknown` that is *not* named here is "not known to the
|
|
2265
|
+
* bridge"; it becomes `lost` (`job_unknown_to_bridge`) only once the
|
|
2266
|
+
* bridge's goal reports show its action free of goals it cannot
|
|
2267
|
+
* attribute — one of those may be that very job — and at once for a
|
|
2268
|
+
* service job, which has no goals to look at.
|
|
2266
2269
|
*
|
|
2267
2270
|
* Defaulted, so a bridge that sends no such field still parses; no jobs
|
|
2268
2271
|
* and no report both mean the same thing to the cloud: nothing to keep
|
|
@@ -2368,9 +2371,27 @@ var cloudInvoke = z8.object({
|
|
|
2368
2371
|
});
|
|
2369
2372
|
var cloudCancel = z8.object({
|
|
2370
2373
|
type: z8.literal("cancel"),
|
|
2374
|
+
request_id: z8.string().min(1).max(64),
|
|
2371
2375
|
slug,
|
|
2372
2376
|
job_id: z8.uuid().nullable()
|
|
2373
2377
|
});
|
|
2378
|
+
var cancelReturnCode = z8.number().int().min(0).max(3);
|
|
2379
|
+
var bridgeCancelResultEntry = z8.object({
|
|
2380
|
+
/** The job the goal belongs to — the bridge's own, or an external goal's derived id. */
|
|
2381
|
+
job_id: z8.uuid(),
|
|
2382
|
+
/** The ROS 2 goal id the cancel was sent for. */
|
|
2383
|
+
goal_id: z8.string().min(1),
|
|
2384
|
+
/** `null` when the action server did not answer the cancel request within the bridge's own bound. */
|
|
2385
|
+
return_code: cancelReturnCode.nullable()
|
|
2386
|
+
});
|
|
2387
|
+
var bridgeCancelResult = z8.object({
|
|
2388
|
+
type: z8.literal("cancel_result"),
|
|
2389
|
+
request_id: z8.string().min(1).max(64),
|
|
2390
|
+
slug,
|
|
2391
|
+
goals: z8.array(bridgeCancelResultEntry),
|
|
2392
|
+
/** Set when the bridge could not send the cancel at all (no such slug, a service, the server gone). */
|
|
2393
|
+
error: z8.object({ code: z8.string().min(1), message: z8.string().min(1) }).nullable()
|
|
2394
|
+
});
|
|
2374
2395
|
var cloudPublish = z8.object({
|
|
2375
2396
|
type: z8.literal("publish"),
|
|
2376
2397
|
slug,
|
|
@@ -2390,7 +2411,11 @@ var bridgeJobUpdate = z8.object({
|
|
|
2390
2411
|
type: z8.literal("job_update"),
|
|
2391
2412
|
job_id: z8.uuid(),
|
|
2392
2413
|
slug,
|
|
2393
|
-
|
|
2414
|
+
/** Never `unknown`: that is the cloud's word for not having heard. */
|
|
2415
|
+
state: reportedJobState,
|
|
2416
|
+
origin: jobOrigin,
|
|
2417
|
+
/** The ROS 2 goal id; `null` for a service job, which has no goal. */
|
|
2418
|
+
goal_id: z8.string().min(1).nullable(),
|
|
2394
2419
|
feedback: z8.unknown().nullable(),
|
|
2395
2420
|
progress: z8.number().min(0).max(1).nullable(),
|
|
2396
2421
|
result: z8.unknown().nullable(),
|
|
@@ -2400,7 +2425,29 @@ var bridgeJobUpdate = z8.object({
|
|
|
2400
2425
|
});
|
|
2401
2426
|
var bridgeJobLost = z8.object({
|
|
2402
2427
|
type: z8.literal("job_lost"),
|
|
2403
|
-
job_ids: z8.array(z8.uuid())
|
|
2428
|
+
job_ids: z8.array(z8.uuid()),
|
|
2429
|
+
error: z8.object({ code: z8.string().min(1), message: z8.string().min(1) }).optional()
|
|
2430
|
+
});
|
|
2431
|
+
var cloudJobQuery = z8.object({
|
|
2432
|
+
type: z8.literal("job_query"),
|
|
2433
|
+
request_id: z8.string().min(1).max(64),
|
|
2434
|
+
job_ids: z8.array(z8.uuid()).min(1)
|
|
2435
|
+
});
|
|
2436
|
+
var bridgeJobStatusEntry = z8.object({
|
|
2437
|
+
job_id: z8.uuid(),
|
|
2438
|
+
/** Never `unknown` — the bridge only ever states a definite fact about a job it recognises. */
|
|
2439
|
+
state: reportedJobState,
|
|
2440
|
+
feedback: z8.unknown().nullable(),
|
|
2441
|
+
progress: z8.number().min(0).max(1).nullable(),
|
|
2442
|
+
result: z8.unknown().nullable(),
|
|
2443
|
+
/** Same shape as `job.error`, `details` included — see `jobs.ts`. */
|
|
2444
|
+
error: z8.object({ code: z8.string().min(1), message: z8.string().min(1), details: z8.unknown().optional() }).nullable()
|
|
2445
|
+
});
|
|
2446
|
+
var bridgeJobStatus = z8.object({
|
|
2447
|
+
type: z8.literal("job_status"),
|
|
2448
|
+
request_id: z8.string().min(1).max(64),
|
|
2449
|
+
jobs: z8.array(bridgeJobStatusEntry),
|
|
2450
|
+
unknown_job_ids: z8.array(z8.uuid())
|
|
2404
2451
|
});
|
|
2405
2452
|
var cloudIntrospectRequest = z8.object({
|
|
2406
2453
|
type: z8.literal("introspect_request"),
|
|
@@ -2589,11 +2636,11 @@ var bridgeCameraState = z8.object({
|
|
|
2589
2636
|
request_id: z8.string().min(1).max(64).nullable()
|
|
2590
2637
|
});
|
|
2591
2638
|
|
|
2592
|
-
// node_modules/.pnpm/@fleetless+contracts@
|
|
2639
|
+
// node_modules/.pnpm/@fleetless+contracts@5.0.0/node_modules/@fleetless/contracts/dist/config-issues.js
|
|
2593
2640
|
var EXPOSURE_SECTIONS = ["datapoints", "actions", "services", "publishers", "cameras"];
|
|
2594
2641
|
var EXPOSURE_SECTION_NAMES = new Set(EXPOSURE_SECTIONS);
|
|
2595
2642
|
|
|
2596
|
-
// node_modules/.pnpm/@fleetless+contracts@
|
|
2643
|
+
// node_modules/.pnpm/@fleetless+contracts@5.0.0/node_modules/@fleetless/contracts/dist/rest.js
|
|
2597
2644
|
import { z as z9 } from "zod";
|
|
2598
2645
|
var robot = z9.object({
|
|
2599
2646
|
id: z9.uuid().meta({
|
|
@@ -3358,13 +3405,13 @@ var slugUsageResponse = z9.object({
|
|
|
3358
3405
|
alert_count: z9.number().int().nonnegative()
|
|
3359
3406
|
});
|
|
3360
3407
|
|
|
3361
|
-
// node_modules/.pnpm/@fleetless+contracts@
|
|
3408
|
+
// node_modules/.pnpm/@fleetless+contracts@5.0.0/node_modules/@fleetless/contracts/dist/realtime.js
|
|
3362
3409
|
import { z as z14 } from "zod";
|
|
3363
3410
|
|
|
3364
|
-
// node_modules/.pnpm/@fleetless+contracts@
|
|
3411
|
+
// node_modules/.pnpm/@fleetless+contracts@5.0.0/node_modules/@fleetless/contracts/dist/client-auth.js
|
|
3365
3412
|
import { z as z13 } from "zod";
|
|
3366
3413
|
|
|
3367
|
-
// node_modules/.pnpm/@fleetless+contracts@
|
|
3414
|
+
// node_modules/.pnpm/@fleetless+contracts@5.0.0/node_modules/@fleetless/contracts/dist/apps.js
|
|
3368
3415
|
import { z as z10 } from "zod";
|
|
3369
3416
|
var appIdentifier = slug;
|
|
3370
3417
|
var app = z10.object({
|
|
@@ -3424,6 +3471,26 @@ var appListResponse = z10.object({
|
|
|
3424
3471
|
description: "Every app of the caller's organisation, oldest first by `created_at`. The org scope is the whole filter \u2014 there is no id to narrow by and nothing to refuse."
|
|
3425
3472
|
})
|
|
3426
3473
|
});
|
|
3474
|
+
var appDeletionSummary = z10.object({
|
|
3475
|
+
user_count: z10.number().int().nonnegative().meta({
|
|
3476
|
+
description: "App users deleted with the app. They are the developer's own customers, not Fleetless users, and exist in no other app."
|
|
3477
|
+
}),
|
|
3478
|
+
role_count: z10.number().int().nonnegative().meta({
|
|
3479
|
+
description: "Roles deleted with the app, each with its per-robot slug grants."
|
|
3480
|
+
}),
|
|
3481
|
+
server_key_count: z10.number().int().nonnegative().meta({
|
|
3482
|
+
description: "Server keys deleted with the app. A client still holding one is refused at its next request."
|
|
3483
|
+
}),
|
|
3484
|
+
invitation_count: z10.number().int().nonnegative().meta({
|
|
3485
|
+
description: "Outstanding invitations \u2014 unspent and unexpired \u2014 that will never be accepted."
|
|
3486
|
+
}),
|
|
3487
|
+
oidc_provider_count: z10.number().int().nonnegative().meta({
|
|
3488
|
+
description: "Identity providers configured for this app. The providers themselves are somebody else's; only this app's configuration of them goes."
|
|
3489
|
+
}),
|
|
3490
|
+
mail_template_count: z10.number().int().nonnegative().meta({
|
|
3491
|
+
description: "Custom mail templates, of at most three. A kind using the Fleetless default text is not counted \u2014 there is no row to lose."
|
|
3492
|
+
})
|
|
3493
|
+
});
|
|
3427
3494
|
var createAppRequest = z10.object({
|
|
3428
3495
|
name: z10.string().min(1).max(120),
|
|
3429
3496
|
identifier: appIdentifier,
|
|
@@ -3546,10 +3613,10 @@ var rolePermissions = z10.object({
|
|
|
3546
3613
|
})
|
|
3547
3614
|
});
|
|
3548
3615
|
|
|
3549
|
-
// node_modules/.pnpm/@fleetless+contracts@
|
|
3616
|
+
// node_modules/.pnpm/@fleetless+contracts@5.0.0/node_modules/@fleetless/contracts/dist/app-users.js
|
|
3550
3617
|
import { z as z12 } from "zod";
|
|
3551
3618
|
|
|
3552
|
-
// node_modules/.pnpm/@fleetless+contracts@
|
|
3619
|
+
// node_modules/.pnpm/@fleetless+contracts@5.0.0/node_modules/@fleetless/contracts/dist/identity.js
|
|
3553
3620
|
import { z as z11 } from "zod";
|
|
3554
3621
|
var password = z11.string().min(12).max(256);
|
|
3555
3622
|
var USER_DISPLAY_NAME_MAX = 120;
|
|
@@ -3711,7 +3778,7 @@ var authMeResponse = z11.object({ org, user: fleetlessUser });
|
|
|
3711
3778
|
var patchOrgRequest = z11.object({ name: z11.string().min(1).max(120) }).strict();
|
|
3712
3779
|
var patchAuthMeRequest = z11.object({ display_name: z11.string().min(1).max(USER_DISPLAY_NAME_MAX).nullable() }).strict();
|
|
3713
3780
|
|
|
3714
|
-
// node_modules/.pnpm/@fleetless+contracts@
|
|
3781
|
+
// node_modules/.pnpm/@fleetless+contracts@5.0.0/node_modules/@fleetless/contracts/dist/app-users.js
|
|
3715
3782
|
var APP_USER_DISPLAY_NAME_MAX = 120;
|
|
3716
3783
|
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");
|
|
3717
3784
|
var appUserStatus = z12.enum(["pending_verification", "active", "blocked"]);
|
|
@@ -3930,7 +3997,9 @@ var appAuthConfig = z12.object({
|
|
|
3930
3997
|
}),
|
|
3931
3998
|
updated_at: z12.iso.datetime().meta({ description: "When the configuration was last written, as an ISO 8601 timestamp." })
|
|
3932
3999
|
});
|
|
3933
|
-
var
|
|
4000
|
+
var putAppAuthRegistrationRequest = appAuthConfig.pick({ self_registration: true, allowed_domains: true, allowed_origins: true }).strict();
|
|
4001
|
+
var putAppAuthUrlsRequest = appAuthConfig.pick({ invite_url: true, verify_url: true, reset_url: true }).strict();
|
|
4002
|
+
var putAppAuthMcpRequest = appAuthConfig.pick({ mcp_enabled: true, mcp_login_url: true }).strict();
|
|
3934
4003
|
var mailTemplateKind = z12.enum(["invite", "verify", "reset"]);
|
|
3935
4004
|
var appMailTemplate = z12.object({
|
|
3936
4005
|
kind: mailTemplateKind.meta({ description: "Which of the three mails this template replaces." }),
|
|
@@ -3962,7 +4031,7 @@ var mailOutcome = z12.object({
|
|
|
3962
4031
|
})
|
|
3963
4032
|
});
|
|
3964
4033
|
|
|
3965
|
-
// node_modules/.pnpm/@fleetless+contracts@
|
|
4034
|
+
// node_modules/.pnpm/@fleetless+contracts@5.0.0/node_modules/@fleetless/contracts/dist/client-auth.js
|
|
3966
4035
|
var clientLoginRequest = z13.object({
|
|
3967
4036
|
app_identifier: appIdentifier.meta({
|
|
3968
4037
|
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."
|
|
@@ -4151,7 +4220,7 @@ var clientIdentity = z13.object({
|
|
|
4151
4220
|
})
|
|
4152
4221
|
});
|
|
4153
4222
|
|
|
4154
|
-
// node_modules/.pnpm/@fleetless+contracts@
|
|
4223
|
+
// node_modules/.pnpm/@fleetless+contracts@5.0.0/node_modules/@fleetless/contracts/dist/realtime.js
|
|
4155
4224
|
var clientAuth = z14.object({
|
|
4156
4225
|
type: z14.literal("auth"),
|
|
4157
4226
|
token: z14.string().min(1)
|
|
@@ -4429,7 +4498,7 @@ var orgEventDropped = z14.object({
|
|
|
4429
4498
|
dropped: z14.number().int().positive()
|
|
4430
4499
|
}).strict();
|
|
4431
4500
|
|
|
4432
|
-
// node_modules/.pnpm/@fleetless+contracts@
|
|
4501
|
+
// node_modules/.pnpm/@fleetless+contracts@5.0.0/node_modules/@fleetless/contracts/dist/client-robots.js
|
|
4433
4502
|
import { z as z15 } from "zod";
|
|
4434
4503
|
var clientRobotListItem = z15.object({
|
|
4435
4504
|
...robot.shape,
|
|
@@ -4446,7 +4515,7 @@ var clientRobotListResponse = z15.object({
|
|
|
4446
4515
|
})
|
|
4447
4516
|
});
|
|
4448
4517
|
|
|
4449
|
-
// node_modules/.pnpm/@fleetless+contracts@
|
|
4518
|
+
// node_modules/.pnpm/@fleetless+contracts@5.0.0/node_modules/@fleetless/contracts/dist/audit.js
|
|
4450
4519
|
import { z as z16 } from "zod";
|
|
4451
4520
|
var auditActor = z16.object({
|
|
4452
4521
|
kind: z16.enum(["developer", "end_user", "app_user", "server_key", "bridge"]),
|
|
@@ -4576,7 +4645,7 @@ var auditListResponse = z16.object({
|
|
|
4576
4645
|
next_cursor: z16.number().int().positive().nullable()
|
|
4577
4646
|
});
|
|
4578
4647
|
|
|
4579
|
-
// node_modules/.pnpm/@fleetless+contracts@
|
|
4648
|
+
// node_modules/.pnpm/@fleetless+contracts@5.0.0/node_modules/@fleetless/contracts/dist/errors.js
|
|
4580
4649
|
import { z as z17 } from "zod";
|
|
4581
4650
|
var apiError = z17.object({
|
|
4582
4651
|
code: z17.string().min(1),
|
|
@@ -4593,7 +4662,7 @@ var parameterInvalidDetails = z17.object({
|
|
|
4593
4662
|
violations: z17.array(parameterViolation).min(1)
|
|
4594
4663
|
});
|
|
4595
4664
|
|
|
4596
|
-
// node_modules/.pnpm/@fleetless+contracts@
|
|
4665
|
+
// node_modules/.pnpm/@fleetless+contracts@5.0.0/node_modules/@fleetless/contracts/dist/oauth.js
|
|
4597
4666
|
import { z as z18 } from "zod";
|
|
4598
4667
|
var oauthErrorCode = z18.enum([
|
|
4599
4668
|
"invalid_request",
|
|
@@ -4833,7 +4902,7 @@ var oauthAuthorizeQuery = z18.object({
|
|
|
4833
4902
|
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."
|
|
4834
4903
|
});
|
|
4835
4904
|
|
|
4836
|
-
// node_modules/.pnpm/@fleetless+contracts@
|
|
4905
|
+
// node_modules/.pnpm/@fleetless+contracts@5.0.0/node_modules/@fleetless/contracts/dist/routes.js
|
|
4837
4906
|
var MCP_APP = MCP_APP_PATHS(":appIdentifier");
|
|
4838
4907
|
var APP_IDENTIFIER = {
|
|
4839
4908
|
name: "appIdentifier",
|
|
@@ -5203,6 +5272,42 @@ var ROUTES = [
|
|
|
5203
5272
|
transport: "http",
|
|
5204
5273
|
notes: "A `default_role_id` naming a role of another app is refused: it is the one cross-app authorization check this shape can carry. Changing the robot set closes every live subscription the app's users hold, since a grant may no longer name a reachable robot."
|
|
5205
5274
|
},
|
|
5275
|
+
{
|
|
5276
|
+
method: "GET",
|
|
5277
|
+
path: "/api/apps/:id/deletion-preview",
|
|
5278
|
+
section: "apps",
|
|
5279
|
+
summary: "Reports what deleting the app would destroy, without destroying it.",
|
|
5280
|
+
audience: "developer",
|
|
5281
|
+
auth: "developer",
|
|
5282
|
+
rateLimited: false,
|
|
5283
|
+
ownerTier: false,
|
|
5284
|
+
status: 200,
|
|
5285
|
+
params: [{ name: "id", description: "The app's uuid, as returned by `POST /api/apps` or listed by `GET /api/apps`." }],
|
|
5286
|
+
query: null,
|
|
5287
|
+
request: null,
|
|
5288
|
+
response: appDeletionSummary,
|
|
5289
|
+
errors: [...DEVELOPER_GUARD, "invalid_uuid", "not_found"],
|
|
5290
|
+
transport: "http",
|
|
5291
|
+
notes: "The same shape the delete's own audit event carries, computed by the same function on purpose: the confirmation dialog and the eventual receipt agree by construction, and any difference between them is real drift rather than two estimates that quietly disagree. \n\n**No `force` parameter, unlike the robot pair this is modelled on.** A robot's open live session is a single nameable state whose interruption is its own hazard, which is why that route makes the caller pass `force` explicitly. An app has no equivalent state to force past, and inventing one would be a guess wearing a guard's clothes \u2014 this preview is the guard."
|
|
5292
|
+
},
|
|
5293
|
+
{
|
|
5294
|
+
method: "DELETE",
|
|
5295
|
+
path: "/api/apps/:id",
|
|
5296
|
+
section: "apps",
|
|
5297
|
+
summary: "Deletes an app and everything it produced.",
|
|
5298
|
+
audience: "developer",
|
|
5299
|
+
auth: "developer",
|
|
5300
|
+
rateLimited: false,
|
|
5301
|
+
ownerTier: true,
|
|
5302
|
+
status: 204,
|
|
5303
|
+
params: [{ name: "id", description: "The app's uuid, as returned by `POST /api/apps` or listed by `GET /api/apps`." }],
|
|
5304
|
+
query: null,
|
|
5305
|
+
request: null,
|
|
5306
|
+
response: null,
|
|
5307
|
+
errors: [...DEVELOPER_GUARD, "tier_required", "invalid_uuid", "not_found"],
|
|
5308
|
+
transport: "http",
|
|
5309
|
+
notes: "Owner tier, and the gate runs **after** the org-scoped lookup: a developer-tier admin therefore sees the same `404` a stranger would for an app outside their org, rather than a tier refusal that confirms the id exists. A full cascade \u2014 its users, roles, server keys, invitations, OIDC provider configuration and mail templates all go, recorded once as `app.deleted` carrying an `appDeletionSummary`. Its robots are untouched: they belong to the org, not to the app. \n\n**No `force` parameter** \u2014 see `GET /api/apps/:id/deletion-preview`."
|
|
5310
|
+
},
|
|
5206
5311
|
{
|
|
5207
5312
|
method: "POST",
|
|
5208
5313
|
path: "/api/apps/:id/roles",
|
|
@@ -5709,13 +5814,31 @@ var ROUTES = [
|
|
|
5709
5814
|
response: appAuthConfig,
|
|
5710
5815
|
errors: [...DEVELOPER_GUARD, "invalid_uuid", "not_found"],
|
|
5711
5816
|
transport: "http",
|
|
5712
|
-
notes: "One row per app, created with the app and never absent \u2014 an app that has configured nothing reads back the defaults rather than a `404`. `oidc_callback_url` is in the answer and not in the request: it is minted by the cloud from its own public base URL, is the same for every app and every provider, and is the value a developer registers at their identity provider."
|
|
5817
|
+
notes: "One row per app, created with the app and never absent \u2014 an app that has configured nothing reads back the defaults rather than a `404`. `oidc_callback_url` is in the answer and not in the request: it is minted by the cloud from its own public base URL, is the same for every app and every provider, and is the value a developer registers at their identity provider. It stays read-only on every slice write below for a second reason: a writable callback URL would let a caller point the return leg of an OIDC sign-in, which carries an authorization code, at a host they own. `updated_at` is read-only for a duller one: the server stamps it on every write, and a client-supplied value would be a lie about when the row last changed."
|
|
5713
5818
|
},
|
|
5714
5819
|
{
|
|
5715
5820
|
method: "PUT",
|
|
5716
|
-
path: "/api/apps/:id/auth-config",
|
|
5821
|
+
path: "/api/apps/:id/auth-config/registration",
|
|
5822
|
+
section: "apps",
|
|
5823
|
+
summary: "Replaces who may self-register, and from where.",
|
|
5824
|
+
audience: "developer",
|
|
5825
|
+
auth: "developer",
|
|
5826
|
+
rateLimited: false,
|
|
5827
|
+
ownerTier: false,
|
|
5828
|
+
status: 200,
|
|
5829
|
+
params: [{ name: "id", description: "The app's uuid, as returned by `POST /api/apps` or listed by `GET /api/apps`." }],
|
|
5830
|
+
query: null,
|
|
5831
|
+
request: putAppAuthRegistrationRequest,
|
|
5832
|
+
response: appAuthConfig,
|
|
5833
|
+
errors: [...DEVELOPER_GUARD, "invalid_uuid", "validation_error", "not_found"],
|
|
5834
|
+
transport: "http",
|
|
5835
|
+
notes: "**A replace, not a merge, and `.strict()`**: `self_registration`, `allowed_domains` and `allowed_origins` all arrive or the write is refused, so a client built against an older shape cannot silently clear a setting it does not know about. `oidc_callback_url` and `updated_at` are the server's, refused in this body as in every slice's \u2014 see `GET`'s notes for why. \n\n`400 validation_error` is where the two field rules land: an entry in `allowed_domains` must be lowercase, since a capitalised one can never match a lowercased address, and an entry in `allowed_origins` must be a bare scheme-host-port with no path, since a browser sends nothing longer in its `Origin` header. Each refuses at configuration time rather than failing silently later. \n\nThe merge is server-side against the stored row, so this write never disturbs the urls or mcp slice."
|
|
5836
|
+
},
|
|
5837
|
+
{
|
|
5838
|
+
method: "PUT",
|
|
5839
|
+
path: "/api/apps/:id/auth-config/urls",
|
|
5717
5840
|
section: "apps",
|
|
5718
|
-
summary: "Replaces the
|
|
5841
|
+
summary: "Replaces the three pages Fleetless's mails point at.",
|
|
5719
5842
|
audience: "developer",
|
|
5720
5843
|
auth: "developer",
|
|
5721
5844
|
rateLimited: false,
|
|
@@ -5723,11 +5846,29 @@ var ROUTES = [
|
|
|
5723
5846
|
status: 200,
|
|
5724
5847
|
params: [{ name: "id", description: "The app's uuid, as returned by `POST /api/apps` or listed by `GET /api/apps`." }],
|
|
5725
5848
|
query: null,
|
|
5726
|
-
request:
|
|
5849
|
+
request: putAppAuthUrlsRequest,
|
|
5727
5850
|
response: appAuthConfig,
|
|
5728
5851
|
errors: [...DEVELOPER_GUARD, "invalid_uuid", "validation_error", "not_found"],
|
|
5729
5852
|
transport: "http",
|
|
5730
|
-
notes: "**A replace, not a merge, and `.strict()`**:
|
|
5853
|
+
notes: "**A replace, not a merge, and `.strict()`**: `invite_url`, `verify_url` and `reset_url` all arrive or the write is refused, so a client built against an older shape cannot silently clear a setting it does not know about. `oidc_callback_url` and `updated_at` are the server's, refused in this body as in every slice's \u2014 see `GET`'s notes for why. \n\n`400 validation_error` is where the field rule lands: a URL template must be https (or `http` on `localhost`) and carry its placeholder exactly once \u2014 a second occurrence leaves one literal in a mailed link, refused here rather than failing silently once the mail is sent. \n\nThe merge is server-side against the stored row, so this write never disturbs the registration or mcp slice."
|
|
5854
|
+
},
|
|
5855
|
+
{
|
|
5856
|
+
method: "PUT",
|
|
5857
|
+
path: "/api/apps/:id/auth-config/mcp",
|
|
5858
|
+
section: "apps",
|
|
5859
|
+
summary: "Replaces the MCP switch and its login URL together.",
|
|
5860
|
+
audience: "developer",
|
|
5861
|
+
auth: "developer",
|
|
5862
|
+
rateLimited: false,
|
|
5863
|
+
ownerTier: false,
|
|
5864
|
+
status: 200,
|
|
5865
|
+
params: [{ name: "id", description: "The app's uuid, as returned by `POST /api/apps` or listed by `GET /api/apps`." }],
|
|
5866
|
+
query: null,
|
|
5867
|
+
request: putAppAuthMcpRequest,
|
|
5868
|
+
response: appAuthConfig,
|
|
5869
|
+
errors: [...DEVELOPER_GUARD, "invalid_uuid", "validation_error", "not_found"],
|
|
5870
|
+
transport: "http",
|
|
5871
|
+
notes: "**A replace, not a merge, and `.strict()`**: `mcp_enabled` and `mcp_login_url` both arrive or the write is refused, so a client built against an older shape cannot silently clear a setting it does not know about. `oidc_callback_url` and `updated_at` are the server's, refused in this body as in every slice's \u2014 see `GET`'s notes for why. \n\n`mcp_login_url` answers to the same rule as the `urls` slice's three templates \u2014 https (or `http` on `localhost`), its placeholder exactly once \u2014 refused as `400 validation_error` rather than left to fail mid-OAuth, in a client's browser where no console screen is watching. \n\nThe merge is server-side against the stored row, so this write never disturbs the registration or urls slice."
|
|
5731
5872
|
},
|
|
5732
5873
|
{
|
|
5733
5874
|
method: "GET",
|
|
@@ -7520,7 +7661,7 @@ var ROUTES = [
|
|
|
7520
7661
|
"internal_error"
|
|
7521
7662
|
],
|
|
7522
7663
|
transport: "http",
|
|
7523
|
-
notes: "**One route for both kinds**, because a path segment naming the kind would demand a fact a role grant does not carry. An action answers `202` with an `invokeResponse` the moment the job exists; a service answers `200` with a `serviceCallResponse` once the result is in \u2014 two shapes, carried by one union (`invokeOrServiceResponse`) and told apart by whether `kind` or a bare `result` arrives. Parameters are checked **before** anything about the world (offline, busy): the same request must get the same verdict whether or not the robot happens to be reachable, or a developer testing against an offline robot never learns their parameters were wrong. A service the robot reports as failed answers `502` carrying **the job's own error code**, which is an open set and not one of the codes above."
|
|
7664
|
+
notes: "**One route for both kinds**, because a path segment naming the kind would demand a fact a role grant does not carry. An action answers `202` with an `invokeResponse` the moment the job exists; a service answers `200` with a `serviceCallResponse` once the result is in \u2014 two shapes, carried by one union (`invokeOrServiceResponse`) and told apart by whether `kind` or a bare `result` arrives. Parameters are checked **before** anything about the world (offline, busy): the same request must get the same verdict whether or not the robot happens to be reachable, or a developer testing against an offline robot never learns their parameters were wrong. A slug is `409 busy` while it holds a `running` job, an `unknown` one the robot has not accounted for yet, or an `external` goal someone else started; the refusal's `details.running` names that job, `state` and `origin` included. A service the robot reports as failed answers `502` carrying **the job's own error code**, which is an open set and not one of the codes above."
|
|
7524
7665
|
},
|
|
7525
7666
|
{
|
|
7526
7667
|
method: "GET",
|
|
@@ -7561,9 +7702,21 @@ var ROUTES = [
|
|
|
7561
7702
|
request: cancelRequest,
|
|
7562
7703
|
requestOptional: true,
|
|
7563
7704
|
response: jobResponse,
|
|
7564
|
-
errors: [
|
|
7705
|
+
errors: [
|
|
7706
|
+
...CLIENT_GUARD,
|
|
7707
|
+
"invalid_uuid",
|
|
7708
|
+
"not_found",
|
|
7709
|
+
"validation_error",
|
|
7710
|
+
"not_cancellable",
|
|
7711
|
+
"robot_offline",
|
|
7712
|
+
"cancel_rejected",
|
|
7713
|
+
"bridge_timeout",
|
|
7714
|
+
"unknown_slug",
|
|
7715
|
+
"action_server_lost",
|
|
7716
|
+
"internal_error"
|
|
7717
|
+
],
|
|
7565
7718
|
transport: "http",
|
|
7566
|
-
notes:
|
|
7719
|
+
notes: "The body is optional: a bodyless `POST` was every caller's shape before `job_id` existed, and absent or `job_id: null` both mean \"cancel whatever is running\". A named `job_id` that is **not** what is running cancels nothing and answers `404` \u2014 the caller named an id and thereby ruled the other one out. An `external` job is cancelled the same way, through its goal id. Cancelling an `unknown` job also cancels every external goal on its action, since one of them may be that job. A service is `422 not_cancellable`: a service call has no goal to cancel. Nothing running is a `200` with `job: null`. The answer waits for the bridge's `cancel_result`: a `200` means the action server accepted the cancel request, not that the goal has ended \u2014 the job's end arrives as its own update. Any goal answered `ERROR_REJECTED` makes it `409 cancel_rejected`, with every goal and its `return_code` in `details.goals`; no answer within `JOB_HEARTBEAT_TIMEOUT_MS` is `504 bridge_timeout`; a cancel the bridge could not send at all is `502` carrying the bridge's own code (`unknown_slug`, `action_server_lost`, `internal_error`)."
|
|
7567
7720
|
},
|
|
7568
7721
|
{
|
|
7569
7722
|
method: "POST",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fleetless/sdk",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.1.0",
|
|
4
4
|
"description": "The official TypeScript SDK for Fleetless client apps — a ROS 2 robot as a REST and realtime API, cameras, jobs, and the app's own user accounts, federated sign-in and MCP consent.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": {
|
|
@@ -76,7 +76,7 @@
|
|
|
76
76
|
"zod": "^4.0.0"
|
|
77
77
|
},
|
|
78
78
|
"devDependencies": {
|
|
79
|
-
"@fleetless/contracts": "
|
|
79
|
+
"@fleetless/contracts": "5.0.0",
|
|
80
80
|
"@types/node": "^22.20.1",
|
|
81
81
|
"tsup": "^8.3.0",
|
|
82
82
|
"typedoc": "0.28.20",
|