@camstack/addon-osd-manager 0.1.2 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (27) hide show
  1. package/dist/MaskShapeCanvas-BEVxAjNq.mjs +13806 -0
  2. package/dist/MotionZonesSettings-DteO0vrm.mjs +309 -0
  3. package/dist/PrivacyMaskSettings-VeD7Fy0-.mjs +290 -0
  4. package/dist/_stub.js +16641 -0
  5. package/dist/_virtual_mf-localSharedImportMap___mfe_internal__addon_osd_manager_page-CL-YG2or.mjs +156 -0
  6. package/dist/_virtual_mf___mfe_internal__addon_osd_manager_page__loadShare___mf_0_camstack_mf_1_sdk__loadShare__.js-plrwWXXt.mjs +25 -0
  7. package/dist/_virtual_mf___mfe_internal__addon_osd_manager_page__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-D722amjy.mjs +26 -0
  8. package/dist/_virtual_mf___mfe_internal__addon_osd_manager_page__loadShare___mf_0_tanstack_mf_1_react_mf_2_query__loadShare__.js-DmzTg7Gl.mjs +25 -0
  9. package/dist/_virtual_mf___mfe_internal__addon_osd_manager_page__loadShare___mf_0_trpc_mf_1_client__loadShare__.js-C7omKvJr.mjs +25 -0
  10. package/dist/_virtual_mf___mfe_internal__addon_osd_manager_page__loadShare___mf_0_trpc_mf_1_react_mf_2_query__loadShare__.js-BpP33rwB.mjs +26 -0
  11. package/dist/_virtual_mf___mfe_internal__addon_osd_manager_page__loadShare__react__loadShare__.js-Bs1t18EM.mjs +70 -0
  12. package/dist/_virtual_mf___mfe_internal__addon_osd_manager_page__loadShare__react_mf_1_jsx_mf_2_runtime__loadShare__.js-DalfdIDw.mjs +26 -0
  13. package/dist/_virtual_mf___mfe_internal__addon_osd_manager_page__loadShare__react_mf_2_dom__loadShare__.js-C0K4h_0e.mjs +25 -0
  14. package/dist/_virtual_mf___mfe_internal__addon_osd_manager_page__loadShare__react_mf_2_dom_mf_1_client__loadShare__.js-Dhy3m6Ij.mjs +25 -0
  15. package/dist/addon-osd-manager.css +3 -0
  16. package/dist/hostInit-BCB8KzuM.mjs +129 -0
  17. package/dist/index.js +271 -2
  18. package/dist/index.mjs +271 -2
  19. package/dist/player-overlays-CwbydND6.mjs +163 -0
  20. package/dist/remoteEntry.js +2 -0
  21. package/dist/remoteEntry.ssr.js +33 -0
  22. package/dist/rolldown-runtime-HEgqtunE.mjs +20 -0
  23. package/dist/trash-2-Ckik0Rau.mjs +49 -0
  24. package/dist/virtualExposes-BgZ5Cn7S.mjs +27 -0
  25. package/dist/virtual_mf-REMOTE_ENTRY_ID___mfe_internal__addon_osd_manager_page__remoteEntry_js-CdG2yVd0.mjs +2857 -0
  26. package/dist/virtual_mf-exposes-ssr___mfe_internal__addon_osd_manager_page__remoteEntry_js-Bgw9YZ5T.mjs +10 -0
  27. package/package.json +35 -4
package/dist/index.js CHANGED
@@ -21791,6 +21791,22 @@ var TerminalProfileInfoSchema = object({
21791
21791
  label: string(),
21792
21792
  description: string().optional()
21793
21793
  });
21794
+ var TerminalOutputEventSchema = discriminatedUnion("kind", [object({
21795
+ seq: number().int().positive(),
21796
+ kind: literal("data"),
21797
+ data: string()
21798
+ }), object({
21799
+ seq: number().int().positive(),
21800
+ kind: literal("exit"),
21801
+ exitCode: number().int(),
21802
+ signal: number().int().optional()
21803
+ })]);
21804
+ var TerminalOutputBatchSchema = object({
21805
+ cursor: number().int().nonnegative(),
21806
+ reset: boolean(),
21807
+ snapshot: string().optional(),
21808
+ events: array(TerminalOutputEventSchema).readonly()
21809
+ });
21794
21810
  /**
21795
21811
  * terminal-session — singleton system capability for interactive TTY sessions.
21796
21812
  *
@@ -21829,6 +21845,28 @@ var terminalSessionCapability = {
21829
21845
  kind: "mutation",
21830
21846
  auth: "admin"
21831
21847
  }),
21848
+ /**
21849
+ * Pull ordered output after a cursor. This capability transport is what
21850
+ * makes remote-agent terminals possible; `reset + snapshot` repairs a
21851
+ * caller that fell behind the bounded replay window.
21852
+ */
21853
+ pullOutput: method(object({
21854
+ sessionId: string(),
21855
+ afterSeq: number().int().nonnegative(),
21856
+ waitMs: number().int().min(0).max(2e3).default(0)
21857
+ }), TerminalOutputBatchSchema, {
21858
+ kind: "mutation",
21859
+ auth: "admin",
21860
+ timeoutMs: 15e3
21861
+ }),
21862
+ /** Write terminal input through the node-routable capability plane. */
21863
+ writeInput: method(object({
21864
+ sessionId: string(),
21865
+ data: string().max(64 * 1024)
21866
+ }), _void(), {
21867
+ kind: "mutation",
21868
+ auth: "admin"
21869
+ }),
21832
21870
  /** Terminate a live session and release its pty. */
21833
21871
  close: method(object({ sessionId: string() }), _void(), {
21834
21872
  kind: "mutation",
@@ -24764,6 +24802,7 @@ var FaceInfoSchema = object({
24764
24802
  var FaceFilterEnum = _enum([
24765
24803
  "unassigned",
24766
24804
  "recognized",
24805
+ "identified",
24767
24806
  "all"
24768
24807
  ]);
24769
24808
  var MediaFileLiteSchema$1 = object({
@@ -24803,6 +24842,8 @@ var faceGalleryCapability = {
24803
24842
  auth: "admin"
24804
24843
  }),
24805
24844
  listRecentFaces: method(object({
24845
+ /** Restrict to one camera. Absent keeps the cluster-wide gallery view. */
24846
+ deviceId: number().int().optional(),
24806
24847
  limit: number().int().positive().optional(),
24807
24848
  filter: FaceFilterEnum.optional(),
24808
24849
  /**
@@ -27346,6 +27387,10 @@ var OsdSourceSchema = discriminatedUnion("kind", [
27346
27387
  capName: string().min(1).max(64),
27347
27388
  /** Dot path inside the slice, e.g. `detected`, `value`, `mode`. */
27348
27389
  valuePath: string().min(1).max(64)
27390
+ }),
27391
+ object({
27392
+ kind: literal("latest-recognition"),
27393
+ recognition: _enum(["person", "plate"])
27349
27394
  })
27350
27395
  ]);
27351
27396
  var OsdSlotBindingSchema = object({
@@ -27484,6 +27529,21 @@ var osdManagerCapability = {
27484
27529
  auth: "admin"
27485
27530
  }),
27486
27531
  /**
27532
+ * Replace one camera's binding configuration from another. Writable source
27533
+ * slots are mapped by ordinal onto writable target slots so different
27534
+ * provider slot ids do not make the copied configuration disappear.
27535
+ */
27536
+ copyDeviceConfiguration: method(object({
27537
+ sourceDeviceId: number().int(),
27538
+ targetDeviceId: number().int()
27539
+ }), object({
27540
+ copied: number().int().nonnegative(),
27541
+ skipped: number().int().nonnegative()
27542
+ }), {
27543
+ kind: "mutation",
27544
+ auth: "admin"
27545
+ }),
27546
+ /**
27487
27547
  * Render without writing. `binding` overrides the stored one so an
27488
27548
  * editor can preview an unsaved change. Mutation kind only to carry
27489
27549
  * the binding object safely; no side effects.
@@ -33668,6 +33728,12 @@ Object.freeze({
33668
33728
  addonId: null,
33669
33729
  access: "delete"
33670
33730
  },
33731
+ "osdManager.copyDeviceConfiguration": {
33732
+ capName: "osd-manager",
33733
+ capScope: "system",
33734
+ addonId: null,
33735
+ access: "create"
33736
+ },
33671
33737
  "osdManager.getConditionSupport": {
33672
33738
  capName: "osd-manager",
33673
33739
  capScope: "system",
@@ -35708,12 +35774,24 @@ Object.freeze({
35708
35774
  addonId: null,
35709
35775
  access: "create"
35710
35776
  },
35777
+ "terminalSession.pullOutput": {
35778
+ capName: "terminal-session",
35779
+ capScope: "system",
35780
+ addonId: null,
35781
+ access: "create"
35782
+ },
35711
35783
  "terminalSession.resize": {
35712
35784
  capName: "terminal-session",
35713
35785
  capScope: "system",
35714
35786
  addonId: null,
35715
35787
  access: "create"
35716
35788
  },
35789
+ "terminalSession.writeInput": {
35790
+ capName: "terminal-session",
35791
+ capScope: "system",
35792
+ addonId: null,
35793
+ access: "create"
35794
+ },
35717
35795
  "toast.onToast": {
35718
35796
  capName: "toast",
35719
35797
  capScope: "system",
@@ -36539,7 +36617,8 @@ var OsdBindingsStore = class {
36539
36617
  * Widening it means giving `evaluateGate` the facts to answer it — a
36540
36618
  * live detection subject would unlock `classes`, `zones`, `minConfidence`.
36541
36619
  */
36542
- var OSD_SUPPORTED_CONDITIONS = ["devices", "deviceState"];
36620
+ var OSD_SUPPORTED_CONDITIONS = ["deviceState"];
36621
+ var OSD_RUNTIME_CONDITIONS = ["devices", ...OSD_SUPPORTED_CONDITIONS];
36543
36622
  var OPEN = { open: true };
36544
36623
  /**
36545
36624
  * Which condition keys are set on `conditions` but outside the supported
@@ -36547,7 +36626,7 @@ var OPEN = { open: true };
36547
36626
  */
36548
36627
  function unsupportedConditionKeys(conditions) {
36549
36628
  if (conditions === void 0) return [];
36550
- const supported = new Set(OSD_SUPPORTED_CONDITIONS);
36629
+ const supported = new Set(OSD_RUNTIME_CONDITIONS);
36551
36630
  const present = [];
36552
36631
  for (const [key, value] of Object.entries(conditions)) {
36553
36632
  if (value === void 0) continue;
@@ -36790,6 +36869,10 @@ function resolveSource(binding, cameraDeviceId, facts) {
36790
36869
  const source = binding.source;
36791
36870
  if (source.kind === "static") return { value: { raw: source.text } };
36792
36871
  if (source.kind === "clock") return { value: { raw: formatClock(facts.atMs, source.pattern, source.timezone) } };
36872
+ if (source.kind === "latest-recognition") {
36873
+ const value = facts.recognitionByDevice.get(cameraDeviceId)?.[source.recognition];
36874
+ return value === void 0 ? { reason: `no recognized ${source.recognition} has been persisted for device ${cameraDeviceId}` } : { value: { raw: value } };
36875
+ }
36793
36876
  const deviceId = source.deviceId ?? cameraDeviceId;
36794
36877
  const deviceState = facts.stateByDevice.get(deviceId);
36795
36878
  if (deviceState === void 0) return { reason: `no state mirrored for device ${deviceId}` };
@@ -36913,6 +36996,10 @@ var OsdManager = class {
36913
36996
  lastWritten = /* @__PURE__ */ new Map();
36914
36997
  /** Cameras with at least one binding — the loop's work list. */
36915
36998
  boundDevices = /* @__PURE__ */ new Set();
36999
+ recognitions = /* @__PURE__ */ new Map();
37000
+ recognitionHydration = /* @__PURE__ */ new Map();
37001
+ recognitionGeneration = /* @__PURE__ */ new Map();
37002
+ recognitionInvalidatedAt = /* @__PURE__ */ new Map();
36916
37003
  timer = null;
36917
37004
  constructor(deps) {
36918
37005
  this.deps = deps;
@@ -36940,6 +37027,36 @@ var OsdManager = class {
36940
37027
  this.lastWritten.clear();
36941
37028
  }
36942
37029
  /**
37030
+ * Keep recognition overlays event-fresh. The persisted-track hydration below
37031
+ * remains the restart/cold-start authority; lifecycle events only advance it.
37032
+ */
37033
+ onTrackLifecycle(payload) {
37034
+ let changed = false;
37035
+ if (payload.label !== void 0 && (payload.bestClassName === "person" || payload.classes.includes("person"))) changed = this.mergeRecognition(payload.deviceId, "person", payload.label, payload.lastSeen, payload.firstSeen) || changed;
37036
+ if (payload.plateText !== void 0) changed = this.mergeRecognition(payload.deviceId, "plate", payload.plateText, payload.lastSeen, payload.firstSeen) || changed;
37037
+ if (!changed || !this.boundDevices.has(payload.deviceId)) return;
37038
+ this.renderDeviceInternal(payload.deviceId, null).catch((err) => {
37039
+ this.logger.warn("osd-manager: recognition-triggered render failed", {
37040
+ tags: { deviceId: payload.deviceId },
37041
+ meta: { error: String(err) }
37042
+ });
37043
+ });
37044
+ }
37045
+ /** Gallery rows are authoritative for corrections, assignments and deletion. */
37046
+ onRecognitionGalleryChanged(deviceId) {
37047
+ this.recognitionGeneration.set(deviceId, (this.recognitionGeneration.get(deviceId) ?? 0) + 1);
37048
+ this.recognitionInvalidatedAt.set(deviceId, this.now());
37049
+ this.recognitions.delete(deviceId);
37050
+ this.recognitionHydration.delete(deviceId);
37051
+ if (!this.boundDevices.has(deviceId)) return;
37052
+ this.renderDeviceInternal(deviceId, null).catch((err) => {
37053
+ this.logger.warn("osd-manager: gallery-triggered render failed", {
37054
+ tags: { deviceId },
37055
+ meta: { error: String(err) }
37056
+ });
37057
+ });
37058
+ }
37059
+ /**
36943
37060
  * Reconcile the work list against the store rather than trusting an event
36944
37061
  * to have arrived (D8). Cheap: one settings read per camera, on the tick
36945
37062
  * cadence, not per frame.
@@ -37033,6 +37150,54 @@ var OsdManager = class {
37033
37150
  });
37034
37151
  return { success: true };
37035
37152
  };
37153
+ copyDeviceConfiguration = async ({ sourceDeviceId, targetDeviceId }) => {
37154
+ if (sourceDeviceId === targetDeviceId) throw new Error("osd-manager: source and target camera must be different");
37155
+ const [sourceStatus, targetStatus, sourceBindings] = await Promise.all([
37156
+ this.deps.readOsdStatus(sourceDeviceId),
37157
+ this.deps.readOsdStatus(targetDeviceId),
37158
+ this.readBindings(sourceDeviceId)
37159
+ ]);
37160
+ if (sourceStatus === null) throw new Error(`osd-manager: source device ${sourceDeviceId} exposes no overlay slots`);
37161
+ if (targetStatus === null) throw new Error(`osd-manager: target device ${targetDeviceId} exposes no overlay slots`);
37162
+ const sourceSlots = sourceStatus.overlays.filter((slot) => slot.readOnly !== true && sourceBindings[slot.id] !== void 0);
37163
+ if (sourceSlots.length === 0) throw new Error(`osd-manager: source device ${sourceDeviceId} has no configured writable slots`);
37164
+ const targetSlots = targetStatus.overlays.filter((slot) => slot.readOnly !== true);
37165
+ const copiedBindings = {};
37166
+ const copyCount = Math.min(sourceSlots.length, targetSlots.length);
37167
+ for (let index = 0; index < copyCount; index += 1) {
37168
+ const sourceSlot = sourceSlots[index];
37169
+ const targetSlot = targetSlots[index];
37170
+ if (sourceSlot === void 0 || targetSlot === void 0) continue;
37171
+ const binding = sourceBindings[sourceSlot.id];
37172
+ if (binding === void 0) continue;
37173
+ const conditions = binding.conditions;
37174
+ const normalizedConditions = conditions === void 0 ? void 0 : (() => {
37175
+ const { devices: _cameraScope, ...rest } = conditions;
37176
+ return Object.keys(rest).length === 0 ? void 0 : rest;
37177
+ })();
37178
+ copiedBindings[targetSlot.id] = {
37179
+ ...binding,
37180
+ conditions: normalizedConditions
37181
+ };
37182
+ }
37183
+ await this.deps.bindings(targetDeviceId).set(copiedBindings);
37184
+ for (const key of [...this.lastWritten.keys()]) if (key.startsWith(`${targetDeviceId}:`)) this.lastWritten.delete(key);
37185
+ if (Object.keys(copiedBindings).length > 0) this.boundDevices.add(targetDeviceId);
37186
+ else this.boundDevices.delete(targetDeviceId);
37187
+ await this.renderDeviceInternal(targetDeviceId, null);
37188
+ this.logger.info("osd-manager: camera configuration copied", {
37189
+ tags: { deviceId: targetDeviceId },
37190
+ meta: {
37191
+ sourceDeviceId,
37192
+ copied: Object.keys(copiedBindings).length,
37193
+ skipped: Math.max(0, sourceSlots.length - targetSlots.length)
37194
+ }
37195
+ });
37196
+ return {
37197
+ copied: Object.keys(copiedBindings).length,
37198
+ skipped: Math.max(0, sourceSlots.length - targetSlots.length)
37199
+ };
37200
+ };
37036
37201
  previewSlot = async ({ deviceId, slotId, binding }) => {
37037
37202
  if (binding !== void 0) assertSupportedConditions(binding.conditions);
37038
37203
  const effective = binding ?? (await this.readBindings(deviceId))[slotId] ?? null;
@@ -37107,6 +37272,7 @@ var OsdManager = class {
37107
37272
  */
37108
37273
  async collectFacts(cameraDeviceId, bindings) {
37109
37274
  const wanted = new Set([cameraDeviceId]);
37275
+ const needsRecognition = Object.values(bindings).some((binding) => binding.source.kind === "latest-recognition");
37110
37276
  for (const binding of Object.values(bindings)) {
37111
37277
  if (binding.source.kind === "device-state" && binding.source.deviceId !== void 0) wanted.add(binding.source.deviceId);
37112
37278
  const gated = binding.conditions?.deviceState?.deviceId;
@@ -37125,12 +37291,59 @@ var OsdManager = class {
37125
37291
  meta: { error: String(err) }
37126
37292
  });
37127
37293
  }
37294
+ if (needsRecognition) await this.hydrateRecognitions(cameraDeviceId);
37295
+ const recognitionByDevice = /* @__PURE__ */ new Map();
37296
+ const known = this.recognitions.get(cameraDeviceId);
37297
+ if (known !== void 0) recognitionByDevice.set(cameraDeviceId, {
37298
+ ...known.person !== void 0 ? { person: known.person.text } : {},
37299
+ ...known.plate !== void 0 ? { plate: known.plate.text } : {}
37300
+ });
37128
37301
  return {
37129
37302
  atMs: this.now(),
37130
37303
  stateByDevice,
37304
+ recognitionByDevice,
37131
37305
  deviceState: (id) => gateState.get(id)
37132
37306
  };
37133
37307
  }
37308
+ async hydrateRecognitions(deviceId) {
37309
+ const existing = this.recognitionHydration.get(deviceId);
37310
+ if (existing !== void 0) return existing;
37311
+ const generation = this.recognitionGeneration.get(deviceId) ?? 0;
37312
+ const hydration = (async () => {
37313
+ try {
37314
+ const latest = await this.deps.readLatestRecognitions(deviceId);
37315
+ if ((this.recognitionGeneration.get(deviceId) ?? 0) !== generation) return;
37316
+ if (latest.person !== void 0) this.mergeRecognition(deviceId, "person", latest.person.text, latest.person.atMs);
37317
+ if (latest.plate !== void 0) this.mergeRecognition(deviceId, "plate", latest.plate.text, latest.plate.atMs);
37318
+ } catch (err) {
37319
+ this.logger.warn("osd-manager: recognition history hydration failed", {
37320
+ tags: { deviceId },
37321
+ meta: { error: String(err) }
37322
+ });
37323
+ this.recognitionHydration.delete(deviceId);
37324
+ }
37325
+ })();
37326
+ this.recognitionHydration.set(deviceId, hydration);
37327
+ await hydration;
37328
+ }
37329
+ mergeRecognition(deviceId, kind, text, atMs, trackFirstSeen) {
37330
+ const normalized = text.trim();
37331
+ if (normalized === "") return false;
37332
+ const invalidatedAt = this.recognitionInvalidatedAt.get(deviceId);
37333
+ if (trackFirstSeen !== void 0 && invalidatedAt !== void 0 && trackFirstSeen <= invalidatedAt) return false;
37334
+ const current = this.recognitions.get(deviceId) ?? {};
37335
+ const previous = current[kind];
37336
+ if (previous !== void 0 && previous.atMs > atMs) return false;
37337
+ if (previous?.atMs === atMs && previous.text === normalized) return false;
37338
+ this.recognitions.set(deviceId, {
37339
+ ...current,
37340
+ [kind]: {
37341
+ text: normalized,
37342
+ atMs
37343
+ }
37344
+ });
37345
+ return true;
37346
+ }
37134
37347
  async readBindings(deviceId) {
37135
37348
  try {
37136
37349
  return await this.deps.bindings(deviceId).get();
@@ -37175,7 +37388,24 @@ function cacheKey(deviceId, slotId) {
37175
37388
  */
37176
37389
  var DEFAULTS = { tickSeconds: DEFAULT_TICK_MS / 1e3 };
37177
37390
  var OsdManagerAddon = class extends BaseAddon {
37391
+ id = "osd-manager";
37178
37392
  manager = null;
37393
+ /**
37394
+ * Module-Federation page declaration surfaced via the `addon-pages-source`
37395
+ * collection cap. Mirrors the manifest `pages[]` entry — admin-ui's
37396
+ * `<AddonPageLoader>` loads `addon_osd_manager_page/page` from
37397
+ * `/api/addon-pages/osd-manager/remoteEntry.js`. Modeled directly on
37398
+ * `addon-benchmark` / `addon-model-studio` (docs/roadmap.md 4d).
37399
+ */
37400
+ pages = [{
37401
+ id: "osd-manager",
37402
+ label: "OSD Manager",
37403
+ icon: "monitor",
37404
+ path: "/addon/osd-manager",
37405
+ remoteName: "addon_osd_manager_page",
37406
+ bundle: "remoteEntry.js",
37407
+ section: "detection"
37408
+ }];
37179
37409
  constructor() {
37180
37410
  super({ ...DEFAULTS });
37181
37411
  }
@@ -37222,13 +37452,52 @@ var OsdManagerAddon = class extends BaseAddon {
37222
37452
  const bindings = await ctx.api.deviceManager.getBindings.query({ deviceId });
37223
37453
  return [...new Set(bindings.entries.map((e) => e.capName))];
37224
37454
  },
37455
+ readLatestRecognitions: async (deviceId) => {
37456
+ const [faces, plates] = await Promise.all([ctx.api.faceGallery.listRecentFaces.query({
37457
+ deviceId,
37458
+ limit: 1,
37459
+ filter: "identified",
37460
+ includeCrops: false
37461
+ }), ctx.api.plateGallery.listPlates.query({
37462
+ deviceId,
37463
+ limit: 1
37464
+ })]);
37465
+ const face = faces[0];
37466
+ const plate = plates[0];
37467
+ return {
37468
+ ...face?.identityName !== void 0 ? { person: {
37469
+ text: face.identityName,
37470
+ atMs: face.timestamp
37471
+ } } : {},
37472
+ ...plate !== void 0 ? { plate: {
37473
+ text: plate.text,
37474
+ atMs: plate.timestamp
37475
+ } } : {}
37476
+ };
37477
+ },
37225
37478
  bindings: (deviceId) => store.forDevice(deviceId)
37226
37479
  });
37227
37480
  this.manager = manager;
37481
+ this.subscribe({ category: EventCategory.PipelineAnalyticsTrackLifecycle }, (event) => {
37482
+ manager.onTrackLifecycle(event.data);
37483
+ });
37484
+ this.subscribe({ category: EventCategory.PipelineAnalyticsFaceGalleryChanged }, (event) => {
37485
+ manager.onRecognitionGalleryChanged(event.data.deviceId);
37486
+ });
37487
+ this.subscribe({ category: EventCategory.PipelineAnalyticsPlateGalleryChanged }, (event) => {
37488
+ manager.onRecognitionGalleryChanged(event.data.deviceId);
37489
+ });
37228
37490
  await manager.start(Math.max(1, this.config.tickSeconds) * 1e3);
37491
+ const pagesProvider = {
37492
+ id: this.id,
37493
+ listPages: () => this.pages
37494
+ };
37229
37495
  return [{
37230
37496
  capability: osdManagerCapability,
37231
37497
  provider: manager
37498
+ }, {
37499
+ capability: addonPagesSourceCapability,
37500
+ provider: pagesProvider
37232
37501
  }];
37233
37502
  }
37234
37503
  async onConfigChanged() {