@camstack/server 1.2.663 → 1.2.665

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 CHANGED
@@ -7,6 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [1.2.665] - 2026-10-28
11
+
12
+ ### Changed
13
+
14
+ - A shared events link can open a track's detail page, and shared links now use the operator's colour palette
15
+
16
+ ## [1.2.664] - 2026-10-27
17
+
18
+ ### Changed
19
+
20
+ - Rebuilt against updated dependencies.
21
+
10
22
  ## [1.2.663] - 2026-10-27
11
23
 
12
24
  ### Changed
@@ -16,6 +16,8 @@ const GRID_VIEW_OPEN_METHODS = new Set([
16
16
  'deviceManager.listAll',
17
17
  'turnProvider.getTurnServers',
18
18
  'live.onEvent',
19
+ // Display data only: preset id + hex swatches, no device or secret.
20
+ 'displayPalette.getPalette',
19
21
  ]);
20
22
  /**
21
23
  * Talk-back, callable only on a token minted with `scope.talk` AND only for an
@@ -58,13 +60,19 @@ function extractDeviceId(input) {
58
60
  * • `pipelineAnalytics.listRecentTracks` — the feed itself
59
61
  * • `pipelineAnalytics.listEventKindsBatch` — the class→macro taxonomy
60
62
  * • `pipelineAnalytics.searchObjectEvents` — CLIP text search
63
+ * • `pipelineAnalytics.getTrack` / `listTrackMedia` — the track detail page
61
64
  *
62
65
  * Intentionally NOT here: everything the grid link gets (WebRTC signalling,
63
66
  * snapshots, TURN, camera metrics) — a shared events page is not a camera
64
67
  * wall — and every mutating analytics method (`deleteTracks`, `setTrackFlags`,
65
68
  * the retrain surface, the export planes).
66
69
  */
67
- const EVENTS_VIEW_OPEN_METHODS = new Set(['auth.me', 'deviceManager.listAll']);
70
+ const EVENTS_VIEW_OPEN_METHODS = new Set([
71
+ 'auth.me',
72
+ 'deviceManager.listAll',
73
+ // Display data only: preset id + hex swatches, no device or secret.
74
+ 'displayPalette.getPalette',
75
+ ]);
68
76
  /**
69
77
  * Methods whose input carries a `deviceIds` ARRAY. The rule is INTERSECTION,
70
78
  * and the outcome is FILTER-AND-SERVE: a request that names at least one
@@ -95,6 +103,21 @@ const EVENTS_VIEW_DEVICE_ARRAY_METHODS = new Set([
95
103
  const EVENTS_VIEW_OPTIONAL_DEVICE_METHODS = new Set([
96
104
  'pipelineAnalytics.searchObjectEvents',
97
105
  ]);
106
+ /**
107
+ * Methods that read ONE track (or its media manifest) and REQUIRE a single
108
+ * numeric `input.deviceId` that is inside the scope. Used by the embed's track
109
+ * detail page (`?mode=track`).
110
+ *
111
+ * Unlike {@link EVENTS_VIEW_OPTIONAL_DEVICE_METHODS} an absent id is DENIED
112
+ * (fail closed): the answer is one row, not a list the response filter could
113
+ * cut. The provider must return null when the stored track belongs to another
114
+ * device than `input.deviceId` — the gate vouches for the id the caller named,
115
+ * the provider vouches that it is the track's own.
116
+ */
117
+ const EVENTS_VIEW_REQUIRED_DEVICE_METHODS = new Set([
118
+ 'pipelineAnalytics.getTrack',
119
+ 'pipelineAnalytics.listTrackMedia',
120
+ ]);
98
121
  /** Pull a `deviceIds` array off a raw tRPC input. Null when absent/malformed. */
99
122
  function extractDeviceIds(input) {
100
123
  if (input === null || typeof input !== 'object')
@@ -133,6 +156,16 @@ function checkEventsViewAccess(scope, path, input) {
133
156
  }
134
157
  return { ok: true };
135
158
  }
159
+ if (EVENTS_VIEW_REQUIRED_DEVICE_METHODS.has(path)) {
160
+ const deviceId = extractDeviceId(input);
161
+ if (deviceId === null) {
162
+ return { ok: false, reason: `'${path}' requires a numeric deviceId for share-view access` };
163
+ }
164
+ if (!scope.deviceIds.includes(deviceId)) {
165
+ return { ok: false, reason: `Device ${deviceId} is outside this share link's scope` };
166
+ }
167
+ return { ok: true };
168
+ }
136
169
  return { ok: false, reason: `'${path}' is not available to share-view tokens` };
137
170
  }
138
171
  function checkShareViewAccess(scope, path, input) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/server",
3
- "version": "1.2.663",
3
+ "version": "1.2.665",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -49,20 +49,20 @@
49
49
  ]
50
50
  },
51
51
  "dependencies": {
52
- "@camstack/addon-admin-ui": "1.2.496",
53
- "@camstack/addon-agent-ui": "1.2.282",
52
+ "@camstack/addon-admin-ui": "1.2.498",
53
+ "@camstack/addon-agent-ui": "1.2.283",
54
54
  "@camstack/addon-auth": "1.2.170",
55
- "@camstack/addon-benchmark": "1.2.282",
55
+ "@camstack/addon-benchmark": "1.2.284",
56
56
  "@camstack/addon-decoder-nodeav": "1.2.144",
57
57
  "@camstack/addon-notifiers": "1.2.623",
58
58
  "@camstack/addon-pipeline": "1.2.631",
59
- "@camstack/addon-pipeline-orchestrator": "1.2.632",
60
- "@camstack/addon-post-analysis": "1.2.644",
59
+ "@camstack/addon-pipeline-orchestrator": "1.2.633",
60
+ "@camstack/addon-post-analysis": "1.2.645",
61
61
  "@camstack/develop": "0.1.38",
62
62
  "@camstack/sdk": "1.2.154",
63
- "@camstack/system": "1.2.500",
64
- "@camstack/types": "1.2.430",
65
- "@camstack/ui-library": "1.2.339",
63
+ "@camstack/system": "1.2.502",
64
+ "@camstack/types": "1.2.432",
65
+ "@camstack/ui-library": "1.2.341",
66
66
  "@fastify/compress": "^9.0.0",
67
67
  "@fastify/cookie": "^11.0.2",
68
68
  "@fastify/cors": "^11.2.0",