@camstack/types 1.2.386 → 1.2.387

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.
@@ -40,9 +40,9 @@ export interface AddonDataPlane {
40
40
  * transport in front of it (auth + reverse-proxy). */
41
41
  export type DataPlaneHandler = (req: IncomingMessage, res: ServerResponse) => void | Promise<void>;
42
42
  /**
43
- * The share-view scope kinds a `csv_*` share token can carry. The hub mints
44
- * and validates them (`share-token.service.ts` builds its enum from this
45
- * list); a data plane names the kinds it ACCEPTS in `share`.
43
+ * The share-view scope kinds a share-link token can carry. The hub mints
44
+ * and validates them (`ShareViewGrantSchema` builds its
45
+ * enum from this list); a data plane names the kinds it ACCEPTS in `share`.
46
46
  */
47
47
  export declare const SHARE_VIEW_KINDS: readonly ['grid-view', 'events-view'];
48
48
  export type ShareViewKind = (typeof SHARE_VIEW_KINDS)[number];
@@ -57,7 +57,7 @@ export interface AddonDataPlaneServeOptions {
57
57
  /** The addon's request handler — real `IncomingMessage`/`ServerResponse`. */
58
58
  readonly handler: DataPlaneHandler;
59
59
  /**
60
- * Share-token scope kinds this plane serves. ABSENT means a `csv_*` share
60
+ * Share-token scope kinds this plane serves. ABSENT means a share-link
61
61
  * token is refused here (403), whatever `access` says: a share link is a
62
62
  * bearer credential for one view of a few devices, not a session, and a
63
63
  * plane that never read the scope headers would serve every device to it.
@@ -9,7 +9,7 @@
9
9
  *
10
10
  * - the data-plane listener binds `127.0.0.1` behind a per-listener secret that
11
11
  * **only the hub** presents, and the hub's `/addon/<id>/…` proxy in front of
12
- * it takes a session cookie, a `cst_` token scoped `{type:'addon'}` or a JWT
12
+ * it takes a session cookie, a token scoped `{type:'addon'}` or a JWT
13
13
  * — an addon holds none of those;
14
14
  * - `ctx.api.<cap>.subscribe` is refused on an addon caller by design, so a
15
15
  * streaming cap method is not available either;
@@ -22,7 +22,7 @@ import { DeviceType } from '../device/device-type.js';
22
22
  * `super_admin` — collapsed onto the single boolean because every
23
23
  * non-admin caller is governed by the same scope-check rules; the
24
24
  * distinction was only ever used to route role-specific procedures
25
- * which we no longer have. CLI / webhook integrations are `cst_*` tokens
25
+ * which we no longer have. CLI / webhook integrations are tokens (`auth.mintToken`)
26
26
  * with `isAdmin: false` + an explicit scope list.
27
27
  */
28
28
  /** Per-method access flavour. Materialised on every cap method via codegen. */
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Per-user ACCOUNT preferences (D894): the hub-side half of the viewer's two
3
+ * settings levels.
4
+ *
5
+ * - DEVICE settings never leave the phone.
6
+ * - ACCOUNT settings live here: one row per `(user, namespace)`, private to
7
+ * that user, synced across every device signed in as them, last write wins
8
+ * unless the writer sends the revision it based its edit on.
9
+ *
10
+ * A setting lives in exactly ONE level; there are no overrides. The caller
11
+ * never names a user: the hub stamps the principal's own id, admin included.
12
+ *
13
+ * The contract the client codes against is the `preferences.*` tRPC router
14
+ * (`server/backend/src/api/core/preferences.router.ts`).
15
+ */
16
+ import { z } from 'zod';
17
+ /** `viewer.app`, `viewer.cameras`, `viewer.grids` … — lowercase, dot/dash separated. */
18
+ export declare const PREFERENCES_NAMESPACE_PATTERN: RegExp;
19
+ /** One row's value, measured as UTF-8 JSON. */
20
+ export declare const PREFERENCES_MAX_VALUE_BYTES: number;
21
+ /** Namespaces one user may hold. */
22
+ export declare const PREFERENCES_MAX_NAMESPACES = 32;
23
+ /** The opaque client id a writer stamps (`updatedByDevice`). */
24
+ export declare const PREFERENCES_MAX_DEVICE_ID_LENGTH = 64;
25
+ export declare const PreferenceNamespaceSchema: z.ZodString;
26
+ export type PreferenceNamespace = z.infer<typeof PreferenceNamespaceSchema>;
27
+ /** A namespace's value: a JSON object, opaque to the hub. */
28
+ export declare const PreferenceValueSchema: z.ZodRecord<z.ZodString, z.ZodUnknown>;
29
+ export type PreferenceValue = z.infer<typeof PreferenceValueSchema>;
30
+ export declare const PreferenceDeviceIdSchema: z.ZodString;
31
+ /** A stored row, as the owner reads it. */
32
+ export declare const PreferenceRowSchema: z.ZodObject<{
33
+ namespace: z.ZodString;
34
+ value: z.ZodRecord<z.ZodString, z.ZodUnknown>;
35
+ revision: z.ZodNumber;
36
+ updatedAt: z.ZodNumber;
37
+ updatedByDevice: z.ZodNullable<z.ZodString>;
38
+ }, z.core.$strip>;
39
+ export type PreferenceRow = z.infer<typeof PreferenceRowSchema>;
40
+ export declare const PreferencesGetInputSchema: z.ZodObject<{
41
+ namespaces: z.ZodOptional<z.ZodArray<z.ZodString>>;
42
+ }, z.core.$strip>;
43
+ export type PreferencesGetInput = z.infer<typeof PreferencesGetInputSchema>;
44
+ export declare const PreferencesGetOutputSchema: z.ZodObject<{
45
+ rows: z.ZodArray<z.ZodObject<{
46
+ namespace: z.ZodString;
47
+ value: z.ZodRecord<z.ZodString, z.ZodUnknown>;
48
+ revision: z.ZodNumber;
49
+ updatedAt: z.ZodNumber;
50
+ updatedByDevice: z.ZodNullable<z.ZodString>;
51
+ }, z.core.$strip>>;
52
+ }, z.core.$strip>;
53
+ export type PreferencesGetOutput = z.infer<typeof PreferencesGetOutputSchema>;
54
+ export declare const PreferencesPutInputSchema: z.ZodObject<{
55
+ namespace: z.ZodString;
56
+ value: z.ZodRecord<z.ZodString, z.ZodUnknown>;
57
+ baseRevision: z.ZodOptional<z.ZodNumber>;
58
+ deviceId: z.ZodOptional<z.ZodString>;
59
+ }, z.core.$strip>;
60
+ export type PreferencesPutInput = z.infer<typeof PreferencesPutInputSchema>;
61
+ export declare const PreferencesPutOutputSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
62
+ status: z.ZodLiteral<"saved">;
63
+ row: z.ZodObject<{
64
+ namespace: z.ZodString;
65
+ value: z.ZodRecord<z.ZodString, z.ZodUnknown>;
66
+ revision: z.ZodNumber;
67
+ updatedAt: z.ZodNumber;
68
+ updatedByDevice: z.ZodNullable<z.ZodString>;
69
+ }, z.core.$strip>;
70
+ }, z.core.$strip>, z.ZodObject<{
71
+ status: z.ZodLiteral<"conflict">;
72
+ current: z.ZodNullable<z.ZodObject<{
73
+ namespace: z.ZodString;
74
+ value: z.ZodRecord<z.ZodString, z.ZodUnknown>;
75
+ revision: z.ZodNumber;
76
+ updatedAt: z.ZodNumber;
77
+ updatedByDevice: z.ZodNullable<z.ZodString>;
78
+ }, z.core.$strip>>;
79
+ }, z.core.$strip>], "status">;
80
+ export type PreferencesPutOutput = z.infer<typeof PreferencesPutOutputSchema>;
81
+ export declare const PreferencesDeleteInputSchema: z.ZodObject<{
82
+ namespace: z.ZodString;
83
+ }, z.core.$strip>;
84
+ export type PreferencesDeleteInput = z.infer<typeof PreferencesDeleteInputSchema>;
85
+ export declare const PreferencesDeleteOutputSchema: z.ZodObject<{
86
+ deleted: z.ZodBoolean;
87
+ }, z.core.$strip>;
88
+ export type PreferencesDeleteOutput = z.infer<typeof PreferencesDeleteOutputSchema>;
89
+ export declare const PreferencesChangedSinceInputSchema: z.ZodObject<{
90
+ revisionByNamespace: z.ZodRecord<z.ZodString, z.ZodNumber>;
91
+ }, z.core.$strip>;
92
+ export type PreferencesChangedSinceInput = z.infer<typeof PreferencesChangedSinceInputSchema>;
93
+ export declare const PreferencesChangedSinceOutputSchema: z.ZodObject<{
94
+ rows: z.ZodArray<z.ZodObject<{
95
+ namespace: z.ZodString;
96
+ value: z.ZodRecord<z.ZodString, z.ZodUnknown>;
97
+ revision: z.ZodNumber;
98
+ updatedAt: z.ZodNumber;
99
+ updatedByDevice: z.ZodNullable<z.ZodString>;
100
+ }, z.core.$strip>>;
101
+ deleted: z.ZodArray<z.ZodString>;
102
+ }, z.core.$strip>;
103
+ export type PreferencesChangedSinceOutput = z.infer<typeof PreferencesChangedSinceOutputSchema>;
@@ -2804,9 +2804,9 @@ var DisposerChain = class {
2804
2804
  */
2805
2805
  var DATAPLANE_SECRET_HEADER = "x-camstack-dataplane-secret";
2806
2806
  /**
2807
- * The share-view scope kinds a `csv_*` share token can carry. The hub mints
2808
- * and validates them (`share-token.service.ts` builds its enum from this
2809
- * list); a data plane names the kinds it ACCEPTS in `share`.
2807
+ * The share-view scope kinds a share-link token can carry. The hub mints
2808
+ * and validates them (`ShareViewGrantSchema` builds its
2809
+ * enum from this list); a data plane names the kinds it ACCEPTS in `share`.
2810
2810
  */
2811
2811
  var SHARE_VIEW_KINDS = ["grid-view", "events-view"];
2812
2812
  //#endregion
@@ -4203,6 +4203,20 @@ function parseSettingsArrayAdoptsFrom(from) {
4203
4203
  function isRecord(value) {
4204
4204
  return typeof value === "object" && value !== null && !Array.isArray(value);
4205
4205
  }
4206
+ /** RFC 7396: objects merge key by key, `null` removes, anything else replaces. */
4207
+ function mergePatch(target, patch) {
4208
+ if (!isRecord(patch)) return target;
4209
+ const out = { ...target };
4210
+ for (const [key, value] of Object.entries(patch)) {
4211
+ if (value === null) {
4212
+ delete out[key];
4213
+ continue;
4214
+ }
4215
+ const current = out[key];
4216
+ out[key] = isRecord(value) && isRecord(current) ? mergePatch(current, value) : value;
4217
+ }
4218
+ return out;
4219
+ }
4206
4220
  function markersOf(decl, body) {
4207
4221
  const out = /* @__PURE__ */ new Map();
4208
4222
  mapSecretLeaves(body, decl.secretPaths, decl.secretArrayKeys, (leaf) => {
@@ -4384,7 +4398,20 @@ function makeInMemoryRecords(owner = "spec") {
4384
4398
  releasedRefs: released
4385
4399
  };
4386
4400
  },
4387
- patch: async () => unimplemented("patch"),
4401
+ patch: async ({ kind, id, data, at, ifRev }) => {
4402
+ const prev = table(kind).get(id);
4403
+ if (prev === void 0) throw new Error(`${kind}/${id}: no such record`);
4404
+ if (ifRev !== void 0 && prev.rev !== ifRev) throw new Error("stale ifRev");
4405
+ const { rev, released } = write(kind, {
4406
+ id,
4407
+ ...at !== void 0 && at !== null ? { at } : prev.at !== null ? { at: prev.at } : {},
4408
+ data: mergePatch(prev.data, data)
4409
+ });
4410
+ return {
4411
+ rev,
4412
+ releasedRefs: released
4413
+ };
4414
+ },
4388
4415
  delete: async ({ kind, id }) => {
4389
4416
  if (writesFail) throw new Error("records engine unreachable");
4390
4417
  const row = table(kind).get(id);
@@ -2804,9 +2804,9 @@ var DisposerChain = class {
2804
2804
  */
2805
2805
  var DATAPLANE_SECRET_HEADER = "x-camstack-dataplane-secret";
2806
2806
  /**
2807
- * The share-view scope kinds a `csv_*` share token can carry. The hub mints
2808
- * and validates them (`share-token.service.ts` builds its enum from this
2809
- * list); a data plane names the kinds it ACCEPTS in `share`.
2807
+ * The share-view scope kinds a share-link token can carry. The hub mints
2808
+ * and validates them (`ShareViewGrantSchema` builds its
2809
+ * enum from this list); a data plane names the kinds it ACCEPTS in `share`.
2810
2810
  */
2811
2811
  var SHARE_VIEW_KINDS = ["grid-view", "events-view"];
2812
2812
  //#endregion
@@ -4203,6 +4203,20 @@ function parseSettingsArrayAdoptsFrom(from) {
4203
4203
  function isRecord(value) {
4204
4204
  return typeof value === "object" && value !== null && !Array.isArray(value);
4205
4205
  }
4206
+ /** RFC 7396: objects merge key by key, `null` removes, anything else replaces. */
4207
+ function mergePatch(target, patch) {
4208
+ if (!isRecord(patch)) return target;
4209
+ const out = { ...target };
4210
+ for (const [key, value] of Object.entries(patch)) {
4211
+ if (value === null) {
4212
+ delete out[key];
4213
+ continue;
4214
+ }
4215
+ const current = out[key];
4216
+ out[key] = isRecord(value) && isRecord(current) ? mergePatch(current, value) : value;
4217
+ }
4218
+ return out;
4219
+ }
4206
4220
  function markersOf(decl, body) {
4207
4221
  const out = /* @__PURE__ */ new Map();
4208
4222
  mapSecretLeaves(body, decl.secretPaths, decl.secretArrayKeys, (leaf) => {
@@ -4384,7 +4398,20 @@ function makeInMemoryRecords(owner = "spec") {
4384
4398
  releasedRefs: released
4385
4399
  };
4386
4400
  },
4387
- patch: async () => unimplemented("patch"),
4401
+ patch: async ({ kind, id, data, at, ifRev }) => {
4402
+ const prev = table(kind).get(id);
4403
+ if (prev === void 0) throw new Error(`${kind}/${id}: no such record`);
4404
+ if (ifRev !== void 0 && prev.rev !== ifRev) throw new Error("stale ifRev");
4405
+ const { rev, released } = write(kind, {
4406
+ id,
4407
+ ...at !== void 0 && at !== null ? { at } : prev.at !== null ? { at: prev.at } : {},
4408
+ data: mergePatch(prev.data, data)
4409
+ });
4410
+ return {
4411
+ rev,
4412
+ releasedRefs: released
4413
+ };
4414
+ },
4388
4415
  delete: async ({ kind, id }) => {
4389
4416
  if (writesFail) throw new Error("records engine unreachable");
4390
4417
  const row = table(kind).get(id);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/types",
3
- "version": "1.2.386",
3
+ "version": "1.2.387",
4
4
  "description": "Shared types, interfaces, and model catalogs for the CamStack detection ecosystem",
5
5
  "keywords": [
6
6
  "camstack",