@camstack/system 1.2.347 → 1.2.348

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 (80) hide show
  1. package/dist/addon-runner.js +2 -2
  2. package/dist/addon-runner.mjs +2 -2
  3. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js +1 -1
  4. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +1 -1
  5. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +1 -1
  6. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +1 -1
  7. package/dist/builtins/alerts/alerts.addon.js +1 -1
  8. package/dist/builtins/alerts/alerts.addon.mjs +1 -1
  9. package/dist/builtins/autotrack/index.js +1 -1
  10. package/dist/builtins/autotrack/index.mjs +1 -1
  11. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +1 -1
  12. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +1 -1
  13. package/dist/builtins/calendars/calendar-color.d.ts +5 -0
  14. package/dist/builtins/calendars/calendar-prefs-store.d.ts +13 -0
  15. package/dist/builtins/calendars/calendars.addon.d.ts +4 -1
  16. package/dist/builtins/calendars/calendars.addon.js +143 -23
  17. package/dist/builtins/calendars/calendars.addon.mjs +143 -23
  18. package/dist/builtins/camera-grid/index.js +1 -1
  19. package/dist/builtins/camera-grid/index.mjs +1 -1
  20. package/dist/builtins/composer/composer.addon.js +2 -2
  21. package/dist/builtins/composer/composer.addon.mjs +2 -2
  22. package/dist/builtins/console-logging/index.js +1 -1
  23. package/dist/builtins/console-logging/index.mjs +1 -1
  24. package/dist/builtins/core-blocks/block-package.d.ts +12 -1
  25. package/dist/builtins/core-blocks/block-settings-store.d.ts +25 -0
  26. package/dist/builtins/core-blocks/block-supervisor.d.ts +6 -1
  27. package/dist/builtins/core-blocks/compile-block.d.ts +33 -2
  28. package/dist/builtins/core-blocks/core-block-store.d.ts +5 -0
  29. package/dist/builtins/core-blocks/core-blocks.addon.d.ts +10 -1
  30. package/dist/builtins/core-blocks/core-blocks.addon.js +363 -20
  31. package/dist/builtins/core-blocks/core-blocks.addon.mjs +360 -21
  32. package/dist/builtins/core-blocks/extract-settings-schema.d.ts +6 -0
  33. package/dist/builtins/core-blocks/index.d.ts +3 -1
  34. package/dist/builtins/core-blocks/index.js +3 -0
  35. package/dist/builtins/core-blocks/index.mjs +2 -2
  36. package/dist/builtins/device-manager/device-manager.addon.js +2 -2
  37. package/dist/builtins/device-manager/device-manager.addon.mjs +2 -2
  38. package/dist/builtins/hub-forwarder/index.js +1 -1
  39. package/dist/builtins/hub-forwarder/index.mjs +1 -1
  40. package/dist/builtins/liveness-monitor/liveness-monitor.addon.js +1 -1
  41. package/dist/builtins/liveness-monitor/liveness-monitor.addon.mjs +1 -1
  42. package/dist/builtins/local-auth/local-auth.addon.js +1 -1
  43. package/dist/builtins/local-auth/local-auth.addon.mjs +1 -1
  44. package/dist/builtins/local-network/local-network.addon.js +3 -3
  45. package/dist/builtins/local-network/local-network.addon.mjs +3 -3
  46. package/dist/builtins/loki-logging/index.js +1 -1
  47. package/dist/builtins/loki-logging/index.mjs +1 -1
  48. package/dist/builtins/native-metrics/native-metrics.addon.js +4 -4
  49. package/dist/builtins/native-metrics/native-metrics.addon.mjs +4 -4
  50. package/dist/builtins/platform-probe/index.js +3 -3
  51. package/dist/builtins/platform-probe/index.mjs +2 -2
  52. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +1 -1
  53. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +1 -1
  54. package/dist/builtins/snapshot/index.js +1 -1
  55. package/dist/builtins/snapshot/index.mjs +1 -1
  56. package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +2 -2
  57. package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +2 -2
  58. package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +0 -0
  59. package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +0 -0
  60. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +1 -1
  61. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +1 -1
  62. package/dist/builtins/system-config/system-config.addon.js +1 -1
  63. package/dist/builtins/system-config/system-config.addon.mjs +1 -1
  64. package/dist/builtins/winston-logging/index.js +1 -1
  65. package/dist/builtins/winston-logging/index.mjs +1 -1
  66. package/dist/{child-cap-dispatch-OLFN-F85.mjs → child-cap-dispatch-B2N_gWV-.mjs} +3 -3
  67. package/dist/{child-cap-dispatch-CVOa1BZI.js → child-cap-dispatch-k3dEOCnu.js} +3 -3
  68. package/dist/{composition-sources-CeZ3tyH8.js → composition-sources-C42s3_1h.js} +1 -1
  69. package/dist/{composition-sources-pQsmMdpR.mjs → composition-sources-D7cxA4Yv.mjs} +1 -1
  70. package/dist/{dist-DTgd2gOR.js → dist-BgV_QADz.js} +5608 -5248
  71. package/dist/{dist-BUFcHq7H.mjs → dist-nUn3vto_.mjs} +5586 -5250
  72. package/dist/index.js +7 -7
  73. package/dist/index.mjs +6 -6
  74. package/dist/{retired-settings-keys-Ddb5cCNR.js → retired-settings-keys-D980hwnw.js} +1 -1
  75. package/dist/{retired-settings-keys-ltKefX3N.mjs → retired-settings-keys-pKNWq-CL.mjs} +1 -1
  76. package/package.json +1 -1
  77. package/dist/{resource-monitor-B1v6E07R.mjs → resource-monitor-B2WZ8_q9.mjs} +1 -1
  78. package/dist/{resource-monitor-DzNn_IZK.js → resource-monitor-BgWGRxN5.js} +1 -1
  79. package/dist/{tls-DAtaKVUT.mjs → tls-DTlVWwAI.mjs} +1 -1
  80. package/dist/{tls-DEjOOARt.js → tls-ue_Xefmv.js} +1 -1
@@ -1,13 +1,13 @@
1
1
  const require_chunk = require("./chunk-Cek0wNdY.js");
2
- const require_child_cap_dispatch = require("./child-cap-dispatch-CVOa1BZI.js");
2
+ const require_child_cap_dispatch = require("./child-cap-dispatch-k3dEOCnu.js");
3
3
  const require_custom_action_registry = require("./custom-action-registry-acBY3mHA.js");
4
4
  let node_path = require("node:path");
5
5
  node_path = require_chunk.__toESM(node_path);
6
+ let node_url = require("node:url");
6
7
  let node_fs = require("node:fs");
7
8
  node_fs = require_chunk.__toESM(node_fs);
8
9
  let node_module = require("node:module");
9
10
  let _camstack_types_addon = require("@camstack/types/addon");
10
- let node_url = require("node:url");
11
11
  //#region src/kernel/moleculer/child-addon-call-dispatch.ts
12
12
  function isRecord$1(value) {
13
13
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -1,10 +1,10 @@
1
- import { Ft as installManifestNativeDeps, H as createUdsLoggerWithControl, It as resolveAddonClass, St as validateProviderRegistrations, Tn as emitHeapDiagnosticReport, U as LocalChildClient, _t as getWorkerNativeCapProvider, bt as setWorkerNativeCapsChangeListener, en as RUNNER_RSS_BUDGET_ENV, f as installManifestSystemDeps, g as createUdsAddonContext, i as killOwnRunnerGroupAfterParentLoss, n as createChildCapDispatch, p as installManifestPythonDeps, pn as startRunnerHeapWatch, u as startRunnerParentDeathWatchdog, vt as getWorkerNativeCapSnapshot } from "./child-cap-dispatch-OLFN-F85.mjs";
1
+ import { Ft as installManifestNativeDeps, H as createUdsLoggerWithControl, It as resolveAddonClass, St as validateProviderRegistrations, Tn as emitHeapDiagnosticReport, U as LocalChildClient, _t as getWorkerNativeCapProvider, bt as setWorkerNativeCapsChangeListener, en as RUNNER_RSS_BUDGET_ENV, f as installManifestSystemDeps, g as createUdsAddonContext, i as killOwnRunnerGroupAfterParentLoss, n as createChildCapDispatch, p as installManifestPythonDeps, pn as startRunnerHeapWatch, u as startRunnerParentDeathWatchdog, vt as getWorkerNativeCapSnapshot } from "./child-cap-dispatch-B2N_gWV-.mjs";
2
2
  import { t as CustomActionRegistry } from "./custom-action-registry-B4Cf4O_X.mjs";
3
3
  import { register } from "node:module";
4
4
  import * as path$1 from "node:path";
5
+ import { pathToFileURL } from "node:url";
5
6
  import * as fs from "node:fs";
6
7
  import { ReadinessRegistry, ReadinessTimeoutError, errMsg, isCollectionArrayMethodName, isProviderOptionalMethodName, normalizeAddonInitResult } from "@camstack/types/addon";
7
- import { pathToFileURL } from "node:url";
8
8
  //#region src/kernel/moleculer/child-addon-call-dispatch.ts
9
9
  function isRecord$1(value) {
10
10
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-DTgd2gOR.js");
6
+ const require_dist = require("../../dist-BgV_QADz.js");
7
7
  const require_settle_sources = require("../../settle-sources-Bhsy57y-.js");
8
8
  let node_crypto = require("node:crypto");
9
9
  let node_path = require("node:path");
@@ -1,4 +1,4 @@
1
- import { Gn as BaseAddon, V as addonPagesCapability, Wn as errMsg, gr as EventCategory } from "../../dist-BUFcHq7H.mjs";
1
+ import { H as addonPagesCapability, Jn as errMsg, Yn as BaseAddon, br as EventCategory } from "../../dist-nUn3vto_.mjs";
2
2
  import { t as settleSourcesWithTimeout } from "../../settle-sources-CDtNC8ub.mjs";
3
3
  import { createHash, randomUUID } from "node:crypto";
4
4
  import * as path$1 from "node:path";
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-DTgd2gOR.js");
6
+ const require_dist = require("../../dist-BgV_QADz.js");
7
7
  const require_settle_sources = require("../../settle-sources-Bhsy57y-.js");
8
8
  let node_crypto = require("node:crypto");
9
9
  let node_path = require("node:path");
@@ -1,4 +1,4 @@
1
- import { Gn as BaseAddon, U as addonWidgetsCapability, Wn as errMsg, gr as EventCategory } from "../../dist-BUFcHq7H.mjs";
1
+ import { Jn as errMsg, W as addonWidgetsCapability, Yn as BaseAddon, br as EventCategory } from "../../dist-nUn3vto_.mjs";
2
2
  import { t as settleSourcesWithTimeout } from "../../settle-sources-CDtNC8ub.mjs";
3
3
  import { createHash, randomUUID } from "node:crypto";
4
4
  import * as path$1 from "node:path";
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-DTgd2gOR.js");
6
+ const require_dist = require("../../dist-BgV_QADz.js");
7
7
  //#region src/builtins/alerts/prune-policy.ts
8
8
  /**
9
9
  * Ids older than `cutoffMs`, oldest first.
@@ -1,4 +1,4 @@
1
- import { Gn as BaseAddon, W as alertsCapability, Wn as errMsg, gr as EventCategory, n as AlertSchema, tr as createEvent } from "../../dist-BUFcHq7H.mjs";
1
+ import { G as alertsCapability, Jn as errMsg, Yn as BaseAddon, ar as createEvent, br as EventCategory, n as AlertSchema } from "../../dist-nUn3vto_.mjs";
2
2
  //#region src/builtins/alerts/prune-policy.ts
3
3
  /**
4
4
  * Ids older than `cutoffMs`, oldest first.
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-DTgd2gOR.js");
6
+ const require_dist = require("../../dist-BgV_QADz.js");
7
7
  //#region src/builtins/autotrack/autotrack-config.ts
8
8
  var DEFAULT_AUTOTRACK_LOOP_CONFIG = {
9
9
  deadZoneFraction: .5,
@@ -1,4 +1,4 @@
1
- import { Gn as BaseAddon, Wn as errMsg, b as FIRST_LEVEL_MACRO_CLASSES, gr as EventCategory, in as ptzAutotrackCapability, q as bareAddonId, sr as isEvent } from "../../dist-BUFcHq7H.mjs";
1
+ import { J as bareAddonId, Jn as errMsg, Yn as BaseAddon, br as EventCategory, dr as isEvent, on as ptzAutotrackCapability, x as FIRST_LEVEL_MACRO_CLASSES } from "../../dist-nUn3vto_.mjs";
2
2
  //#region src/builtins/autotrack/autotrack-config.ts
3
3
  var DEFAULT_AUTOTRACK_LOOP_CONFIG = {
4
4
  deadZoneFraction: .5,
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-DTgd2gOR.js");
6
+ const require_dist = require("../../dist-BgV_QADz.js");
7
7
  let node_crypto = require("node:crypto");
8
8
  let buffer = require("buffer");
9
9
  let node_fs_promises = require("node:fs/promises");
@@ -1,4 +1,4 @@
1
- import { Gn as BaseAddon, K as backupCapability, Kt as mayWriteToLocation, cr as nodePin, gr as EventCategory, hr as toNodeId, m as DATABASE_SNAPSHOT_SUFFIX, yn as storageOccupancyCapability } from "../../dist-BUFcHq7H.mjs";
1
+ import { Cn as storageOccupancyCapability, Yn as BaseAddon, br as EventCategory, fr as nodePin, h as DATABASE_SNAPSHOT_SUFFIX, q as backupCapability, qt as mayWriteToLocation, yr as toNodeId } from "../../dist-nUn3vto_.mjs";
2
2
  import { randomBytes, randomUUID } from "node:crypto";
3
3
  import { Buffer as Buffer$1 } from "buffer";
4
4
  import * as fsp from "node:fs/promises";
@@ -0,0 +1,5 @@
1
+ import { CalendarColor } from '@camstack/types';
2
+ /** Fixed palette — high-contrast hues that read on light and dark chrome. */
3
+ export declare const CALENDAR_COLOR_PALETTE: readonly CalendarColor[];
4
+ /** Stable FNV-1a-ish hash → palette index. */
5
+ export declare function defaultCalendarColor(calendarId: string): CalendarColor;
@@ -0,0 +1,13 @@
1
+ import { CalendarPreferences, SettingsStoreClient } from '@camstack/types';
2
+ export declare const CALENDARS_USER_PREFS_COLLECTION = "calendars:user-prefs";
3
+ export declare function declareCalendarPrefsSchema(store: SettingsStoreClient): Promise<void>;
4
+ export declare function loadCalendarPreferences(store: SettingsStoreClient, userId: string): Promise<CalendarPreferences>;
5
+ export declare function saveCalendarPreferences(store: SettingsStoreClient, userId: string, prefs: CalendarPreferences, nowMs: number): Promise<void>;
6
+ /**
7
+ * Patch one calendar's preference entry. `color: null` clears the override;
8
+ * omitting a field leaves it unchanged. An entry that becomes empty is dropped.
9
+ */
10
+ export declare function patchCalendarPreference(current: CalendarPreferences, calendarId: string, patch: {
11
+ readonly visible?: boolean;
12
+ readonly color?: string | null;
13
+ }): CalendarPreferences;
@@ -1,11 +1,14 @@
1
1
  import { BaseAddon, ProviderRegistration } from '@camstack/types';
2
2
  export declare class CalendarsAddon extends BaseAddon {
3
3
  readonly id = "calendars";
4
+ private prefsDeclared;
4
5
  constructor();
5
6
  protected onInitialize(): Promise<ProviderRegistration[]>;
7
+ private ensurePrefsSchema;
6
8
  private sources;
7
9
  private listCalendars;
8
10
  private listEvents;
9
- private importFromHomeAssistant;
11
+ private getPreferences;
12
+ private setCalendarPreference;
10
13
  }
11
14
  export default CalendarsAddon;
@@ -3,15 +3,120 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-DTgd2gOR.js");
6
+ const require_dist = require("../../dist-BgV_QADz.js");
7
7
  const require_settle_sources = require("../../settle-sources-Bhsy57y-.js");
8
+ let zod = require("zod");
9
+ //#region src/builtins/calendars/calendar-color.ts
10
+ /** Fixed palette — high-contrast hues that read on light and dark chrome. */
11
+ var CALENDAR_COLOR_PALETTE = [
12
+ "#2563EB",
13
+ "#DC2626",
14
+ "#16A34A",
15
+ "#D97706",
16
+ "#7C3AED",
17
+ "#0891B2",
18
+ "#DB2777",
19
+ "#65A30D",
20
+ "#EA580C",
21
+ "#4F46E5",
22
+ "#0D9488",
23
+ "#BE123C"
24
+ ];
25
+ /** Stable FNV-1a-ish hash → palette index. */
26
+ function defaultCalendarColor(calendarId) {
27
+ let hash = 2166136261;
28
+ for (let i = 0; i < calendarId.length; i += 1) {
29
+ hash ^= calendarId.charCodeAt(i);
30
+ hash = Math.imul(hash, 16777619);
31
+ }
32
+ return CALENDAR_COLOR_PALETTE[Math.abs(hash) % CALENDAR_COLOR_PALETTE.length];
33
+ }
34
+ //#endregion
35
+ //#region src/builtins/calendars/calendar-prefs-store.ts
36
+ /**
37
+ * Per-user calendar UI preferences (colour override + visibility).
38
+ *
39
+ * One row per `userId`. The calendars builtin owns declare + read/write;
40
+ * the browser never talks to `settingsStore` directly.
41
+ *
42
+ * @durable class=config owner=calendars
43
+ * write="`setCalendarPreference` upserts the caller's row"
44
+ * retention="none — a missing row reads as empty prefs (all visible,
45
+ * system colours). Losing the table silently resets every operator's
46
+ * colour/hide choices."
47
+ */
48
+ var CALENDARS_USER_PREFS_COLLECTION = "calendars:user-prefs";
49
+ var COLUMNS = [
50
+ {
51
+ name: "userId",
52
+ type: "TEXT",
53
+ primaryKey: true,
54
+ notNull: true
55
+ },
56
+ {
57
+ name: "calendars",
58
+ type: "JSON",
59
+ notNull: true
60
+ },
61
+ {
62
+ name: "updatedAt",
63
+ type: "INTEGER",
64
+ notNull: true
65
+ }
66
+ ];
67
+ var StoredRowSchema = zod.z.object({
68
+ calendars: zod.z.record(zod.z.string(), zod.z.unknown()),
69
+ updatedAt: zod.z.number()
70
+ });
71
+ async function declareCalendarPrefsSchema(store) {
72
+ await store.declareCollection.mutate({
73
+ collection: CALENDARS_USER_PREFS_COLLECTION,
74
+ columns: COLUMNS
75
+ });
76
+ }
77
+ async function loadCalendarPreferences(store, userId) {
78
+ const raw = await store.get.query({
79
+ collection: CALENDARS_USER_PREFS_COLLECTION,
80
+ key: userId
81
+ });
82
+ if (raw === null || raw === void 0 || typeof raw !== "object") return { calendars: {} };
83
+ const parsed = StoredRowSchema.safeParse(raw);
84
+ if (!parsed.success) return { calendars: {} };
85
+ const prefs = require_dist.CalendarPreferencesSchema.safeParse({ calendars: parsed.data.calendars });
86
+ return prefs.success ? prefs.data : { calendars: {} };
87
+ }
88
+ async function saveCalendarPreferences(store, userId, prefs, nowMs) {
89
+ await store.set.mutate({
90
+ collection: CALENDARS_USER_PREFS_COLLECTION,
91
+ key: userId,
92
+ value: {
93
+ calendars: prefs.calendars,
94
+ updatedAt: nowMs
95
+ }
96
+ });
97
+ }
98
+ /**
99
+ * Patch one calendar's preference entry. `color: null` clears the override;
100
+ * omitting a field leaves it unchanged. An entry that becomes empty is dropped.
101
+ */
102
+ function patchCalendarPreference(current, calendarId, patch) {
103
+ const next = { ...current.calendars[calendarId] ?? {} };
104
+ if (patch.visible !== void 0) next.visible = patch.visible;
105
+ if (patch.color === null) delete next.color;
106
+ else if (patch.color !== void 0) next.color = patch.color;
107
+ const calendars = { ...current.calendars };
108
+ if (next.visible === void 0 && next.color === void 0) delete calendars[calendarId];
109
+ else calendars[calendarId] = next;
110
+ return { calendars };
111
+ }
112
+ //#endregion
8
113
  //#region src/builtins/calendars/calendars.addon.ts
9
114
  /**
10
115
  * Hub calendars aggregator — walks `calendar-source` providers and stamps
11
- * cluster-stable ids (`<providerAddonId>:<localId>`).
116
+ * cluster-stable ids (`<providerAddonId>:<localId>`). Owns per-user UI
117
+ * preferences (colour / visibility) via `calendars:user-prefs`.
12
118
  */
13
119
  var PER_SOURCE_TIMEOUT_MS = 2500;
14
- var HA_ADDON_ID = "provider-homeassistant";
15
120
  function stampId(providerAddonId, localId) {
16
121
  return `${providerAddonId}:${localId}`;
17
122
  }
@@ -20,8 +125,18 @@ function localIdOf(stamped, providerAddonId) {
20
125
  if (!stamped.startsWith(prefix)) return null;
21
126
  return stamped.slice(prefix.length);
22
127
  }
128
+ function withSystemColors(entry) {
129
+ const defaultColor = defaultCalendarColor(entry.id);
130
+ return {
131
+ ...entry,
132
+ defaultColor,
133
+ color: defaultColor,
134
+ visible: true
135
+ };
136
+ }
23
137
  var CalendarsAddon = class extends require_dist.BaseAddon {
24
138
  id = "calendars";
139
+ prefsDeclared = false;
25
140
  constructor() {
26
141
  super({});
27
142
  }
@@ -29,7 +144,12 @@ var CalendarsAddon = class extends require_dist.BaseAddon {
29
144
  const provider = {
30
145
  listCalendars: async () => this.listCalendars(),
31
146
  listEvents: async (input) => this.listEvents(input),
32
- importFromHomeAssistant: async () => this.importFromHomeAssistant()
147
+ getPreferences: async ({ caller }) => this.getPreferences(caller),
148
+ setCalendarPreference: async ({ caller, calendarId, visible, color }) => this.setCalendarPreference(caller, {
149
+ calendarId,
150
+ visible,
151
+ color
152
+ })
33
153
  };
34
154
  this.ctx.logger.info("Initialized — aggregating calendar-source providers");
35
155
  return [{
@@ -37,6 +157,11 @@ var CalendarsAddon = class extends require_dist.BaseAddon {
37
157
  provider
38
158
  }];
39
159
  }
160
+ async ensurePrefsSchema() {
161
+ if (this.prefsDeclared) return;
162
+ await declareCalendarPrefsSchema(this.ctx.api.settingsStore);
163
+ this.prefsDeclared = true;
164
+ }
40
165
  sources() {
41
166
  return (this.capabilities?.getCollectionEntries("calendar-source") ?? []).map(([id, provider]) => ({
42
167
  id,
@@ -45,7 +170,7 @@ var CalendarsAddon = class extends require_dist.BaseAddon {
45
170
  }
46
171
  async listCalendars() {
47
172
  const settled = await require_settle_sources.settleSourcesWithTimeout(this.sources().map((s) => [s.id, async () => {
48
- return (await s.provider.listCalendars()).map((cal) => ({
173
+ return (await s.provider.listCalendars()).map((cal) => withSystemColors({
49
174
  ...cal,
50
175
  id: stampId(s.id, cal.id),
51
176
  providerAddonId: s.id
@@ -85,24 +210,19 @@ var CalendarsAddon = class extends require_dist.BaseAddon {
85
210
  } });
86
211
  return out.toSorted((a, b) => a.startMs - b.startMs);
87
212
  }
88
- async importFromHomeAssistant() {
89
- const ha = this.sources().find((s) => s.id === HA_ADDON_ID || s.id.includes("homeassistant"));
90
- if (ha === void 0) return {
91
- imported: 0,
92
- error: "No Home Assistant calendar-source provider is registered"
93
- };
94
- try {
95
- return {
96
- imported: (await ha.provider.listCalendars()).length,
97
- providerAddonId: ha.id
98
- };
99
- } catch (err) {
100
- return {
101
- imported: 0,
102
- providerAddonId: ha.id,
103
- error: require_dist.errMsg(err)
104
- };
105
- }
213
+ async getPreferences(caller) {
214
+ await this.ensurePrefsSchema();
215
+ return loadCalendarPreferences(this.ctx.api.settingsStore, caller.userId);
216
+ }
217
+ async setCalendarPreference(caller, patch) {
218
+ await this.ensurePrefsSchema();
219
+ const store = this.ctx.api.settingsStore;
220
+ const next = patchCalendarPreference(await loadCalendarPreferences(store, caller.userId), patch.calendarId, {
221
+ visible: patch.visible,
222
+ color: patch.color
223
+ });
224
+ await saveCalendarPreferences(store, caller.userId, next, Date.now());
225
+ return next;
106
226
  }
107
227
  };
108
228
  //#endregion
@@ -1,12 +1,117 @@
1
- import { Gn as BaseAddon, Wn as errMsg, Z as calendarsCapability } from "../../dist-BUFcHq7H.mjs";
1
+ import { Q as calendarsCapability, Yn as BaseAddon, f as CalendarPreferencesSchema } from "../../dist-nUn3vto_.mjs";
2
2
  import { t as settleSourcesWithTimeout } from "../../settle-sources-CDtNC8ub.mjs";
3
+ import { z } from "zod";
4
+ //#region src/builtins/calendars/calendar-color.ts
5
+ /** Fixed palette — high-contrast hues that read on light and dark chrome. */
6
+ var CALENDAR_COLOR_PALETTE = [
7
+ "#2563EB",
8
+ "#DC2626",
9
+ "#16A34A",
10
+ "#D97706",
11
+ "#7C3AED",
12
+ "#0891B2",
13
+ "#DB2777",
14
+ "#65A30D",
15
+ "#EA580C",
16
+ "#4F46E5",
17
+ "#0D9488",
18
+ "#BE123C"
19
+ ];
20
+ /** Stable FNV-1a-ish hash → palette index. */
21
+ function defaultCalendarColor(calendarId) {
22
+ let hash = 2166136261;
23
+ for (let i = 0; i < calendarId.length; i += 1) {
24
+ hash ^= calendarId.charCodeAt(i);
25
+ hash = Math.imul(hash, 16777619);
26
+ }
27
+ return CALENDAR_COLOR_PALETTE[Math.abs(hash) % CALENDAR_COLOR_PALETTE.length];
28
+ }
29
+ //#endregion
30
+ //#region src/builtins/calendars/calendar-prefs-store.ts
31
+ /**
32
+ * Per-user calendar UI preferences (colour override + visibility).
33
+ *
34
+ * One row per `userId`. The calendars builtin owns declare + read/write;
35
+ * the browser never talks to `settingsStore` directly.
36
+ *
37
+ * @durable class=config owner=calendars
38
+ * write="`setCalendarPreference` upserts the caller's row"
39
+ * retention="none — a missing row reads as empty prefs (all visible,
40
+ * system colours). Losing the table silently resets every operator's
41
+ * colour/hide choices."
42
+ */
43
+ var CALENDARS_USER_PREFS_COLLECTION = "calendars:user-prefs";
44
+ var COLUMNS = [
45
+ {
46
+ name: "userId",
47
+ type: "TEXT",
48
+ primaryKey: true,
49
+ notNull: true
50
+ },
51
+ {
52
+ name: "calendars",
53
+ type: "JSON",
54
+ notNull: true
55
+ },
56
+ {
57
+ name: "updatedAt",
58
+ type: "INTEGER",
59
+ notNull: true
60
+ }
61
+ ];
62
+ var StoredRowSchema = z.object({
63
+ calendars: z.record(z.string(), z.unknown()),
64
+ updatedAt: z.number()
65
+ });
66
+ async function declareCalendarPrefsSchema(store) {
67
+ await store.declareCollection.mutate({
68
+ collection: CALENDARS_USER_PREFS_COLLECTION,
69
+ columns: COLUMNS
70
+ });
71
+ }
72
+ async function loadCalendarPreferences(store, userId) {
73
+ const raw = await store.get.query({
74
+ collection: CALENDARS_USER_PREFS_COLLECTION,
75
+ key: userId
76
+ });
77
+ if (raw === null || raw === void 0 || typeof raw !== "object") return { calendars: {} };
78
+ const parsed = StoredRowSchema.safeParse(raw);
79
+ if (!parsed.success) return { calendars: {} };
80
+ const prefs = CalendarPreferencesSchema.safeParse({ calendars: parsed.data.calendars });
81
+ return prefs.success ? prefs.data : { calendars: {} };
82
+ }
83
+ async function saveCalendarPreferences(store, userId, prefs, nowMs) {
84
+ await store.set.mutate({
85
+ collection: CALENDARS_USER_PREFS_COLLECTION,
86
+ key: userId,
87
+ value: {
88
+ calendars: prefs.calendars,
89
+ updatedAt: nowMs
90
+ }
91
+ });
92
+ }
93
+ /**
94
+ * Patch one calendar's preference entry. `color: null` clears the override;
95
+ * omitting a field leaves it unchanged. An entry that becomes empty is dropped.
96
+ */
97
+ function patchCalendarPreference(current, calendarId, patch) {
98
+ const next = { ...current.calendars[calendarId] ?? {} };
99
+ if (patch.visible !== void 0) next.visible = patch.visible;
100
+ if (patch.color === null) delete next.color;
101
+ else if (patch.color !== void 0) next.color = patch.color;
102
+ const calendars = { ...current.calendars };
103
+ if (next.visible === void 0 && next.color === void 0) delete calendars[calendarId];
104
+ else calendars[calendarId] = next;
105
+ return { calendars };
106
+ }
107
+ //#endregion
3
108
  //#region src/builtins/calendars/calendars.addon.ts
4
109
  /**
5
110
  * Hub calendars aggregator — walks `calendar-source` providers and stamps
6
- * cluster-stable ids (`<providerAddonId>:<localId>`).
111
+ * cluster-stable ids (`<providerAddonId>:<localId>`). Owns per-user UI
112
+ * preferences (colour / visibility) via `calendars:user-prefs`.
7
113
  */
8
114
  var PER_SOURCE_TIMEOUT_MS = 2500;
9
- var HA_ADDON_ID = "provider-homeassistant";
10
115
  function stampId(providerAddonId, localId) {
11
116
  return `${providerAddonId}:${localId}`;
12
117
  }
@@ -15,8 +120,18 @@ function localIdOf(stamped, providerAddonId) {
15
120
  if (!stamped.startsWith(prefix)) return null;
16
121
  return stamped.slice(prefix.length);
17
122
  }
123
+ function withSystemColors(entry) {
124
+ const defaultColor = defaultCalendarColor(entry.id);
125
+ return {
126
+ ...entry,
127
+ defaultColor,
128
+ color: defaultColor,
129
+ visible: true
130
+ };
131
+ }
18
132
  var CalendarsAddon = class extends BaseAddon {
19
133
  id = "calendars";
134
+ prefsDeclared = false;
20
135
  constructor() {
21
136
  super({});
22
137
  }
@@ -24,7 +139,12 @@ var CalendarsAddon = class extends BaseAddon {
24
139
  const provider = {
25
140
  listCalendars: async () => this.listCalendars(),
26
141
  listEvents: async (input) => this.listEvents(input),
27
- importFromHomeAssistant: async () => this.importFromHomeAssistant()
142
+ getPreferences: async ({ caller }) => this.getPreferences(caller),
143
+ setCalendarPreference: async ({ caller, calendarId, visible, color }) => this.setCalendarPreference(caller, {
144
+ calendarId,
145
+ visible,
146
+ color
147
+ })
28
148
  };
29
149
  this.ctx.logger.info("Initialized — aggregating calendar-source providers");
30
150
  return [{
@@ -32,6 +152,11 @@ var CalendarsAddon = class extends BaseAddon {
32
152
  provider
33
153
  }];
34
154
  }
155
+ async ensurePrefsSchema() {
156
+ if (this.prefsDeclared) return;
157
+ await declareCalendarPrefsSchema(this.ctx.api.settingsStore);
158
+ this.prefsDeclared = true;
159
+ }
35
160
  sources() {
36
161
  return (this.capabilities?.getCollectionEntries("calendar-source") ?? []).map(([id, provider]) => ({
37
162
  id,
@@ -40,7 +165,7 @@ var CalendarsAddon = class extends BaseAddon {
40
165
  }
41
166
  async listCalendars() {
42
167
  const settled = await settleSourcesWithTimeout(this.sources().map((s) => [s.id, async () => {
43
- return (await s.provider.listCalendars()).map((cal) => ({
168
+ return (await s.provider.listCalendars()).map((cal) => withSystemColors({
44
169
  ...cal,
45
170
  id: stampId(s.id, cal.id),
46
171
  providerAddonId: s.id
@@ -80,24 +205,19 @@ var CalendarsAddon = class extends BaseAddon {
80
205
  } });
81
206
  return out.toSorted((a, b) => a.startMs - b.startMs);
82
207
  }
83
- async importFromHomeAssistant() {
84
- const ha = this.sources().find((s) => s.id === HA_ADDON_ID || s.id.includes("homeassistant"));
85
- if (ha === void 0) return {
86
- imported: 0,
87
- error: "No Home Assistant calendar-source provider is registered"
88
- };
89
- try {
90
- return {
91
- imported: (await ha.provider.listCalendars()).length,
92
- providerAddonId: ha.id
93
- };
94
- } catch (err) {
95
- return {
96
- imported: 0,
97
- providerAddonId: ha.id,
98
- error: errMsg(err)
99
- };
100
- }
208
+ async getPreferences(caller) {
209
+ await this.ensurePrefsSchema();
210
+ return loadCalendarPreferences(this.ctx.api.settingsStore, caller.userId);
211
+ }
212
+ async setCalendarPreference(caller, patch) {
213
+ await this.ensurePrefsSchema();
214
+ const store = this.ctx.api.settingsStore;
215
+ const next = patchCalendarPreference(await loadCalendarPreferences(store, caller.userId), patch.calendarId, {
216
+ visible: patch.visible,
217
+ color: patch.color
218
+ });
219
+ await saveCalendarPreferences(store, caller.userId, next, Date.now());
220
+ return next;
101
221
  }
102
222
  };
103
223
  //#endregion
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-DTgd2gOR.js");
6
+ const require_dist = require("../../dist-BgV_QADz.js");
7
7
  let zod = require("zod");
8
8
  let _camstack_types_node = require("@camstack/types/node");
9
9
  let node_path = require("node:path");
@@ -1,4 +1,4 @@
1
- import { An as buildFfmpegArgs, Gn as BaseAddon, O as MOTION_CLOSE_AFTER_MS, Q as cameraGridLayoutCapability, Un as DeviceType, Vn as DeviceFeature, Wn as errMsg, Xt as motionCapability, _ as DERIVED_CAMERA_SILENCED_CAP_NAMES, ar as hydrateSchema, dt as declarationOwnerNodeId, gn as snapshotCapability, gr as EventCategory, i as BaseDevice, qt as memoizePinnedFfmpeg, tr as createEvent, v as DeclaredDevices, xn as streamCatalogCapability } from "../../dist-BUFcHq7H.mjs";
1
+ import { $ as cameraGridLayoutCapability, Gn as DeviceFeature, Jn as errMsg, Jt as memoizePinnedFfmpeg, Pn as buildFfmpegArgs, Tn as streamCatalogCapability, Yn as BaseAddon, Zt as motionCapability, ar as createEvent, bn as snapshotCapability, br as EventCategory, ft as declarationOwnerNodeId, i as BaseDevice, k as MOTION_CLOSE_AFTER_MS, lr as hydrateSchema, qn as DeviceType, v as DERIVED_CAMERA_SILENCED_CAP_NAMES, y as DeclaredDevices } from "../../dist-nUn3vto_.mjs";
2
2
  import { z } from "zod";
3
3
  import { FfmpegProcess } from "@camstack/types/node";
4
4
  import { join } from "node:path";
@@ -3,8 +3,8 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-DTgd2gOR.js");
7
- const require_composition_sources = require("../../composition-sources-CeZ3tyH8.js");
6
+ const require_dist = require("../../dist-BgV_QADz.js");
7
+ const require_composition_sources = require("../../composition-sources-C42s3_1h.js");
8
8
  let zod = require("zod");
9
9
  //#region src/builtins/shared/device-state-changed.ts
10
10
  /** Structural narrowing helper for untrusted bus payloads. */
@@ -1,5 +1,5 @@
1
- import { Bn as toExpressionValue, Ct as evaluateCompositionField, Fn as compositionItemFieldPath, Gn as BaseAddon, In as compositionSliceKey, Ln as compositionSourceKey, Mn as composedDeviceRef, Nn as composedDeviceStableId, Pn as compositionFeatureEnabled, Rn as createStatefulExpressionMemory, Un as DeviceType, Wn as errMsg, Y as buildCapabilityLookup, c as COMPOSED_ITEM_FIXED_FIELDS, et as composerCapability, gr as EventCategory, i as BaseDevice, jn as cloneStatefulExpressionMemory, kn as COMPOSER_ADDON_ID, t as ALL_CAPABILITY_DEFINITIONS, tn as planComposition, tr as createEvent, tt as compositionFieldKey, v as DeclaredDevices, zn as disarmRoseMemory } from "../../dist-BUFcHq7H.mjs";
2
- import { n as normalizedNativeOwner } from "../../composition-sources-pQsmMdpR.mjs";
1
+ import { Bn as compositionSliceKey, Fn as cloneStatefulExpressionMemory, Hn as createStatefulExpressionMemory, In as composedDeviceRef, Jn as errMsg, Ln as composedDeviceStableId, Nn as COMPOSER_ADDON_ID, Rn as compositionFeatureEnabled, Un as disarmRoseMemory, Vn as compositionSourceKey, Wn as toExpressionValue, X as buildCapabilityLookup, Yn as BaseAddon, ar as createEvent, br as EventCategory, c as COMPOSED_ITEM_FIXED_FIELDS, i as BaseDevice, nt as compositionFieldKey, qn as DeviceType, rn as planComposition, t as ALL_CAPABILITY_DEFINITIONS, tt as composerCapability, wt as evaluateCompositionField, y as DeclaredDevices, zn as compositionItemFieldPath } from "../../dist-nUn3vto_.mjs";
2
+ import { n as normalizedNativeOwner } from "../../composition-sources-D7cxA4Yv.mjs";
3
3
  import { z } from "zod";
4
4
  //#region src/builtins/shared/device-state-changed.ts
5
5
  /** Structural narrowing helper for untrusted bus payloads. */
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-DTgd2gOR.js");
6
+ const require_dist = require("../../dist-BgV_QADz.js");
7
7
  const require_formatter = require("../../formatter-DqAKDlvN.js");
8
8
  //#region src/builtins/console-logging/console-destination.ts
9
9
  var LEVEL_RANK = {
@@ -1,4 +1,4 @@
1
- import { Gn as BaseAddon, Ht as logDestinationCapability } from "../../dist-BUFcHq7H.mjs";
1
+ import { Ut as logDestinationCapability, Yn as BaseAddon } from "../../dist-nUn3vto_.mjs";
2
2
  import { t as formatLogLine } from "../../formatter-B7qW8bPJ.mjs";
3
3
  //#region src/builtins/console-logging/console-destination.ts
4
4
  var LEVEL_RANK = {