@camstack/addon-provider-tuya 0.2.41 → 0.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.
- package/dist/addon.js +154 -19
- package/dist/addon.mjs +154 -19
- package/package.json +1 -1
package/dist/addon.js
CHANGED
|
@@ -8859,18 +8859,61 @@ var RelocateFootageInputSchema = object({
|
|
|
8859
8859
|
* `RecordingConfig.enabled` or camera wrapper bindings. */
|
|
8860
8860
|
var StorageMigrationLeaseInputSchema = object({ leaseId: string().min(1) });
|
|
8861
8861
|
var StorageMigrationFootageMoveInputSchema = RelocateFootageInputSchema.extend({ leaseId: string().min(1) });
|
|
8862
|
+
/**
|
|
8863
|
+
* What a `relocateMedia` pass DOES. One engine, three passes — never a second
|
|
8864
|
+
* mover (the engine already walks both collections with a timestamp cursor and
|
|
8865
|
+
* already has a stamp-without-copy path).
|
|
8866
|
+
*
|
|
8867
|
+
* - `move` — the default and the historical behaviour: event-media and
|
|
8868
|
+
* retrain blobs move to `toLocationId` and their rows are
|
|
8869
|
+
* stamped. The enrolled gallery is skipped (D197).
|
|
8870
|
+
* - `seal` — ROWS ONLY, no bytes. Every row whose `locationId` is NULL is
|
|
8871
|
+
* stamped with `toLocationId`. `toLocationId` here is the id the
|
|
8872
|
+
* bytes ALREADY sit on — today's `eventMedia` default — because
|
|
8873
|
+
* a NULL row means "wherever `eventMedia` points *now*", and the
|
|
8874
|
+
* instant a repoint moves that pointer the row reads from the
|
|
8875
|
+
* new disk while its bytes are on the old one.
|
|
8876
|
+
* - `gallery` — the inverse selection of `move`: ONLY the retention-exempt
|
|
8877
|
+
* (enrolled-gallery) rows, which `move` deliberately skips.
|
|
8878
|
+
* `galleryMedia` is `cardinality: 'single'`, so this pass can
|
|
8879
|
+
* never run beside a live second location: it is stop-the-world
|
|
8880
|
+
* by construction, which is acceptable only because the gallery
|
|
8881
|
+
* is a few KB per enrolled sample.
|
|
8882
|
+
*/
|
|
8883
|
+
var MediaRelocateModeSchema = _enum([
|
|
8884
|
+
"move",
|
|
8885
|
+
"seal",
|
|
8886
|
+
"gallery"
|
|
8887
|
+
]);
|
|
8862
8888
|
var RelocateMediaInputSchema = object({
|
|
8863
8889
|
toLocationId: string(),
|
|
8864
|
-
throttleMbps: number().min(1).max(1e3).optional()
|
|
8890
|
+
throttleMbps: number().min(1).max(1e3).optional(),
|
|
8891
|
+
/** Omitted = `move`, the pre-existing behaviour. */
|
|
8892
|
+
mode: MediaRelocateModeSchema.optional()
|
|
8893
|
+
});
|
|
8894
|
+
/** How many rows still carry NO `locationId` — the population a repoint would
|
|
8895
|
+
* silently re-aim at a disk that does not hold their bytes. Zero is the only
|
|
8896
|
+
* value that permits a non-blocking `eventMedia` cutover. */
|
|
8897
|
+
var UnstampedEventMediaCountSchema = object({
|
|
8898
|
+
media: number().int().nonnegative(),
|
|
8899
|
+
retrainFrames: number().int().nonnegative(),
|
|
8900
|
+
total: number().int().nonnegative()
|
|
8865
8901
|
});
|
|
8866
8902
|
var StorageMigrationMediaMoveInputSchema = RelocateMediaInputSchema.extend({ leaseId: string().min(1) });
|
|
8867
|
-
/** The independently selectable logical storage classes
|
|
8868
|
-
*
|
|
8869
|
-
*
|
|
8903
|
+
/** The independently selectable logical storage classes — every class
|
|
8904
|
+
* `storage.listLocationDeclarations` reports, so an operator never meets a
|
|
8905
|
+
* Zod enum error where they should meet an explanation.
|
|
8906
|
+
*
|
|
8907
|
+
* `recordings` encompasses the high and mid segment profiles; `recordingsLow`
|
|
8908
|
+
* is low segments; `eventMedia` is post-analysis blobs; `galleryMedia` is the
|
|
8909
|
+
* enrolled gallery; `backups` is the system backup archive. The last two have
|
|
8910
|
+
* their own rules — see {@link StorageMigrationFindingCodeSchema}. */
|
|
8870
8911
|
var StorageMigrationClassSchema = _enum([
|
|
8871
8912
|
"recordings",
|
|
8872
8913
|
"recordingsLow",
|
|
8873
|
-
"eventMedia"
|
|
8914
|
+
"eventMedia",
|
|
8915
|
+
"backups",
|
|
8916
|
+
"galleryMedia"
|
|
8874
8917
|
]);
|
|
8875
8918
|
/** A destination is always an existing, fully-qualified location id. The
|
|
8876
8919
|
* migration API intentionally never changes a source location's `basePath`:
|
|
@@ -8878,20 +8921,56 @@ var StorageMigrationClassSchema = _enum([
|
|
|
8878
8921
|
var StorageMigrationDestinationsSchema = object({
|
|
8879
8922
|
recordings: string().min(1).optional(),
|
|
8880
8923
|
recordingsLow: string().min(1).optional(),
|
|
8881
|
-
eventMedia: string().min(1).optional()
|
|
8924
|
+
eventMedia: string().min(1).optional(),
|
|
8925
|
+
backups: string().min(1).optional(),
|
|
8926
|
+
galleryMedia: string().min(1).optional()
|
|
8882
8927
|
}).refine((value) => Object.keys(value).length > 0, { message: "select at least one storage class" });
|
|
8928
|
+
/**
|
|
8929
|
+
* How a migration sequences the cutover against the byte move.
|
|
8930
|
+
*
|
|
8931
|
+
* - `blocking` — the historical order: pause, move every byte, repoint,
|
|
8932
|
+
* resume. Recording is stopped for the whole move. Right
|
|
8933
|
+
* for a small or a cold class, and the only legal mode for
|
|
8934
|
+
* a `cardinality: 'single'` class.
|
|
8935
|
+
* - `nonBlocking` — repoint FIRST, drain behind: seal, pause, repoint,
|
|
8936
|
+
* refresh, resume, then move the past with everything
|
|
8937
|
+
* running. The pause is three bounded instants (a detach +
|
|
8938
|
+
* attach round, a write-gate drain, a lease) instead of one
|
|
8939
|
+
* bounded by bytes. 1.09 TB at 7–14 MB/s is thirty hours of
|
|
8940
|
+
* stopped recording under `blocking`; the same move is
|
|
8941
|
+
* seconds of stopped recording under `nonBlocking`.
|
|
8942
|
+
*
|
|
8943
|
+
* The mode is on the JOB, not only on the input, because `status` is where an
|
|
8944
|
+
* operator finds out which one is running.
|
|
8945
|
+
*/
|
|
8946
|
+
var StorageMigrationModeSchema = _enum(["blocking", "nonBlocking"]);
|
|
8883
8947
|
/** Shared input for planning and starting an orchestrated storage migration. */
|
|
8884
8948
|
var StorageMigrationInputSchema = object({
|
|
8885
8949
|
destinations: StorageMigrationDestinationsSchema,
|
|
8886
|
-
throttleMbps: number().min(1).max(1e3).optional()
|
|
8950
|
+
throttleMbps: number().min(1).max(1e3).optional(),
|
|
8951
|
+
/** Omitted = `blocking`, which stays the default. */
|
|
8952
|
+
mode: StorageMigrationModeSchema.optional()
|
|
8887
8953
|
});
|
|
8888
|
-
/**
|
|
8889
|
-
*
|
|
8890
|
-
*
|
|
8954
|
+
/**
|
|
8955
|
+
* The durable coordinator state machine.
|
|
8956
|
+
*
|
|
8957
|
+
* `blocking`:
|
|
8958
|
+
* planning → pausing → moving → verifying → repointing → refreshing → resuming → done
|
|
8959
|
+
*
|
|
8960
|
+
* `nonBlocking`:
|
|
8961
|
+
* planning → sealing → pausing → repointing → refreshing → resuming → draining → verifying → done
|
|
8962
|
+
*
|
|
8963
|
+
* Same phases, different order plus two new ones — not a second mover.
|
|
8964
|
+
* `sealing` closes the `eventMedia` NULL-row hole BEFORE anything is paused;
|
|
8965
|
+
* `draining` runs the same movers UNLEASED, after every writer is back up.
|
|
8966
|
+
* `repointing` is still the only phase that changes a default location.
|
|
8967
|
+
*/
|
|
8891
8968
|
var StorageMigrationPhaseSchema = _enum([
|
|
8892
8969
|
"planning",
|
|
8970
|
+
"sealing",
|
|
8893
8971
|
"pausing",
|
|
8894
8972
|
"moving",
|
|
8973
|
+
"draining",
|
|
8895
8974
|
"verifying",
|
|
8896
8975
|
"repointing",
|
|
8897
8976
|
"refreshing",
|
|
@@ -8916,6 +8995,9 @@ var StorageMigrationMoveSchema = object({
|
|
|
8916
8995
|
var StorageMigrationJobSchema = object({
|
|
8917
8996
|
jobId: string(),
|
|
8918
8997
|
phase: StorageMigrationPhaseSchema,
|
|
8998
|
+
/** Which order this job is running. `status` is the only place an operator
|
|
8999
|
+
* can tell a seconds-long cutover from a thirty-hour one. */
|
|
9000
|
+
mode: StorageMigrationModeSchema,
|
|
8919
9001
|
destinations: StorageMigrationDestinationsSchema,
|
|
8920
9002
|
throttleMbps: number(),
|
|
8921
9003
|
moves: array(StorageMigrationMoveSchema),
|
|
@@ -8928,13 +9010,30 @@ var StorageMigrationJobSchema = object({
|
|
|
8928
9010
|
finishedAt: number().nullable(),
|
|
8929
9011
|
error: string().nullable()
|
|
8930
9012
|
});
|
|
9013
|
+
var StorageMigrationFindingSchema = object({
|
|
9014
|
+
code: _enum([
|
|
9015
|
+
"sharesDeviceWithSource",
|
|
9016
|
+
"deviceIdentityUnknown",
|
|
9017
|
+
"unstampedEventMediaRows",
|
|
9018
|
+
"blockingOnly",
|
|
9019
|
+
"noMover"
|
|
9020
|
+
]),
|
|
9021
|
+
storageClass: StorageMigrationClassSchema,
|
|
9022
|
+
/** Human-readable, already carrying the ids and counts. */
|
|
9023
|
+
message: string()
|
|
9024
|
+
});
|
|
8931
9025
|
var StorageMigrationPlanSchema = object({
|
|
8932
9026
|
destinations: StorageMigrationDestinationsSchema,
|
|
9027
|
+
/** The mode this plan was built for. A plan is only valid for its mode: the
|
|
9028
|
+
* `eventMedia` seal gate and the single-cardinality refusal both depend on
|
|
9029
|
+
* it. */
|
|
9030
|
+
mode: StorageMigrationModeSchema,
|
|
8933
9031
|
moves: array(object({
|
|
8934
9032
|
storageClass: StorageMigrationClassSchema,
|
|
8935
9033
|
fromLocationId: string(),
|
|
8936
9034
|
toLocationId: string()
|
|
8937
|
-
}))
|
|
9035
|
+
})),
|
|
9036
|
+
findings: array(StorageMigrationFindingSchema)
|
|
8938
9037
|
});
|
|
8939
9038
|
/**
|
|
8940
9039
|
* `StorageLocationType` — an addon-declared id that identifies the *kind* of
|
|
@@ -19804,7 +19903,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
19804
19903
|
}), method(RelocateMediaInputSchema, object({ jobId: string() }), {
|
|
19805
19904
|
kind: "mutation",
|
|
19806
19905
|
auth: "admin"
|
|
19807
|
-
}), method(object({}), array(RelocateJobSchema).readonly(), {
|
|
19906
|
+
}), method(object({}), UnstampedEventMediaCountSchema, { auth: "admin" }), method(object({}), array(RelocateJobSchema).readonly(), {
|
|
19808
19907
|
kind: "query",
|
|
19809
19908
|
auth: "admin"
|
|
19810
19909
|
}), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
|
|
@@ -21711,7 +21810,10 @@ method(object({
|
|
|
21711
21810
|
}), StorageLocationSchema, {
|
|
21712
21811
|
kind: "mutation",
|
|
21713
21812
|
auth: "admin"
|
|
21714
|
-
}), method(object({
|
|
21813
|
+
}), method(object({
|
|
21814
|
+
id: string(),
|
|
21815
|
+
force: boolean().optional()
|
|
21816
|
+
}), _void(), {
|
|
21715
21817
|
kind: "mutation",
|
|
21716
21818
|
auth: "admin"
|
|
21717
21819
|
}), method(object({ id: string() }), object({
|
|
@@ -25787,6 +25889,33 @@ var intercomCapability = {
|
|
|
25787
25889
|
deviceNative: true,
|
|
25788
25890
|
mode: "singleton",
|
|
25789
25891
|
deviceTypes: [DeviceType.Camera],
|
|
25892
|
+
/**
|
|
25893
|
+
* **Auth tier: `protected` on every method — deliberate, and load-bearing.**
|
|
25894
|
+
*
|
|
25895
|
+
* Talking through a camera is an OPERATE action, not a CONFIGURE one. This
|
|
25896
|
+
* cap has no configuration surface at all: all six methods open, feed and
|
|
25897
|
+
* close one live audio session against one `deviceId`. That is the same
|
|
25898
|
+
* authority as `ptz.move` or `snapshot.getSnapshot`, both `protected` — and
|
|
25899
|
+
* the opposite of `ptz.savePreset` / `snapshot.invalidateCache`, which are
|
|
25900
|
+
* `admin` because they change what the device IS.
|
|
25901
|
+
*
|
|
25902
|
+
* `protected` does not mean ungated: `protectedProcedure` runs the
|
|
25903
|
+
* `METHOD_ACCESS_MAP` scope check, and every method here is `scope: 'device'`
|
|
25904
|
+
* with `access: 'create'` and a `deviceId` in its input. So a caller needs a
|
|
25905
|
+
* grant that covers THAT camera at `create` — a `camera-viewer` (`view`
|
|
25906
|
+
* only) still cannot talk, and a grant on camera 5 cannot talk through
|
|
25907
|
+
* camera 7.
|
|
25908
|
+
*
|
|
25909
|
+
* Every method was `auth: 'admin'` from the initial commit, which made the
|
|
25910
|
+
* cap unreachable by every non-admin principal — `adminProcedure` throws
|
|
25911
|
+
* `FORBIDDEN: Admin required` BEFORE the scope check runs, so the scope
|
|
25912
|
+
* machinery generated for this cap (`METHOD_ACCESS_MAP`,
|
|
25913
|
+
* `DEVICE_SCOPED_CAPS`, `METHOD_DEVICE_SELECTORS`) was complete and dead. The
|
|
25914
|
+
* `camera-operator` scope preset has promised "PTZ control, intercom,
|
|
25915
|
+
* snapshots" since that same commit; the promise could not be kept. Recorded
|
|
25916
|
+
* as D289; `scripts/check-scope-preset-promises.ts` now fails the build if a
|
|
25917
|
+
* preset promises a cap no row of that preset can reach.
|
|
25918
|
+
*/
|
|
25790
25919
|
methods: {
|
|
25791
25920
|
/**
|
|
25792
25921
|
* Open a server-side WebRTC audio-only session. Returns an SDP
|
|
@@ -25799,7 +25928,7 @@ var intercomCapability = {
|
|
|
25799
25928
|
sdpOffer: string()
|
|
25800
25929
|
}), {
|
|
25801
25930
|
kind: "mutation",
|
|
25802
|
-
auth: "
|
|
25931
|
+
auth: "protected"
|
|
25803
25932
|
}),
|
|
25804
25933
|
handleAnswer: method(object({
|
|
25805
25934
|
deviceId: number(),
|
|
@@ -25807,7 +25936,7 @@ var intercomCapability = {
|
|
|
25807
25936
|
sdpAnswer: string()
|
|
25808
25937
|
}), _void(), {
|
|
25809
25938
|
kind: "mutation",
|
|
25810
|
-
auth: "
|
|
25939
|
+
auth: "protected"
|
|
25811
25940
|
}),
|
|
25812
25941
|
/** Close explicitly. Server also auto-closes on 30s idle. */
|
|
25813
25942
|
stopSession: method(object({
|
|
@@ -25815,7 +25944,7 @@ var intercomCapability = {
|
|
|
25815
25944
|
sessionId: string()
|
|
25816
25945
|
}), _void(), {
|
|
25817
25946
|
kind: "mutation",
|
|
25818
|
-
auth: "
|
|
25947
|
+
auth: "protected"
|
|
25819
25948
|
}),
|
|
25820
25949
|
/**
|
|
25821
25950
|
* Open a raw-PCM talk session (no WebRTC SDP plumbing). Used by
|
|
@@ -25828,7 +25957,7 @@ var intercomCapability = {
|
|
|
25828
25957
|
*/
|
|
25829
25958
|
startTalkSession: method(object({ deviceId: number() }), object({ sessionId: string() }), {
|
|
25830
25959
|
kind: "mutation",
|
|
25831
|
-
auth: "
|
|
25960
|
+
auth: "protected"
|
|
25832
25961
|
}),
|
|
25833
25962
|
/**
|
|
25834
25963
|
* Push one chunk of talk-back audio onto the active talk session.
|
|
@@ -25863,12 +25992,12 @@ var intercomCapability = {
|
|
|
25863
25992
|
sequenceNumber: number().int()
|
|
25864
25993
|
}), object({ accepted: boolean() }), {
|
|
25865
25994
|
kind: "mutation",
|
|
25866
|
-
auth: "
|
|
25995
|
+
auth: "protected"
|
|
25867
25996
|
}),
|
|
25868
25997
|
/** Close the raw-PCM talk session. Idempotent. */
|
|
25869
25998
|
endTalkSession: method(object({ deviceId: number() }), _void(), {
|
|
25870
25999
|
kind: "mutation",
|
|
25871
|
-
auth: "
|
|
26000
|
+
auth: "protected"
|
|
25872
26001
|
})
|
|
25873
26002
|
},
|
|
25874
26003
|
events: { onStatusChanged: { data: object({
|
|
@@ -35549,6 +35678,12 @@ Object.freeze({
|
|
|
35549
35678
|
addonId: null,
|
|
35550
35679
|
access: "create"
|
|
35551
35680
|
},
|
|
35681
|
+
"pipelineAnalytics.countUnstampedEventMedia": {
|
|
35682
|
+
capName: "pipeline-analytics",
|
|
35683
|
+
capScope: "device",
|
|
35684
|
+
addonId: null,
|
|
35685
|
+
access: "view"
|
|
35686
|
+
},
|
|
35552
35687
|
"pipelineAnalytics.deleteDeviceEvents": {
|
|
35553
35688
|
capName: "pipeline-analytics",
|
|
35554
35689
|
capScope: "device",
|
package/dist/addon.mjs
CHANGED
|
@@ -8858,18 +8858,61 @@ var RelocateFootageInputSchema = object({
|
|
|
8858
8858
|
* `RecordingConfig.enabled` or camera wrapper bindings. */
|
|
8859
8859
|
var StorageMigrationLeaseInputSchema = object({ leaseId: string().min(1) });
|
|
8860
8860
|
var StorageMigrationFootageMoveInputSchema = RelocateFootageInputSchema.extend({ leaseId: string().min(1) });
|
|
8861
|
+
/**
|
|
8862
|
+
* What a `relocateMedia` pass DOES. One engine, three passes — never a second
|
|
8863
|
+
* mover (the engine already walks both collections with a timestamp cursor and
|
|
8864
|
+
* already has a stamp-without-copy path).
|
|
8865
|
+
*
|
|
8866
|
+
* - `move` — the default and the historical behaviour: event-media and
|
|
8867
|
+
* retrain blobs move to `toLocationId` and their rows are
|
|
8868
|
+
* stamped. The enrolled gallery is skipped (D197).
|
|
8869
|
+
* - `seal` — ROWS ONLY, no bytes. Every row whose `locationId` is NULL is
|
|
8870
|
+
* stamped with `toLocationId`. `toLocationId` here is the id the
|
|
8871
|
+
* bytes ALREADY sit on — today's `eventMedia` default — because
|
|
8872
|
+
* a NULL row means "wherever `eventMedia` points *now*", and the
|
|
8873
|
+
* instant a repoint moves that pointer the row reads from the
|
|
8874
|
+
* new disk while its bytes are on the old one.
|
|
8875
|
+
* - `gallery` — the inverse selection of `move`: ONLY the retention-exempt
|
|
8876
|
+
* (enrolled-gallery) rows, which `move` deliberately skips.
|
|
8877
|
+
* `galleryMedia` is `cardinality: 'single'`, so this pass can
|
|
8878
|
+
* never run beside a live second location: it is stop-the-world
|
|
8879
|
+
* by construction, which is acceptable only because the gallery
|
|
8880
|
+
* is a few KB per enrolled sample.
|
|
8881
|
+
*/
|
|
8882
|
+
var MediaRelocateModeSchema = _enum([
|
|
8883
|
+
"move",
|
|
8884
|
+
"seal",
|
|
8885
|
+
"gallery"
|
|
8886
|
+
]);
|
|
8861
8887
|
var RelocateMediaInputSchema = object({
|
|
8862
8888
|
toLocationId: string(),
|
|
8863
|
-
throttleMbps: number().min(1).max(1e3).optional()
|
|
8889
|
+
throttleMbps: number().min(1).max(1e3).optional(),
|
|
8890
|
+
/** Omitted = `move`, the pre-existing behaviour. */
|
|
8891
|
+
mode: MediaRelocateModeSchema.optional()
|
|
8892
|
+
});
|
|
8893
|
+
/** How many rows still carry NO `locationId` — the population a repoint would
|
|
8894
|
+
* silently re-aim at a disk that does not hold their bytes. Zero is the only
|
|
8895
|
+
* value that permits a non-blocking `eventMedia` cutover. */
|
|
8896
|
+
var UnstampedEventMediaCountSchema = object({
|
|
8897
|
+
media: number().int().nonnegative(),
|
|
8898
|
+
retrainFrames: number().int().nonnegative(),
|
|
8899
|
+
total: number().int().nonnegative()
|
|
8864
8900
|
});
|
|
8865
8901
|
var StorageMigrationMediaMoveInputSchema = RelocateMediaInputSchema.extend({ leaseId: string().min(1) });
|
|
8866
|
-
/** The independently selectable logical storage classes
|
|
8867
|
-
*
|
|
8868
|
-
*
|
|
8902
|
+
/** The independently selectable logical storage classes — every class
|
|
8903
|
+
* `storage.listLocationDeclarations` reports, so an operator never meets a
|
|
8904
|
+
* Zod enum error where they should meet an explanation.
|
|
8905
|
+
*
|
|
8906
|
+
* `recordings` encompasses the high and mid segment profiles; `recordingsLow`
|
|
8907
|
+
* is low segments; `eventMedia` is post-analysis blobs; `galleryMedia` is the
|
|
8908
|
+
* enrolled gallery; `backups` is the system backup archive. The last two have
|
|
8909
|
+
* their own rules — see {@link StorageMigrationFindingCodeSchema}. */
|
|
8869
8910
|
var StorageMigrationClassSchema = _enum([
|
|
8870
8911
|
"recordings",
|
|
8871
8912
|
"recordingsLow",
|
|
8872
|
-
"eventMedia"
|
|
8913
|
+
"eventMedia",
|
|
8914
|
+
"backups",
|
|
8915
|
+
"galleryMedia"
|
|
8873
8916
|
]);
|
|
8874
8917
|
/** A destination is always an existing, fully-qualified location id. The
|
|
8875
8918
|
* migration API intentionally never changes a source location's `basePath`:
|
|
@@ -8877,20 +8920,56 @@ var StorageMigrationClassSchema = _enum([
|
|
|
8877
8920
|
var StorageMigrationDestinationsSchema = object({
|
|
8878
8921
|
recordings: string().min(1).optional(),
|
|
8879
8922
|
recordingsLow: string().min(1).optional(),
|
|
8880
|
-
eventMedia: string().min(1).optional()
|
|
8923
|
+
eventMedia: string().min(1).optional(),
|
|
8924
|
+
backups: string().min(1).optional(),
|
|
8925
|
+
galleryMedia: string().min(1).optional()
|
|
8881
8926
|
}).refine((value) => Object.keys(value).length > 0, { message: "select at least one storage class" });
|
|
8927
|
+
/**
|
|
8928
|
+
* How a migration sequences the cutover against the byte move.
|
|
8929
|
+
*
|
|
8930
|
+
* - `blocking` — the historical order: pause, move every byte, repoint,
|
|
8931
|
+
* resume. Recording is stopped for the whole move. Right
|
|
8932
|
+
* for a small or a cold class, and the only legal mode for
|
|
8933
|
+
* a `cardinality: 'single'` class.
|
|
8934
|
+
* - `nonBlocking` — repoint FIRST, drain behind: seal, pause, repoint,
|
|
8935
|
+
* refresh, resume, then move the past with everything
|
|
8936
|
+
* running. The pause is three bounded instants (a detach +
|
|
8937
|
+
* attach round, a write-gate drain, a lease) instead of one
|
|
8938
|
+
* bounded by bytes. 1.09 TB at 7–14 MB/s is thirty hours of
|
|
8939
|
+
* stopped recording under `blocking`; the same move is
|
|
8940
|
+
* seconds of stopped recording under `nonBlocking`.
|
|
8941
|
+
*
|
|
8942
|
+
* The mode is on the JOB, not only on the input, because `status` is where an
|
|
8943
|
+
* operator finds out which one is running.
|
|
8944
|
+
*/
|
|
8945
|
+
var StorageMigrationModeSchema = _enum(["blocking", "nonBlocking"]);
|
|
8882
8946
|
/** Shared input for planning and starting an orchestrated storage migration. */
|
|
8883
8947
|
var StorageMigrationInputSchema = object({
|
|
8884
8948
|
destinations: StorageMigrationDestinationsSchema,
|
|
8885
|
-
throttleMbps: number().min(1).max(1e3).optional()
|
|
8949
|
+
throttleMbps: number().min(1).max(1e3).optional(),
|
|
8950
|
+
/** Omitted = `blocking`, which stays the default. */
|
|
8951
|
+
mode: StorageMigrationModeSchema.optional()
|
|
8886
8952
|
});
|
|
8887
|
-
/**
|
|
8888
|
-
*
|
|
8889
|
-
*
|
|
8953
|
+
/**
|
|
8954
|
+
* The durable coordinator state machine.
|
|
8955
|
+
*
|
|
8956
|
+
* `blocking`:
|
|
8957
|
+
* planning → pausing → moving → verifying → repointing → refreshing → resuming → done
|
|
8958
|
+
*
|
|
8959
|
+
* `nonBlocking`:
|
|
8960
|
+
* planning → sealing → pausing → repointing → refreshing → resuming → draining → verifying → done
|
|
8961
|
+
*
|
|
8962
|
+
* Same phases, different order plus two new ones — not a second mover.
|
|
8963
|
+
* `sealing` closes the `eventMedia` NULL-row hole BEFORE anything is paused;
|
|
8964
|
+
* `draining` runs the same movers UNLEASED, after every writer is back up.
|
|
8965
|
+
* `repointing` is still the only phase that changes a default location.
|
|
8966
|
+
*/
|
|
8890
8967
|
var StorageMigrationPhaseSchema = _enum([
|
|
8891
8968
|
"planning",
|
|
8969
|
+
"sealing",
|
|
8892
8970
|
"pausing",
|
|
8893
8971
|
"moving",
|
|
8972
|
+
"draining",
|
|
8894
8973
|
"verifying",
|
|
8895
8974
|
"repointing",
|
|
8896
8975
|
"refreshing",
|
|
@@ -8915,6 +8994,9 @@ var StorageMigrationMoveSchema = object({
|
|
|
8915
8994
|
var StorageMigrationJobSchema = object({
|
|
8916
8995
|
jobId: string(),
|
|
8917
8996
|
phase: StorageMigrationPhaseSchema,
|
|
8997
|
+
/** Which order this job is running. `status` is the only place an operator
|
|
8998
|
+
* can tell a seconds-long cutover from a thirty-hour one. */
|
|
8999
|
+
mode: StorageMigrationModeSchema,
|
|
8918
9000
|
destinations: StorageMigrationDestinationsSchema,
|
|
8919
9001
|
throttleMbps: number(),
|
|
8920
9002
|
moves: array(StorageMigrationMoveSchema),
|
|
@@ -8927,13 +9009,30 @@ var StorageMigrationJobSchema = object({
|
|
|
8927
9009
|
finishedAt: number().nullable(),
|
|
8928
9010
|
error: string().nullable()
|
|
8929
9011
|
});
|
|
9012
|
+
var StorageMigrationFindingSchema = object({
|
|
9013
|
+
code: _enum([
|
|
9014
|
+
"sharesDeviceWithSource",
|
|
9015
|
+
"deviceIdentityUnknown",
|
|
9016
|
+
"unstampedEventMediaRows",
|
|
9017
|
+
"blockingOnly",
|
|
9018
|
+
"noMover"
|
|
9019
|
+
]),
|
|
9020
|
+
storageClass: StorageMigrationClassSchema,
|
|
9021
|
+
/** Human-readable, already carrying the ids and counts. */
|
|
9022
|
+
message: string()
|
|
9023
|
+
});
|
|
8930
9024
|
var StorageMigrationPlanSchema = object({
|
|
8931
9025
|
destinations: StorageMigrationDestinationsSchema,
|
|
9026
|
+
/** The mode this plan was built for. A plan is only valid for its mode: the
|
|
9027
|
+
* `eventMedia` seal gate and the single-cardinality refusal both depend on
|
|
9028
|
+
* it. */
|
|
9029
|
+
mode: StorageMigrationModeSchema,
|
|
8932
9030
|
moves: array(object({
|
|
8933
9031
|
storageClass: StorageMigrationClassSchema,
|
|
8934
9032
|
fromLocationId: string(),
|
|
8935
9033
|
toLocationId: string()
|
|
8936
|
-
}))
|
|
9034
|
+
})),
|
|
9035
|
+
findings: array(StorageMigrationFindingSchema)
|
|
8937
9036
|
});
|
|
8938
9037
|
/**
|
|
8939
9038
|
* `StorageLocationType` — an addon-declared id that identifies the *kind* of
|
|
@@ -19803,7 +19902,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
19803
19902
|
}), method(RelocateMediaInputSchema, object({ jobId: string() }), {
|
|
19804
19903
|
kind: "mutation",
|
|
19805
19904
|
auth: "admin"
|
|
19806
|
-
}), method(object({}), array(RelocateJobSchema).readonly(), {
|
|
19905
|
+
}), method(object({}), UnstampedEventMediaCountSchema, { auth: "admin" }), method(object({}), array(RelocateJobSchema).readonly(), {
|
|
19807
19906
|
kind: "query",
|
|
19808
19907
|
auth: "admin"
|
|
19809
19908
|
}), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
|
|
@@ -21710,7 +21809,10 @@ method(object({
|
|
|
21710
21809
|
}), StorageLocationSchema, {
|
|
21711
21810
|
kind: "mutation",
|
|
21712
21811
|
auth: "admin"
|
|
21713
|
-
}), method(object({
|
|
21812
|
+
}), method(object({
|
|
21813
|
+
id: string(),
|
|
21814
|
+
force: boolean().optional()
|
|
21815
|
+
}), _void(), {
|
|
21714
21816
|
kind: "mutation",
|
|
21715
21817
|
auth: "admin"
|
|
21716
21818
|
}), method(object({ id: string() }), object({
|
|
@@ -25786,6 +25888,33 @@ var intercomCapability = {
|
|
|
25786
25888
|
deviceNative: true,
|
|
25787
25889
|
mode: "singleton",
|
|
25788
25890
|
deviceTypes: [DeviceType.Camera],
|
|
25891
|
+
/**
|
|
25892
|
+
* **Auth tier: `protected` on every method — deliberate, and load-bearing.**
|
|
25893
|
+
*
|
|
25894
|
+
* Talking through a camera is an OPERATE action, not a CONFIGURE one. This
|
|
25895
|
+
* cap has no configuration surface at all: all six methods open, feed and
|
|
25896
|
+
* close one live audio session against one `deviceId`. That is the same
|
|
25897
|
+
* authority as `ptz.move` or `snapshot.getSnapshot`, both `protected` — and
|
|
25898
|
+
* the opposite of `ptz.savePreset` / `snapshot.invalidateCache`, which are
|
|
25899
|
+
* `admin` because they change what the device IS.
|
|
25900
|
+
*
|
|
25901
|
+
* `protected` does not mean ungated: `protectedProcedure` runs the
|
|
25902
|
+
* `METHOD_ACCESS_MAP` scope check, and every method here is `scope: 'device'`
|
|
25903
|
+
* with `access: 'create'` and a `deviceId` in its input. So a caller needs a
|
|
25904
|
+
* grant that covers THAT camera at `create` — a `camera-viewer` (`view`
|
|
25905
|
+
* only) still cannot talk, and a grant on camera 5 cannot talk through
|
|
25906
|
+
* camera 7.
|
|
25907
|
+
*
|
|
25908
|
+
* Every method was `auth: 'admin'` from the initial commit, which made the
|
|
25909
|
+
* cap unreachable by every non-admin principal — `adminProcedure` throws
|
|
25910
|
+
* `FORBIDDEN: Admin required` BEFORE the scope check runs, so the scope
|
|
25911
|
+
* machinery generated for this cap (`METHOD_ACCESS_MAP`,
|
|
25912
|
+
* `DEVICE_SCOPED_CAPS`, `METHOD_DEVICE_SELECTORS`) was complete and dead. The
|
|
25913
|
+
* `camera-operator` scope preset has promised "PTZ control, intercom,
|
|
25914
|
+
* snapshots" since that same commit; the promise could not be kept. Recorded
|
|
25915
|
+
* as D289; `scripts/check-scope-preset-promises.ts` now fails the build if a
|
|
25916
|
+
* preset promises a cap no row of that preset can reach.
|
|
25917
|
+
*/
|
|
25789
25918
|
methods: {
|
|
25790
25919
|
/**
|
|
25791
25920
|
* Open a server-side WebRTC audio-only session. Returns an SDP
|
|
@@ -25798,7 +25927,7 @@ var intercomCapability = {
|
|
|
25798
25927
|
sdpOffer: string()
|
|
25799
25928
|
}), {
|
|
25800
25929
|
kind: "mutation",
|
|
25801
|
-
auth: "
|
|
25930
|
+
auth: "protected"
|
|
25802
25931
|
}),
|
|
25803
25932
|
handleAnswer: method(object({
|
|
25804
25933
|
deviceId: number(),
|
|
@@ -25806,7 +25935,7 @@ var intercomCapability = {
|
|
|
25806
25935
|
sdpAnswer: string()
|
|
25807
25936
|
}), _void(), {
|
|
25808
25937
|
kind: "mutation",
|
|
25809
|
-
auth: "
|
|
25938
|
+
auth: "protected"
|
|
25810
25939
|
}),
|
|
25811
25940
|
/** Close explicitly. Server also auto-closes on 30s idle. */
|
|
25812
25941
|
stopSession: method(object({
|
|
@@ -25814,7 +25943,7 @@ var intercomCapability = {
|
|
|
25814
25943
|
sessionId: string()
|
|
25815
25944
|
}), _void(), {
|
|
25816
25945
|
kind: "mutation",
|
|
25817
|
-
auth: "
|
|
25946
|
+
auth: "protected"
|
|
25818
25947
|
}),
|
|
25819
25948
|
/**
|
|
25820
25949
|
* Open a raw-PCM talk session (no WebRTC SDP plumbing). Used by
|
|
@@ -25827,7 +25956,7 @@ var intercomCapability = {
|
|
|
25827
25956
|
*/
|
|
25828
25957
|
startTalkSession: method(object({ deviceId: number() }), object({ sessionId: string() }), {
|
|
25829
25958
|
kind: "mutation",
|
|
25830
|
-
auth: "
|
|
25959
|
+
auth: "protected"
|
|
25831
25960
|
}),
|
|
25832
25961
|
/**
|
|
25833
25962
|
* Push one chunk of talk-back audio onto the active talk session.
|
|
@@ -25862,12 +25991,12 @@ var intercomCapability = {
|
|
|
25862
25991
|
sequenceNumber: number().int()
|
|
25863
25992
|
}), object({ accepted: boolean() }), {
|
|
25864
25993
|
kind: "mutation",
|
|
25865
|
-
auth: "
|
|
25994
|
+
auth: "protected"
|
|
25866
25995
|
}),
|
|
25867
25996
|
/** Close the raw-PCM talk session. Idempotent. */
|
|
25868
25997
|
endTalkSession: method(object({ deviceId: number() }), _void(), {
|
|
25869
25998
|
kind: "mutation",
|
|
25870
|
-
auth: "
|
|
25999
|
+
auth: "protected"
|
|
25871
26000
|
})
|
|
25872
26001
|
},
|
|
25873
26002
|
events: { onStatusChanged: { data: object({
|
|
@@ -35548,6 +35677,12 @@ Object.freeze({
|
|
|
35548
35677
|
addonId: null,
|
|
35549
35678
|
access: "create"
|
|
35550
35679
|
},
|
|
35680
|
+
"pipelineAnalytics.countUnstampedEventMedia": {
|
|
35681
|
+
capName: "pipeline-analytics",
|
|
35682
|
+
capScope: "device",
|
|
35683
|
+
addonId: null,
|
|
35684
|
+
access: "view"
|
|
35685
|
+
},
|
|
35551
35686
|
"pipelineAnalytics.deleteDeviceEvents": {
|
|
35552
35687
|
capName: "pipeline-analytics",
|
|
35553
35688
|
capScope: "device",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@camstack/addon-provider-tuya",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.43",
|
|
4
4
|
"description": "Tuya / Smart Life device-provider addon for CamStack — account-onboarded (Tuya IoT cloud fetch of device localKeys) + LOCAL DP control via the @apocaliss92/nodetuya encrypted-LAN client, exposing switch / water-heater-family kettle entities",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"camstack",
|