@camstack/addon-tailscale 1.2.42 → 1.2.43

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.
@@ -24,7 +24,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
24
24
  enumerable: true
25
25
  }) : target, mod));
26
26
  //#endregion
27
- const require_dist = require("../dist-XsZAD0zE.js");
27
+ const require_dist = require("../dist-Bzn0_Gfg.js");
28
28
  let node_child_process = require("node:child_process");
29
29
  let node_util = require("node:util");
30
30
  let node_fs = require("node:fs");
@@ -1,4 +1,4 @@
1
- import { a as EventCategory, i as BaseAddon, n as networkAccessCapability, r as BOOT_RECOVERY_BACKOFF_MS, t as meshNetworkCapability } from "../dist-D1h1qkz3.mjs";
1
+ import { a as EventCategory, i as BaseAddon, n as networkAccessCapability, r as BOOT_RECOVERY_BACKOFF_MS, t as meshNetworkCapability } from "../dist-cWp3ATn9.mjs";
2
2
  import { execFile, spawn } from "node:child_process";
3
3
  import { promisify } from "node:util";
4
4
  import * as fs from "node:fs";
@@ -8056,18 +8056,61 @@ var RelocateFootageInputSchema = object({
8056
8056
  * `RecordingConfig.enabled` or camera wrapper bindings. */
8057
8057
  var StorageMigrationLeaseInputSchema = object({ leaseId: string().min(1) });
8058
8058
  var StorageMigrationFootageMoveInputSchema = RelocateFootageInputSchema.extend({ leaseId: string().min(1) });
8059
+ /**
8060
+ * What a `relocateMedia` pass DOES. One engine, three passes — never a second
8061
+ * mover (the engine already walks both collections with a timestamp cursor and
8062
+ * already has a stamp-without-copy path).
8063
+ *
8064
+ * - `move` — the default and the historical behaviour: event-media and
8065
+ * retrain blobs move to `toLocationId` and their rows are
8066
+ * stamped. The enrolled gallery is skipped (D197).
8067
+ * - `seal` — ROWS ONLY, no bytes. Every row whose `locationId` is NULL is
8068
+ * stamped with `toLocationId`. `toLocationId` here is the id the
8069
+ * bytes ALREADY sit on — today's `eventMedia` default — because
8070
+ * a NULL row means "wherever `eventMedia` points *now*", and the
8071
+ * instant a repoint moves that pointer the row reads from the
8072
+ * new disk while its bytes are on the old one.
8073
+ * - `gallery` — the inverse selection of `move`: ONLY the retention-exempt
8074
+ * (enrolled-gallery) rows, which `move` deliberately skips.
8075
+ * `galleryMedia` is `cardinality: 'single'`, so this pass can
8076
+ * never run beside a live second location: it is stop-the-world
8077
+ * by construction, which is acceptable only because the gallery
8078
+ * is a few KB per enrolled sample.
8079
+ */
8080
+ var MediaRelocateModeSchema = _enum([
8081
+ "move",
8082
+ "seal",
8083
+ "gallery"
8084
+ ]);
8059
8085
  var RelocateMediaInputSchema = object({
8060
8086
  toLocationId: string(),
8061
- throttleMbps: number().min(1).max(1e3).optional()
8087
+ throttleMbps: number().min(1).max(1e3).optional(),
8088
+ /** Omitted = `move`, the pre-existing behaviour. */
8089
+ mode: MediaRelocateModeSchema.optional()
8090
+ });
8091
+ /** How many rows still carry NO `locationId` — the population a repoint would
8092
+ * silently re-aim at a disk that does not hold their bytes. Zero is the only
8093
+ * value that permits a non-blocking `eventMedia` cutover. */
8094
+ var UnstampedEventMediaCountSchema = object({
8095
+ media: number().int().nonnegative(),
8096
+ retrainFrames: number().int().nonnegative(),
8097
+ total: number().int().nonnegative()
8062
8098
  });
8063
8099
  var StorageMigrationMediaMoveInputSchema = RelocateMediaInputSchema.extend({ leaseId: string().min(1) });
8064
- /** The independently selectable logical storage classes. `recordings`
8065
- * encompasses the high and mid segment profiles; `recordingsLow` is low
8066
- * segments; `eventMedia` is post-analysis blobs. */
8100
+ /** The independently selectable logical storage classes — every class
8101
+ * `storage.listLocationDeclarations` reports, so an operator never meets a
8102
+ * Zod enum error where they should meet an explanation.
8103
+ *
8104
+ * `recordings` encompasses the high and mid segment profiles; `recordingsLow`
8105
+ * is low segments; `eventMedia` is post-analysis blobs; `galleryMedia` is the
8106
+ * enrolled gallery; `backups` is the system backup archive. The last two have
8107
+ * their own rules — see {@link StorageMigrationFindingCodeSchema}. */
8067
8108
  var StorageMigrationClassSchema = _enum([
8068
8109
  "recordings",
8069
8110
  "recordingsLow",
8070
- "eventMedia"
8111
+ "eventMedia",
8112
+ "backups",
8113
+ "galleryMedia"
8071
8114
  ]);
8072
8115
  /** A destination is always an existing, fully-qualified location id. The
8073
8116
  * migration API intentionally never changes a source location's `basePath`:
@@ -8075,20 +8118,56 @@ var StorageMigrationClassSchema = _enum([
8075
8118
  var StorageMigrationDestinationsSchema = object({
8076
8119
  recordings: string().min(1).optional(),
8077
8120
  recordingsLow: string().min(1).optional(),
8078
- eventMedia: string().min(1).optional()
8121
+ eventMedia: string().min(1).optional(),
8122
+ backups: string().min(1).optional(),
8123
+ galleryMedia: string().min(1).optional()
8079
8124
  }).refine((value) => Object.keys(value).length > 0, { message: "select at least one storage class" });
8125
+ /**
8126
+ * How a migration sequences the cutover against the byte move.
8127
+ *
8128
+ * - `blocking` — the historical order: pause, move every byte, repoint,
8129
+ * resume. Recording is stopped for the whole move. Right
8130
+ * for a small or a cold class, and the only legal mode for
8131
+ * a `cardinality: 'single'` class.
8132
+ * - `nonBlocking` — repoint FIRST, drain behind: seal, pause, repoint,
8133
+ * refresh, resume, then move the past with everything
8134
+ * running. The pause is three bounded instants (a detach +
8135
+ * attach round, a write-gate drain, a lease) instead of one
8136
+ * bounded by bytes. 1.09 TB at 7–14 MB/s is thirty hours of
8137
+ * stopped recording under `blocking`; the same move is
8138
+ * seconds of stopped recording under `nonBlocking`.
8139
+ *
8140
+ * The mode is on the JOB, not only on the input, because `status` is where an
8141
+ * operator finds out which one is running.
8142
+ */
8143
+ var StorageMigrationModeSchema = _enum(["blocking", "nonBlocking"]);
8080
8144
  /** Shared input for planning and starting an orchestrated storage migration. */
8081
8145
  var StorageMigrationInputSchema = object({
8082
8146
  destinations: StorageMigrationDestinationsSchema,
8083
- throttleMbps: number().min(1).max(1e3).optional()
8147
+ throttleMbps: number().min(1).max(1e3).optional(),
8148
+ /** Omitted = `blocking`, which stays the default. */
8149
+ mode: StorageMigrationModeSchema.optional()
8084
8150
  });
8085
- /** The durable coordinator state machine. The only phase that changes default
8086
- * locations is `repointing`, after every selected mover has completed and been
8087
- * verified. */
8151
+ /**
8152
+ * The durable coordinator state machine.
8153
+ *
8154
+ * `blocking`:
8155
+ * planning → pausing → moving → verifying → repointing → refreshing → resuming → done
8156
+ *
8157
+ * `nonBlocking`:
8158
+ * planning → sealing → pausing → repointing → refreshing → resuming → draining → verifying → done
8159
+ *
8160
+ * Same phases, different order plus two new ones — not a second mover.
8161
+ * `sealing` closes the `eventMedia` NULL-row hole BEFORE anything is paused;
8162
+ * `draining` runs the same movers UNLEASED, after every writer is back up.
8163
+ * `repointing` is still the only phase that changes a default location.
8164
+ */
8088
8165
  var StorageMigrationPhaseSchema = _enum([
8089
8166
  "planning",
8167
+ "sealing",
8090
8168
  "pausing",
8091
8169
  "moving",
8170
+ "draining",
8092
8171
  "verifying",
8093
8172
  "repointing",
8094
8173
  "refreshing",
@@ -8113,6 +8192,9 @@ var StorageMigrationMoveSchema = object({
8113
8192
  var StorageMigrationJobSchema = object({
8114
8193
  jobId: string(),
8115
8194
  phase: StorageMigrationPhaseSchema,
8195
+ /** Which order this job is running. `status` is the only place an operator
8196
+ * can tell a seconds-long cutover from a thirty-hour one. */
8197
+ mode: StorageMigrationModeSchema,
8116
8198
  destinations: StorageMigrationDestinationsSchema,
8117
8199
  throttleMbps: number(),
8118
8200
  moves: array(StorageMigrationMoveSchema),
@@ -8125,13 +8207,30 @@ var StorageMigrationJobSchema = object({
8125
8207
  finishedAt: number().nullable(),
8126
8208
  error: string().nullable()
8127
8209
  });
8210
+ var StorageMigrationFindingSchema = object({
8211
+ code: _enum([
8212
+ "sharesDeviceWithSource",
8213
+ "deviceIdentityUnknown",
8214
+ "unstampedEventMediaRows",
8215
+ "blockingOnly",
8216
+ "noMover"
8217
+ ]),
8218
+ storageClass: StorageMigrationClassSchema,
8219
+ /** Human-readable, already carrying the ids and counts. */
8220
+ message: string()
8221
+ });
8128
8222
  var StorageMigrationPlanSchema = object({
8129
8223
  destinations: StorageMigrationDestinationsSchema,
8224
+ /** The mode this plan was built for. A plan is only valid for its mode: the
8225
+ * `eventMedia` seal gate and the single-cardinality refusal both depend on
8226
+ * it. */
8227
+ mode: StorageMigrationModeSchema,
8130
8228
  moves: array(object({
8131
8229
  storageClass: StorageMigrationClassSchema,
8132
8230
  fromLocationId: string(),
8133
8231
  toLocationId: string()
8134
- }))
8232
+ })),
8233
+ findings: array(StorageMigrationFindingSchema)
8135
8234
  });
8136
8235
  /**
8137
8236
  * `StorageLocationType` — an addon-declared id that identifies the *kind* of
@@ -18659,7 +18758,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
18659
18758
  }), method(RelocateMediaInputSchema, object({ jobId: string() }), {
18660
18759
  kind: "mutation",
18661
18760
  auth: "admin"
18662
- }), method(object({}), array(RelocateJobSchema).readonly(), {
18761
+ }), method(object({}), UnstampedEventMediaCountSchema, { auth: "admin" }), method(object({}), array(RelocateJobSchema).readonly(), {
18663
18762
  kind: "query",
18664
18763
  auth: "admin"
18665
18764
  }), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
@@ -20566,7 +20665,10 @@ method(object({
20566
20665
  }), StorageLocationSchema, {
20567
20666
  kind: "mutation",
20568
20667
  auth: "admin"
20569
- }), method(object({ id: string() }), _void(), {
20668
+ }), method(object({
20669
+ id: string(),
20670
+ force: boolean().optional()
20671
+ }), _void(), {
20570
20672
  kind: "mutation",
20571
20673
  auth: "admin"
20572
20674
  }), method(object({ id: string() }), object({
@@ -31100,6 +31202,12 @@ Object.freeze({
31100
31202
  addonId: null,
31101
31203
  access: "create"
31102
31204
  },
31205
+ "pipelineAnalytics.countUnstampedEventMedia": {
31206
+ capName: "pipeline-analytics",
31207
+ capScope: "device",
31208
+ addonId: null,
31209
+ access: "view"
31210
+ },
31103
31211
  "pipelineAnalytics.deleteDeviceEvents": {
31104
31212
  capName: "pipeline-analytics",
31105
31213
  capScope: "device",
@@ -8056,18 +8056,61 @@ var RelocateFootageInputSchema = object({
8056
8056
  * `RecordingConfig.enabled` or camera wrapper bindings. */
8057
8057
  var StorageMigrationLeaseInputSchema = object({ leaseId: string().min(1) });
8058
8058
  var StorageMigrationFootageMoveInputSchema = RelocateFootageInputSchema.extend({ leaseId: string().min(1) });
8059
+ /**
8060
+ * What a `relocateMedia` pass DOES. One engine, three passes — never a second
8061
+ * mover (the engine already walks both collections with a timestamp cursor and
8062
+ * already has a stamp-without-copy path).
8063
+ *
8064
+ * - `move` — the default and the historical behaviour: event-media and
8065
+ * retrain blobs move to `toLocationId` and their rows are
8066
+ * stamped. The enrolled gallery is skipped (D197).
8067
+ * - `seal` — ROWS ONLY, no bytes. Every row whose `locationId` is NULL is
8068
+ * stamped with `toLocationId`. `toLocationId` here is the id the
8069
+ * bytes ALREADY sit on — today's `eventMedia` default — because
8070
+ * a NULL row means "wherever `eventMedia` points *now*", and the
8071
+ * instant a repoint moves that pointer the row reads from the
8072
+ * new disk while its bytes are on the old one.
8073
+ * - `gallery` — the inverse selection of `move`: ONLY the retention-exempt
8074
+ * (enrolled-gallery) rows, which `move` deliberately skips.
8075
+ * `galleryMedia` is `cardinality: 'single'`, so this pass can
8076
+ * never run beside a live second location: it is stop-the-world
8077
+ * by construction, which is acceptable only because the gallery
8078
+ * is a few KB per enrolled sample.
8079
+ */
8080
+ var MediaRelocateModeSchema = _enum([
8081
+ "move",
8082
+ "seal",
8083
+ "gallery"
8084
+ ]);
8059
8085
  var RelocateMediaInputSchema = object({
8060
8086
  toLocationId: string(),
8061
- throttleMbps: number().min(1).max(1e3).optional()
8087
+ throttleMbps: number().min(1).max(1e3).optional(),
8088
+ /** Omitted = `move`, the pre-existing behaviour. */
8089
+ mode: MediaRelocateModeSchema.optional()
8090
+ });
8091
+ /** How many rows still carry NO `locationId` — the population a repoint would
8092
+ * silently re-aim at a disk that does not hold their bytes. Zero is the only
8093
+ * value that permits a non-blocking `eventMedia` cutover. */
8094
+ var UnstampedEventMediaCountSchema = object({
8095
+ media: number().int().nonnegative(),
8096
+ retrainFrames: number().int().nonnegative(),
8097
+ total: number().int().nonnegative()
8062
8098
  });
8063
8099
  var StorageMigrationMediaMoveInputSchema = RelocateMediaInputSchema.extend({ leaseId: string().min(1) });
8064
- /** The independently selectable logical storage classes. `recordings`
8065
- * encompasses the high and mid segment profiles; `recordingsLow` is low
8066
- * segments; `eventMedia` is post-analysis blobs. */
8100
+ /** The independently selectable logical storage classes — every class
8101
+ * `storage.listLocationDeclarations` reports, so an operator never meets a
8102
+ * Zod enum error where they should meet an explanation.
8103
+ *
8104
+ * `recordings` encompasses the high and mid segment profiles; `recordingsLow`
8105
+ * is low segments; `eventMedia` is post-analysis blobs; `galleryMedia` is the
8106
+ * enrolled gallery; `backups` is the system backup archive. The last two have
8107
+ * their own rules — see {@link StorageMigrationFindingCodeSchema}. */
8067
8108
  var StorageMigrationClassSchema = _enum([
8068
8109
  "recordings",
8069
8110
  "recordingsLow",
8070
- "eventMedia"
8111
+ "eventMedia",
8112
+ "backups",
8113
+ "galleryMedia"
8071
8114
  ]);
8072
8115
  /** A destination is always an existing, fully-qualified location id. The
8073
8116
  * migration API intentionally never changes a source location's `basePath`:
@@ -8075,20 +8118,56 @@ var StorageMigrationClassSchema = _enum([
8075
8118
  var StorageMigrationDestinationsSchema = object({
8076
8119
  recordings: string().min(1).optional(),
8077
8120
  recordingsLow: string().min(1).optional(),
8078
- eventMedia: string().min(1).optional()
8121
+ eventMedia: string().min(1).optional(),
8122
+ backups: string().min(1).optional(),
8123
+ galleryMedia: string().min(1).optional()
8079
8124
  }).refine((value) => Object.keys(value).length > 0, { message: "select at least one storage class" });
8125
+ /**
8126
+ * How a migration sequences the cutover against the byte move.
8127
+ *
8128
+ * - `blocking` — the historical order: pause, move every byte, repoint,
8129
+ * resume. Recording is stopped for the whole move. Right
8130
+ * for a small or a cold class, and the only legal mode for
8131
+ * a `cardinality: 'single'` class.
8132
+ * - `nonBlocking` — repoint FIRST, drain behind: seal, pause, repoint,
8133
+ * refresh, resume, then move the past with everything
8134
+ * running. The pause is three bounded instants (a detach +
8135
+ * attach round, a write-gate drain, a lease) instead of one
8136
+ * bounded by bytes. 1.09 TB at 7–14 MB/s is thirty hours of
8137
+ * stopped recording under `blocking`; the same move is
8138
+ * seconds of stopped recording under `nonBlocking`.
8139
+ *
8140
+ * The mode is on the JOB, not only on the input, because `status` is where an
8141
+ * operator finds out which one is running.
8142
+ */
8143
+ var StorageMigrationModeSchema = _enum(["blocking", "nonBlocking"]);
8080
8144
  /** Shared input for planning and starting an orchestrated storage migration. */
8081
8145
  var StorageMigrationInputSchema = object({
8082
8146
  destinations: StorageMigrationDestinationsSchema,
8083
- throttleMbps: number().min(1).max(1e3).optional()
8147
+ throttleMbps: number().min(1).max(1e3).optional(),
8148
+ /** Omitted = `blocking`, which stays the default. */
8149
+ mode: StorageMigrationModeSchema.optional()
8084
8150
  });
8085
- /** The durable coordinator state machine. The only phase that changes default
8086
- * locations is `repointing`, after every selected mover has completed and been
8087
- * verified. */
8151
+ /**
8152
+ * The durable coordinator state machine.
8153
+ *
8154
+ * `blocking`:
8155
+ * planning → pausing → moving → verifying → repointing → refreshing → resuming → done
8156
+ *
8157
+ * `nonBlocking`:
8158
+ * planning → sealing → pausing → repointing → refreshing → resuming → draining → verifying → done
8159
+ *
8160
+ * Same phases, different order plus two new ones — not a second mover.
8161
+ * `sealing` closes the `eventMedia` NULL-row hole BEFORE anything is paused;
8162
+ * `draining` runs the same movers UNLEASED, after every writer is back up.
8163
+ * `repointing` is still the only phase that changes a default location.
8164
+ */
8088
8165
  var StorageMigrationPhaseSchema = _enum([
8089
8166
  "planning",
8167
+ "sealing",
8090
8168
  "pausing",
8091
8169
  "moving",
8170
+ "draining",
8092
8171
  "verifying",
8093
8172
  "repointing",
8094
8173
  "refreshing",
@@ -8113,6 +8192,9 @@ var StorageMigrationMoveSchema = object({
8113
8192
  var StorageMigrationJobSchema = object({
8114
8193
  jobId: string(),
8115
8194
  phase: StorageMigrationPhaseSchema,
8195
+ /** Which order this job is running. `status` is the only place an operator
8196
+ * can tell a seconds-long cutover from a thirty-hour one. */
8197
+ mode: StorageMigrationModeSchema,
8116
8198
  destinations: StorageMigrationDestinationsSchema,
8117
8199
  throttleMbps: number(),
8118
8200
  moves: array(StorageMigrationMoveSchema),
@@ -8125,13 +8207,30 @@ var StorageMigrationJobSchema = object({
8125
8207
  finishedAt: number().nullable(),
8126
8208
  error: string().nullable()
8127
8209
  });
8210
+ var StorageMigrationFindingSchema = object({
8211
+ code: _enum([
8212
+ "sharesDeviceWithSource",
8213
+ "deviceIdentityUnknown",
8214
+ "unstampedEventMediaRows",
8215
+ "blockingOnly",
8216
+ "noMover"
8217
+ ]),
8218
+ storageClass: StorageMigrationClassSchema,
8219
+ /** Human-readable, already carrying the ids and counts. */
8220
+ message: string()
8221
+ });
8128
8222
  var StorageMigrationPlanSchema = object({
8129
8223
  destinations: StorageMigrationDestinationsSchema,
8224
+ /** The mode this plan was built for. A plan is only valid for its mode: the
8225
+ * `eventMedia` seal gate and the single-cardinality refusal both depend on
8226
+ * it. */
8227
+ mode: StorageMigrationModeSchema,
8130
8228
  moves: array(object({
8131
8229
  storageClass: StorageMigrationClassSchema,
8132
8230
  fromLocationId: string(),
8133
8231
  toLocationId: string()
8134
- }))
8232
+ })),
8233
+ findings: array(StorageMigrationFindingSchema)
8135
8234
  });
8136
8235
  /**
8137
8236
  * `StorageLocationType` — an addon-declared id that identifies the *kind* of
@@ -18659,7 +18758,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
18659
18758
  }), method(RelocateMediaInputSchema, object({ jobId: string() }), {
18660
18759
  kind: "mutation",
18661
18760
  auth: "admin"
18662
- }), method(object({}), array(RelocateJobSchema).readonly(), {
18761
+ }), method(object({}), UnstampedEventMediaCountSchema, { auth: "admin" }), method(object({}), array(RelocateJobSchema).readonly(), {
18663
18762
  kind: "query",
18664
18763
  auth: "admin"
18665
18764
  }), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
@@ -20566,7 +20665,10 @@ method(object({
20566
20665
  }), StorageLocationSchema, {
20567
20666
  kind: "mutation",
20568
20667
  auth: "admin"
20569
- }), method(object({ id: string() }), _void(), {
20668
+ }), method(object({
20669
+ id: string(),
20670
+ force: boolean().optional()
20671
+ }), _void(), {
20570
20672
  kind: "mutation",
20571
20673
  auth: "admin"
20572
20674
  }), method(object({ id: string() }), object({
@@ -31100,6 +31202,12 @@ Object.freeze({
31100
31202
  addonId: null,
31101
31203
  access: "create"
31102
31204
  },
31205
+ "pipelineAnalytics.countUnstampedEventMedia": {
31206
+ capName: "pipeline-analytics",
31207
+ capScope: "device",
31208
+ addonId: null,
31209
+ access: "view"
31210
+ },
31103
31211
  "pipelineAnalytics.deleteDeviceEvents": {
31104
31212
  capName: "pipeline-analytics",
31105
31213
  capScope: "device",
@@ -2,7 +2,7 @@ Object.defineProperties(exports, {
2
2
  __esModule: { value: true },
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
- const require_dist = require("../dist-XsZAD0zE.js");
5
+ const require_dist = require("../dist-Bzn0_Gfg.js");
6
6
  let node_crypto = require("node:crypto");
7
7
  let node_child_process = require("node:child_process");
8
8
  //#region src/ingress/tailscale-cli.ts
@@ -1,4 +1,4 @@
1
- import { a as EventCategory, i as BaseAddon, n as networkAccessCapability } from "../dist-D1h1qkz3.mjs";
1
+ import { a as EventCategory, i as BaseAddon, n as networkAccessCapability } from "../dist-cWp3ATn9.mjs";
2
2
  import { randomUUID } from "node:crypto";
3
3
  import { execFile } from "node:child_process";
4
4
  import { promisify } from "node:util";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-tailscale",
3
- "version": "1.2.42",
3
+ "version": "1.2.43",
4
4
  "description": "Tailscale bundle for CamStack — joins the host to a tailnet (client) and exposes the hub via Serve/Funnel (ingress). Multi-entry npm package shipping 2 addons under a single bundle.",
5
5
  "keywords": [
6
6
  "camstack",