@camstack/addon-provider-rtsp 0.1.25 → 0.1.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/addon.mjs CHANGED
@@ -8693,10 +8693,30 @@ const StatusSchema = object({
8693
8693
  }
8694
8694
  });
8695
8695
  const LinkStateSchema = _enum(["unlinked", "linked", "error"]);
8696
+ const ExportSetupFieldSchema = object({
8697
+ label: string(),
8698
+ value: string(),
8699
+ /** Mask the value by default + render a reveal toggle (client id, secrets). */
8700
+ secret: boolean().optional()
8701
+ });
8702
+ const ExportSetupSchema = object({
8703
+ /** A string to render as a scannable QR — HAP `X-HM://…` URI, a pairing URL, etc. Omitted when there's nothing to scan. */
8704
+ qr: string().optional(),
8705
+ /** Label/value rows shown with a copy button (HAP setup code, OAuth URLs, client id, linked-account count, …). */
8706
+ fields: array(ExportSetupFieldSchema).readonly().optional(),
8707
+ /** Free-form operator instructions rendered above the fields. */
8708
+ note: string().optional()
8709
+ });
8696
8710
  const DeviceExportStatusSchema = object({
8697
8711
  linkState: LinkStateSchema,
8698
8712
  exposedDeviceCount: number(),
8699
- error: string().optional()
8713
+ error: string().optional(),
8714
+ /**
8715
+ * Optional pairing/account info the panel renders in a generic
8716
+ * "Setup" section. Addon-agnostic — the addon id identifies the
8717
+ * export target, never an `ecosystem` key here.
8718
+ */
8719
+ setup: ExportSetupSchema.optional()
8700
8720
  });
8701
8721
  const DeviceKindSchema = string();
8702
8722
  const ExposedDeviceSchema = object({
@@ -10366,51 +10386,6 @@ const AuthResultSchema = object({
10366
10386
  validateToken: method(object({ token: string() }), AuthResultSchema.nullable())
10367
10387
  }
10368
10388
  });
10369
- const AuthProviderInfoSchema = object({
10370
- /** Stable id matching the addon id (used for `getLoginUrl({addonId,…})`). */
10371
- addonId: string(),
10372
- /**
10373
- * Per-instance id when one addon registers multiple "logical"
10374
- * providers (e.g. OIDC with Google + Microsoft + custom). The login
10375
- * URL becomes `/addon/${addonId}/${instanceId}/start` — handler reads
10376
- * `:instanceId` from the route. Empty/unset means the addon is a
10377
- * single-instance provider; the URL is `/addon/${addonId}/start`.
10378
- */
10379
- instanceId: string().optional(),
10380
- /** Display label shown on the login button + admin row. */
10381
- displayName: string(),
10382
- /** Optional iconography hint (lucide-react icon name OR emoji). */
10383
- icon: string().optional(),
10384
- /** When true, the provider exposes a redirect-based login flow
10385
- * (`getLoginUrl` returns a URL the browser navigates to). */
10386
- hasRedirectFlow: boolean(),
10387
- /** When true, the provider exposes a credential-form login flow
10388
- * (`validateCredentials` accepts username + password). */
10389
- hasCredentialFlow: boolean(),
10390
- /** Provider kind, drives admin-UI hint dispatch (oidc / saml / totp / …). */
10391
- kind: string().optional(),
10392
- /** Operator-facing status string (e.g. "Connected to https://login.acme.com"). */
10393
- status: string().optional(),
10394
- /** When false, the provider is registered but disabled by config; the
10395
- * UI surfaces it as inactive without enumerating it for login. */
10396
- enabled: boolean()
10397
- });
10398
- ({
10399
- methods: {
10400
- /** All registered auth providers, both enabled and disabled. */
10401
- listProviders: method(_void(), array(AuthProviderInfoSchema).readonly()),
10402
- /**
10403
- * Toggle a provider's enabled flag. Disabled providers stay
10404
- * registered but aren't surfaced on the login page. The orchestrator
10405
- * persists the state in `addon-settings` so it survives restarts.
10406
- */
10407
- setProviderEnabled: method(
10408
- object({ addonId: string(), enabled: boolean() }),
10409
- object({ success: literal(true) }),
10410
- { kind: "mutation", auth: "admin" }
10411
- )
10412
- }
10413
- });
10414
10389
  const NetworkEndpointSchema = object({
10415
10390
  url: string(),
10416
10391
  hostname: string(),
@@ -10442,55 +10417,13 @@ const NetworkEndpointEntrySchema = NetworkEndpointSchema.extend({
10442
10417
  getEndpoint: method(_void(), NetworkEndpointSchema.nullable()),
10443
10418
  getStatus: method(_void(), NetworkAccessStatusSchema),
10444
10419
  /**
10445
- * Enumerate every active ingress entry. Default implementation (when
10446
- * the provider omits this method) is derived from `getEndpoint()` —
10447
- * see the remote-access orchestrator for the fallback path.
10420
+ * Enumerate every active ingress entry. Providers that expose only a
10421
+ * single endpoint may omit this method; callers fall back to
10422
+ * `getEndpoint()` in that case.
10448
10423
  */
10449
10424
  listEndpoints: method(_void(), array(NetworkEndpointEntrySchema).readonly())
10450
10425
  }
10451
10426
  });
10452
- const RemoteAccessEndpointSchema = object({
10453
- url: string(),
10454
- hostname: string(),
10455
- port: number(),
10456
- protocol: _enum(["http", "https"])
10457
- });
10458
- const RemoteAccessProviderInfoSchema = object({
10459
- /** Stable id matching the addon id. */
10460
- addonId: string(),
10461
- /** Display label shown on the admin row — sourced from the addon manifest. */
10462
- displayName: string(),
10463
- /** When false, the provider is registered but disabled. */
10464
- enabled: boolean(),
10465
- /** True when the underlying tunnel/connection is up. */
10466
- connected: boolean(),
10467
- /** Public-facing endpoint, when connected. Null otherwise. */
10468
- endpoint: RemoteAccessEndpointSchema.nullable(),
10469
- /** Last error message (when connected=false), if available. */
10470
- error: string().optional()
10471
- });
10472
- ({
10473
- methods: {
10474
- /** All registered remote-access providers + their live status. */
10475
- listProviders: method(_void(), array(RemoteAccessProviderInfoSchema).readonly()),
10476
- /**
10477
- * Start a specific provider's tunnel. Per-provider config still
10478
- * lives on the addon's settings panel; this is just the on/off
10479
- * trigger so the admin UI can manage the lifecycle from one place.
10480
- */
10481
- startProvider: method(
10482
- object({ addonId: string() }),
10483
- RemoteAccessEndpointSchema,
10484
- { kind: "mutation", auth: "admin" }
10485
- ),
10486
- /** Stop a specific provider's tunnel (idempotent on already-stopped). */
10487
- stopProvider: method(
10488
- object({ addonId: string() }),
10489
- object({ success: literal(true) }),
10490
- { kind: "mutation", auth: "admin" }
10491
- )
10492
- }
10493
- });
10494
10427
  const TurnServerSchema = object({
10495
10428
  /** Single URL or list of URLs (e.g. "turn:turn.example.com:3478?transport=udp"). */
10496
10429
  urls: union([string(), array(string())]),
@@ -10510,45 +10443,6 @@ const TurnServerSchema = object({
10510
10443
  )
10511
10444
  }
10512
10445
  });
10513
- const TurnProviderInfoSchema = object({
10514
- /** Stable id matching the addon id. */
10515
- addonId: string(),
10516
- /** Display label shown on the admin row — sourced from the addon manifest. */
10517
- displayName: string(),
10518
- /** When false, the provider is registered but disabled. */
10519
- enabled: boolean(),
10520
- /** Number of servers this provider is currently exposing. */
10521
- serverCount: number(),
10522
- /**
10523
- * Flat list of every TURN/STUN URL this provider currently exposes.
10524
- * One row per URL (multi-URL ICE server entries are flattened). The
10525
- * admin UI shows this in a compact per-provider list so operators
10526
- * can verify what's actually being negotiated without having to dig
10527
- * into the combined `getAllServers` output.
10528
- */
10529
- urls: array(string()).readonly(),
10530
- /** Last fetch error (when serverCount=0 due to API failure), if any. */
10531
- error: string().optional()
10532
- });
10533
- ({
10534
- methods: {
10535
- /** All registered TURN providers + per-provider stats. */
10536
- listProviders: method(_void(), array(TurnProviderInfoSchema).readonly()),
10537
- /**
10538
- * Combined list of TURN/STUN servers from all ENABLED providers.
10539
- * Consumed by the WebRTC layer at session-creation time —
10540
- * implementations may fetch fresh short-lived credentials each
10541
- * call (e.g. Cloudflare API), so consumers SHOULD call per-session.
10542
- */
10543
- getAllServers: method(_void(), array(TurnServerSchema).readonly()),
10544
- /** Toggle a provider's enabled flag. */
10545
- setProviderEnabled: method(
10546
- object({ addonId: string(), enabled: boolean() }),
10547
- object({ success: literal(true) }),
10548
- { kind: "mutation", auth: "admin" }
10549
- )
10550
- }
10551
- });
10552
10446
  const SnapshotImageSchema = object({
10553
10447
  base64: string(),
10554
10448
  contentType: string()
@@ -12028,7 +11922,7 @@ const AllowedAddressesSchema = object({
12028
11922
  )
12029
11923
  }
12030
11924
  });
12031
- const MeshEndpointSchema$1 = object({
11925
+ const MeshEndpointSchema = object({
12032
11926
  /** Stable identifier within the provider (e.g. `mesh-ipv4`, `magicdns`, `funnel`). */
12033
11927
  id: string(),
12034
11928
  /** Operator-facing label (e.g. "Mesh IPv4", "MagicDNS"). */
@@ -12101,7 +11995,7 @@ const MeshStatusSchema = object({
12101
11995
  /** Number of peers visible to this host (excluding self). */
12102
11996
  peerCount: number(),
12103
11997
  /** Every endpoint this provider exposes for the current host. */
12104
- endpoints: array(MeshEndpointSchema$1).readonly(),
11998
+ endpoints: array(MeshEndpointSchema).readonly(),
12105
11999
  /** Last error from the daemon, when not joined. */
12106
12000
  error: string().optional(),
12107
12001
  // ── Account / tenant identity (generic across providers) ────────
@@ -12134,7 +12028,25 @@ const MeshStatusSchema = object({
12134
12028
  * doesn't rotate keys for the bound host. Operator-facing surface
12135
12029
  * for "your access expires on …" banners.
12136
12030
  */
12137
- keyExpiry: number().nullable()
12031
+ keyExpiry: number().nullable(),
12032
+ // ── Onboard-daemon handoff (Tailscale, generic slot) ────────────
12033
+ /**
12034
+ * When the provider runs its OWN mesh daemon (e.g. the Tailscale
12035
+ * client addon in `onboard` mode spawns a private `tailscaled`),
12036
+ * this carries the local control-socket path. Companion addons that
12037
+ * must drive the SAME daemon — chiefly `tailscale-ingress` for
12038
+ * Serve/Funnel — read it to point their CLI at the right socket
12039
+ * instead of the system default. Empty when the provider uses the
12040
+ * host's system daemon (or doesn't have the concept).
12041
+ */
12042
+ daemonSocket: string().optional(),
12043
+ /**
12044
+ * Path to the mesh CLI binary the provider downloaded for onboard
12045
+ * mode. Companion addons reuse it so they don't need a system
12046
+ * install when the operator chose a fully self-contained mesh.
12047
+ * Empty in host mode.
12048
+ */
12049
+ daemonCliPath: string().optional()
12138
12050
  });
12139
12051
  ({
12140
12052
  methods: {
@@ -12246,105 +12158,6 @@ const MeshStatusSchema = object({
12246
12158
  // tabs driven by this cap.
12247
12159
  }
12248
12160
  });
12249
- const MeshEndpointSchema = object({
12250
- id: string(),
12251
- label: string(),
12252
- scope: _enum(["mesh", "public"]),
12253
- url: string(),
12254
- hostname: string(),
12255
- port: number(),
12256
- protocol: _enum(["http", "https"])
12257
- });
12258
- const MeshProviderInfoSchema = object({
12259
- /** Stable id matching the addon id. */
12260
- addonId: string(),
12261
- /** Display label shown on the admin row — sourced from the addon manifest. */
12262
- displayName: string(),
12263
- /** True when the host is joined to this provider's mesh. */
12264
- joined: boolean(),
12265
- /** Local mesh IP (empty when not joined). */
12266
- meshIp: string(),
12267
- /** MagicDNS / mesh hostname (empty when not configured). */
12268
- magicDnsHostname: string(),
12269
- /** Peer count (excluding self). */
12270
- peerCount: number(),
12271
- /** Active endpoints (mesh IP + MagicDNS + optional public Funnel). */
12272
- endpoints: array(MeshEndpointSchema).readonly(),
12273
- /** Last error reported by the provider. */
12274
- error: string().optional(),
12275
- // ── Generic identity fields mirrored from MeshStatus ─────────────
12276
- /** Tenant / tailnet / network display name. Empty pre-join. */
12277
- tenantName: string(),
12278
- /** Mesh DNS suffix (e.g. tailXXXX.ts.net). Empty when not configured. */
12279
- magicDnsSuffix: string(),
12280
- /** Authenticated user / account login. Null for token-only providers. */
12281
- userLogin: string().nullable(),
12282
- /** Provider control-plane URL. */
12283
- controlPlaneUrl: string(),
12284
- /** Machine-key expiry (epoch ms). Null when keys don't rotate. */
12285
- keyExpiry: number().nullable()
12286
- });
12287
- ({
12288
- methods: {
12289
- /** All registered mesh-network providers + live status. */
12290
- listProviders: method(_void(), array(MeshProviderInfoSchema).readonly()),
12291
- /**
12292
- * Join the mesh of a specific provider. Per-provider config still
12293
- * lives on its settings panel; the orchestrator forwards.
12294
- */
12295
- joinProvider: method(
12296
- object({
12297
- addonId: string(),
12298
- authKey: string().min(8),
12299
- hostname: string().optional()
12300
- }),
12301
- object({ joined: literal(true) }),
12302
- { kind: "mutation" }
12303
- ),
12304
- leaveProvider: method(
12305
- object({ addonId: string() }),
12306
- object({ success: literal(true) }),
12307
- { kind: "mutation" }
12308
- ),
12309
- /**
12310
- * Browser-redirect login flow. Forwards to the named provider's
12311
- * `mesh-network.startLogin` and returns the URL the daemon
12312
- * prints. UI opens it in a new tab, then polls `listProviders`
12313
- * for `joined: true`.
12314
- */
12315
- startLoginProvider: method(
12316
- object({
12317
- addonId: string(),
12318
- hostname: string().optional()
12319
- }),
12320
- object({ loginUrl: string() }),
12321
- { kind: "mutation" }
12322
- ),
12323
- /**
12324
- * Sign out of the provider's account entirely (`mesh-network.logout`).
12325
- * Distinct from `leaveProvider` which only takes the host off-mesh;
12326
- * `logoutProvider` wipes credentials so the next start requires a
12327
- * fresh login.
12328
- */
12329
- logoutProvider: method(
12330
- object({ addonId: string() }),
12331
- object({ loggedOut: literal(true) }),
12332
- { kind: "mutation" }
12333
- ),
12334
- /**
12335
- * Per-provider peer list. Forwards to `mesh-network.listPeers` on
12336
- * the addressed provider. Separate from `listProviders` because
12337
- * peer payloads can be large on a heavily-populated tailnet —
12338
- * fetch only when the operator opens the Peers tab.
12339
- */
12340
- listProviderPeers: method(
12341
- object({ addonId: string() }),
12342
- object({
12343
- peers: array(MeshPeerSchema).readonly()
12344
- })
12345
- )
12346
- }
12347
- });
12348
12161
  const MethodAccessSchema = _enum(["view", "create", "delete"]);
12349
12162
  const AllowedProviderSchema = union([literal("*"), array(string())]);
12350
12163
  const AllowedDevicesSchema = record(string(), union([literal("*"), array(string())]));
@@ -13020,6 +12833,21 @@ const AddonAutoUpdateSchema = ChannelWithInheritSchema;
13020
12833
  const RestartAddonResultSchema = unknown();
13021
12834
  const InstallPackageResultSchema = unknown();
13022
12835
  const ReloadPackagesResultSchema = unknown();
12836
+ const UpdateFrameworkPackageResultSchema = object({
12837
+ packageName: string(),
12838
+ fromVersion: string(),
12839
+ toVersion: string(),
12840
+ /** Ms-epoch the server scheduled its self-restart. */
12841
+ restartingAt: number()
12842
+ });
12843
+ const FrameworkPackageStatusSchema = object({
12844
+ packageName: string(),
12845
+ currentVersion: string(),
12846
+ latestVersion: string().nullable(),
12847
+ hasUpdate: boolean(),
12848
+ /** Optional manifest description for the row tooltip. */
12849
+ description: string().optional()
12850
+ });
13023
12851
  const LogStreamEntrySchema = object({
13024
12852
  timestamp: string(),
13025
12853
  level: string(),
@@ -13079,13 +12907,29 @@ const CustomActionInputSchema = object({
13079
12907
  object({ query: string().optional() }),
13080
12908
  array(SearchResultSchema)
13081
12909
  ),
12910
+ /**
12911
+ * Available package updates for a node. `nodeId` omitted (or
12912
+ * `'hub'`) checks the hub's own installed packages; an agent
12913
+ * `nodeId` checks that agent's installed roster against npm
12914
+ * (the hub does the npm lookups + diff — agents stay npm-free).
12915
+ */
13082
12916
  listUpdates: method(
13083
- _void(),
12917
+ object({ nodeId: string().optional() }),
13084
12918
  array(PackageUpdateSchema).readonly(),
13085
12919
  { auth: "admin" }
13086
12920
  ),
12921
+ /**
12922
+ * Update one package on a node. `nodeId` omitted (or `'hub'`)
12923
+ * installs on the hub via npm; an agent `nodeId` makes the hub
12924
+ * pack the resolved version and push the tarball to that agent
12925
+ * (`$agent.deploy` + `$agent.reload`) — agents need no npm runtime.
12926
+ */
13087
12927
  updatePackage: method(
13088
- object({ name: string().min(1), version: string().optional() }),
12928
+ object({
12929
+ name: string().min(1),
12930
+ version: string().optional(),
12931
+ nodeId: string().optional()
12932
+ }),
13089
12933
  unknown(),
13090
12934
  { kind: "mutation", auth: "admin" }
13091
12935
  ),
@@ -13106,12 +12950,128 @@ const CustomActionInputSchema = object({
13106
12950
  object({ rolledBackTo: string().nullable() }),
13107
12951
  { kind: "mutation", auth: "admin" }
13108
12952
  ),
13109
- forceRefresh: method(_void(), unknown(), { kind: "mutation", auth: "admin" }),
12953
+ /** Re-check updates for a node, bypassing any cache. `nodeId`
12954
+ * omitted (or `'hub'`) refreshes the hub; an agent `nodeId`
12955
+ * re-checks that agent's roster. */
12956
+ forceRefresh: method(
12957
+ object({ nodeId: string().optional() }),
12958
+ unknown(),
12959
+ { kind: "mutation", auth: "admin" }
12960
+ ),
13110
12961
  restartServer: method(
13111
12962
  object({ confirm: literal(true) }),
13112
12963
  unknown(),
13113
12964
  { kind: "mutation", auth: "admin" }
13114
12965
  ),
12966
+ /**
12967
+ * Most-recent restart marker (kind / packageName / from→to versions
12968
+ * / requestedBy / requestedAt). Returns `null` when this process
12969
+ * didn't boot from a tracked restart, or when the
12970
+ * post-boot retention window (5 min) has elapsed.
12971
+ *
12972
+ * Drives the admin-UI reconnect overlay's success toast — the
12973
+ * `system.restart-completed` event itself is fired before the
12974
+ * client has time to re-subscribe, so the client queries this on
12975
+ * first reconnect instead.
12976
+ */
12977
+ getLastRestart: method(
12978
+ _void(),
12979
+ object({
12980
+ kind: _enum(["framework-update", "manual", "system"]),
12981
+ packageName: string().optional(),
12982
+ fromVersion: string().optional(),
12983
+ toVersion: string().optional(),
12984
+ requestedBy: string().optional(),
12985
+ requestedAt: number()
12986
+ }).nullable(),
12987
+ { auth: "admin" }
12988
+ ),
12989
+ /**
12990
+ * Snapshot of the framework packages installed under the hub's
12991
+ * `<appRoot>/node_modules/`. Each row carries the currently
12992
+ * installed version and (best-effort) the latest version
12993
+ * available on npm. Drives the admin-UI "System packages" panel.
12994
+ *
12995
+ * Spec: docs/superpowers/specs/2026-05-14-framework-live-update-design.md
12996
+ */
12997
+ listFrameworkPackages: method(
12998
+ _void(),
12999
+ array(FrameworkPackageStatusSchema).readonly(),
13000
+ { auth: "admin" }
13001
+ ),
13002
+ /**
13003
+ * Cluster-wide capability-provider discovery. Returns the list of
13004
+ * `{ addonId, mode, isActive }` tuples for whatever addon(s)
13005
+ * currently provide the requested capability across the cluster.
13006
+ *
13007
+ * Why this lives on `addons` (and not on a `capabilities` cap of
13008
+ * its own): the hub's main-process `CapabilityRegistry` already
13009
+ * aggregates registrations from every forked group-runner and
13010
+ * remote agent via Moleculer event propagation — there's no
13011
+ * cross-process registry mirror to build, just an introspection
13012
+ * shim.
13013
+ *
13014
+ * Use this from addon code when you need to know whether another
13015
+ * addon has registered a specific cap (e.g. `tailscale-ingress`
13016
+ * checking `tailscale-client` is up before calling `tailscale
13017
+ * serve`). Don't reach for `ctx.capabilities.getCollectionEntries`
13018
+ * — that reads the LOCAL registry of the calling addon's group
13019
+ * runner and never sees providers in other processes. See
13020
+ * `CLAUDE.md` → Critical rules → ctx.api vs ctx.capabilities.
13021
+ */
13022
+ listCapabilityProviders: method(
13023
+ object({ capName: string().min(1) }),
13024
+ array(object({
13025
+ addonId: string(),
13026
+ mode: _enum(["singleton", "collection"]),
13027
+ isActive: boolean()
13028
+ })).readonly()
13029
+ ),
13030
+ /**
13031
+ * Toggle a single collection-cap provider on/off. Generic write-side
13032
+ * counterpart of `listCapabilityProviders` — drives the per-provider
13033
+ * Enable/Disable affordance in admin pages (TURN servers, etc.)
13034
+ * without needing a bespoke orchestrator cap.
13035
+ *
13036
+ * Reaches the hub's `CapabilityRegistry` directly:
13037
+ * `enableCollectionProvider` / `disableCollectionProvider` flip the
13038
+ * registry-level `disabledProviders` set. `getCollectionEntries`
13039
+ * already filters disabled providers out, so a disabled provider
13040
+ * drops out of every collection aggregate immediately. Only valid
13041
+ * for `mode: 'collection'` caps — the registry no-ops + warns for
13042
+ * singletons.
13043
+ */
13044
+ setCapabilityProviderEnabled: method(
13045
+ object({
13046
+ capName: string().min(1),
13047
+ addonId: string().min(1),
13048
+ enabled: boolean()
13049
+ }),
13050
+ object({ success: literal(true) }),
13051
+ { kind: "mutation", auth: "admin" }
13052
+ ),
13053
+ /**
13054
+ * Live-update one of the framework packages marked
13055
+ * `camstack.system: true` (`@camstack/types|kernel|core|sdk|ui-library`).
13056
+ * Runs `npm install --prefix <appRoot> <name>@<version> --no-save`,
13057
+ * writes a `.restart-pending` marker, emits `system.restarting`
13058
+ * and schedules a graceful process exit. The supervisor (Docker /
13059
+ * Electron / systemd) brings the hub back up; on first boot after
13060
+ * the restart the marker fires `system.restart-completed`.
13061
+ *
13062
+ * `version` defaults to `'latest'`. The allow-list of valid
13063
+ * `packageName` values is enforced server-side.
13064
+ *
13065
+ * Spec: docs/superpowers/specs/2026-05-14-framework-live-update-design.md
13066
+ */
13067
+ updateFrameworkPackage: method(
13068
+ object({
13069
+ packageName: string().min(1),
13070
+ version: string().optional()
13071
+ }),
13072
+ UpdateFrameworkPackageResultSchema,
13073
+ { kind: "mutation", auth: "admin" }
13074
+ ),
13115
13075
  getVersions: method(
13116
13076
  object({ name: string() }),
13117
13077
  array(PackageVersionInfoSchema).readonly()
@@ -13182,6 +13142,7 @@ var EventCategory = /* @__PURE__ */ ((EventCategory2) => {
13182
13142
  EventCategory2["SystemBoot"] = "system.boot";
13183
13143
  EventCategory2["SystemAddonsReady"] = "system.addons-ready";
13184
13144
  EventCategory2["SystemRestarting"] = "system.restarting";
13145
+ EventCategory2["SystemRestartCompleted"] = "system.restart-completed";
13185
13146
  EventCategory2["SystemReadyState"] = "system.ready-state";
13186
13147
  EventCategory2["AddonStarted"] = "addon.started";
13187
13148
  EventCategory2["AddonStopped"] = "addon.stopped";