@camstack/types 1.2.361 → 1.2.363

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/index.js CHANGED
@@ -8326,6 +8326,570 @@ var authProviderCapability = {
8326
8326
  mount: { kind: "skip" }
8327
8327
  };
8328
8328
  //#endregion
8329
+ //#region src/capabilities/settings-store.cap.ts
8330
+ /**
8331
+ * Query filter for settings-store collections.
8332
+ */
8333
+ var QueryFilterSchema = zod.z.object({
8334
+ where: zod.z.record(zod.z.string(), zod.z.unknown()).optional(),
8335
+ whereIn: zod.z.record(zod.z.string(), zod.z.array(zod.z.unknown())).optional(),
8336
+ whereBetween: zod.z.record(zod.z.string(), zod.z.tuple([zod.z.unknown(), zod.z.unknown()])).optional(),
8337
+ /** NULL-safe exclusion: matches rows whose field is NULL OR != the value. */
8338
+ whereNot: zod.z.record(zod.z.string(), zod.z.unknown()).optional(),
8339
+ /** NULL-safe exclusion of a SET — `whereNot` for more than one value. An
8340
+ * empty list excludes nothing. See `QueryFilter.whereNotIn`. */
8341
+ whereNotIn: zod.z.record(zod.z.string(), zod.z.array(zod.z.unknown())).optional(),
8342
+ orderBy: zod.z.object({
8343
+ field: zod.z.string(),
8344
+ direction: zod.z.enum(["asc", "desc"])
8345
+ }).optional(),
8346
+ limit: zod.z.number().optional(),
8347
+ offset: zod.z.number().optional()
8348
+ });
8349
+ /**
8350
+ * The predicate half of a filter, for BULK MUTATIONS.
8351
+ *
8352
+ * Deliberately not `QueryFilterSchema`: `orderBy` / `limit` / `offset` have no
8353
+ * meaning for a statement that rewrites a set, and accepting them would invite
8354
+ * a caller to believe `limit` bounds the damage. Every field is optional here
8355
+ * only so the shape stays composable — the implementation REJECTS a filter
8356
+ * that compiles to no predicate, because that is the whole collection.
8357
+ */
8358
+ var MutationFilterSchema = zod.z.object({
8359
+ where: zod.z.record(zod.z.string(), zod.z.unknown()).optional(),
8360
+ whereIn: zod.z.record(zod.z.string(), zod.z.array(zod.z.unknown())).optional(),
8361
+ whereBetween: zod.z.record(zod.z.string(), zod.z.tuple([zod.z.unknown(), zod.z.unknown()])).optional(),
8362
+ whereNot: zod.z.record(zod.z.string(), zod.z.unknown()).optional(),
8363
+ whereNotIn: zod.z.record(zod.z.string(), zod.z.array(zod.z.unknown())).optional()
8364
+ });
8365
+ /**
8366
+ * One scalar an {@link settingsStoreCapability.methods.aggregate} call asks for.
8367
+ *
8368
+ * `as` names the slot in the result, so the SAME column may be asked twice with
8369
+ * two operations (`MIN(startMs)` and `MAX(startMs)` in one round trip) — which
8370
+ * a `Record<column, op>` shape could not express.
8371
+ */
8372
+ var AggregateFieldSchema = zod.z.object({
8373
+ /** Result key. */
8374
+ as: zod.z.string().min(1),
8375
+ /** Column to aggregate. Must be a real column of a declared collection. */
8376
+ field: zod.z.string().min(1),
8377
+ op: zod.z.enum([
8378
+ "sum",
8379
+ "min",
8380
+ "max"
8381
+ ])
8382
+ });
8383
+ /**
8384
+ * `COUNT(*)` plus one number per requested field.
8385
+ *
8386
+ * `null` means NO ROW MATCHED, never zero: a `SUM` over an empty set and a sum
8387
+ * that really is 0 are different facts, and an accounting caller that renders
8388
+ * "0 bytes, oldest = 0" for "nothing here" reports a lie about a disk.
8389
+ */
8390
+ var AggregateResultSchema = zod.z.object({
8391
+ count: zod.z.number().int(),
8392
+ values: zod.z.record(zod.z.string(), zod.z.number().nullable())
8393
+ });
8394
+ /** A single stored record: `{ id, data }`. */
8395
+ var SettingsRecordSchema = zod.z.object({
8396
+ id: zod.z.string(),
8397
+ data: zod.z.record(zod.z.string(), zod.z.unknown())
8398
+ });
8399
+ /**
8400
+ * One record of a BULK insert — {@link SettingsRecordSchema} with the id made
8401
+ * optional.
8402
+ *
8403
+ * A separate schema rather than loosening the shared one: every other method
8404
+ * on this cap addresses a row BY its id, and making that field optional
8405
+ * everywhere would turn a forgotten key into a silently generated one on
8406
+ * `update` and `delete` as well.
8407
+ */
8408
+ var BulkRecordSchema = zod.z.object({
8409
+ id: zod.z.string().optional(),
8410
+ data: zod.z.record(zod.z.string(), zod.z.unknown())
8411
+ });
8412
+ /**
8413
+ * The database FILES one `sqlite-settings` engine process owns (D851).
8414
+ * Closed on purpose: a file is a thing the engine opens, backs up and gives a
8415
+ * serving thread, so a new one is a code change, never a string a caller
8416
+ * invents. `settings` is `camstack.db` and the default for every collection
8417
+ * that names no file.
8418
+ */
8419
+ var DataStoreDatabaseSchema = zod.z.enum([
8420
+ "settings",
8421
+ "events",
8422
+ "history"
8423
+ ]);
8424
+ /** Every database file, in a stable order (settings first). */
8425
+ var DATA_STORE_DATABASES = DataStoreDatabaseSchema.options;
8426
+ /**
8427
+ * One write inside a {@link settingsStoreCapability.methods.transact} call.
8428
+ * The three that a "replace this set, bump that revision" write needs, plus
8429
+ * the batched upsert a rollup writer needs.
8430
+ */
8431
+ var TransactOpSchema = zod.z.discriminatedUnion("op", [
8432
+ zod.z.object({
8433
+ op: zod.z.literal("deleteWhere"),
8434
+ collection: zod.z.string(),
8435
+ filter: MutationFilterSchema
8436
+ }),
8437
+ zod.z.object({
8438
+ op: zod.z.literal("insertMany"),
8439
+ collection: zod.z.string(),
8440
+ records: zod.z.array(BulkRecordSchema).readonly()
8441
+ }),
8442
+ zod.z.object({
8443
+ op: zod.z.literal("update"),
8444
+ collection: zod.z.string(),
8445
+ id: zod.z.string(),
8446
+ data: zod.z.record(zod.z.string(), zod.z.unknown())
8447
+ }),
8448
+ zod.z.object({
8449
+ op: zod.z.literal("upsertMany"),
8450
+ collection: zod.z.string(),
8451
+ conflict: zod.z.array(zod.z.string()).readonly(),
8452
+ records: zod.z.array(BulkRecordSchema).readonly()
8453
+ })
8454
+ ]);
8455
+ /**
8456
+ * The precondition of a transaction: the row `key` of `collection` must hold
8457
+ * `equals` in `column`, read INSIDE the transaction.
8458
+ */
8459
+ var TransactGuardSchema = zod.z.object({
8460
+ collection: zod.z.string(),
8461
+ key: zod.z.string(),
8462
+ column: zod.z.string(),
8463
+ equals: zod.z.unknown()
8464
+ });
8465
+ /**
8466
+ * Column declaration for a structured (SQL-backed) collection.
8467
+ *
8468
+ * Logical types — the backend translates each to the matching SQLite
8469
+ * storage class and handles per-type marshaling:
8470
+ * - `TEXT` / `INTEGER` / `REAL` — native SQLite types, pass-through
8471
+ * - `JSON` — TEXT under the hood; serialised on write, parsed on read
8472
+ * - `BOOLEAN` — INTEGER 0/1 under the hood; coerced both directions
8473
+ */
8474
+ var CollectionColumnSchema = zod.z.object({
8475
+ name: zod.z.string(),
8476
+ type: zod.z.enum([
8477
+ "TEXT",
8478
+ "INTEGER",
8479
+ "REAL",
8480
+ "JSON",
8481
+ "BOOLEAN"
8482
+ ]),
8483
+ primaryKey: zod.z.boolean().optional(),
8484
+ notNull: zod.z.boolean().optional(),
8485
+ unique: zod.z.boolean().optional(),
8486
+ /**
8487
+ * Column DEFAULT. Required for B2: the four `ensureTable` consumers declare
8488
+ * columns like `enabled INTEGER NOT NULL DEFAULT 1`, and without this the
8489
+ * collection surface simply cannot express their existing tables — which is
8490
+ * why they were still on the uncapped `table*` API.
8491
+ */
8492
+ defaultValue: zod.z.union([
8493
+ zod.z.string(),
8494
+ zod.z.number(),
8495
+ zod.z.boolean()
8496
+ ]).optional()
8497
+ });
8498
+ var CollectionIndexSchema = zod.z.object({
8499
+ name: zod.z.string(),
8500
+ columns: zod.z.array(zod.z.string()).readonly(),
8501
+ unique: zod.z.boolean().optional()
8502
+ });
8503
+ /**
8504
+ * The input of `declareCollection` — ONE schema for the door and for the
8505
+ * engine behind it, so the two surfaces cannot drift (the dispatcher forwards
8506
+ * the payload untouched).
8507
+ *
8508
+ * - `database` — the file the collection lives in (D851). Absent means
8509
+ * `settings`. A declaration naming a file other than the one the table is
8510
+ * already in is REFUSED by the engine, never moved.
8511
+ * - `primaryKey` — a COMPOSITE key, as column names. A single name is the same
8512
+ * as `primaryKey: true` on that column. A composite-keyed collection has no
8513
+ * `id`: it is written with `insertMany` / `upsertMany` / `transact` and read
8514
+ * with `query` / `count` / `aggregate` / `deleteWhere`; the calls that
8515
+ * address one row by id are refused.
8516
+ * - `withoutRowid` — emit `WITHOUT ROWID`. Requires a primary key.
8517
+ */
8518
+ var DeclareCollectionInputSchema = zod.z.object({
8519
+ namespace: zod.z.string().optional(),
8520
+ collection: zod.z.string(),
8521
+ columns: zod.z.array(CollectionColumnSchema).readonly(),
8522
+ indexes: zod.z.array(CollectionIndexSchema).readonly().optional(),
8523
+ database: DataStoreDatabaseSchema.optional(),
8524
+ primaryKey: zod.z.array(zod.z.string()).readonly().optional(),
8525
+ withoutRowid: zod.z.boolean().optional()
8526
+ });
8527
+ /**
8528
+ * settings-store — singleton capability for addon-scoped persistence.
8529
+ *
8530
+ * Every method operates within a `collection`. An optional `namespace`
8531
+ * field provides access to additional data spaces beyond the default
8532
+ * addon settings — useful for business data (events, tracks, faces, etc.).
8533
+ *
8534
+ * **Scoping is the CALLER's, and it is opt-in.** The table is
8535
+ * `namespace ? `${namespace}:${collection}` : collection` — nothing
8536
+ * consults the identity of the caller. An earlier version of this comment
8537
+ * claimed the implementation prefixes every collection with the calling
8538
+ * addon's ID and that "addons never see each other's data"; that was never
8539
+ * true, and this same file contradicted it under `declareCollection`. What
8540
+ * exists is `addon-context-factory`, which passes `namespace: addonId` ON
8541
+ * THE ADDON'S BEHALF for the `addon-settings` / `addon-devices` paths only.
8542
+ * Business collections use bare names, and any caller may name any
8543
+ * namespace, or none. Making the door enforce it is tracked separately —
8544
+ * it renames tables, so it needs a migration.
8545
+ *
8546
+ * **So every method is `auth: 'admin'` (D634).** Because nothing scopes a
8547
+ * call to its caller, a `protected` method here was a raw, unredacted read
8548
+ * (and write) of every addon's collections for any role holding
8549
+ * `category:system` — which is every role: a `viewer` could read every
8550
+ * notifier token in plaintext from `notifiers:notification-targets`. No
8551
+ * browser or app client calls this cap. Addons are not affected: an
8552
+ * addon's `ctx.api` cap call is resolved to the provider directly and never
8553
+ * enters the tRPC router (so the tier gates sessions and tokens, never
8554
+ * addons), and the hub itself calls it through the capability registry.
8555
+ *
8556
+ * - `{ collection: 'addon-settings' }` → table `addon-settings`
8557
+ * - `{ namespace: 'my-addon', collection: 'addon-settings' }` →
8558
+ * table `my-addon:addon-settings`
8559
+ *
8560
+ * Served by the **storage-orchestrator** builtin, which dispatches to the
8561
+ * `data-store-provider` engine registered for the collection
8562
+ * (`sqlite-settings`, a SQLite WAL backend, today). One addon owns the
8563
+ * data door; engines sit behind it
8564
+ * ([D44](../../../../docs/decisions/adr-0044.md)).
8565
+ * Addons access it via `ctx.api.settingsStore.*`.
8566
+ */
8567
+ var settingsStoreCapability = {
8568
+ name: "settings-store",
8569
+ scope: "system",
8570
+ mode: "singleton",
8571
+ methods: {
8572
+ /** Get a single value by key from a collection. */
8573
+ get: require_sleep.method(zod.z.object({
8574
+ namespace: zod.z.string().optional(),
8575
+ collection: zod.z.string(),
8576
+ key: zod.z.string()
8577
+ }), zod.z.unknown(), { auth: "admin" }),
8578
+ /** Set a value by key in a collection (upsert). */
8579
+ set: require_sleep.method(zod.z.object({
8580
+ namespace: zod.z.string().optional(),
8581
+ collection: zod.z.string(),
8582
+ key: zod.z.string(),
8583
+ value: zod.z.unknown()
8584
+ }), zod.z.void(), {
8585
+ kind: "mutation",
8586
+ auth: "admin"
8587
+ }),
8588
+ /**
8589
+ * Rows matching a filter.
8590
+ *
8591
+ * `columns` is a SQL-level projection: the engine SELECTs only those
8592
+ * columns (plus the primary key) instead of the whole row. It is the only
8593
+ * way to stop paying disk for a column that is discarded — a heavy JSON
8594
+ * column dominates the row, and dropping it in JS after the read pays every
8595
+ * byte first. Measured on the live `pipeline-analytics:tracks` table: a
8596
+ * 501-row page is 4.6 MB whole and 0.11 MB projected, same index, same
8597
+ * plan.
8598
+ *
8599
+ * The engine REFUSES a column it cannot serve rather than omitting it —
8600
+ * see `SettingsQueryInput.columns` for why a projection may not be
8601
+ * forgiving the way a predicate is.
8602
+ */
8603
+ query: require_sleep.method(zod.z.object({
8604
+ namespace: zod.z.string().optional(),
8605
+ collection: zod.z.string(),
8606
+ filter: QueryFilterSchema.optional(),
8607
+ columns: zod.z.array(zod.z.string()).readonly().optional()
8608
+ }), zod.z.array(SettingsRecordSchema).readonly(), { auth: "admin" }),
8609
+ /**
8610
+ * Make a SLOT hold this row — insert it, or update whatever already
8611
+ * occupies the slot — and answer with the id the row HAS.
8612
+ *
8613
+ * ## Why the store needed this
8614
+ *
8615
+ * {@link set} is already an upsert, but its slot is the PRIMARY KEY: the
8616
+ * caller has to know the id to address the row. That is exactly what a
8617
+ * collection keyed by an `INTEGER` rowid alias cannot do — SQLite assigns
8618
+ * the id, so a writer whose uniqueness rule is "one row per
8619
+ * `(ownerKind, ownerId, kind, slot)`" has no id to name and no way to
8620
+ * express the rule. {@link insert} can express it (a UNIQUE index
8621
+ * arbitrates) but only by THROWING at the loser of a race, and the loser
8622
+ * here is a legitimate re-capture, not an error.
8623
+ *
8624
+ * Getting there without this method means read-then-write: query the slot,
8625
+ * then `insert` or `update`. Two statements instead of one, a race between
8626
+ * them, and a recovery path that has to recognise a UNIQUE violation by its
8627
+ * MESSAGE — across a process boundary, because the store lives behind an
8628
+ * RPC door. A string match would be the whole gate, and a store that
8629
+ * rephrased its error would lose the row silently. One statement has no
8630
+ * such gate (D482).
8631
+ *
8632
+ * ## The contract
8633
+ *
8634
+ * `conflict` names the DECLARED columns that identify the slot. They must
8635
+ * be covered by a UNIQUE index on the collection — SQLite resolves an
8636
+ * `ON CONFLICT` target against its indexes and REFUSES the statement when
8637
+ * none matches, so a wrong list is a loud error on the first write, never a
8638
+ * silently duplicated row. An empty list is refused rather than passed on:
8639
+ * `ON CONFLICT()` is not valid SQL, and the intent it would most likely
8640
+ * encode ("no slot, just insert") is {@link insert}.
8641
+ *
8642
+ * Row shape is {@link insert}'s: `record.id` is used when the collection
8643
+ * needs a supplied key and IGNORED when the primary key is an `INTEGER`
8644
+ * rowid alias — exactly as `insert` and `insertMany` already treat it.
8645
+ *
8646
+ * Returns the id either way: the one SQLite assigned on an insert, or the
8647
+ * one the row it updated already had. A caller cannot tell which happened,
8648
+ * and deliberately — every caller wants the slot's id, and one that needed
8649
+ * to distinguish creation from replacement would have to read first anyway.
8650
+ */
8651
+ upsert: require_sleep.method(zod.z.object({
8652
+ namespace: zod.z.string().optional(),
8653
+ collection: zod.z.string(),
8654
+ /** Declared columns identifying the slot; must be covered by a UNIQUE
8655
+ * index on the collection. Never empty. */
8656
+ conflict: zod.z.array(zod.z.string()).readonly(),
8657
+ record: BulkRecordSchema
8658
+ }), zod.z.object({
8659
+ /** The id the row HAS: assigned by SQLite on an insert, or the existing
8660
+ * row's own id on an update. */
8661
+ id: zod.z.union([zod.z.string(), zod.z.number()]) }), {
8662
+ kind: "mutation",
8663
+ auth: "admin"
8664
+ }),
8665
+ /**
8666
+ * {@link upsert} for a BATCH, in ONE transaction on ONE prepared statement.
8667
+ *
8668
+ * The write-side twin of {@link insertMany} for rows that may already
8669
+ * exist: a rollup writer recomputes a bucket and must overwrite it, and
8670
+ * N round trips with N COMMITs is the cost {@link insertMany} was added to
8671
+ * avoid. `conflict` has the meaning it has on {@link upsert} (declared
8672
+ * columns covered by a UNIQUE index or the primary key, never empty).
8673
+ *
8674
+ * Every record of a batch must carry the SAME set of declared columns and
8675
+ * every `conflict` column: one batch is one statement shape, and a record
8676
+ * that silently bound NULL over a column it did not mention would erase
8677
+ * it. A heterogeneous batch is refused whole. **All or nothing.**
8678
+ */
8679
+ upsertMany: require_sleep.method(zod.z.object({
8680
+ namespace: zod.z.string().optional(),
8681
+ collection: zod.z.string(),
8682
+ conflict: zod.z.array(zod.z.string()).readonly(),
8683
+ records: zod.z.array(BulkRecordSchema).readonly()
8684
+ }), zod.z.object({ upserted: zod.z.number().int() }), {
8685
+ kind: "mutation",
8686
+ auth: "admin"
8687
+ }),
8688
+ /** Insert a new record. */
8689
+ insert: require_sleep.method(zod.z.object({
8690
+ namespace: zod.z.string().optional(),
8691
+ collection: zod.z.string(),
8692
+ record: zod.z.object({
8693
+ id: zod.z.string().optional(),
8694
+ data: zod.z.record(zod.z.string(), zod.z.unknown())
8695
+ })
8696
+ }), zod.z.object({
8697
+ /**
8698
+ * The id the row ACTUALLY got (D473): the one supplied, the UUID minted
8699
+ * for an absent one, or the ROWID SQLite assigned on an `INTEGER`
8700
+ * primary key — which is the only place an auto key is knowable.
8701
+ */
8702
+ id: zod.z.union([zod.z.string(), zod.z.number()]) }), {
8703
+ kind: "mutation",
8704
+ auth: "admin"
8705
+ }),
8706
+ /**
8707
+ * Insert MANY records in ONE transaction, returning how many landed.
8708
+ *
8709
+ * The write-side twin of {@link deleteWhere}, and it exists for the same
8710
+ * reason: without it, appending a batch is N round trips and N COMMITs on
8711
+ * the single shared connection that also serves every cluster-wide
8712
+ * configuration read. The durable load series writes one process row per
8713
+ * process per sample — 76 rows every 10 s on the live fleet — and the
8714
+ * operator's rule for it is *one transaction per sample, never one per
8715
+ * row*. `insert` cannot express that; nothing else could.
8716
+ *
8717
+ * **All or nothing.** A batch that fails on its fifth row leaves none of
8718
+ * the five behind. A half-written sample is worse than a missing one: the
8719
+ * missing one reads as "nobody reported", which is true, while the half
8720
+ * one reads as "these were the only processes running", which is not.
8721
+ *
8722
+ * `id` is OPTIONAL per record, and that is the difference from
8723
+ * {@link insert}. A collection whose primary key is an `INTEGER` rowid
8724
+ * alias has no id to supply — SQLite assigns it, for free, and inventing a
8725
+ * `randomUUID()` for such a column would write a 36-character string into
8726
+ * an integer key. Omitted on a TEXT key, a uuid is generated exactly as
8727
+ * `insert` does.
8728
+ */
8729
+ insertMany: require_sleep.method(zod.z.object({
8730
+ namespace: zod.z.string().optional(),
8731
+ collection: zod.z.string(),
8732
+ records: zod.z.array(BulkRecordSchema).readonly()
8733
+ }), zod.z.object({ inserted: zod.z.number().int() }), {
8734
+ kind: "mutation",
8735
+ auth: "admin"
8736
+ }),
8737
+ /**
8738
+ * Several writes, ONE transaction, behind an optional precondition.
8739
+ *
8740
+ * The multi-collection twin of {@link insertMany}: a write that has to move
8741
+ * a set of rows in one collection AND a revision in another cannot be
8742
+ * expressed as separate calls without a window in which a reader (or a
8743
+ * crash) sees half of it. The retrain annotation save replaces a frame's
8744
+ * rows, its dismissed set and its revision this way.
8745
+ *
8746
+ * `guard`, when given, is read inside the transaction: if the row is
8747
+ * missing or its column differs from `equals`, NOTHING is written and the
8748
+ * answer is `{ applied: false, current }` with what was found — the
8749
+ * compare-and-set a revisioned write needs, with no second reader able to
8750
+ * slip between the check and the writes.
8751
+ *
8752
+ * **All or nothing**, like {@link insertMany}: a throw in any op rolls the
8753
+ * whole call back. Ops run in the order given (delete before insert to
8754
+ * replace a set). `namespace` applies to every collection named.
8755
+ */
8756
+ transact: require_sleep.method(zod.z.object({
8757
+ namespace: zod.z.string().optional(),
8758
+ guard: TransactGuardSchema.optional(),
8759
+ ops: zod.z.array(TransactOpSchema).readonly()
8760
+ }), zod.z.object({
8761
+ applied: zod.z.boolean(),
8762
+ current: zod.z.unknown().optional()
8763
+ }), {
8764
+ kind: "mutation",
8765
+ auth: "admin"
8766
+ }),
8767
+ /** Update an existing record by ID. */
8768
+ update: require_sleep.method(zod.z.object({
8769
+ namespace: zod.z.string().optional(),
8770
+ collection: zod.z.string(),
8771
+ id: zod.z.string(),
8772
+ data: zod.z.record(zod.z.string(), zod.z.unknown())
8773
+ }), zod.z.void(), {
8774
+ kind: "mutation",
8775
+ auth: "admin"
8776
+ }),
8777
+ /** Delete a record by key/ID. */
8778
+ delete: require_sleep.method(zod.z.object({
8779
+ namespace: zod.z.string().optional(),
8780
+ collection: zod.z.string(),
8781
+ key: zod.z.string()
8782
+ }), zod.z.void(), {
8783
+ kind: "mutation",
8784
+ auth: "admin"
8785
+ }),
8786
+ /**
8787
+ * Delete every record matching `filter`, in ONE statement, returning how
8788
+ * many rows went. This exists because its absence made every retention
8789
+ * path in the system an N+1 drain loop: `delete` takes a key, so a sweep
8790
+ * had to SELECT a page of full rows — every column, including the fat
8791
+ * ones — purely to learn their ids, then issue one call per row.
8792
+ *
8793
+ * **The filter is required and must resolve.** A predicate naming
8794
+ * something the collection cannot express is an ERROR here, not a
8795
+ * widening as it is on `query`, and a filter with no predicates is an
8796
+ * error rather than "every row". Deleting a whole collection is a
8797
+ * legitimate intent, but it must be asked for by name — not reached by
8798
+ * an empty object.
8799
+ */
8800
+ deleteWhere: require_sleep.method(zod.z.object({
8801
+ namespace: zod.z.string().optional(),
8802
+ collection: zod.z.string(),
8803
+ filter: MutationFilterSchema
8804
+ }), zod.z.object({ deleted: zod.z.number().int() }), {
8805
+ kind: "mutation",
8806
+ auth: "admin"
8807
+ }),
8808
+ /**
8809
+ * Apply `data` to every record matching `filter`, in one statement,
8810
+ * returning how many rows changed. Same filter contract as
8811
+ * {@link deleteWhere} — an unresolvable predicate is an error.
8812
+ */
8813
+ updateWhere: require_sleep.method(zod.z.object({
8814
+ namespace: zod.z.string().optional(),
8815
+ collection: zod.z.string(),
8816
+ filter: MutationFilterSchema,
8817
+ data: zod.z.record(zod.z.string(), zod.z.unknown())
8818
+ }), zod.z.object({ updated: zod.z.number().int() }), {
8819
+ kind: "mutation",
8820
+ auth: "admin"
8821
+ }),
8822
+ /** Count entries in a collection, optionally filtered. */
8823
+ count: require_sleep.method(zod.z.object({
8824
+ namespace: zod.z.string().optional(),
8825
+ collection: zod.z.string(),
8826
+ filter: QueryFilterSchema.optional()
8827
+ }), zod.z.number(), { auth: "admin" }),
8828
+ /**
8829
+ * `COUNT(*)` and one `SUM` / `MIN` / `MAX` per requested field, in ONE
8830
+ * statement, over the rows `filter` selects.
8831
+ *
8832
+ * Exists because "how much is there" was being answered by materialising
8833
+ * "what is there". The recorder's storage-pressure sweep asked its in-RAM
8834
+ * footage index for bytes/count/oldest/newest across a set of storage
8835
+ * locations twice a minute, and the only way to answer that from a map is
8836
+ * to visit every row — 7.1 M of them on the live hub, ~15 M row visits a
8837
+ * minute on the main thread, which is also why the whole archive had to
8838
+ * stay resident to be visited. The question is a sum; nothing needs to be
8839
+ * materialised to answer it.
8840
+ *
8841
+ * **The engine REFUSES a field it cannot serve**, exactly as
8842
+ * `query.columns` does and unlike a PREDICATE, which is skipped when
8843
+ * unresolvable. A dropped predicate over-matches and the caller sees extra
8844
+ * rows; a dropped aggregate returns a NUMBER that is wrong and looks
8845
+ * exactly like a real one. That asymmetry is what this repo has already
8846
+ * paid for once in `count`.
8847
+ */
8848
+ aggregate: require_sleep.method(zod.z.object({
8849
+ namespace: zod.z.string().optional(),
8850
+ collection: zod.z.string(),
8851
+ fields: zod.z.array(AggregateFieldSchema).readonly(),
8852
+ filter: QueryFilterSchema.optional()
8853
+ }), AggregateResultSchema, { auth: "admin" }),
8854
+ /** Grouped counts per ((field-origin)/bucketSize) bucket, filtered. */
8855
+ histogram: require_sleep.method(zod.z.object({
8856
+ namespace: zod.z.string().optional(),
8857
+ collection: zod.z.string(),
8858
+ field: zod.z.string(),
8859
+ bucketSize: zod.z.number().int().positive(),
8860
+ origin: zod.z.number().int(),
8861
+ filter: QueryFilterSchema.optional()
8862
+ }), zod.z.array(zod.z.object({
8863
+ bucket: zod.z.number().int(),
8864
+ count: zod.z.number().int()
8865
+ })).readonly(), { auth: "admin" }),
8866
+ /** Check if a collection is empty. */
8867
+ isEmpty: require_sleep.method(zod.z.object({
8868
+ namespace: zod.z.string().optional(),
8869
+ collection: zod.z.string()
8870
+ }), zod.z.boolean(), { auth: "admin" }),
8871
+ /**
8872
+ * Declare a typed (SQL-backed) collection with explicit columns +
8873
+ * indexes. Idempotent: re-declaring an existing collection with the
8874
+ * same shape is a no-op; shape changes (new columns, new indexes)
8875
+ * are applied additively. Subsequent `insert` / `update` / `delete`
8876
+ * / `query` calls on this collection use typed columns instead of
8877
+ * JSON-blob storage — `record.data` fields are spread across
8878
+ * columns, `query.filter.where` matches real columns (no
8879
+ * `json_extract` overhead), `orderBy` uses column indexes.
8880
+ *
8881
+ * Addons call this in `onInitialize` before their first read/write.
8882
+ * Collection names should be namespaced by addon (e.g.
8883
+ * `pipeline-analytics:object-events`) to avoid cross-addon
8884
+ * clashes — no automatic prefix is added.
8885
+ */
8886
+ declareCollection: require_sleep.method(DeclareCollectionInputSchema, zod.z.void(), {
8887
+ kind: "mutation",
8888
+ auth: "admin"
8889
+ })
8890
+ }
8891
+ };
8892
+ //#endregion
8329
8893
  //#region src/capabilities/database-snapshot.cap.ts
8330
8894
  /**
8331
8895
  * The suffix of a verified snapshot, written next to the live database it
@@ -8354,7 +8918,11 @@ var DATABASE_SNAPSHOT_TIMEOUT_MS = 30 * 6e4;
8354
8918
  * database has no sidecars and is just as owned). Paths are absolute on the
8355
8919
  * owner's host.
8356
8920
  */
8357
- var DatabaseSnapshotTargetsSchema = zod.z.object({ databases: zod.z.array(zod.z.object({ livePath: zod.z.string() })) });
8921
+ var DatabaseSnapshotTargetsSchema = zod.z.object({ databases: zod.z.array(zod.z.object({
8922
+ /** Which owned file this is — the handle `writeSnapshot` takes. */
8923
+ databaseId: DataStoreDatabaseSchema,
8924
+ livePath: zod.z.string()
8925
+ })) });
8358
8926
  /** One b-tree table of the snapshot and the rows it holds. */
8359
8927
  var DatabaseSnapshotTableSchema = zod.z.object({
8360
8928
  name: zod.z.string(),
@@ -8387,6 +8955,10 @@ var DatabaseSnapshotResultSchema = zod.z.object({
8387
8955
  /** When the pinned read transaction began (ms epoch) — the snapshot's instant. */
8388
8956
  takenAt: zod.z.number()
8389
8957
  });
8958
+ /** A snapshot the owner wrote, with the file it belongs to. */
8959
+ var DatabaseSnapshotWrittenSchema = DatabaseSnapshotResultSchema.extend({ databaseId: DataStoreDatabaseSchema });
8960
+ /** Which database `writeSnapshot` copies. Required: an unstated ask is not guessed. */
8961
+ var DatabaseSnapshotRequestSchema = zod.z.object({ databaseId: DataStoreDatabaseSchema });
8390
8962
  /**
8391
8963
  * A snapshot as an ARCHIVE records it (`ArchiveManifest.sqliteSnapshots`):
8392
8964
  * the same facts, with both paths relative to the archive root (the node's
@@ -8396,7 +8968,9 @@ var ArchiveSqliteSnapshotSchema = DatabaseSnapshotResultSchema.extend({
8396
8968
  /** Archive-relative path of the live database the archive does NOT carry. */
8397
8969
  livePath: zod.z.string(),
8398
8970
  /** Archive-relative path of the verified copy it carries in its place. */
8399
- snapshotPath: zod.z.string()
8971
+ snapshotPath: zod.z.string(),
8972
+ /** Absent on an archive made before several files were owned: that was `settings`. */
8973
+ databaseId: DataStoreDatabaseSchema.optional()
8400
8974
  });
8401
8975
  /**
8402
8976
  * database-snapshot — the OWNER of a live SQLite database writes a consistent,
@@ -8421,17 +8995,21 @@ var databaseSnapshotCapability = {
8421
8995
  internal: true,
8422
8996
  methods: {
8423
8997
  /**
8424
- * Which databases this owner snapshots. Answered from memory — no file is
8425
- * touched — so a backup can ask it before deciding anything.
8998
+ * EVERY database file this owner has open, with its id. Answered from
8999
+ * memory — no file is touched — so a backup can ask it before deciding
9000
+ * anything. A file created at runtime is listed from the moment it opens,
9001
+ * so no backup can leave it out (D693).
8426
9002
  */
8427
9003
  listDatabases: require_sleep.method(zod.z.object({}), DatabaseSnapshotTargetsSchema, { auth: "admin" }),
8428
9004
  /**
8429
- * Write `<db>.backup-snapshot` and return what it holds. Throws — and
8430
- * leaves no file under the final name — when the copy fails
8431
- * `integrity_check` or its row counts differ from the pinned source's.
8432
- * A second call while one is running joins it.
9005
+ * Write `<db>.backup-snapshot` for ONE database and return what it holds.
9006
+ * Throws — and leaves no file under the final name — when the copy fails
9007
+ * `integrity_check` or its row counts differ from the pinned source's, or
9008
+ * when the database is not open. A second call for the SAME database while
9009
+ * one is running joins it; different databases run one after the other
9010
+ * (the disk reserve check is per copy).
8433
9011
  */
8434
- writeSnapshot: require_sleep.method(zod.z.object({}), DatabaseSnapshotResultSchema, {
9012
+ writeSnapshot: require_sleep.method(DatabaseSnapshotRequestSchema, DatabaseSnapshotWrittenSchema, {
8435
9013
  kind: "mutation",
8436
9014
  auth: "admin",
8437
9015
  timeoutMs: DATABASE_SNAPSHOT_TIMEOUT_MS
@@ -8554,7 +9132,12 @@ var BackupArchiveEntrySchema = zod.z.object({
8554
9132
  /** Top-level locations included in the archive (db, addons, tls, …). */
8555
9133
  locations: zod.z.array(zod.z.string()).readonly(),
8556
9134
  /** Present when the archive is encrypted; restore then needs that key. */
8557
- encryption: BackupArchiveEncryptionSchema.optional()
9135
+ encryption: BackupArchiveEncryptionSchema.optional(),
9136
+ /**
9137
+ * The databases the run asked to carry (its retention class). Absent on an
9138
+ * archive made before several files were owned: that was `['settings']`.
9139
+ */
9140
+ databases: zod.z.array(DataStoreDatabaseSchema).readonly().optional()
8558
9141
  });
8559
9142
  var BackupEntrySchema = zod.z.object({
8560
9143
  id: zod.z.string(),
@@ -8588,7 +9171,12 @@ var ArchiveManifestSchema = zod.z.object({
8588
9171
  * Live SQLite databases this archive carries as their OWNER's verified
8589
9172
  * snapshot instead of as files (D693). Absent on archives made before.
8590
9173
  */
8591
- sqliteSnapshots: zod.z.array(ArchiveSqliteSnapshotSchema).optional()
9174
+ sqliteSnapshots: zod.z.array(ArchiveSqliteSnapshotSchema).optional(),
9175
+ /**
9176
+ * Owned database files the run did NOT carry (not selected): left out of the
9177
+ * tar and the entry list alike. Absent when every owned file was carried.
9178
+ */
9179
+ omittedDatabases: zod.z.array(DataStoreDatabaseSchema).optional()
8592
9180
  });
8593
9181
  var LocationStatSchema = zod.z.object({
8594
9182
  name: zod.z.string(),
@@ -8710,6 +9298,12 @@ var BackupScheduleSchema = zod.z.object({
8710
9298
  /** Optional subset of source locations to include; omitted = all. */
8711
9299
  dataSources: zod.z.array(zod.z.string()).readonly().optional(),
8712
9300
  /**
9301
+ * Which database files this schedule carries. Absent = `['settings']`
9302
+ * (an unstated ask is the minimum, D382). Events and history run weekly,
9303
+ * settings nightly (D852).
9304
+ */
9305
+ databases: zod.z.array(DataStoreDatabaseSchema).readonly().optional(),
9306
+ /**
8713
9307
  * ms-epoch of the last tick that FIRED this schedule. Stamped before the
8714
9308
  * archive runs (it is the dedupe anchor), so it says "attempted", never
8715
9309
  * "succeeded" — a run refused by every destination stamps it too.
@@ -8761,7 +9355,9 @@ var backupCapability = {
8761
9355
  * retention). Omitted = each destination's own policy
8762
9356
  * retention (manual runs).
8763
9357
  */
8764
- retentionCount: zod.z.number().int().min(1).max(1e3).optional()
9358
+ retentionCount: zod.z.number().int().min(1).max(1e3).optional(),
9359
+ /** Database files to carry; omitted = `['settings']`. */
9360
+ databases: zod.z.array(DataStoreDatabaseSchema).optional()
8765
9361
  }).optional(), BackupTriggerResultSchema, {
8766
9362
  kind: "mutation",
8767
9363
  auth: "admin"
@@ -8919,6 +9515,16 @@ var backupCapability = {
8919
9515
  */
8920
9516
  listSchedules: require_sleep.method(zod.z.void(), zod.z.array(BackupScheduleSchema).readonly(), { auth: "admin" }),
8921
9517
  /**
9518
+ * The database files that exist on this hub right now (the owner's open
9519
+ * files), so the selection UI can offer all of them and mark a file that
9520
+ * is not created yet. `answered: false` = the owner did not answer, which
9521
+ * is not the same as "none exist".
9522
+ */
9523
+ listAvailableDatabases: require_sleep.method(zod.z.void(), zod.z.object({
9524
+ answered: zod.z.boolean(),
9525
+ databases: zod.z.array(DataStoreDatabaseSchema).readonly()
9526
+ }), { auth: "admin" }),
9527
+ /**
8922
9528
  * Create or replace a schedule. An empty / absent `id` mints a new
8923
9529
  * one; a present `id` replaces in place. `cron` is validated
8924
9530
  * server-side; `locationIds` must reference existing `backups`
@@ -8931,7 +9537,8 @@ var backupCapability = {
8931
9537
  enabled: zod.z.boolean(),
8932
9538
  locationIds: zod.z.array(zod.z.string()).readonly(),
8933
9539
  retentionCount: zod.z.number().int().min(1).max(1e3),
8934
- dataSources: zod.z.array(zod.z.string()).readonly().optional()
9540
+ dataSources: zod.z.array(zod.z.string()).readonly().optional(),
9541
+ databases: zod.z.array(DataStoreDatabaseSchema).readonly().optional()
8935
9542
  }), BackupScheduleSchema, {
8936
9543
  kind: "mutation",
8937
9544
  auth: "admin"
@@ -12320,828 +12927,264 @@ var CoreBlockCompileInputSchema = zod.z.object({
12320
12927
  return;
12321
12928
  }
12322
12929
  if (val.code === void 0) ctx.addIssue({
12323
- code: "custom",
12324
- message: "code or files is required",
12325
- path: ["code"]
12326
- });
12327
- });
12328
- var coreBlocksCapability = {
12329
- name: "core-blocks",
12330
- scope: "system",
12331
- mode: "singleton",
12332
- methods: {
12333
- list: require_sleep.method(zod.z.object({}), zod.z.object({ blocks: zod.z.array(CoreBlockSchema) }), { auth: "admin" }),
12334
- get: require_sleep.method(zod.z.object({ blockId: zod.z.string() }), zod.z.object({ block: CoreBlockSchema.nullable() }), { auth: "admin" }),
12335
- /**
12336
- * Create a block. The code is COMPILED first: storing source that does not
12337
- * compile turns an editor error into a fork failure the operator meets
12338
- * minutes later in a log.
12339
- */
12340
- create: require_sleep.method(zod.z.object({ block: CoreBlockInputSchema }), zod.z.object({ block: CoreBlockSchema }), {
12341
- kind: "mutation",
12342
- auth: "admin",
12343
- caller: "required"
12344
- }),
12345
- update: require_sleep.method(zod.z.object({
12346
- blockId: zod.z.string(),
12347
- block: CoreBlockInputFieldsSchema.partial()
12348
- }), zod.z.object({ block: CoreBlockSchema }), {
12349
- kind: "mutation",
12350
- auth: "admin",
12351
- caller: "required"
12352
- }),
12353
- delete: require_sleep.method(zod.z.object({ blockId: zod.z.string() }), zod.z.object({ success: zod.z.literal(true) }), {
12354
- kind: "mutation",
12355
- auth: "admin"
12356
- }),
12357
- setEnabled: require_sleep.method(zod.z.object({
12358
- blockId: zod.z.string(),
12359
- enabled: zod.z.boolean()
12360
- }), zod.z.object({ block: CoreBlockSchema }), {
12361
- kind: "mutation",
12362
- auth: "admin"
12363
- }),
12364
- /**
12365
- * Stop this block's runner and let the supervisor bring it back.
12366
- *
12367
- * **It stores nothing.** There is no "restart requested" flag and no second
12368
- * lifecycle field: the supervisor already stops and respawns a runner when
12369
- * the code hash changes, and this exposes that same path deliberately
12370
- * (D62 — a switch writes the authority that already owned the function).
12371
- * The next reconcile pass remains the authority, so a restart that lost a
12372
- * race is corrected within one pass rather than leaving a stale flag behind.
12373
- *
12374
- * Refused for a DISABLED block: nothing would come back, and a button that
12375
- * silently does nothing is worse than one that says why.
12376
- */
12377
- restart: require_sleep.method(zod.z.object({ blockId: zod.z.string() }), zod.z.object({ block: CoreBlockSchema }), {
12378
- kind: "mutation",
12379
- auth: "admin"
12380
- }),
12381
- /**
12382
- * Type-check without saving — what the editor calls as the author types, so
12383
- * the compiler's verdict is the same one the server will reach.
12384
- * Accepts `{ code }` or `{ files, entry }` (multi-file project).
12385
- */
12386
- compile: require_sleep.method(CoreBlockCompileInputSchema, CoreBlockCompileResultSchema, {
12387
- kind: "mutation",
12388
- auth: "admin"
12389
- }),
12390
- /**
12391
- * Hydrated settings form for one block, or null until a `settingsSchema`
12392
- * is known (extracted from the compiled entry's named export, or set on
12393
- * the block). Values live in the `core-blocks:settings` collection.
12394
- */
12395
- getBlockSettings: require_sleep.method(zod.z.object({ blockId: zod.z.string() }), SettingsSchemaWithValuesSchema.nullable(), { auth: "admin" }),
12396
- /**
12397
- * Patch persisted preference values for one block. The schema is not
12398
- * rewritten here — only values. Scripts read the same blob via
12399
- * `ctx.settings.readAddonStore()` (mirrored into the block addon's
12400
- * `addon-settings` namespace on every patch).
12401
- */
12402
- updateBlockSettings: require_sleep.method(zod.z.object({
12403
- blockId: zod.z.string(),
12404
- patch: SettingsPatchSchema
12405
- }), SettingsUpdateResultSchema, {
12406
- kind: "mutation",
12407
- auth: "admin"
12408
- }),
12409
- /**
12410
- * The declaration files the editor type-checks against.
12411
- *
12412
- * Served rather than bundled: the graph is 3.4 MB across 344 files, and
12413
- * bundling it would roughly double the admin remote. Served rather than
12414
- * hand-stubbed: a block runs with the same `ctx` an addon gets, so a stub
12415
- * would drift and the editor would confidently autocomplete methods that
12416
- * do not exist.
12417
- */
12418
- getTypeDefs: require_sleep.method(zod.z.object({}), zod.z.object({ libs: zod.z.array(zod.z.object({
12419
- filePath: zod.z.string(),
12420
- content: zod.z.string()
12421
- })) }), { auth: "admin" }),
12422
- /**
12423
- * Create a composition block (D659). VALIDATED first against the live
12424
- * sources and every stored composition; a refusal names every problem by
12425
- * path and reason (D391) and stores nothing.
12426
- */
12427
- createComposition: require_sleep.method(zod.z.object({ block: CompositionBlockInputSchema }), zod.z.object({ block: CoreBlockSchema }), {
12428
- kind: "mutation",
12429
- auth: "admin",
12430
- caller: "required"
12431
- }),
12432
- /**
12433
- * Patch a composition block. A changed `composition` is validated exactly
12434
- * as on create. `expectedUpdatedAt` is the `updatedAt` the caller READ: a
12435
- * block changed since is refused by name, never silently overwritten.
12436
- */
12437
- updateComposition: require_sleep.method(zod.z.object({
12438
- blockId: zod.z.string(),
12439
- expectedUpdatedAt: zod.z.number(),
12440
- block: CompositionBlockInputSchema.partial()
12441
- }), zod.z.object({ block: CoreBlockSchema }), {
12442
- kind: "mutation",
12443
- auth: "admin",
12444
- caller: "required"
12445
- }),
12446
- /** One composition and the composer's state for it, or `not-loaded` (D315). */
12447
- getComposition: require_sleep.method(zod.z.object({ blockId: zod.z.string() }), CompositionGetReadSchema, { auth: "admin" }),
12448
- listCompositions: require_sleep.method(zod.z.object({}), CompositionListReadSchema, { auth: "admin" }),
12449
- /**
12450
- * The composition that customizes an existing device (D663), found by its
12451
- * TARGET — never by the block's derived name. One per device at most.
12452
- */
12453
- getCustomization: require_sleep.method(zod.z.object({
12454
- addonId: zod.z.string().min(1),
12455
- stableId: zod.z.string().min(1)
12456
- }), CompositionCustomizationReadSchema, { auth: "admin" }),
12457
- /**
12458
- * The capabilities a composition may BUILD on a device of `deviceType`
12459
- * (a new device, or added to an existing one), with their fields — the
12460
- * editor's feature list and the presets' availability (G2, D676). Built
12461
- * from the validator's own blockers; a replace of a BOUND cap is not
12462
- * listed here (the device's bindings say what it has).
12463
- */
12464
- listComposableCaps: require_sleep.method(zod.z.object({ deviceType: zod.z.enum(require_err_msg.DeviceType) }), ComposableCapabilitiesSchema, { auth: "admin" }),
12465
- /**
12466
- * Validate without saving — the same verdict the save reaches. A mutation
12467
- * for its body size; it writes nothing, so its access is `view`.
12468
- */
12469
- validateComposition: require_sleep.method(zod.z.object({
12470
- composition: require_composition.CompositionSchema,
12471
- blockId: zod.z.string().optional()
12472
- }), CompositionValidationSchema, {
12473
- kind: "mutation",
12474
- auth: "admin",
12475
- access: "view"
12476
- })
12477
- }
12478
- };
12479
- //#endregion
12480
- //#region src/capabilities/custom-model-registry.cap.ts
12481
- /**
12482
- * `custom-model-registry` — collection cap exposing operator-registered
12483
- * custom detection models. Each provider (today: `addon-model-studio`)
12484
- * contributes a list of `CustomModelDescriptor`s; the hub auto-concatenates
12485
- * them across providers (`concatCollection`).
12486
- *
12487
- * The detection-pipeline is *aware* of this cap: when at least one provider
12488
- * exists it unions these descriptors into the per-step model picker and the
12489
- * runtime model-resolution path, alongside the static catalog. When no
12490
- * provider exists the consumer no-ops entirely (identical to the catalog-only
12491
- * behaviour).
12492
- *
12493
- * A descriptor carries a full `ModelCatalogEntry` directly — the same shape
12494
- * the static catalog uses — so the existing download/resolution code consumes
12495
- * it unchanged. `stepId` is the detection step the model targets
12496
- * (e.g. `'object-detection'`).
12497
- */
12498
- var CustomModelDescriptorSchema = zod.z.object({
12499
- stepId: zod.z.string(),
12500
- entry: ModelCatalogEntrySchema
12501
- });
12502
- /** One regular file of an imported bundle, as the producer measured it. */
12503
- var ModelBundleFileSchema = zod.z.object({
12504
- /** Relative path inside the bundle tar; an mlpackage member is `<x>.mlpackage/<member>`. */
12505
- path: zod.z.string().min(1),
12506
- bytes: zod.z.number().int().nonnegative(),
12507
- sha256: zod.z.string().regex(/^[0-9a-f]{64}$/)
12508
- });
12509
- var ImportModelBundleInputSchema = zod.z.object({
12510
- /** The registry provider that keeps the model (Model Studio). */
12511
- addonId: zod.z.string(),
12512
- stepId: zod.z.string().min(1),
12513
- /**
12514
- * The catalog rows to register, complete, every format URL already
12515
- * `camstack-local://<modelId>/<file>` naming a file of the bundle. One
12516
- * bundle may carry several rows (a base and its INT8 variant).
12517
- */
12518
- entries: zod.z.array(ModelCatalogEntrySchema).min(1).max(4),
12519
- /** The bundle tar, offered by the producer over `ctx.peerBytes` (same host). */
12520
- bundle: zod.z.object({
12521
- ticket: require_sleep.PeerBytesTicketSchema,
12522
- bytes: zod.z.number().int().positive(),
12523
- sha256: zod.z.string().regex(/^[0-9a-f]{64}$/)
12524
- }),
12525
- /** Every file the tar must hold; anything missing, extra or different is refused. */
12526
- files: zod.z.array(ModelBundleFileSchema).min(1).max(64),
12527
- /** Convert missing engine formats and push the model to every agent afterwards. */
12528
- distribute: zod.z.boolean()
12529
- });
12530
- var ImportModelBundleResultSchema = zod.z.discriminatedUnion("kind", [zod.z.object({
12531
- kind: zod.z.literal("imported"),
12532
- modelIds: zod.z.array(zod.z.string()).readonly(),
12533
- distributed: zod.z.array(zod.z.object({
12534
- modelId: zod.z.string(),
12535
- nodeId: zod.z.string(),
12536
- format: zod.z.enum(require_sleep.MODEL_FORMATS),
12537
- ok: zod.z.boolean(),
12538
- error: zod.z.string().optional()
12539
- })).readonly()
12540
- }), zod.z.object({
12541
- kind: zod.z.literal("refused"),
12542
- reason: zod.z.enum([
12543
- "transfer-failed",
12544
- "checksum-mismatch",
12545
- "bundle-mismatch",
12546
- "invalid-entry",
12547
- "id-taken"
12548
- ]),
12549
- detail: zod.z.string()
12550
- })]);
12551
- var customModelRegistryCapability = {
12552
- name: "custom-model-registry",
12553
- scope: "system",
12554
- mode: "collection",
12555
- internal: true,
12556
- methods: {
12557
- /**
12558
- * `internal: true` did not gate the mount (see the 2026-08-26 note on
12559
- * `data-store-provider`) — this was reachable on the AppRouter by ANY
12560
- * authenticated session at the default `auth: 'protected'`. The only
12561
- * consumer, the detection-pipeline's model resolution
12562
- * (`addon-pipeline/src/detection-pipeline/provider.ts`), calls
12563
- * `ctx.api.customModelRegistry.listModels.query()` — UDS/Moleculer,
12564
- * never tRPC — so `auth: 'admin'` costs it nothing.
12565
- */
12566
- listModels: require_sleep.method(zod.z.void(), zod.z.array(CustomModelDescriptorSchema).readonly(), { auth: "admin" }),
12567
- /**
12568
- * Register a model whose files arrive as ONE bundle tar (D806): the tar
12569
- * is taken over `ctx.peerBytes`, checked against `bundle.sha256` and
12570
- * every row of `files`, unpacked into the hub's flat modelsDir (directory
12571
- * formats included), each format's `.revision` record written, the rows
12572
- * upserted under the operator's name, the hub marked available and —
12573
- * when asked — engine formats converted and the model distributed. A
12574
- * model id already registered by another source is refused, never
12575
- * overwritten.
12576
- */
12577
- importModelBundle: require_sleep.method(ImportModelBundleInputSchema, ImportModelBundleResultSchema, {
12578
- kind: "mutation",
12579
- auth: "admin",
12580
- timeoutMs: 30 * 6e4
12581
- })
12582
- }
12583
- };
12584
- //#endregion
12585
- //#region src/capabilities/settings-store.cap.ts
12586
- /**
12587
- * Query filter for settings-store collections.
12588
- */
12589
- var QueryFilterSchema = zod.z.object({
12590
- where: zod.z.record(zod.z.string(), zod.z.unknown()).optional(),
12591
- whereIn: zod.z.record(zod.z.string(), zod.z.array(zod.z.unknown())).optional(),
12592
- whereBetween: zod.z.record(zod.z.string(), zod.z.tuple([zod.z.unknown(), zod.z.unknown()])).optional(),
12593
- /** NULL-safe exclusion: matches rows whose field is NULL OR != the value. */
12594
- whereNot: zod.z.record(zod.z.string(), zod.z.unknown()).optional(),
12595
- /** NULL-safe exclusion of a SET — `whereNot` for more than one value. An
12596
- * empty list excludes nothing. See `QueryFilter.whereNotIn`. */
12597
- whereNotIn: zod.z.record(zod.z.string(), zod.z.array(zod.z.unknown())).optional(),
12598
- orderBy: zod.z.object({
12599
- field: zod.z.string(),
12600
- direction: zod.z.enum(["asc", "desc"])
12601
- }).optional(),
12602
- limit: zod.z.number().optional(),
12603
- offset: zod.z.number().optional()
12604
- });
12605
- /**
12606
- * The predicate half of a filter, for BULK MUTATIONS.
12607
- *
12608
- * Deliberately not `QueryFilterSchema`: `orderBy` / `limit` / `offset` have no
12609
- * meaning for a statement that rewrites a set, and accepting them would invite
12610
- * a caller to believe `limit` bounds the damage. Every field is optional here
12611
- * only so the shape stays composable — the implementation REJECTS a filter
12612
- * that compiles to no predicate, because that is the whole collection.
12613
- */
12614
- var MutationFilterSchema = zod.z.object({
12615
- where: zod.z.record(zod.z.string(), zod.z.unknown()).optional(),
12616
- whereIn: zod.z.record(zod.z.string(), zod.z.array(zod.z.unknown())).optional(),
12617
- whereBetween: zod.z.record(zod.z.string(), zod.z.tuple([zod.z.unknown(), zod.z.unknown()])).optional(),
12618
- whereNot: zod.z.record(zod.z.string(), zod.z.unknown()).optional(),
12619
- whereNotIn: zod.z.record(zod.z.string(), zod.z.array(zod.z.unknown())).optional()
12620
- });
12621
- /**
12622
- * One scalar an {@link settingsStoreCapability.methods.aggregate} call asks for.
12623
- *
12624
- * `as` names the slot in the result, so the SAME column may be asked twice with
12625
- * two operations (`MIN(startMs)` and `MAX(startMs)` in one round trip) — which
12626
- * a `Record<column, op>` shape could not express.
12627
- */
12628
- var AggregateFieldSchema = zod.z.object({
12629
- /** Result key. */
12630
- as: zod.z.string().min(1),
12631
- /** Column to aggregate. Must be a real column of a declared collection. */
12632
- field: zod.z.string().min(1),
12633
- op: zod.z.enum([
12634
- "sum",
12635
- "min",
12636
- "max"
12637
- ])
12638
- });
12639
- /**
12640
- * `COUNT(*)` plus one number per requested field.
12641
- *
12642
- * `null` means NO ROW MATCHED, never zero: a `SUM` over an empty set and a sum
12643
- * that really is 0 are different facts, and an accounting caller that renders
12644
- * "0 bytes, oldest = 0" for "nothing here" reports a lie about a disk.
12645
- */
12646
- var AggregateResultSchema = zod.z.object({
12647
- count: zod.z.number().int(),
12648
- values: zod.z.record(zod.z.string(), zod.z.number().nullable())
12649
- });
12650
- /** A single stored record: `{ id, data }`. */
12651
- var SettingsRecordSchema = zod.z.object({
12652
- id: zod.z.string(),
12653
- data: zod.z.record(zod.z.string(), zod.z.unknown())
12654
- });
12655
- /**
12656
- * One record of a BULK insert — {@link SettingsRecordSchema} with the id made
12657
- * optional.
12658
- *
12659
- * A separate schema rather than loosening the shared one: every other method
12660
- * on this cap addresses a row BY its id, and making that field optional
12661
- * everywhere would turn a forgotten key into a silently generated one on
12662
- * `update` and `delete` as well.
12663
- */
12664
- var BulkRecordSchema = zod.z.object({
12665
- id: zod.z.string().optional(),
12666
- data: zod.z.record(zod.z.string(), zod.z.unknown())
12667
- });
12668
- /**
12669
- * The database FILES one `sqlite-settings` engine process owns (D851).
12670
- * Closed on purpose: a file is a thing the engine opens, backs up and gives a
12671
- * serving thread, so a new one is a code change, never a string a caller
12672
- * invents. `settings` is `camstack.db` and the default for every collection
12673
- * that names no file.
12674
- */
12675
- var DataStoreDatabaseSchema = zod.z.enum([
12676
- "settings",
12677
- "events",
12678
- "history"
12679
- ]);
12680
- /** Every database file, in a stable order (settings first). */
12681
- var DATA_STORE_DATABASES = DataStoreDatabaseSchema.options;
12682
- /**
12683
- * One write inside a {@link settingsStoreCapability.methods.transact} call.
12684
- * The three that a "replace this set, bump that revision" write needs, plus
12685
- * the batched upsert a rollup writer needs.
12686
- */
12687
- var TransactOpSchema = zod.z.discriminatedUnion("op", [
12688
- zod.z.object({
12689
- op: zod.z.literal("deleteWhere"),
12690
- collection: zod.z.string(),
12691
- filter: MutationFilterSchema
12692
- }),
12693
- zod.z.object({
12694
- op: zod.z.literal("insertMany"),
12695
- collection: zod.z.string(),
12696
- records: zod.z.array(BulkRecordSchema).readonly()
12697
- }),
12698
- zod.z.object({
12699
- op: zod.z.literal("update"),
12700
- collection: zod.z.string(),
12701
- id: zod.z.string(),
12702
- data: zod.z.record(zod.z.string(), zod.z.unknown())
12703
- }),
12704
- zod.z.object({
12705
- op: zod.z.literal("upsertMany"),
12706
- collection: zod.z.string(),
12707
- conflict: zod.z.array(zod.z.string()).readonly(),
12708
- records: zod.z.array(BulkRecordSchema).readonly()
12709
- })
12710
- ]);
12711
- /**
12712
- * The precondition of a transaction: the row `key` of `collection` must hold
12713
- * `equals` in `column`, read INSIDE the transaction.
12714
- */
12715
- var TransactGuardSchema = zod.z.object({
12716
- collection: zod.z.string(),
12717
- key: zod.z.string(),
12718
- column: zod.z.string(),
12719
- equals: zod.z.unknown()
12720
- });
12721
- /**
12722
- * Column declaration for a structured (SQL-backed) collection.
12723
- *
12724
- * Logical types — the backend translates each to the matching SQLite
12725
- * storage class and handles per-type marshaling:
12726
- * - `TEXT` / `INTEGER` / `REAL` — native SQLite types, pass-through
12727
- * - `JSON` — TEXT under the hood; serialised on write, parsed on read
12728
- * - `BOOLEAN` — INTEGER 0/1 under the hood; coerced both directions
12729
- */
12730
- var CollectionColumnSchema = zod.z.object({
12731
- name: zod.z.string(),
12732
- type: zod.z.enum([
12733
- "TEXT",
12734
- "INTEGER",
12735
- "REAL",
12736
- "JSON",
12737
- "BOOLEAN"
12738
- ]),
12739
- primaryKey: zod.z.boolean().optional(),
12740
- notNull: zod.z.boolean().optional(),
12741
- unique: zod.z.boolean().optional(),
12742
- /**
12743
- * Column DEFAULT. Required for B2: the four `ensureTable` consumers declare
12744
- * columns like `enabled INTEGER NOT NULL DEFAULT 1`, and without this the
12745
- * collection surface simply cannot express their existing tables — which is
12746
- * why they were still on the uncapped `table*` API.
12747
- */
12748
- defaultValue: zod.z.union([
12749
- zod.z.string(),
12750
- zod.z.number(),
12751
- zod.z.boolean()
12752
- ]).optional()
12753
- });
12754
- var CollectionIndexSchema = zod.z.object({
12755
- name: zod.z.string(),
12756
- columns: zod.z.array(zod.z.string()).readonly(),
12757
- unique: zod.z.boolean().optional()
12758
- });
12759
- /**
12760
- * The input of `declareCollection` — ONE schema for the door and for the
12761
- * engine behind it, so the two surfaces cannot drift (the dispatcher forwards
12762
- * the payload untouched).
12763
- *
12764
- * - `database` — the file the collection lives in (D851). Absent means
12765
- * `settings`. A declaration naming a file other than the one the table is
12766
- * already in is REFUSED by the engine, never moved.
12767
- * - `primaryKey` — a COMPOSITE key, as column names. A single name is the same
12768
- * as `primaryKey: true` on that column. A composite-keyed collection has no
12769
- * `id`: it is written with `insertMany` / `upsertMany` / `transact` and read
12770
- * with `query` / `count` / `aggregate` / `deleteWhere`; the calls that
12771
- * address one row by id are refused.
12772
- * - `withoutRowid` — emit `WITHOUT ROWID`. Requires a primary key.
12773
- */
12774
- var DeclareCollectionInputSchema = zod.z.object({
12775
- namespace: zod.z.string().optional(),
12776
- collection: zod.z.string(),
12777
- columns: zod.z.array(CollectionColumnSchema).readonly(),
12778
- indexes: zod.z.array(CollectionIndexSchema).readonly().optional(),
12779
- database: DataStoreDatabaseSchema.optional(),
12780
- primaryKey: zod.z.array(zod.z.string()).readonly().optional(),
12781
- withoutRowid: zod.z.boolean().optional()
12782
- });
12783
- /**
12784
- * settings-store — singleton capability for addon-scoped persistence.
12785
- *
12786
- * Every method operates within a `collection`. An optional `namespace`
12787
- * field provides access to additional data spaces beyond the default
12788
- * addon settings — useful for business data (events, tracks, faces, etc.).
12789
- *
12790
- * **Scoping is the CALLER's, and it is opt-in.** The table is
12791
- * `namespace ? `${namespace}:${collection}` : collection` — nothing
12792
- * consults the identity of the caller. An earlier version of this comment
12793
- * claimed the implementation prefixes every collection with the calling
12794
- * addon's ID and that "addons never see each other's data"; that was never
12795
- * true, and this same file contradicted it under `declareCollection`. What
12796
- * exists is `addon-context-factory`, which passes `namespace: addonId` ON
12797
- * THE ADDON'S BEHALF for the `addon-settings` / `addon-devices` paths only.
12798
- * Business collections use bare names, and any caller may name any
12799
- * namespace, or none. Making the door enforce it is tracked separately —
12800
- * it renames tables, so it needs a migration.
12801
- *
12802
- * **So every method is `auth: 'admin'` (D634).** Because nothing scopes a
12803
- * call to its caller, a `protected` method here was a raw, unredacted read
12804
- * (and write) of every addon's collections for any role holding
12805
- * `category:system` — which is every role: a `viewer` could read every
12806
- * notifier token in plaintext from `notifiers:notification-targets`. No
12807
- * browser or app client calls this cap. Addons are not affected: an
12808
- * addon's `ctx.api` cap call is resolved to the provider directly and never
12809
- * enters the tRPC router (so the tier gates sessions and tokens, never
12810
- * addons), and the hub itself calls it through the capability registry.
12811
- *
12812
- * - `{ collection: 'addon-settings' }` → table `addon-settings`
12813
- * - `{ namespace: 'my-addon', collection: 'addon-settings' }` →
12814
- * table `my-addon:addon-settings`
12815
- *
12816
- * Served by the **storage-orchestrator** builtin, which dispatches to the
12817
- * `data-store-provider` engine registered for the collection
12818
- * (`sqlite-settings`, a SQLite WAL backend, today). One addon owns the
12819
- * data door; engines sit behind it
12820
- * ([D44](../../../../docs/decisions/adr-0044.md)).
12821
- * Addons access it via `ctx.api.settingsStore.*`.
12822
- */
12823
- var settingsStoreCapability = {
12824
- name: "settings-store",
12930
+ code: "custom",
12931
+ message: "code or files is required",
12932
+ path: ["code"]
12933
+ });
12934
+ });
12935
+ var coreBlocksCapability = {
12936
+ name: "core-blocks",
12825
12937
  scope: "system",
12826
12938
  mode: "singleton",
12827
12939
  methods: {
12828
- /** Get a single value by key from a collection. */
12829
- get: require_sleep.method(zod.z.object({
12830
- namespace: zod.z.string().optional(),
12831
- collection: zod.z.string(),
12832
- key: zod.z.string()
12833
- }), zod.z.unknown(), { auth: "admin" }),
12834
- /** Set a value by key in a collection (upsert). */
12835
- set: require_sleep.method(zod.z.object({
12836
- namespace: zod.z.string().optional(),
12837
- collection: zod.z.string(),
12838
- key: zod.z.string(),
12839
- value: zod.z.unknown()
12840
- }), zod.z.void(), {
12940
+ list: require_sleep.method(zod.z.object({}), zod.z.object({ blocks: zod.z.array(CoreBlockSchema) }), { auth: "admin" }),
12941
+ get: require_sleep.method(zod.z.object({ blockId: zod.z.string() }), zod.z.object({ block: CoreBlockSchema.nullable() }), { auth: "admin" }),
12942
+ /**
12943
+ * Create a block. The code is COMPILED first: storing source that does not
12944
+ * compile turns an editor error into a fork failure the operator meets
12945
+ * minutes later in a log.
12946
+ */
12947
+ create: require_sleep.method(zod.z.object({ block: CoreBlockInputSchema }), zod.z.object({ block: CoreBlockSchema }), {
12948
+ kind: "mutation",
12949
+ auth: "admin",
12950
+ caller: "required"
12951
+ }),
12952
+ update: require_sleep.method(zod.z.object({
12953
+ blockId: zod.z.string(),
12954
+ block: CoreBlockInputFieldsSchema.partial()
12955
+ }), zod.z.object({ block: CoreBlockSchema }), {
12956
+ kind: "mutation",
12957
+ auth: "admin",
12958
+ caller: "required"
12959
+ }),
12960
+ delete: require_sleep.method(zod.z.object({ blockId: zod.z.string() }), zod.z.object({ success: zod.z.literal(true) }), {
12841
12961
  kind: "mutation",
12842
12962
  auth: "admin"
12843
12963
  }),
12844
- /**
12845
- * Rows matching a filter.
12846
- *
12847
- * `columns` is a SQL-level projection: the engine SELECTs only those
12848
- * columns (plus the primary key) instead of the whole row. It is the only
12849
- * way to stop paying disk for a column that is discarded — a heavy JSON
12850
- * column dominates the row, and dropping it in JS after the read pays every
12851
- * byte first. Measured on the live `pipeline-analytics:tracks` table: a
12852
- * 501-row page is 4.6 MB whole and 0.11 MB projected, same index, same
12853
- * plan.
12854
- *
12855
- * The engine REFUSES a column it cannot serve rather than omitting it —
12856
- * see `SettingsQueryInput.columns` for why a projection may not be
12857
- * forgiving the way a predicate is.
12858
- */
12859
- query: require_sleep.method(zod.z.object({
12860
- namespace: zod.z.string().optional(),
12861
- collection: zod.z.string(),
12862
- filter: QueryFilterSchema.optional(),
12863
- columns: zod.z.array(zod.z.string()).readonly().optional()
12864
- }), zod.z.array(SettingsRecordSchema).readonly(), { auth: "admin" }),
12865
- /**
12866
- * Make a SLOT hold this row — insert it, or update whatever already
12867
- * occupies the slot — and answer with the id the row HAS.
12868
- *
12869
- * ## Why the store needed this
12870
- *
12871
- * {@link set} is already an upsert, but its slot is the PRIMARY KEY: the
12872
- * caller has to know the id to address the row. That is exactly what a
12873
- * collection keyed by an `INTEGER` rowid alias cannot do — SQLite assigns
12874
- * the id, so a writer whose uniqueness rule is "one row per
12875
- * `(ownerKind, ownerId, kind, slot)`" has no id to name and no way to
12876
- * express the rule. {@link insert} can express it (a UNIQUE index
12877
- * arbitrates) but only by THROWING at the loser of a race, and the loser
12878
- * here is a legitimate re-capture, not an error.
12879
- *
12880
- * Getting there without this method means read-then-write: query the slot,
12881
- * then `insert` or `update`. Two statements instead of one, a race between
12882
- * them, and a recovery path that has to recognise a UNIQUE violation by its
12883
- * MESSAGE — across a process boundary, because the store lives behind an
12884
- * RPC door. A string match would be the whole gate, and a store that
12885
- * rephrased its error would lose the row silently. One statement has no
12886
- * such gate (D482).
12887
- *
12888
- * ## The contract
12889
- *
12890
- * `conflict` names the DECLARED columns that identify the slot. They must
12891
- * be covered by a UNIQUE index on the collection — SQLite resolves an
12892
- * `ON CONFLICT` target against its indexes and REFUSES the statement when
12893
- * none matches, so a wrong list is a loud error on the first write, never a
12894
- * silently duplicated row. An empty list is refused rather than passed on:
12895
- * `ON CONFLICT()` is not valid SQL, and the intent it would most likely
12896
- * encode ("no slot, just insert") is {@link insert}.
12897
- *
12898
- * Row shape is {@link insert}'s: `record.id` is used when the collection
12899
- * needs a supplied key and IGNORED when the primary key is an `INTEGER`
12900
- * rowid alias — exactly as `insert` and `insertMany` already treat it.
12901
- *
12902
- * Returns the id either way: the one SQLite assigned on an insert, or the
12903
- * one the row it updated already had. A caller cannot tell which happened,
12904
- * and deliberately — every caller wants the slot's id, and one that needed
12905
- * to distinguish creation from replacement would have to read first anyway.
12906
- */
12907
- upsert: require_sleep.method(zod.z.object({
12908
- namespace: zod.z.string().optional(),
12909
- collection: zod.z.string(),
12910
- /** Declared columns identifying the slot; must be covered by a UNIQUE
12911
- * index on the collection. Never empty. */
12912
- conflict: zod.z.array(zod.z.string()).readonly(),
12913
- record: BulkRecordSchema
12914
- }), zod.z.object({
12915
- /** The id the row HAS: assigned by SQLite on an insert, or the existing
12916
- * row's own id on an update. */
12917
- id: zod.z.union([zod.z.string(), zod.z.number()]) }), {
12964
+ setEnabled: require_sleep.method(zod.z.object({
12965
+ blockId: zod.z.string(),
12966
+ enabled: zod.z.boolean()
12967
+ }), zod.z.object({ block: CoreBlockSchema }), {
12918
12968
  kind: "mutation",
12919
12969
  auth: "admin"
12920
12970
  }),
12921
12971
  /**
12922
- * {@link upsert} for a BATCH, in ONE transaction on ONE prepared statement.
12972
+ * Stop this block's runner and let the supervisor bring it back.
12923
12973
  *
12924
- * The write-side twin of {@link insertMany} for rows that may already
12925
- * exist: a rollup writer recomputes a bucket and must overwrite it, and
12926
- * N round trips with N COMMITs is the cost {@link insertMany} was added to
12927
- * avoid. `conflict` has the meaning it has on {@link upsert} (declared
12928
- * columns covered by a UNIQUE index or the primary key, never empty).
12974
+ * **It stores nothing.** There is no "restart requested" flag and no second
12975
+ * lifecycle field: the supervisor already stops and respawns a runner when
12976
+ * the code hash changes, and this exposes that same path deliberately
12977
+ * (D62 — a switch writes the authority that already owned the function).
12978
+ * The next reconcile pass remains the authority, so a restart that lost a
12979
+ * race is corrected within one pass rather than leaving a stale flag behind.
12929
12980
  *
12930
- * Every record of a batch must carry the SAME set of declared columns and
12931
- * every `conflict` column: one batch is one statement shape, and a record
12932
- * that silently bound NULL over a column it did not mention would erase
12933
- * it. A heterogeneous batch is refused whole. **All or nothing.**
12981
+ * Refused for a DISABLED block: nothing would come back, and a button that
12982
+ * silently does nothing is worse than one that says why.
12934
12983
  */
12935
- upsertMany: require_sleep.method(zod.z.object({
12936
- namespace: zod.z.string().optional(),
12937
- collection: zod.z.string(),
12938
- conflict: zod.z.array(zod.z.string()).readonly(),
12939
- records: zod.z.array(BulkRecordSchema).readonly()
12940
- }), zod.z.object({ upserted: zod.z.number().int() }), {
12984
+ restart: require_sleep.method(zod.z.object({ blockId: zod.z.string() }), zod.z.object({ block: CoreBlockSchema }), {
12941
12985
  kind: "mutation",
12942
12986
  auth: "admin"
12943
12987
  }),
12944
- /** Insert a new record. */
12945
- insert: require_sleep.method(zod.z.object({
12946
- namespace: zod.z.string().optional(),
12947
- collection: zod.z.string(),
12948
- record: zod.z.object({
12949
- id: zod.z.string().optional(),
12950
- data: zod.z.record(zod.z.string(), zod.z.unknown())
12951
- })
12952
- }), zod.z.object({
12953
12988
  /**
12954
- * The id the row ACTUALLY got (D473): the one supplied, the UUID minted
12955
- * for an absent one, or the ROWID SQLite assigned on an `INTEGER`
12956
- * primary key — which is the only place an auto key is knowable.
12989
+ * Type-check without saving — what the editor calls as the author types, so
12990
+ * the compiler's verdict is the same one the server will reach.
12991
+ * Accepts `{ code }` or `{ files, entry }` (multi-file project).
12957
12992
  */
12958
- id: zod.z.union([zod.z.string(), zod.z.number()]) }), {
12993
+ compile: require_sleep.method(CoreBlockCompileInputSchema, CoreBlockCompileResultSchema, {
12959
12994
  kind: "mutation",
12960
12995
  auth: "admin"
12961
12996
  }),
12962
12997
  /**
12963
- * Insert MANY records in ONE transaction, returning how many landed.
12964
- *
12965
- * The write-side twin of {@link deleteWhere}, and it exists for the same
12966
- * reason: without it, appending a batch is N round trips and N COMMITs on
12967
- * the single shared connection that also serves every cluster-wide
12968
- * configuration read. The durable load series writes one process row per
12969
- * process per sample — 76 rows every 10 s on the live fleet — and the
12970
- * operator's rule for it is *one transaction per sample, never one per
12971
- * row*. `insert` cannot express that; nothing else could.
12972
- *
12973
- * **All or nothing.** A batch that fails on its fifth row leaves none of
12974
- * the five behind. A half-written sample is worse than a missing one: the
12975
- * missing one reads as "nobody reported", which is true, while the half
12976
- * one reads as "these were the only processes running", which is not.
12977
- *
12978
- * `id` is OPTIONAL per record, and that is the difference from
12979
- * {@link insert}. A collection whose primary key is an `INTEGER` rowid
12980
- * alias has no id to supply — SQLite assigns it, for free, and inventing a
12981
- * `randomUUID()` for such a column would write a 36-character string into
12982
- * an integer key. Omitted on a TEXT key, a uuid is generated exactly as
12983
- * `insert` does.
12998
+ * Hydrated settings form for one block, or null until a `settingsSchema`
12999
+ * is known (extracted from the compiled entry's named export, or set on
13000
+ * the block). Values live in the `core-blocks:settings` collection.
12984
13001
  */
12985
- insertMany: require_sleep.method(zod.z.object({
12986
- namespace: zod.z.string().optional(),
12987
- collection: zod.z.string(),
12988
- records: zod.z.array(BulkRecordSchema).readonly()
12989
- }), zod.z.object({ inserted: zod.z.number().int() }), {
13002
+ getBlockSettings: require_sleep.method(zod.z.object({ blockId: zod.z.string() }), SettingsSchemaWithValuesSchema.nullable(), { auth: "admin" }),
13003
+ /**
13004
+ * Patch persisted preference values for one block. The schema is not
13005
+ * rewritten here — only values. Scripts read the same blob via
13006
+ * `ctx.settings.readAddonStore()` (mirrored into the block addon's
13007
+ * `addon-settings` namespace on every patch).
13008
+ */
13009
+ updateBlockSettings: require_sleep.method(zod.z.object({
13010
+ blockId: zod.z.string(),
13011
+ patch: SettingsPatchSchema
13012
+ }), SettingsUpdateResultSchema, {
12990
13013
  kind: "mutation",
12991
13014
  auth: "admin"
12992
13015
  }),
12993
13016
  /**
12994
- * Several writes, ONE transaction, behind an optional precondition.
12995
- *
12996
- * The multi-collection twin of {@link insertMany}: a write that has to move
12997
- * a set of rows in one collection AND a revision in another cannot be
12998
- * expressed as separate calls without a window in which a reader (or a
12999
- * crash) sees half of it. The retrain annotation save replaces a frame's
13000
- * rows, its dismissed set and its revision this way.
13001
- *
13002
- * `guard`, when given, is read inside the transaction: if the row is
13003
- * missing or its column differs from `equals`, NOTHING is written and the
13004
- * answer is `{ applied: false, current }` with what was found — the
13005
- * compare-and-set a revisioned write needs, with no second reader able to
13006
- * slip between the check and the writes.
13017
+ * The declaration files the editor type-checks against.
13007
13018
  *
13008
- * **All or nothing**, like {@link insertMany}: a throw in any op rolls the
13009
- * whole call back. Ops run in the order given (delete before insert to
13010
- * replace a set). `namespace` applies to every collection named.
13019
+ * Served rather than bundled: the graph is 3.4 MB across 344 files, and
13020
+ * bundling it would roughly double the admin remote. Served rather than
13021
+ * hand-stubbed: a block runs with the same `ctx` an addon gets, so a stub
13022
+ * would drift and the editor would confidently autocomplete methods that
13023
+ * do not exist.
13011
13024
  */
13012
- transact: require_sleep.method(zod.z.object({
13013
- namespace: zod.z.string().optional(),
13014
- guard: TransactGuardSchema.optional(),
13015
- ops: zod.z.array(TransactOpSchema).readonly()
13016
- }), zod.z.object({
13017
- applied: zod.z.boolean(),
13018
- current: zod.z.unknown().optional()
13019
- }), {
13020
- kind: "mutation",
13021
- auth: "admin"
13022
- }),
13023
- /** Update an existing record by ID. */
13024
- update: require_sleep.method(zod.z.object({
13025
- namespace: zod.z.string().optional(),
13026
- collection: zod.z.string(),
13027
- id: zod.z.string(),
13028
- data: zod.z.record(zod.z.string(), zod.z.unknown())
13029
- }), zod.z.void(), {
13030
- kind: "mutation",
13031
- auth: "admin"
13032
- }),
13033
- /** Delete a record by key/ID. */
13034
- delete: require_sleep.method(zod.z.object({
13035
- namespace: zod.z.string().optional(),
13036
- collection: zod.z.string(),
13037
- key: zod.z.string()
13038
- }), zod.z.void(), {
13025
+ getTypeDefs: require_sleep.method(zod.z.object({}), zod.z.object({ libs: zod.z.array(zod.z.object({
13026
+ filePath: zod.z.string(),
13027
+ content: zod.z.string()
13028
+ })) }), { auth: "admin" }),
13029
+ /**
13030
+ * Create a composition block (D659). VALIDATED first against the live
13031
+ * sources and every stored composition; a refusal names every problem by
13032
+ * path and reason (D391) and stores nothing.
13033
+ */
13034
+ createComposition: require_sleep.method(zod.z.object({ block: CompositionBlockInputSchema }), zod.z.object({ block: CoreBlockSchema }), {
13039
13035
  kind: "mutation",
13040
- auth: "admin"
13036
+ auth: "admin",
13037
+ caller: "required"
13041
13038
  }),
13042
13039
  /**
13043
- * Delete every record matching `filter`, in ONE statement, returning how
13044
- * many rows went. This exists because its absence made every retention
13045
- * path in the system an N+1 drain loop: `delete` takes a key, so a sweep
13046
- * had to SELECT a page of full rows — every column, including the fat
13047
- * ones — purely to learn their ids, then issue one call per row.
13048
- *
13049
- * **The filter is required and must resolve.** A predicate naming
13050
- * something the collection cannot express is an ERROR here, not a
13051
- * widening as it is on `query`, and a filter with no predicates is an
13052
- * error rather than "every row". Deleting a whole collection is a
13053
- * legitimate intent, but it must be asked for by name — not reached by
13054
- * an empty object.
13040
+ * Patch a composition block. A changed `composition` is validated exactly
13041
+ * as on create. `expectedUpdatedAt` is the `updatedAt` the caller READ: a
13042
+ * block changed since is refused by name, never silently overwritten.
13055
13043
  */
13056
- deleteWhere: require_sleep.method(zod.z.object({
13057
- namespace: zod.z.string().optional(),
13058
- collection: zod.z.string(),
13059
- filter: MutationFilterSchema
13060
- }), zod.z.object({ deleted: zod.z.number().int() }), {
13044
+ updateComposition: require_sleep.method(zod.z.object({
13045
+ blockId: zod.z.string(),
13046
+ expectedUpdatedAt: zod.z.number(),
13047
+ block: CompositionBlockInputSchema.partial()
13048
+ }), zod.z.object({ block: CoreBlockSchema }), {
13061
13049
  kind: "mutation",
13062
- auth: "admin"
13050
+ auth: "admin",
13051
+ caller: "required"
13063
13052
  }),
13053
+ /** One composition and the composer's state for it, or `not-loaded` (D315). */
13054
+ getComposition: require_sleep.method(zod.z.object({ blockId: zod.z.string() }), CompositionGetReadSchema, { auth: "admin" }),
13055
+ listCompositions: require_sleep.method(zod.z.object({}), CompositionListReadSchema, { auth: "admin" }),
13064
13056
  /**
13065
- * Apply `data` to every record matching `filter`, in one statement,
13066
- * returning how many rows changed. Same filter contract as
13067
- * {@link deleteWhere} — an unresolvable predicate is an error.
13057
+ * The composition that customizes an existing device (D663), found by its
13058
+ * TARGET — never by the block's derived name. One per device at most.
13068
13059
  */
13069
- updateWhere: require_sleep.method(zod.z.object({
13070
- namespace: zod.z.string().optional(),
13071
- collection: zod.z.string(),
13072
- filter: MutationFilterSchema,
13073
- data: zod.z.record(zod.z.string(), zod.z.unknown())
13074
- }), zod.z.object({ updated: zod.z.number().int() }), {
13060
+ getCustomization: require_sleep.method(zod.z.object({
13061
+ addonId: zod.z.string().min(1),
13062
+ stableId: zod.z.string().min(1)
13063
+ }), CompositionCustomizationReadSchema, { auth: "admin" }),
13064
+ /**
13065
+ * The capabilities a composition may BUILD on a device of `deviceType`
13066
+ * (a new device, or added to an existing one), with their fields — the
13067
+ * editor's feature list and the presets' availability (G2, D676). Built
13068
+ * from the validator's own blockers; a replace of a BOUND cap is not
13069
+ * listed here (the device's bindings say what it has).
13070
+ */
13071
+ listComposableCaps: require_sleep.method(zod.z.object({ deviceType: zod.z.enum(require_err_msg.DeviceType) }), ComposableCapabilitiesSchema, { auth: "admin" }),
13072
+ /**
13073
+ * Validate without saving — the same verdict the save reaches. A mutation
13074
+ * for its body size; it writes nothing, so its access is `view`.
13075
+ */
13076
+ validateComposition: require_sleep.method(zod.z.object({
13077
+ composition: require_composition.CompositionSchema,
13078
+ blockId: zod.z.string().optional()
13079
+ }), CompositionValidationSchema, {
13075
13080
  kind: "mutation",
13076
- auth: "admin"
13077
- }),
13078
- /** Count entries in a collection, optionally filtered. */
13079
- count: require_sleep.method(zod.z.object({
13080
- namespace: zod.z.string().optional(),
13081
- collection: zod.z.string(),
13082
- filter: QueryFilterSchema.optional()
13083
- }), zod.z.number(), { auth: "admin" }),
13081
+ auth: "admin",
13082
+ access: "view"
13083
+ })
13084
+ }
13085
+ };
13086
+ //#endregion
13087
+ //#region src/capabilities/custom-model-registry.cap.ts
13088
+ /**
13089
+ * `custom-model-registry` — collection cap exposing operator-registered
13090
+ * custom detection models. Each provider (today: `addon-model-studio`)
13091
+ * contributes a list of `CustomModelDescriptor`s; the hub auto-concatenates
13092
+ * them across providers (`concatCollection`).
13093
+ *
13094
+ * The detection-pipeline is *aware* of this cap: when at least one provider
13095
+ * exists it unions these descriptors into the per-step model picker and the
13096
+ * runtime model-resolution path, alongside the static catalog. When no
13097
+ * provider exists the consumer no-ops entirely (identical to the catalog-only
13098
+ * behaviour).
13099
+ *
13100
+ * A descriptor carries a full `ModelCatalogEntry` directly — the same shape
13101
+ * the static catalog uses — so the existing download/resolution code consumes
13102
+ * it unchanged. `stepId` is the detection step the model targets
13103
+ * (e.g. `'object-detection'`).
13104
+ */
13105
+ var CustomModelDescriptorSchema = zod.z.object({
13106
+ stepId: zod.z.string(),
13107
+ entry: ModelCatalogEntrySchema
13108
+ });
13109
+ /** One regular file of an imported bundle, as the producer measured it. */
13110
+ var ModelBundleFileSchema = zod.z.object({
13111
+ /** Relative path inside the bundle tar; an mlpackage member is `<x>.mlpackage/<member>`. */
13112
+ path: zod.z.string().min(1),
13113
+ bytes: zod.z.number().int().nonnegative(),
13114
+ sha256: zod.z.string().regex(/^[0-9a-f]{64}$/)
13115
+ });
13116
+ var ImportModelBundleInputSchema = zod.z.object({
13117
+ /** The registry provider that keeps the model (Model Studio). */
13118
+ addonId: zod.z.string(),
13119
+ stepId: zod.z.string().min(1),
13120
+ /**
13121
+ * The catalog rows to register, complete, every format URL already
13122
+ * `camstack-local://<modelId>/<file>` naming a file of the bundle. One
13123
+ * bundle may carry several rows (a base and its INT8 variant).
13124
+ */
13125
+ entries: zod.z.array(ModelCatalogEntrySchema).min(1).max(4),
13126
+ /** The bundle tar, offered by the producer over `ctx.peerBytes` (same host). */
13127
+ bundle: zod.z.object({
13128
+ ticket: require_sleep.PeerBytesTicketSchema,
13129
+ bytes: zod.z.number().int().positive(),
13130
+ sha256: zod.z.string().regex(/^[0-9a-f]{64}$/)
13131
+ }),
13132
+ /** Every file the tar must hold; anything missing, extra or different is refused. */
13133
+ files: zod.z.array(ModelBundleFileSchema).min(1).max(64),
13134
+ /** Convert missing engine formats and push the model to every agent afterwards. */
13135
+ distribute: zod.z.boolean()
13136
+ });
13137
+ var ImportModelBundleResultSchema = zod.z.discriminatedUnion("kind", [zod.z.object({
13138
+ kind: zod.z.literal("imported"),
13139
+ modelIds: zod.z.array(zod.z.string()).readonly(),
13140
+ distributed: zod.z.array(zod.z.object({
13141
+ modelId: zod.z.string(),
13142
+ nodeId: zod.z.string(),
13143
+ format: zod.z.enum(require_sleep.MODEL_FORMATS),
13144
+ ok: zod.z.boolean(),
13145
+ error: zod.z.string().optional()
13146
+ })).readonly()
13147
+ }), zod.z.object({
13148
+ kind: zod.z.literal("refused"),
13149
+ reason: zod.z.enum([
13150
+ "transfer-failed",
13151
+ "checksum-mismatch",
13152
+ "bundle-mismatch",
13153
+ "invalid-entry",
13154
+ "id-taken"
13155
+ ]),
13156
+ detail: zod.z.string()
13157
+ })]);
13158
+ var customModelRegistryCapability = {
13159
+ name: "custom-model-registry",
13160
+ scope: "system",
13161
+ mode: "collection",
13162
+ internal: true,
13163
+ methods: {
13084
13164
  /**
13085
- * `COUNT(*)` and one `SUM` / `MIN` / `MAX` per requested field, in ONE
13086
- * statement, over the rows `filter` selects.
13087
- *
13088
- * Exists because "how much is there" was being answered by materialising
13089
- * "what is there". The recorder's storage-pressure sweep asked its in-RAM
13090
- * footage index for bytes/count/oldest/newest across a set of storage
13091
- * locations twice a minute, and the only way to answer that from a map is
13092
- * to visit every row — 7.1 M of them on the live hub, ~15 M row visits a
13093
- * minute on the main thread, which is also why the whole archive had to
13094
- * stay resident to be visited. The question is a sum; nothing needs to be
13095
- * materialised to answer it.
13096
- *
13097
- * **The engine REFUSES a field it cannot serve**, exactly as
13098
- * `query.columns` does and unlike a PREDICATE, which is skipped when
13099
- * unresolvable. A dropped predicate over-matches and the caller sees extra
13100
- * rows; a dropped aggregate returns a NUMBER that is wrong and looks
13101
- * exactly like a real one. That asymmetry is what this repo has already
13102
- * paid for once in `count`.
13165
+ * `internal: true` did not gate the mount (see the 2026-08-26 note on
13166
+ * `data-store-provider`) — this was reachable on the AppRouter by ANY
13167
+ * authenticated session at the default `auth: 'protected'`. The only
13168
+ * consumer, the detection-pipeline's model resolution
13169
+ * (`addon-pipeline/src/detection-pipeline/provider.ts`), calls
13170
+ * `ctx.api.customModelRegistry.listModels.query()` — UDS/Moleculer,
13171
+ * never tRPC — so `auth: 'admin'` costs it nothing.
13103
13172
  */
13104
- aggregate: require_sleep.method(zod.z.object({
13105
- namespace: zod.z.string().optional(),
13106
- collection: zod.z.string(),
13107
- fields: zod.z.array(AggregateFieldSchema).readonly(),
13108
- filter: QueryFilterSchema.optional()
13109
- }), AggregateResultSchema, { auth: "admin" }),
13110
- /** Grouped counts per ((field-origin)/bucketSize) bucket, filtered. */
13111
- histogram: require_sleep.method(zod.z.object({
13112
- namespace: zod.z.string().optional(),
13113
- collection: zod.z.string(),
13114
- field: zod.z.string(),
13115
- bucketSize: zod.z.number().int().positive(),
13116
- origin: zod.z.number().int(),
13117
- filter: QueryFilterSchema.optional()
13118
- }), zod.z.array(zod.z.object({
13119
- bucket: zod.z.number().int(),
13120
- count: zod.z.number().int()
13121
- })).readonly(), { auth: "admin" }),
13122
- /** Check if a collection is empty. */
13123
- isEmpty: require_sleep.method(zod.z.object({
13124
- namespace: zod.z.string().optional(),
13125
- collection: zod.z.string()
13126
- }), zod.z.boolean(), { auth: "admin" }),
13173
+ listModels: require_sleep.method(zod.z.void(), zod.z.array(CustomModelDescriptorSchema).readonly(), { auth: "admin" }),
13127
13174
  /**
13128
- * Declare a typed (SQL-backed) collection with explicit columns +
13129
- * indexes. Idempotent: re-declaring an existing collection with the
13130
- * same shape is a no-op; shape changes (new columns, new indexes)
13131
- * are applied additively. Subsequent `insert` / `update` / `delete`
13132
- * / `query` calls on this collection use typed columns instead of
13133
- * JSON-blob storage — `record.data` fields are spread across
13134
- * columns, `query.filter.where` matches real columns (no
13135
- * `json_extract` overhead), `orderBy` uses column indexes.
13136
- *
13137
- * Addons call this in `onInitialize` before their first read/write.
13138
- * Collection names should be namespaced by addon (e.g.
13139
- * `pipeline-analytics:object-events`) to avoid cross-addon
13140
- * clashes — no automatic prefix is added.
13175
+ * Register a model whose files arrive as ONE bundle tar (D806): the tar
13176
+ * is taken over `ctx.peerBytes`, checked against `bundle.sha256` and
13177
+ * every row of `files`, unpacked into the hub's flat modelsDir (directory
13178
+ * formats included), each format's `.revision` record written, the rows
13179
+ * upserted under the operator's name, the hub marked available and —
13180
+ * when asked — engine formats converted and the model distributed. A
13181
+ * model id already registered by another source is refused, never
13182
+ * overwritten.
13141
13183
  */
13142
- declareCollection: require_sleep.method(DeclareCollectionInputSchema, zod.z.void(), {
13184
+ importModelBundle: require_sleep.method(ImportModelBundleInputSchema, ImportModelBundleResultSchema, {
13143
13185
  kind: "mutation",
13144
- auth: "admin"
13186
+ auth: "admin",
13187
+ timeoutMs: 30 * 6e4
13145
13188
  })
13146
13189
  }
13147
13190
  };
@@ -37862,6 +37905,18 @@ var CalendarInfoSchema = zod.z.object({
37862
37905
  source: CalendarSourceKindSchema,
37863
37906
  enabled: zod.z.boolean()
37864
37907
  });
37908
+ /**
37909
+ * Time contract of {@link CalendarEvent}.
37910
+ *
37911
+ * - Timed event: `startMs` / `endMs` are real instants; `endMs` is exclusive.
37912
+ * - All-day event (`allDay: true`): the event is a run of calendar DATES, not
37913
+ * instants. `startMs` is UTC midnight of the first date and `endMs` is UTC
37914
+ * midnight of the day AFTER the last date (RFC 5545 exclusive DTEND), so a
37915
+ * one-day event spans exactly 24 h. Every provider produces that and no
37916
+ * consumer may read the instants in a local timezone: use
37917
+ * {@link calendarEventLocalSpan}. Reading UTC midnight as local time put an
37918
+ * all-day event on the following day for any viewer ahead of UTC.
37919
+ */
37865
37920
  var CalendarEventSchema = zod.z.object({
37866
37921
  id: zod.z.string().min(1),
37867
37922
  calendarId: zod.z.string().min(1),
@@ -37888,6 +37943,40 @@ var calendarSourceCapability = {
37888
37943
  listEvents: require_sleep.method(CalendarListEventsInputSchema, zod.z.array(CalendarEventSchema).readonly(), { auth: "admin" })
37889
37944
  }
37890
37945
  };
37946
+ function localMidnightOfUtcDate(utcMidnightMs) {
37947
+ const d = new Date(utcMidnightMs);
37948
+ return new Date(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate()).getTime();
37949
+ }
37950
+ /**
37951
+ * The interval an event occupies on the viewer's local clock, end exclusive.
37952
+ * A timed event is returned as is; an all-day event's UTC dates are re-read as
37953
+ * local calendar dates (local midnight to local midnight, DST-safe). A
37954
+ * degenerate all-day end (`<=` start) is widened to one day.
37955
+ */
37956
+ function calendarEventLocalSpan(ev) {
37957
+ if (ev.allDay !== true) return {
37958
+ startMs: ev.startMs,
37959
+ endMs: ev.endMs
37960
+ };
37961
+ const startMs = localMidnightOfUtcDate(ev.startMs);
37962
+ const endMs = localMidnightOfUtcDate(ev.endMs);
37963
+ if (endMs > startMs) return {
37964
+ startMs,
37965
+ endMs
37966
+ };
37967
+ const start = new Date(startMs);
37968
+ return {
37969
+ startMs,
37970
+ endMs: new Date(start.getFullYear(), start.getMonth(), start.getDate() + 1).getTime()
37971
+ };
37972
+ }
37973
+ /** Does the event touch the local calendar day starting at `dayStartMs`? */
37974
+ function calendarEventOnLocalDay(ev, dayStartMs) {
37975
+ const day = new Date(dayStartMs);
37976
+ const dayEndMs = new Date(day.getFullYear(), day.getMonth(), day.getDate() + 1).getTime();
37977
+ const span = calendarEventLocalSpan(ev);
37978
+ return span.startMs < dayEndMs && span.endMs > dayStartMs;
37979
+ }
37891
37980
  //#endregion
37892
37981
  //#region src/capabilities/calendars.cap.ts
37893
37982
  /**
@@ -41161,7 +41250,15 @@ var HubAddressBookSchema = zod.z.object({
41161
41250
  publicEndpoint: HubAddressRoleResolutionSchema
41162
41251
  }),
41163
41252
  /** The `hub=` an app link carries (D709), or null. */
41164
- appLinkHub: zod.z.string().nullable()
41253
+ appLinkHub: zod.z.string().nullable(),
41254
+ /**
41255
+ * Every origin a browser can really reach this hub at, in the scheme each
41256
+ * listener serves: `https://<lan>:<httpsPort>`, and `http://<lan>:<httpPort>`
41257
+ * while LAN HTTP is on, plus the public and custom addresses. Distinct from
41258
+ * `rows`, which show `http://` only while LAN HTTP is on. Never loopback,
41259
+ * never the app link. Absent on a hub older than D794's amendment.
41260
+ */
41261
+ listenerOrigins: zod.z.array(zod.z.string()).readonly().optional()
41165
41262
  });
41166
41263
  var AllowedAddressesSchema = zod.z.object({
41167
41264
  /**
@@ -55400,6 +55497,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
55400
55497
  addonId: null,
55401
55498
  access: "view"
55402
55499
  },
55500
+ "backup.listAvailableDatabases": {
55501
+ capName: "backup",
55502
+ capScope: "system",
55503
+ addonId: null,
55504
+ access: "view"
55505
+ },
55403
55506
  "backup.listDestinations": {
55404
55507
  capName: "backup",
55405
55508
  capScope: "system",
@@ -70716,6 +70819,7 @@ function createSystemProxy(api) {
70716
70819
  upsertDestinationPolicy: (input) => dispatch("backup", "upsertDestinationPolicy", "mutation", input),
70717
70820
  previewSchedule: (input) => dispatch("backup", "previewSchedule", "query", input),
70718
70821
  listSchedules: (input) => dispatch("backup", "listSchedules", "query", input),
70822
+ listAvailableDatabases: (input) => dispatch("backup", "listAvailableDatabases", "query", input),
70719
70823
  upsertSchedule: (input) => dispatch("backup", "upsertSchedule", "mutation", input),
70720
70824
  deleteSchedule: (input) => dispatch("backup", "deleteSchedule", "mutation", input)
70721
70825
  },
@@ -80262,9 +80366,11 @@ exports.DISPLAY_ICON_VOCABULARY = DISPLAY_ICON_VOCABULARY;
80262
80366
  exports.DOORBELL_RISE_DEBOUNCE_MS = DOORBELL_RISE_DEBOUNCE_MS;
80263
80367
  exports.DataStoreDatabaseSchema = DataStoreDatabaseSchema;
80264
80368
  exports.DataStoreEngineInfoSchema = EngineInfoSchema;
80369
+ exports.DatabaseSnapshotRequestSchema = DatabaseSnapshotRequestSchema;
80265
80370
  exports.DatabaseSnapshotResultSchema = DatabaseSnapshotResultSchema;
80266
80371
  exports.DatabaseSnapshotTableSchema = DatabaseSnapshotTableSchema;
80267
80372
  exports.DatabaseSnapshotTargetsSchema = DatabaseSnapshotTargetsSchema;
80373
+ exports.DatabaseSnapshotWrittenSchema = DatabaseSnapshotWrittenSchema;
80268
80374
  exports.DayNightModeSchema = DayNightModeSchema;
80269
80375
  exports.DayNightOptionsSchema = DayNightOptionsSchema;
80270
80376
  exports.DayNightSettingsPatchSchema = DayNightSettingsPatchSchema;
@@ -81620,6 +81726,8 @@ exports.buildVideoArgs = require_composition.buildVideoArgs;
81620
81726
  exports.buildViewerLink = buildViewerLink;
81621
81727
  exports.builtCapabilityBlockers = builtCapabilityBlockers;
81622
81728
  exports.buttonCapability = buttonCapability;
81729
+ exports.calendarEventLocalSpan = calendarEventLocalSpan;
81730
+ exports.calendarEventOnLocalDay = calendarEventOnLocalDay;
81623
81731
  exports.calendarSourceCapability = calendarSourceCapability;
81624
81732
  exports.calendarsCapability = calendarsCapability;
81625
81733
  exports.cameraCredentialsCapability = cameraCredentialsCapability;