@camstack/system 1.2.423 → 1.2.425

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.
Files changed (97) hide show
  1. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js +1 -1
  2. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +1 -1
  3. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +1 -1
  4. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +1 -1
  5. package/dist/builtins/alerts/alerts.addon.js +1 -1
  6. package/dist/builtins/alerts/alerts.addon.mjs +1 -1
  7. package/dist/builtins/autotrack/index.js +1 -1
  8. package/dist/builtins/autotrack/index.mjs +1 -1
  9. package/dist/builtins/backup-orchestrator/backup-databases.d.ts +51 -0
  10. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.d.ts +13 -0
  11. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +248 -17
  12. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +248 -17
  13. package/dist/builtins/backup-orchestrator/manifest-store.d.ts +23 -3
  14. package/dist/builtins/backup-orchestrator/run-queue.d.ts +3 -0
  15. package/dist/builtins/backup-orchestrator/schedule-store.d.ts +7 -1
  16. package/dist/builtins/backup-orchestrator/seed-marker-store.d.ts +34 -0
  17. package/dist/builtins/calendars/calendars.addon.js +1 -1
  18. package/dist/builtins/calendars/calendars.addon.mjs +1 -1
  19. package/dist/builtins/camera-grid/index.js +1 -1
  20. package/dist/builtins/camera-grid/index.mjs +1 -1
  21. package/dist/builtins/composer/composer.addon.js +2 -2
  22. package/dist/builtins/composer/composer.addon.mjs +2 -2
  23. package/dist/builtins/console-logging/index.js +1 -1
  24. package/dist/builtins/console-logging/index.mjs +1 -1
  25. package/dist/builtins/core-blocks/core-blocks.addon.js +2 -2
  26. package/dist/builtins/core-blocks/core-blocks.addon.mjs +2 -2
  27. package/dist/builtins/device-manager/device-manager.addon.js +2 -2
  28. package/dist/builtins/device-manager/device-manager.addon.mjs +2 -2
  29. package/dist/builtins/hub-forwarder/index.js +1 -1
  30. package/dist/builtins/hub-forwarder/index.mjs +1 -1
  31. package/dist/builtins/keychain/index.js +3 -3
  32. package/dist/builtins/keychain/index.mjs +3 -3
  33. package/dist/builtins/liveness-monitor/liveness-monitor.addon.js +1 -1
  34. package/dist/builtins/liveness-monitor/liveness-monitor.addon.mjs +1 -1
  35. package/dist/builtins/local-auth/local-auth.addon.js +2 -2
  36. package/dist/builtins/local-auth/local-auth.addon.mjs +2 -2
  37. package/dist/builtins/local-network/local-network.addon.js +1 -1
  38. package/dist/builtins/local-network/local-network.addon.mjs +1 -1
  39. package/dist/builtins/loki-logging/index.js +1 -1
  40. package/dist/builtins/loki-logging/index.mjs +1 -1
  41. package/dist/builtins/native-metrics/native-metrics.addon.js +1 -1
  42. package/dist/builtins/native-metrics/native-metrics.addon.mjs +1 -1
  43. package/dist/builtins/platform-probe/index.js +1 -1
  44. package/dist/builtins/platform-probe/index.mjs +1 -1
  45. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +1 -1
  46. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +1 -1
  47. package/dist/builtins/snapshot/index.js +1 -1
  48. package/dist/builtins/snapshot/index.mjs +1 -1
  49. package/dist/builtins/sqlite-storage/database-snapshot-provider.d.ts +18 -0
  50. package/dist/builtins/sqlite-storage/file-host-client.d.ts +59 -0
  51. package/dist/builtins/sqlite-storage/file-host-handlers.d.ts +23 -0
  52. package/dist/builtins/sqlite-storage/file-host-protocol.d.ts +151 -0
  53. package/dist/builtins/sqlite-storage/file-host-worker.d.ts +1 -0
  54. package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +1 -1
  55. package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +1 -1
  56. package/dist/builtins/sqlite-storage/index.js +21 -20
  57. package/dist/builtins/sqlite-storage/index.mjs +2 -1
  58. package/dist/builtins/sqlite-storage/owned-sqlite-file.d.ts +136 -0
  59. package/dist/builtins/sqlite-storage/placement-errors.d.ts +60 -0
  60. package/dist/builtins/sqlite-storage/placement-router.d.ts +80 -0
  61. package/dist/builtins/sqlite-storage/retired-collections.d.ts +7 -0
  62. package/dist/builtins/sqlite-storage/sqlite-settings-backend.d.ts +68 -8
  63. package/dist/builtins/sqlite-storage/sqlite-settings.addon.d.ts +23 -26
  64. package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +0 -0
  65. package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +0 -0
  66. package/dist/builtins/sqlite-storage/vector-provider.d.ts +24 -0
  67. package/dist/builtins/sqlite-storage/wal-maintenance.d.ts +17 -0
  68. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +3 -1
  69. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +3 -1
  70. package/dist/builtins/system-backup/system-backup.service.d.ts +48 -15
  71. package/dist/builtins/system-config/system-config.addon.js +2 -2
  72. package/dist/builtins/system-config/system-config.addon.mjs +2 -2
  73. package/dist/builtins/winston-logging/index.js +1 -1
  74. package/dist/builtins/winston-logging/index.mjs +1 -1
  75. package/dist/{composition-sources-CgiAeG-2.js → composition-sources-197keifF.js} +1 -1
  76. package/dist/{composition-sources-BXDchWFn.mjs → composition-sources-DmzTSy26.mjs} +1 -1
  77. package/dist/{constants-1_7QtPNo.js → constants-B5Jd8Zch.js} +1 -1
  78. package/dist/{constants-C2dhkIuF.mjs → constants-CkNLi-XW.mjs} +1 -1
  79. package/dist/{dist-DimotS8e.mjs → dist-DMWeqeTF.mjs} +863 -750
  80. package/dist/{dist-VIIxVsBW.js → dist-DnALrQF-.js} +866 -747
  81. package/dist/file-host-worker.js +144 -0
  82. package/dist/file-host-worker.mjs +144 -0
  83. package/dist/index.js +9 -8
  84. package/dist/index.mjs +6 -5
  85. package/dist/{jwt-signing-key-C8nMdNYW.mjs → jwt-signing-key-CCHXAtrs.mjs} +1 -1
  86. package/dist/{jwt-signing-key-C8s9syVg.js → jwt-signing-key-DeqG7LD9.js} +1 -1
  87. package/dist/{restore-archive-DjppfrIB.js → restore-archive-C4UhQOsg.js} +156 -65
  88. package/dist/{restore-archive-bOMZwY0D.mjs → restore-archive-GevpOHw8.mjs} +151 -66
  89. package/dist/{retired-settings-keys-_muTvNyh.js → retired-settings-keys-0FOsnzIE.js} +1 -1
  90. package/dist/{retired-settings-keys-BYnjMBE-.mjs → retired-settings-keys-CdVFl7m2.mjs} +1 -1
  91. package/dist/sqlite-snapshot-worker.js +1 -1
  92. package/dist/sqlite-snapshot-worker.mjs +1 -1
  93. package/dist/wal-checkpoint-worker.js +1 -1
  94. package/dist/wal-checkpoint-worker.mjs +1 -1
  95. package/dist/wal-maintenance-BtfyfuT5.mjs +0 -0
  96. package/dist/wal-maintenance-DJV1rde2.js +0 -0
  97. package/package.json +1 -1
@@ -10880,6 +10880,568 @@ var authProviderCapability = {
10880
10880
  mount: { kind: "skip" }
10881
10881
  };
10882
10882
  /**
10883
+ * Query filter for settings-store collections.
10884
+ */
10885
+ var QueryFilterSchema = z.object({
10886
+ where: z.record(z.string(), z.unknown()).optional(),
10887
+ whereIn: z.record(z.string(), z.array(z.unknown())).optional(),
10888
+ whereBetween: z.record(z.string(), z.tuple([z.unknown(), z.unknown()])).optional(),
10889
+ /** NULL-safe exclusion: matches rows whose field is NULL OR != the value. */
10890
+ whereNot: z.record(z.string(), z.unknown()).optional(),
10891
+ /** NULL-safe exclusion of a SET — `whereNot` for more than one value. An
10892
+ * empty list excludes nothing. See `QueryFilter.whereNotIn`. */
10893
+ whereNotIn: z.record(z.string(), z.array(z.unknown())).optional(),
10894
+ orderBy: z.object({
10895
+ field: z.string(),
10896
+ direction: z.enum(["asc", "desc"])
10897
+ }).optional(),
10898
+ limit: z.number().optional(),
10899
+ offset: z.number().optional()
10900
+ });
10901
+ /**
10902
+ * The predicate half of a filter, for BULK MUTATIONS.
10903
+ *
10904
+ * Deliberately not `QueryFilterSchema`: `orderBy` / `limit` / `offset` have no
10905
+ * meaning for a statement that rewrites a set, and accepting them would invite
10906
+ * a caller to believe `limit` bounds the damage. Every field is optional here
10907
+ * only so the shape stays composable — the implementation REJECTS a filter
10908
+ * that compiles to no predicate, because that is the whole collection.
10909
+ */
10910
+ var MutationFilterSchema = z.object({
10911
+ where: z.record(z.string(), z.unknown()).optional(),
10912
+ whereIn: z.record(z.string(), z.array(z.unknown())).optional(),
10913
+ whereBetween: z.record(z.string(), z.tuple([z.unknown(), z.unknown()])).optional(),
10914
+ whereNot: z.record(z.string(), z.unknown()).optional(),
10915
+ whereNotIn: z.record(z.string(), z.array(z.unknown())).optional()
10916
+ });
10917
+ /**
10918
+ * One scalar an {@link settingsStoreCapability.methods.aggregate} call asks for.
10919
+ *
10920
+ * `as` names the slot in the result, so the SAME column may be asked twice with
10921
+ * two operations (`MIN(startMs)` and `MAX(startMs)` in one round trip) — which
10922
+ * a `Record<column, op>` shape could not express.
10923
+ */
10924
+ var AggregateFieldSchema = z.object({
10925
+ /** Result key. */
10926
+ as: z.string().min(1),
10927
+ /** Column to aggregate. Must be a real column of a declared collection. */
10928
+ field: z.string().min(1),
10929
+ op: z.enum([
10930
+ "sum",
10931
+ "min",
10932
+ "max"
10933
+ ])
10934
+ });
10935
+ /**
10936
+ * `COUNT(*)` plus one number per requested field.
10937
+ *
10938
+ * `null` means NO ROW MATCHED, never zero: a `SUM` over an empty set and a sum
10939
+ * that really is 0 are different facts, and an accounting caller that renders
10940
+ * "0 bytes, oldest = 0" for "nothing here" reports a lie about a disk.
10941
+ */
10942
+ var AggregateResultSchema = z.object({
10943
+ count: z.number().int(),
10944
+ values: z.record(z.string(), z.number().nullable())
10945
+ });
10946
+ /** A single stored record: `{ id, data }`. */
10947
+ var SettingsRecordSchema = z.object({
10948
+ id: z.string(),
10949
+ data: z.record(z.string(), z.unknown())
10950
+ });
10951
+ /**
10952
+ * One record of a BULK insert — {@link SettingsRecordSchema} with the id made
10953
+ * optional.
10954
+ *
10955
+ * A separate schema rather than loosening the shared one: every other method
10956
+ * on this cap addresses a row BY its id, and making that field optional
10957
+ * everywhere would turn a forgotten key into a silently generated one on
10958
+ * `update` and `delete` as well.
10959
+ */
10960
+ var BulkRecordSchema = z.object({
10961
+ id: z.string().optional(),
10962
+ data: z.record(z.string(), z.unknown())
10963
+ });
10964
+ /**
10965
+ * The database FILES one `sqlite-settings` engine process owns (D851).
10966
+ * Closed on purpose: a file is a thing the engine opens, backs up and gives a
10967
+ * serving thread, so a new one is a code change, never a string a caller
10968
+ * invents. `settings` is `camstack.db` and the default for every collection
10969
+ * that names no file.
10970
+ */
10971
+ var DataStoreDatabaseSchema = z.enum([
10972
+ "settings",
10973
+ "events",
10974
+ "history"
10975
+ ]);
10976
+ /** Every database file, in a stable order (settings first). */
10977
+ var DATA_STORE_DATABASES = DataStoreDatabaseSchema.options;
10978
+ /**
10979
+ * One write inside a {@link settingsStoreCapability.methods.transact} call.
10980
+ * The three that a "replace this set, bump that revision" write needs, plus
10981
+ * the batched upsert a rollup writer needs.
10982
+ */
10983
+ var TransactOpSchema = z.discriminatedUnion("op", [
10984
+ z.object({
10985
+ op: z.literal("deleteWhere"),
10986
+ collection: z.string(),
10987
+ filter: MutationFilterSchema
10988
+ }),
10989
+ z.object({
10990
+ op: z.literal("insertMany"),
10991
+ collection: z.string(),
10992
+ records: z.array(BulkRecordSchema).readonly()
10993
+ }),
10994
+ z.object({
10995
+ op: z.literal("update"),
10996
+ collection: z.string(),
10997
+ id: z.string(),
10998
+ data: z.record(z.string(), z.unknown())
10999
+ }),
11000
+ z.object({
11001
+ op: z.literal("upsertMany"),
11002
+ collection: z.string(),
11003
+ conflict: z.array(z.string()).readonly(),
11004
+ records: z.array(BulkRecordSchema).readonly()
11005
+ })
11006
+ ]);
11007
+ /**
11008
+ * The precondition of a transaction: the row `key` of `collection` must hold
11009
+ * `equals` in `column`, read INSIDE the transaction.
11010
+ */
11011
+ var TransactGuardSchema = z.object({
11012
+ collection: z.string(),
11013
+ key: z.string(),
11014
+ column: z.string(),
11015
+ equals: z.unknown()
11016
+ });
11017
+ /**
11018
+ * Column declaration for a structured (SQL-backed) collection.
11019
+ *
11020
+ * Logical types — the backend translates each to the matching SQLite
11021
+ * storage class and handles per-type marshaling:
11022
+ * - `TEXT` / `INTEGER` / `REAL` — native SQLite types, pass-through
11023
+ * - `JSON` — TEXT under the hood; serialised on write, parsed on read
11024
+ * - `BOOLEAN` — INTEGER 0/1 under the hood; coerced both directions
11025
+ */
11026
+ var CollectionColumnSchema = z.object({
11027
+ name: z.string(),
11028
+ type: z.enum([
11029
+ "TEXT",
11030
+ "INTEGER",
11031
+ "REAL",
11032
+ "JSON",
11033
+ "BOOLEAN"
11034
+ ]),
11035
+ primaryKey: z.boolean().optional(),
11036
+ notNull: z.boolean().optional(),
11037
+ unique: z.boolean().optional(),
11038
+ /**
11039
+ * Column DEFAULT. Required for B2: the four `ensureTable` consumers declare
11040
+ * columns like `enabled INTEGER NOT NULL DEFAULT 1`, and without this the
11041
+ * collection surface simply cannot express their existing tables — which is
11042
+ * why they were still on the uncapped `table*` API.
11043
+ */
11044
+ defaultValue: z.union([
11045
+ z.string(),
11046
+ z.number(),
11047
+ z.boolean()
11048
+ ]).optional()
11049
+ });
11050
+ var CollectionIndexSchema = z.object({
11051
+ name: z.string(),
11052
+ columns: z.array(z.string()).readonly(),
11053
+ unique: z.boolean().optional()
11054
+ });
11055
+ /**
11056
+ * The input of `declareCollection` — ONE schema for the door and for the
11057
+ * engine behind it, so the two surfaces cannot drift (the dispatcher forwards
11058
+ * the payload untouched).
11059
+ *
11060
+ * - `database` — the file the collection lives in (D851). Absent means
11061
+ * `settings`. A declaration naming a file other than the one the table is
11062
+ * already in is REFUSED by the engine, never moved.
11063
+ * - `primaryKey` — a COMPOSITE key, as column names. A single name is the same
11064
+ * as `primaryKey: true` on that column. A composite-keyed collection has no
11065
+ * `id`: it is written with `insertMany` / `upsertMany` / `transact` and read
11066
+ * with `query` / `count` / `aggregate` / `deleteWhere`; the calls that
11067
+ * address one row by id are refused.
11068
+ * - `withoutRowid` — emit `WITHOUT ROWID`. Requires a primary key.
11069
+ */
11070
+ var DeclareCollectionInputSchema = z.object({
11071
+ namespace: z.string().optional(),
11072
+ collection: z.string(),
11073
+ columns: z.array(CollectionColumnSchema).readonly(),
11074
+ indexes: z.array(CollectionIndexSchema).readonly().optional(),
11075
+ database: DataStoreDatabaseSchema.optional(),
11076
+ primaryKey: z.array(z.string()).readonly().optional(),
11077
+ withoutRowid: z.boolean().optional()
11078
+ });
11079
+ /**
11080
+ * settings-store — singleton capability for addon-scoped persistence.
11081
+ *
11082
+ * Every method operates within a `collection`. An optional `namespace`
11083
+ * field provides access to additional data spaces beyond the default
11084
+ * addon settings — useful for business data (events, tracks, faces, etc.).
11085
+ *
11086
+ * **Scoping is the CALLER's, and it is opt-in.** The table is
11087
+ * `namespace ? `${namespace}:${collection}` : collection` — nothing
11088
+ * consults the identity of the caller. An earlier version of this comment
11089
+ * claimed the implementation prefixes every collection with the calling
11090
+ * addon's ID and that "addons never see each other's data"; that was never
11091
+ * true, and this same file contradicted it under `declareCollection`. What
11092
+ * exists is `addon-context-factory`, which passes `namespace: addonId` ON
11093
+ * THE ADDON'S BEHALF for the `addon-settings` / `addon-devices` paths only.
11094
+ * Business collections use bare names, and any caller may name any
11095
+ * namespace, or none. Making the door enforce it is tracked separately —
11096
+ * it renames tables, so it needs a migration.
11097
+ *
11098
+ * **So every method is `auth: 'admin'` (D634).** Because nothing scopes a
11099
+ * call to its caller, a `protected` method here was a raw, unredacted read
11100
+ * (and write) of every addon's collections for any role holding
11101
+ * `category:system` — which is every role: a `viewer` could read every
11102
+ * notifier token in plaintext from `notifiers:notification-targets`. No
11103
+ * browser or app client calls this cap. Addons are not affected: an
11104
+ * addon's `ctx.api` cap call is resolved to the provider directly and never
11105
+ * enters the tRPC router (so the tier gates sessions and tokens, never
11106
+ * addons), and the hub itself calls it through the capability registry.
11107
+ *
11108
+ * - `{ collection: 'addon-settings' }` → table `addon-settings`
11109
+ * - `{ namespace: 'my-addon', collection: 'addon-settings' }` →
11110
+ * table `my-addon:addon-settings`
11111
+ *
11112
+ * Served by the **storage-orchestrator** builtin, which dispatches to the
11113
+ * `data-store-provider` engine registered for the collection
11114
+ * (`sqlite-settings`, a SQLite WAL backend, today). One addon owns the
11115
+ * data door; engines sit behind it
11116
+ * ([D44](../../../../docs/decisions/adr-0044.md)).
11117
+ * Addons access it via `ctx.api.settingsStore.*`.
11118
+ */
11119
+ var settingsStoreCapability = {
11120
+ name: "settings-store",
11121
+ scope: "system",
11122
+ mode: "singleton",
11123
+ methods: {
11124
+ /** Get a single value by key from a collection. */
11125
+ get: method(z.object({
11126
+ namespace: z.string().optional(),
11127
+ collection: z.string(),
11128
+ key: z.string()
11129
+ }), z.unknown(), { auth: "admin" }),
11130
+ /** Set a value by key in a collection (upsert). */
11131
+ set: method(z.object({
11132
+ namespace: z.string().optional(),
11133
+ collection: z.string(),
11134
+ key: z.string(),
11135
+ value: z.unknown()
11136
+ }), z.void(), {
11137
+ kind: "mutation",
11138
+ auth: "admin"
11139
+ }),
11140
+ /**
11141
+ * Rows matching a filter.
11142
+ *
11143
+ * `columns` is a SQL-level projection: the engine SELECTs only those
11144
+ * columns (plus the primary key) instead of the whole row. It is the only
11145
+ * way to stop paying disk for a column that is discarded — a heavy JSON
11146
+ * column dominates the row, and dropping it in JS after the read pays every
11147
+ * byte first. Measured on the live `pipeline-analytics:tracks` table: a
11148
+ * 501-row page is 4.6 MB whole and 0.11 MB projected, same index, same
11149
+ * plan.
11150
+ *
11151
+ * The engine REFUSES a column it cannot serve rather than omitting it —
11152
+ * see `SettingsQueryInput.columns` for why a projection may not be
11153
+ * forgiving the way a predicate is.
11154
+ */
11155
+ query: method(z.object({
11156
+ namespace: z.string().optional(),
11157
+ collection: z.string(),
11158
+ filter: QueryFilterSchema.optional(),
11159
+ columns: z.array(z.string()).readonly().optional()
11160
+ }), z.array(SettingsRecordSchema).readonly(), { auth: "admin" }),
11161
+ /**
11162
+ * Make a SLOT hold this row — insert it, or update whatever already
11163
+ * occupies the slot — and answer with the id the row HAS.
11164
+ *
11165
+ * ## Why the store needed this
11166
+ *
11167
+ * {@link set} is already an upsert, but its slot is the PRIMARY KEY: the
11168
+ * caller has to know the id to address the row. That is exactly what a
11169
+ * collection keyed by an `INTEGER` rowid alias cannot do — SQLite assigns
11170
+ * the id, so a writer whose uniqueness rule is "one row per
11171
+ * `(ownerKind, ownerId, kind, slot)`" has no id to name and no way to
11172
+ * express the rule. {@link insert} can express it (a UNIQUE index
11173
+ * arbitrates) but only by THROWING at the loser of a race, and the loser
11174
+ * here is a legitimate re-capture, not an error.
11175
+ *
11176
+ * Getting there without this method means read-then-write: query the slot,
11177
+ * then `insert` or `update`. Two statements instead of one, a race between
11178
+ * them, and a recovery path that has to recognise a UNIQUE violation by its
11179
+ * MESSAGE — across a process boundary, because the store lives behind an
11180
+ * RPC door. A string match would be the whole gate, and a store that
11181
+ * rephrased its error would lose the row silently. One statement has no
11182
+ * such gate (D482).
11183
+ *
11184
+ * ## The contract
11185
+ *
11186
+ * `conflict` names the DECLARED columns that identify the slot. They must
11187
+ * be covered by a UNIQUE index on the collection — SQLite resolves an
11188
+ * `ON CONFLICT` target against its indexes and REFUSES the statement when
11189
+ * none matches, so a wrong list is a loud error on the first write, never a
11190
+ * silently duplicated row. An empty list is refused rather than passed on:
11191
+ * `ON CONFLICT()` is not valid SQL, and the intent it would most likely
11192
+ * encode ("no slot, just insert") is {@link insert}.
11193
+ *
11194
+ * Row shape is {@link insert}'s: `record.id` is used when the collection
11195
+ * needs a supplied key and IGNORED when the primary key is an `INTEGER`
11196
+ * rowid alias — exactly as `insert` and `insertMany` already treat it.
11197
+ *
11198
+ * Returns the id either way: the one SQLite assigned on an insert, or the
11199
+ * one the row it updated already had. A caller cannot tell which happened,
11200
+ * and deliberately — every caller wants the slot's id, and one that needed
11201
+ * to distinguish creation from replacement would have to read first anyway.
11202
+ */
11203
+ upsert: method(z.object({
11204
+ namespace: z.string().optional(),
11205
+ collection: z.string(),
11206
+ /** Declared columns identifying the slot; must be covered by a UNIQUE
11207
+ * index on the collection. Never empty. */
11208
+ conflict: z.array(z.string()).readonly(),
11209
+ record: BulkRecordSchema
11210
+ }), z.object({
11211
+ /** The id the row HAS: assigned by SQLite on an insert, or the existing
11212
+ * row's own id on an update. */
11213
+ id: z.union([z.string(), z.number()]) }), {
11214
+ kind: "mutation",
11215
+ auth: "admin"
11216
+ }),
11217
+ /**
11218
+ * {@link upsert} for a BATCH, in ONE transaction on ONE prepared statement.
11219
+ *
11220
+ * The write-side twin of {@link insertMany} for rows that may already
11221
+ * exist: a rollup writer recomputes a bucket and must overwrite it, and
11222
+ * N round trips with N COMMITs is the cost {@link insertMany} was added to
11223
+ * avoid. `conflict` has the meaning it has on {@link upsert} (declared
11224
+ * columns covered by a UNIQUE index or the primary key, never empty).
11225
+ *
11226
+ * Every record of a batch must carry the SAME set of declared columns and
11227
+ * every `conflict` column: one batch is one statement shape, and a record
11228
+ * that silently bound NULL over a column it did not mention would erase
11229
+ * it. A heterogeneous batch is refused whole. **All or nothing.**
11230
+ */
11231
+ upsertMany: method(z.object({
11232
+ namespace: z.string().optional(),
11233
+ collection: z.string(),
11234
+ conflict: z.array(z.string()).readonly(),
11235
+ records: z.array(BulkRecordSchema).readonly()
11236
+ }), z.object({ upserted: z.number().int() }), {
11237
+ kind: "mutation",
11238
+ auth: "admin"
11239
+ }),
11240
+ /** Insert a new record. */
11241
+ insert: method(z.object({
11242
+ namespace: z.string().optional(),
11243
+ collection: z.string(),
11244
+ record: z.object({
11245
+ id: z.string().optional(),
11246
+ data: z.record(z.string(), z.unknown())
11247
+ })
11248
+ }), z.object({
11249
+ /**
11250
+ * The id the row ACTUALLY got (D473): the one supplied, the UUID minted
11251
+ * for an absent one, or the ROWID SQLite assigned on an `INTEGER`
11252
+ * primary key — which is the only place an auto key is knowable.
11253
+ */
11254
+ id: z.union([z.string(), z.number()]) }), {
11255
+ kind: "mutation",
11256
+ auth: "admin"
11257
+ }),
11258
+ /**
11259
+ * Insert MANY records in ONE transaction, returning how many landed.
11260
+ *
11261
+ * The write-side twin of {@link deleteWhere}, and it exists for the same
11262
+ * reason: without it, appending a batch is N round trips and N COMMITs on
11263
+ * the single shared connection that also serves every cluster-wide
11264
+ * configuration read. The durable load series writes one process row per
11265
+ * process per sample — 76 rows every 10 s on the live fleet — and the
11266
+ * operator's rule for it is *one transaction per sample, never one per
11267
+ * row*. `insert` cannot express that; nothing else could.
11268
+ *
11269
+ * **All or nothing.** A batch that fails on its fifth row leaves none of
11270
+ * the five behind. A half-written sample is worse than a missing one: the
11271
+ * missing one reads as "nobody reported", which is true, while the half
11272
+ * one reads as "these were the only processes running", which is not.
11273
+ *
11274
+ * `id` is OPTIONAL per record, and that is the difference from
11275
+ * {@link insert}. A collection whose primary key is an `INTEGER` rowid
11276
+ * alias has no id to supply — SQLite assigns it, for free, and inventing a
11277
+ * `randomUUID()` for such a column would write a 36-character string into
11278
+ * an integer key. Omitted on a TEXT key, a uuid is generated exactly as
11279
+ * `insert` does.
11280
+ */
11281
+ insertMany: method(z.object({
11282
+ namespace: z.string().optional(),
11283
+ collection: z.string(),
11284
+ records: z.array(BulkRecordSchema).readonly()
11285
+ }), z.object({ inserted: z.number().int() }), {
11286
+ kind: "mutation",
11287
+ auth: "admin"
11288
+ }),
11289
+ /**
11290
+ * Several writes, ONE transaction, behind an optional precondition.
11291
+ *
11292
+ * The multi-collection twin of {@link insertMany}: a write that has to move
11293
+ * a set of rows in one collection AND a revision in another cannot be
11294
+ * expressed as separate calls without a window in which a reader (or a
11295
+ * crash) sees half of it. The retrain annotation save replaces a frame's
11296
+ * rows, its dismissed set and its revision this way.
11297
+ *
11298
+ * `guard`, when given, is read inside the transaction: if the row is
11299
+ * missing or its column differs from `equals`, NOTHING is written and the
11300
+ * answer is `{ applied: false, current }` with what was found — the
11301
+ * compare-and-set a revisioned write needs, with no second reader able to
11302
+ * slip between the check and the writes.
11303
+ *
11304
+ * **All or nothing**, like {@link insertMany}: a throw in any op rolls the
11305
+ * whole call back. Ops run in the order given (delete before insert to
11306
+ * replace a set). `namespace` applies to every collection named.
11307
+ */
11308
+ transact: method(z.object({
11309
+ namespace: z.string().optional(),
11310
+ guard: TransactGuardSchema.optional(),
11311
+ ops: z.array(TransactOpSchema).readonly()
11312
+ }), z.object({
11313
+ applied: z.boolean(),
11314
+ current: z.unknown().optional()
11315
+ }), {
11316
+ kind: "mutation",
11317
+ auth: "admin"
11318
+ }),
11319
+ /** Update an existing record by ID. */
11320
+ update: method(z.object({
11321
+ namespace: z.string().optional(),
11322
+ collection: z.string(),
11323
+ id: z.string(),
11324
+ data: z.record(z.string(), z.unknown())
11325
+ }), z.void(), {
11326
+ kind: "mutation",
11327
+ auth: "admin"
11328
+ }),
11329
+ /** Delete a record by key/ID. */
11330
+ delete: method(z.object({
11331
+ namespace: z.string().optional(),
11332
+ collection: z.string(),
11333
+ key: z.string()
11334
+ }), z.void(), {
11335
+ kind: "mutation",
11336
+ auth: "admin"
11337
+ }),
11338
+ /**
11339
+ * Delete every record matching `filter`, in ONE statement, returning how
11340
+ * many rows went. This exists because its absence made every retention
11341
+ * path in the system an N+1 drain loop: `delete` takes a key, so a sweep
11342
+ * had to SELECT a page of full rows — every column, including the fat
11343
+ * ones — purely to learn their ids, then issue one call per row.
11344
+ *
11345
+ * **The filter is required and must resolve.** A predicate naming
11346
+ * something the collection cannot express is an ERROR here, not a
11347
+ * widening as it is on `query`, and a filter with no predicates is an
11348
+ * error rather than "every row". Deleting a whole collection is a
11349
+ * legitimate intent, but it must be asked for by name — not reached by
11350
+ * an empty object.
11351
+ */
11352
+ deleteWhere: method(z.object({
11353
+ namespace: z.string().optional(),
11354
+ collection: z.string(),
11355
+ filter: MutationFilterSchema
11356
+ }), z.object({ deleted: z.number().int() }), {
11357
+ kind: "mutation",
11358
+ auth: "admin"
11359
+ }),
11360
+ /**
11361
+ * Apply `data` to every record matching `filter`, in one statement,
11362
+ * returning how many rows changed. Same filter contract as
11363
+ * {@link deleteWhere} — an unresolvable predicate is an error.
11364
+ */
11365
+ updateWhere: method(z.object({
11366
+ namespace: z.string().optional(),
11367
+ collection: z.string(),
11368
+ filter: MutationFilterSchema,
11369
+ data: z.record(z.string(), z.unknown())
11370
+ }), z.object({ updated: z.number().int() }), {
11371
+ kind: "mutation",
11372
+ auth: "admin"
11373
+ }),
11374
+ /** Count entries in a collection, optionally filtered. */
11375
+ count: method(z.object({
11376
+ namespace: z.string().optional(),
11377
+ collection: z.string(),
11378
+ filter: QueryFilterSchema.optional()
11379
+ }), z.number(), { auth: "admin" }),
11380
+ /**
11381
+ * `COUNT(*)` and one `SUM` / `MIN` / `MAX` per requested field, in ONE
11382
+ * statement, over the rows `filter` selects.
11383
+ *
11384
+ * Exists because "how much is there" was being answered by materialising
11385
+ * "what is there". The recorder's storage-pressure sweep asked its in-RAM
11386
+ * footage index for bytes/count/oldest/newest across a set of storage
11387
+ * locations twice a minute, and the only way to answer that from a map is
11388
+ * to visit every row — 7.1 M of them on the live hub, ~15 M row visits a
11389
+ * minute on the main thread, which is also why the whole archive had to
11390
+ * stay resident to be visited. The question is a sum; nothing needs to be
11391
+ * materialised to answer it.
11392
+ *
11393
+ * **The engine REFUSES a field it cannot serve**, exactly as
11394
+ * `query.columns` does and unlike a PREDICATE, which is skipped when
11395
+ * unresolvable. A dropped predicate over-matches and the caller sees extra
11396
+ * rows; a dropped aggregate returns a NUMBER that is wrong and looks
11397
+ * exactly like a real one. That asymmetry is what this repo has already
11398
+ * paid for once in `count`.
11399
+ */
11400
+ aggregate: method(z.object({
11401
+ namespace: z.string().optional(),
11402
+ collection: z.string(),
11403
+ fields: z.array(AggregateFieldSchema).readonly(),
11404
+ filter: QueryFilterSchema.optional()
11405
+ }), AggregateResultSchema, { auth: "admin" }),
11406
+ /** Grouped counts per ((field-origin)/bucketSize) bucket, filtered. */
11407
+ histogram: method(z.object({
11408
+ namespace: z.string().optional(),
11409
+ collection: z.string(),
11410
+ field: z.string(),
11411
+ bucketSize: z.number().int().positive(),
11412
+ origin: z.number().int(),
11413
+ filter: QueryFilterSchema.optional()
11414
+ }), z.array(z.object({
11415
+ bucket: z.number().int(),
11416
+ count: z.number().int()
11417
+ })).readonly(), { auth: "admin" }),
11418
+ /** Check if a collection is empty. */
11419
+ isEmpty: method(z.object({
11420
+ namespace: z.string().optional(),
11421
+ collection: z.string()
11422
+ }), z.boolean(), { auth: "admin" }),
11423
+ /**
11424
+ * Declare a typed (SQL-backed) collection with explicit columns +
11425
+ * indexes. Idempotent: re-declaring an existing collection with the
11426
+ * same shape is a no-op; shape changes (new columns, new indexes)
11427
+ * are applied additively. Subsequent `insert` / `update` / `delete`
11428
+ * / `query` calls on this collection use typed columns instead of
11429
+ * JSON-blob storage — `record.data` fields are spread across
11430
+ * columns, `query.filter.where` matches real columns (no
11431
+ * `json_extract` overhead), `orderBy` uses column indexes.
11432
+ *
11433
+ * Addons call this in `onInitialize` before their first read/write.
11434
+ * Collection names should be namespaced by addon (e.g.
11435
+ * `pipeline-analytics:object-events`) to avoid cross-addon
11436
+ * clashes — no automatic prefix is added.
11437
+ */
11438
+ declareCollection: method(DeclareCollectionInputSchema, z.void(), {
11439
+ kind: "mutation",
11440
+ auth: "admin"
11441
+ })
11442
+ }
11443
+ };
11444
+ /**
10883
11445
  * The suffix of a verified snapshot, written next to the live database it
10884
11446
  * copies: `<db>.backup-snapshot`. A restore promotes it back over `<db>`
10885
11447
  * (`server/backend/src/sqlite-restore.ts` spells the same string — the
@@ -10906,7 +11468,11 @@ var DATABASE_SNAPSHOT_TIMEOUT_MS = 30 * 6e4;
10906
11468
  * database has no sidecars and is just as owned). Paths are absolute on the
10907
11469
  * owner's host.
10908
11470
  */
10909
- var DatabaseSnapshotTargetsSchema = z.object({ databases: z.array(z.object({ livePath: z.string() })) });
11471
+ var DatabaseSnapshotTargetsSchema = z.object({ databases: z.array(z.object({
11472
+ /** Which owned file this is — the handle `writeSnapshot` takes. */
11473
+ databaseId: DataStoreDatabaseSchema,
11474
+ livePath: z.string()
11475
+ })) });
10910
11476
  /** One b-tree table of the snapshot and the rows it holds. */
10911
11477
  var DatabaseSnapshotTableSchema = z.object({
10912
11478
  name: z.string(),
@@ -10939,6 +11505,10 @@ var DatabaseSnapshotResultSchema = z.object({
10939
11505
  /** When the pinned read transaction began (ms epoch) — the snapshot's instant. */
10940
11506
  takenAt: z.number()
10941
11507
  });
11508
+ /** A snapshot the owner wrote, with the file it belongs to. */
11509
+ var DatabaseSnapshotWrittenSchema = DatabaseSnapshotResultSchema.extend({ databaseId: DataStoreDatabaseSchema });
11510
+ /** Which database `writeSnapshot` copies. Required: an unstated ask is not guessed. */
11511
+ var DatabaseSnapshotRequestSchema = z.object({ databaseId: DataStoreDatabaseSchema });
10942
11512
  /**
10943
11513
  * A snapshot as an ARCHIVE records it (`ArchiveManifest.sqliteSnapshots`):
10944
11514
  * the same facts, with both paths relative to the archive root (the node's
@@ -10948,7 +11518,9 @@ var ArchiveSqliteSnapshotSchema = DatabaseSnapshotResultSchema.extend({
10948
11518
  /** Archive-relative path of the live database the archive does NOT carry. */
10949
11519
  livePath: z.string(),
10950
11520
  /** Archive-relative path of the verified copy it carries in its place. */
10951
- snapshotPath: z.string()
11521
+ snapshotPath: z.string(),
11522
+ /** Absent on an archive made before several files were owned: that was `settings`. */
11523
+ databaseId: DataStoreDatabaseSchema.optional()
10952
11524
  });
10953
11525
  /**
10954
11526
  * database-snapshot — the OWNER of a live SQLite database writes a consistent,
@@ -10973,17 +11545,21 @@ var databaseSnapshotCapability = {
10973
11545
  internal: true,
10974
11546
  methods: {
10975
11547
  /**
10976
- * Which databases this owner snapshots. Answered from memory — no file is
10977
- * touched — so a backup can ask it before deciding anything.
11548
+ * EVERY database file this owner has open, with its id. Answered from
11549
+ * memory — no file is touched — so a backup can ask it before deciding
11550
+ * anything. A file created at runtime is listed from the moment it opens,
11551
+ * so no backup can leave it out (D693).
10978
11552
  */
10979
11553
  listDatabases: method(z.object({}), DatabaseSnapshotTargetsSchema, { auth: "admin" }),
10980
11554
  /**
10981
- * Write `<db>.backup-snapshot` and return what it holds. Throws — and
10982
- * leaves no file under the final name — when the copy fails
10983
- * `integrity_check` or its row counts differ from the pinned source's.
10984
- * A second call while one is running joins it.
11555
+ * Write `<db>.backup-snapshot` for ONE database and return what it holds.
11556
+ * Throws — and leaves no file under the final name — when the copy fails
11557
+ * `integrity_check` or its row counts differ from the pinned source's, or
11558
+ * when the database is not open. A second call for the SAME database while
11559
+ * one is running joins it; different databases run one after the other
11560
+ * (the disk reserve check is per copy).
10985
11561
  */
10986
- writeSnapshot: method(z.object({}), DatabaseSnapshotResultSchema, {
11562
+ writeSnapshot: method(DatabaseSnapshotRequestSchema, DatabaseSnapshotWrittenSchema, {
10987
11563
  kind: "mutation",
10988
11564
  auth: "admin",
10989
11565
  timeoutMs: DATABASE_SNAPSHOT_TIMEOUT_MS
@@ -11106,7 +11682,12 @@ var BackupArchiveEntrySchema = z.object({
11106
11682
  /** Top-level locations included in the archive (db, addons, tls, …). */
11107
11683
  locations: z.array(z.string()).readonly(),
11108
11684
  /** Present when the archive is encrypted; restore then needs that key. */
11109
- encryption: BackupArchiveEncryptionSchema.optional()
11685
+ encryption: BackupArchiveEncryptionSchema.optional(),
11686
+ /**
11687
+ * The databases the run asked to carry (its retention class). Absent on an
11688
+ * archive made before several files were owned: that was `['settings']`.
11689
+ */
11690
+ databases: z.array(DataStoreDatabaseSchema).readonly().optional()
11110
11691
  });
11111
11692
  var BackupEntrySchema = z.object({
11112
11693
  id: z.string(),
@@ -11140,7 +11721,12 @@ var ArchiveManifestSchema = z.object({
11140
11721
  * Live SQLite databases this archive carries as their OWNER's verified
11141
11722
  * snapshot instead of as files (D693). Absent on archives made before.
11142
11723
  */
11143
- sqliteSnapshots: z.array(ArchiveSqliteSnapshotSchema).optional()
11724
+ sqliteSnapshots: z.array(ArchiveSqliteSnapshotSchema).optional(),
11725
+ /**
11726
+ * Owned database files the run did NOT carry (not selected): left out of the
11727
+ * tar and the entry list alike. Absent when every owned file was carried.
11728
+ */
11729
+ omittedDatabases: z.array(DataStoreDatabaseSchema).optional()
11144
11730
  });
11145
11731
  var LocationStatSchema = z.object({
11146
11732
  name: z.string(),
@@ -11262,6 +11848,12 @@ var BackupScheduleSchema = z.object({
11262
11848
  /** Optional subset of source locations to include; omitted = all. */
11263
11849
  dataSources: z.array(z.string()).readonly().optional(),
11264
11850
  /**
11851
+ * Which database files this schedule carries. Absent = `['settings']`
11852
+ * (an unstated ask is the minimum, D382). Events and history run weekly,
11853
+ * settings nightly (D852).
11854
+ */
11855
+ databases: z.array(DataStoreDatabaseSchema).readonly().optional(),
11856
+ /**
11265
11857
  * ms-epoch of the last tick that FIRED this schedule. Stamped before the
11266
11858
  * archive runs (it is the dedupe anchor), so it says "attempted", never
11267
11859
  * "succeeded" — a run refused by every destination stamps it too.
@@ -11313,7 +11905,9 @@ var backupCapability = {
11313
11905
  * retention). Omitted = each destination's own policy
11314
11906
  * retention (manual runs).
11315
11907
  */
11316
- retentionCount: z.number().int().min(1).max(1e3).optional()
11908
+ retentionCount: z.number().int().min(1).max(1e3).optional(),
11909
+ /** Database files to carry; omitted = `['settings']`. */
11910
+ databases: z.array(DataStoreDatabaseSchema).optional()
11317
11911
  }).optional(), BackupTriggerResultSchema, {
11318
11912
  kind: "mutation",
11319
11913
  auth: "admin"
@@ -11483,7 +12077,8 @@ var backupCapability = {
11483
12077
  enabled: z.boolean(),
11484
12078
  locationIds: z.array(z.string()).readonly(),
11485
12079
  retentionCount: z.number().int().min(1).max(1e3),
11486
- dataSources: z.array(z.string()).readonly().optional()
12080
+ dataSources: z.array(z.string()).readonly().optional(),
12081
+ databases: z.array(DataStoreDatabaseSchema).readonly().optional()
11487
12082
  }), BackupScheduleSchema, {
11488
12083
  kind: "mutation",
11489
12084
  auth: "admin"
@@ -14776,776 +15371,277 @@ var CoreBlockCompileResultSchema = z.object({
14776
15371
  * Compile input: legacy single-file `{ code }`, or a multi-file project.
14777
15372
  * When `files` is present, it wins over `code`.
14778
15373
  */
14779
- var CoreBlockCompileInputSchema = z.object({
14780
- code: z.string().optional(),
14781
- files: CoreBlockFilesSchema.optional(),
14782
- entry: z.string().min(1).max(260).optional()
14783
- }).superRefine((val, ctx) => {
14784
- if (val.files !== void 0) {
14785
- const entry = val.entry ?? "main.ts";
14786
- if (val.files[entry] === void 0) ctx.addIssue({
14787
- code: "custom",
14788
- message: `files must include the entry "${entry}"`,
14789
- path: ["files"]
14790
- });
14791
- return;
14792
- }
14793
- if (val.code === void 0) ctx.addIssue({
14794
- code: "custom",
14795
- message: "code or files is required",
14796
- path: ["code"]
14797
- });
14798
- });
14799
- var coreBlocksCapability = {
14800
- name: "core-blocks",
14801
- scope: "system",
14802
- mode: "singleton",
14803
- methods: {
14804
- list: method(z.object({}), z.object({ blocks: z.array(CoreBlockSchema) }), { auth: "admin" }),
14805
- get: method(z.object({ blockId: z.string() }), z.object({ block: CoreBlockSchema.nullable() }), { auth: "admin" }),
14806
- /**
14807
- * Create a block. The code is COMPILED first: storing source that does not
14808
- * compile turns an editor error into a fork failure the operator meets
14809
- * minutes later in a log.
14810
- */
14811
- create: method(z.object({ block: CoreBlockInputSchema }), z.object({ block: CoreBlockSchema }), {
14812
- kind: "mutation",
14813
- auth: "admin",
14814
- caller: "required"
14815
- }),
14816
- update: method(z.object({
14817
- blockId: z.string(),
14818
- block: CoreBlockInputFieldsSchema.partial()
14819
- }), z.object({ block: CoreBlockSchema }), {
14820
- kind: "mutation",
14821
- auth: "admin",
14822
- caller: "required"
14823
- }),
14824
- delete: method(z.object({ blockId: z.string() }), z.object({ success: z.literal(true) }), {
14825
- kind: "mutation",
14826
- auth: "admin"
14827
- }),
14828
- setEnabled: method(z.object({
14829
- blockId: z.string(),
14830
- enabled: z.boolean()
14831
- }), z.object({ block: CoreBlockSchema }), {
14832
- kind: "mutation",
14833
- auth: "admin"
14834
- }),
14835
- /**
14836
- * Stop this block's runner and let the supervisor bring it back.
14837
- *
14838
- * **It stores nothing.** There is no "restart requested" flag and no second
14839
- * lifecycle field: the supervisor already stops and respawns a runner when
14840
- * the code hash changes, and this exposes that same path deliberately
14841
- * (D62 — a switch writes the authority that already owned the function).
14842
- * The next reconcile pass remains the authority, so a restart that lost a
14843
- * race is corrected within one pass rather than leaving a stale flag behind.
14844
- *
14845
- * Refused for a DISABLED block: nothing would come back, and a button that
14846
- * silently does nothing is worse than one that says why.
14847
- */
14848
- restart: method(z.object({ blockId: z.string() }), z.object({ block: CoreBlockSchema }), {
14849
- kind: "mutation",
14850
- auth: "admin"
14851
- }),
14852
- /**
14853
- * Type-check without saving — what the editor calls as the author types, so
14854
- * the compiler's verdict is the same one the server will reach.
14855
- * Accepts `{ code }` or `{ files, entry }` (multi-file project).
14856
- */
14857
- compile: method(CoreBlockCompileInputSchema, CoreBlockCompileResultSchema, {
14858
- kind: "mutation",
14859
- auth: "admin"
14860
- }),
14861
- /**
14862
- * Hydrated settings form for one block, or null until a `settingsSchema`
14863
- * is known (extracted from the compiled entry's named export, or set on
14864
- * the block). Values live in the `core-blocks:settings` collection.
14865
- */
14866
- getBlockSettings: method(z.object({ blockId: z.string() }), SettingsSchemaWithValuesSchema.nullable(), { auth: "admin" }),
14867
- /**
14868
- * Patch persisted preference values for one block. The schema is not
14869
- * rewritten here — only values. Scripts read the same blob via
14870
- * `ctx.settings.readAddonStore()` (mirrored into the block addon's
14871
- * `addon-settings` namespace on every patch).
14872
- */
14873
- updateBlockSettings: method(z.object({
14874
- blockId: z.string(),
14875
- patch: SettingsPatchSchema
14876
- }), SettingsUpdateResultSchema, {
14877
- kind: "mutation",
14878
- auth: "admin"
14879
- }),
14880
- /**
14881
- * The declaration files the editor type-checks against.
14882
- *
14883
- * Served rather than bundled: the graph is 3.4 MB across 344 files, and
14884
- * bundling it would roughly double the admin remote. Served rather than
14885
- * hand-stubbed: a block runs with the same `ctx` an addon gets, so a stub
14886
- * would drift and the editor would confidently autocomplete methods that
14887
- * do not exist.
14888
- */
14889
- getTypeDefs: method(z.object({}), z.object({ libs: z.array(z.object({
14890
- filePath: z.string(),
14891
- content: z.string()
14892
- })) }), { auth: "admin" }),
14893
- /**
14894
- * Create a composition block (D659). VALIDATED first against the live
14895
- * sources and every stored composition; a refusal names every problem by
14896
- * path and reason (D391) and stores nothing.
14897
- */
14898
- createComposition: method(z.object({ block: CompositionBlockInputSchema }), z.object({ block: CoreBlockSchema }), {
14899
- kind: "mutation",
14900
- auth: "admin",
14901
- caller: "required"
14902
- }),
14903
- /**
14904
- * Patch a composition block. A changed `composition` is validated exactly
14905
- * as on create. `expectedUpdatedAt` is the `updatedAt` the caller READ: a
14906
- * block changed since is refused by name, never silently overwritten.
14907
- */
14908
- updateComposition: method(z.object({
14909
- blockId: z.string(),
14910
- expectedUpdatedAt: z.number(),
14911
- block: CompositionBlockInputSchema.partial()
14912
- }), z.object({ block: CoreBlockSchema }), {
14913
- kind: "mutation",
14914
- auth: "admin",
14915
- caller: "required"
14916
- }),
14917
- /** One composition and the composer's state for it, or `not-loaded` (D315). */
14918
- getComposition: method(z.object({ blockId: z.string() }), CompositionGetReadSchema, { auth: "admin" }),
14919
- listCompositions: method(z.object({}), CompositionListReadSchema, { auth: "admin" }),
14920
- /**
14921
- * The composition that customizes an existing device (D663), found by its
14922
- * TARGET — never by the block's derived name. One per device at most.
14923
- */
14924
- getCustomization: method(z.object({
14925
- addonId: z.string().min(1),
14926
- stableId: z.string().min(1)
14927
- }), CompositionCustomizationReadSchema, { auth: "admin" }),
14928
- /**
14929
- * The capabilities a composition may BUILD on a device of `deviceType`
14930
- * (a new device, or added to an existing one), with their fields — the
14931
- * editor's feature list and the presets' availability (G2, D676). Built
14932
- * from the validator's own blockers; a replace of a BOUND cap is not
14933
- * listed here (the device's bindings say what it has).
14934
- */
14935
- listComposableCaps: method(z.object({ deviceType: z.enum(DeviceType) }), ComposableCapabilitiesSchema, { auth: "admin" }),
14936
- /**
14937
- * Validate without saving — the same verdict the save reaches. A mutation
14938
- * for its body size; it writes nothing, so its access is `view`.
14939
- */
14940
- validateComposition: method(z.object({
14941
- composition: CompositionSchema,
14942
- blockId: z.string().optional()
14943
- }), CompositionValidationSchema, {
14944
- kind: "mutation",
14945
- auth: "admin",
14946
- access: "view"
14947
- })
14948
- }
14949
- };
14950
- /**
14951
- * `custom-model-registry` — collection cap exposing operator-registered
14952
- * custom detection models. Each provider (today: `addon-model-studio`)
14953
- * contributes a list of `CustomModelDescriptor`s; the hub auto-concatenates
14954
- * them across providers (`concatCollection`).
14955
- *
14956
- * The detection-pipeline is *aware* of this cap: when at least one provider
14957
- * exists it unions these descriptors into the per-step model picker and the
14958
- * runtime model-resolution path, alongside the static catalog. When no
14959
- * provider exists the consumer no-ops entirely (identical to the catalog-only
14960
- * behaviour).
14961
- *
14962
- * A descriptor carries a full `ModelCatalogEntry` directly — the same shape
14963
- * the static catalog uses — so the existing download/resolution code consumes
14964
- * it unchanged. `stepId` is the detection step the model targets
14965
- * (e.g. `'object-detection'`).
14966
- */
14967
- var CustomModelDescriptorSchema = z.object({
14968
- stepId: z.string(),
14969
- entry: ModelCatalogEntrySchema
14970
- });
14971
- /** One regular file of an imported bundle, as the producer measured it. */
14972
- var ModelBundleFileSchema = z.object({
14973
- /** Relative path inside the bundle tar; an mlpackage member is `<x>.mlpackage/<member>`. */
14974
- path: z.string().min(1),
14975
- bytes: z.number().int().nonnegative(),
14976
- sha256: z.string().regex(/^[0-9a-f]{64}$/)
14977
- });
14978
- var ImportModelBundleInputSchema = z.object({
14979
- /** The registry provider that keeps the model (Model Studio). */
14980
- addonId: z.string(),
14981
- stepId: z.string().min(1),
14982
- /**
14983
- * The catalog rows to register, complete, every format URL already
14984
- * `camstack-local://<modelId>/<file>` naming a file of the bundle. One
14985
- * bundle may carry several rows (a base and its INT8 variant).
14986
- */
14987
- entries: z.array(ModelCatalogEntrySchema).min(1).max(4),
14988
- /** The bundle tar, offered by the producer over `ctx.peerBytes` (same host). */
14989
- bundle: z.object({
14990
- ticket: PeerBytesTicketSchema,
14991
- bytes: z.number().int().positive(),
14992
- sha256: z.string().regex(/^[0-9a-f]{64}$/)
14993
- }),
14994
- /** Every file the tar must hold; anything missing, extra or different is refused. */
14995
- files: z.array(ModelBundleFileSchema).min(1).max(64),
14996
- /** Convert missing engine formats and push the model to every agent afterwards. */
14997
- distribute: z.boolean()
14998
- });
14999
- var ImportModelBundleResultSchema = z.discriminatedUnion("kind", [z.object({
15000
- kind: z.literal("imported"),
15001
- modelIds: z.array(z.string()).readonly(),
15002
- distributed: z.array(z.object({
15003
- modelId: z.string(),
15004
- nodeId: z.string(),
15005
- format: z.enum(MODEL_FORMATS),
15006
- ok: z.boolean(),
15007
- error: z.string().optional()
15008
- })).readonly()
15009
- }), z.object({
15010
- kind: z.literal("refused"),
15011
- reason: z.enum([
15012
- "transfer-failed",
15013
- "checksum-mismatch",
15014
- "bundle-mismatch",
15015
- "invalid-entry",
15016
- "id-taken"
15017
- ]),
15018
- detail: z.string()
15019
- })]);
15020
- var customModelRegistryCapability = {
15021
- name: "custom-model-registry",
15022
- scope: "system",
15023
- mode: "collection",
15024
- internal: true,
15025
- methods: {
15026
- /**
15027
- * `internal: true` did not gate the mount (see the 2026-08-26 note on
15028
- * `data-store-provider`) — this was reachable on the AppRouter by ANY
15029
- * authenticated session at the default `auth: 'protected'`. The only
15030
- * consumer, the detection-pipeline's model resolution
15031
- * (`addon-pipeline/src/detection-pipeline/provider.ts`), calls
15032
- * `ctx.api.customModelRegistry.listModels.query()` — UDS/Moleculer,
15033
- * never tRPC — so `auth: 'admin'` costs it nothing.
15034
- */
15035
- listModels: method(z.void(), z.array(CustomModelDescriptorSchema).readonly(), { auth: "admin" }),
15036
- /**
15037
- * Register a model whose files arrive as ONE bundle tar (D806): the tar
15038
- * is taken over `ctx.peerBytes`, checked against `bundle.sha256` and
15039
- * every row of `files`, unpacked into the hub's flat modelsDir (directory
15040
- * formats included), each format's `.revision` record written, the rows
15041
- * upserted under the operator's name, the hub marked available and —
15042
- * when asked — engine formats converted and the model distributed. A
15043
- * model id already registered by another source is refused, never
15044
- * overwritten.
15045
- */
15046
- importModelBundle: method(ImportModelBundleInputSchema, ImportModelBundleResultSchema, {
15047
- kind: "mutation",
15048
- auth: "admin",
15049
- timeoutMs: 30 * 6e4
15050
- })
15051
- }
15052
- };
15053
- /**
15054
- * Query filter for settings-store collections.
15055
- */
15056
- var QueryFilterSchema = z.object({
15057
- where: z.record(z.string(), z.unknown()).optional(),
15058
- whereIn: z.record(z.string(), z.array(z.unknown())).optional(),
15059
- whereBetween: z.record(z.string(), z.tuple([z.unknown(), z.unknown()])).optional(),
15060
- /** NULL-safe exclusion: matches rows whose field is NULL OR != the value. */
15061
- whereNot: z.record(z.string(), z.unknown()).optional(),
15062
- /** NULL-safe exclusion of a SET — `whereNot` for more than one value. An
15063
- * empty list excludes nothing. See `QueryFilter.whereNotIn`. */
15064
- whereNotIn: z.record(z.string(), z.array(z.unknown())).optional(),
15065
- orderBy: z.object({
15066
- field: z.string(),
15067
- direction: z.enum(["asc", "desc"])
15068
- }).optional(),
15069
- limit: z.number().optional(),
15070
- offset: z.number().optional()
15071
- });
15072
- /**
15073
- * The predicate half of a filter, for BULK MUTATIONS.
15074
- *
15075
- * Deliberately not `QueryFilterSchema`: `orderBy` / `limit` / `offset` have no
15076
- * meaning for a statement that rewrites a set, and accepting them would invite
15077
- * a caller to believe `limit` bounds the damage. Every field is optional here
15078
- * only so the shape stays composable — the implementation REJECTS a filter
15079
- * that compiles to no predicate, because that is the whole collection.
15080
- */
15081
- var MutationFilterSchema = z.object({
15082
- where: z.record(z.string(), z.unknown()).optional(),
15083
- whereIn: z.record(z.string(), z.array(z.unknown())).optional(),
15084
- whereBetween: z.record(z.string(), z.tuple([z.unknown(), z.unknown()])).optional(),
15085
- whereNot: z.record(z.string(), z.unknown()).optional(),
15086
- whereNotIn: z.record(z.string(), z.array(z.unknown())).optional()
15087
- });
15088
- /**
15089
- * One scalar an {@link settingsStoreCapability.methods.aggregate} call asks for.
15090
- *
15091
- * `as` names the slot in the result, so the SAME column may be asked twice with
15092
- * two operations (`MIN(startMs)` and `MAX(startMs)` in one round trip) — which
15093
- * a `Record<column, op>` shape could not express.
15094
- */
15095
- var AggregateFieldSchema = z.object({
15096
- /** Result key. */
15097
- as: z.string().min(1),
15098
- /** Column to aggregate. Must be a real column of a declared collection. */
15099
- field: z.string().min(1),
15100
- op: z.enum([
15101
- "sum",
15102
- "min",
15103
- "max"
15104
- ])
15105
- });
15106
- /**
15107
- * `COUNT(*)` plus one number per requested field.
15108
- *
15109
- * `null` means NO ROW MATCHED, never zero: a `SUM` over an empty set and a sum
15110
- * that really is 0 are different facts, and an accounting caller that renders
15111
- * "0 bytes, oldest = 0" for "nothing here" reports a lie about a disk.
15112
- */
15113
- var AggregateResultSchema = z.object({
15114
- count: z.number().int(),
15115
- values: z.record(z.string(), z.number().nullable())
15116
- });
15117
- /** A single stored record: `{ id, data }`. */
15118
- var SettingsRecordSchema = z.object({
15119
- id: z.string(),
15120
- data: z.record(z.string(), z.unknown())
15121
- });
15122
- /**
15123
- * One record of a BULK insert — {@link SettingsRecordSchema} with the id made
15124
- * optional.
15125
- *
15126
- * A separate schema rather than loosening the shared one: every other method
15127
- * on this cap addresses a row BY its id, and making that field optional
15128
- * everywhere would turn a forgotten key into a silently generated one on
15129
- * `update` and `delete` as well.
15130
- */
15131
- var BulkRecordSchema = z.object({
15132
- id: z.string().optional(),
15133
- data: z.record(z.string(), z.unknown())
15134
- });
15135
- /**
15136
- * One write inside a {@link settingsStoreCapability.methods.transact} call.
15137
- * Only the three that a "replace this set, bump that revision" write needs.
15138
- */
15139
- var TransactOpSchema = z.discriminatedUnion("op", [
15140
- z.object({
15141
- op: z.literal("deleteWhere"),
15142
- collection: z.string(),
15143
- filter: MutationFilterSchema
15144
- }),
15145
- z.object({
15146
- op: z.literal("insertMany"),
15147
- collection: z.string(),
15148
- records: z.array(BulkRecordSchema).readonly()
15149
- }),
15150
- z.object({
15151
- op: z.literal("update"),
15152
- collection: z.string(),
15153
- id: z.string(),
15154
- data: z.record(z.string(), z.unknown())
15155
- })
15156
- ]);
15157
- /**
15158
- * The precondition of a transaction: the row `key` of `collection` must hold
15159
- * `equals` in `column`, read INSIDE the transaction.
15160
- */
15161
- var TransactGuardSchema = z.object({
15162
- collection: z.string(),
15163
- key: z.string(),
15164
- column: z.string(),
15165
- equals: z.unknown()
15166
- });
15167
- /**
15168
- * Column declaration for a structured (SQL-backed) collection.
15169
- *
15170
- * Logical types — the backend translates each to the matching SQLite
15171
- * storage class and handles per-type marshaling:
15172
- * - `TEXT` / `INTEGER` / `REAL` — native SQLite types, pass-through
15173
- * - `JSON` — TEXT under the hood; serialised on write, parsed on read
15174
- * - `BOOLEAN` — INTEGER 0/1 under the hood; coerced both directions
15175
- */
15176
- var CollectionColumnSchema = z.object({
15177
- name: z.string(),
15178
- type: z.enum([
15179
- "TEXT",
15180
- "INTEGER",
15181
- "REAL",
15182
- "JSON",
15183
- "BOOLEAN"
15184
- ]),
15185
- primaryKey: z.boolean().optional(),
15186
- notNull: z.boolean().optional(),
15187
- unique: z.boolean().optional(),
15188
- /**
15189
- * Column DEFAULT. Required for B2: the four `ensureTable` consumers declare
15190
- * columns like `enabled INTEGER NOT NULL DEFAULT 1`, and without this the
15191
- * collection surface simply cannot express their existing tables — which is
15192
- * why they were still on the uncapped `table*` API.
15193
- */
15194
- defaultValue: z.union([
15195
- z.string(),
15196
- z.number(),
15197
- z.boolean()
15198
- ]).optional()
15199
- });
15200
- var CollectionIndexSchema = z.object({
15201
- name: z.string(),
15202
- columns: z.array(z.string()).readonly(),
15203
- unique: z.boolean().optional()
15204
- });
15205
- /**
15206
- * settings-store — singleton capability for addon-scoped persistence.
15207
- *
15208
- * Every method operates within a `collection`. An optional `namespace`
15209
- * field provides access to additional data spaces beyond the default
15210
- * addon settings — useful for business data (events, tracks, faces, etc.).
15211
- *
15212
- * **Scoping is the CALLER's, and it is opt-in.** The table is
15213
- * `namespace ? `${namespace}:${collection}` : collection` — nothing
15214
- * consults the identity of the caller. An earlier version of this comment
15215
- * claimed the implementation prefixes every collection with the calling
15216
- * addon's ID and that "addons never see each other's data"; that was never
15217
- * true, and this same file contradicted it under `declareCollection`. What
15218
- * exists is `addon-context-factory`, which passes `namespace: addonId` ON
15219
- * THE ADDON'S BEHALF for the `addon-settings` / `addon-devices` paths only.
15220
- * Business collections use bare names, and any caller may name any
15221
- * namespace, or none. Making the door enforce it is tracked separately —
15222
- * it renames tables, so it needs a migration.
15223
- *
15224
- * **So every method is `auth: 'admin'` (D634).** Because nothing scopes a
15225
- * call to its caller, a `protected` method here was a raw, unredacted read
15226
- * (and write) of every addon's collections for any role holding
15227
- * `category:system` — which is every role: a `viewer` could read every
15228
- * notifier token in plaintext from `notifiers:notification-targets`. No
15229
- * browser or app client calls this cap. Addons are not affected: an
15230
- * addon's `ctx.api` cap call is resolved to the provider directly and never
15231
- * enters the tRPC router (so the tier gates sessions and tokens, never
15232
- * addons), and the hub itself calls it through the capability registry.
15233
- *
15234
- * - `{ collection: 'addon-settings' }` → table `addon-settings`
15235
- * - `{ namespace: 'my-addon', collection: 'addon-settings' }` →
15236
- * table `my-addon:addon-settings`
15237
- *
15238
- * Served by the **storage-orchestrator** builtin, which dispatches to the
15239
- * `data-store-provider` engine registered for the collection
15240
- * (`sqlite-settings`, a SQLite WAL backend, today). One addon owns the
15241
- * data door; engines sit behind it
15242
- * ([D44](../../../../docs/decisions/adr-0044.md)).
15243
- * Addons access it via `ctx.api.settingsStore.*`.
15244
- */
15245
- var settingsStoreCapability = {
15246
- name: "settings-store",
15374
+ var CoreBlockCompileInputSchema = z.object({
15375
+ code: z.string().optional(),
15376
+ files: CoreBlockFilesSchema.optional(),
15377
+ entry: z.string().min(1).max(260).optional()
15378
+ }).superRefine((val, ctx) => {
15379
+ if (val.files !== void 0) {
15380
+ const entry = val.entry ?? "main.ts";
15381
+ if (val.files[entry] === void 0) ctx.addIssue({
15382
+ code: "custom",
15383
+ message: `files must include the entry "${entry}"`,
15384
+ path: ["files"]
15385
+ });
15386
+ return;
15387
+ }
15388
+ if (val.code === void 0) ctx.addIssue({
15389
+ code: "custom",
15390
+ message: "code or files is required",
15391
+ path: ["code"]
15392
+ });
15393
+ });
15394
+ var coreBlocksCapability = {
15395
+ name: "core-blocks",
15247
15396
  scope: "system",
15248
15397
  mode: "singleton",
15249
15398
  methods: {
15250
- /** Get a single value by key from a collection. */
15251
- get: method(z.object({
15252
- namespace: z.string().optional(),
15253
- collection: z.string(),
15254
- key: z.string()
15255
- }), z.unknown(), { auth: "admin" }),
15256
- /** Set a value by key in a collection (upsert). */
15257
- set: method(z.object({
15258
- namespace: z.string().optional(),
15259
- collection: z.string(),
15260
- key: z.string(),
15261
- value: z.unknown()
15262
- }), z.void(), {
15263
- kind: "mutation",
15264
- auth: "admin"
15265
- }),
15266
- /**
15267
- * Rows matching a filter.
15268
- *
15269
- * `columns` is a SQL-level projection: the engine SELECTs only those
15270
- * columns (plus the primary key) instead of the whole row. It is the only
15271
- * way to stop paying disk for a column that is discarded — a heavy JSON
15272
- * column dominates the row, and dropping it in JS after the read pays every
15273
- * byte first. Measured on the live `pipeline-analytics:tracks` table: a
15274
- * 501-row page is 4.6 MB whole and 0.11 MB projected, same index, same
15275
- * plan.
15276
- *
15277
- * The engine REFUSES a column it cannot serve rather than omitting it —
15278
- * see `SettingsQueryInput.columns` for why a projection may not be
15279
- * forgiving the way a predicate is.
15280
- */
15281
- query: method(z.object({
15282
- namespace: z.string().optional(),
15283
- collection: z.string(),
15284
- filter: QueryFilterSchema.optional(),
15285
- columns: z.array(z.string()).readonly().optional()
15286
- }), z.array(SettingsRecordSchema).readonly(), { auth: "admin" }),
15399
+ list: method(z.object({}), z.object({ blocks: z.array(CoreBlockSchema) }), { auth: "admin" }),
15400
+ get: method(z.object({ blockId: z.string() }), z.object({ block: CoreBlockSchema.nullable() }), { auth: "admin" }),
15287
15401
  /**
15288
- * Make a SLOT hold this row — insert it, or update whatever already
15289
- * occupies the slot — and answer with the id the row HAS.
15290
- *
15291
- * ## Why the store needed this
15292
- *
15293
- * {@link set} is already an upsert, but its slot is the PRIMARY KEY: the
15294
- * caller has to know the id to address the row. That is exactly what a
15295
- * collection keyed by an `INTEGER` rowid alias cannot do — SQLite assigns
15296
- * the id, so a writer whose uniqueness rule is "one row per
15297
- * `(ownerKind, ownerId, kind, slot)`" has no id to name and no way to
15298
- * express the rule. {@link insert} can express it (a UNIQUE index
15299
- * arbitrates) but only by THROWING at the loser of a race, and the loser
15300
- * here is a legitimate re-capture, not an error.
15301
- *
15302
- * Getting there without this method means read-then-write: query the slot,
15303
- * then `insert` or `update`. Two statements instead of one, a race between
15304
- * them, and a recovery path that has to recognise a UNIQUE violation by its
15305
- * MESSAGE — across a process boundary, because the store lives behind an
15306
- * RPC door. A string match would be the whole gate, and a store that
15307
- * rephrased its error would lose the row silently. One statement has no
15308
- * such gate (D482).
15309
- *
15310
- * ## The contract
15311
- *
15312
- * `conflict` names the DECLARED columns that identify the slot. They must
15313
- * be covered by a UNIQUE index on the collection — SQLite resolves an
15314
- * `ON CONFLICT` target against its indexes and REFUSES the statement when
15315
- * none matches, so a wrong list is a loud error on the first write, never a
15316
- * silently duplicated row. An empty list is refused rather than passed on:
15317
- * `ON CONFLICT()` is not valid SQL, and the intent it would most likely
15318
- * encode ("no slot, just insert") is {@link insert}.
15319
- *
15320
- * Row shape is {@link insert}'s: `record.id` is used when the collection
15321
- * needs a supplied key and IGNORED when the primary key is an `INTEGER`
15322
- * rowid alias — exactly as `insert` and `insertMany` already treat it.
15323
- *
15324
- * Returns the id either way: the one SQLite assigned on an insert, or the
15325
- * one the row it updated already had. A caller cannot tell which happened,
15326
- * and deliberately — every caller wants the slot's id, and one that needed
15327
- * to distinguish creation from replacement would have to read first anyway.
15402
+ * Create a block. The code is COMPILED first: storing source that does not
15403
+ * compile turns an editor error into a fork failure the operator meets
15404
+ * minutes later in a log.
15328
15405
  */
15329
- upsert: method(z.object({
15330
- namespace: z.string().optional(),
15331
- collection: z.string(),
15332
- /** Declared columns identifying the slot; must be covered by a UNIQUE
15333
- * index on the collection. Never empty. */
15334
- conflict: z.array(z.string()).readonly(),
15335
- record: BulkRecordSchema
15336
- }), z.object({
15337
- /** The id the row HAS: assigned by SQLite on an insert, or the existing
15338
- * row's own id on an update. */
15339
- id: z.union([z.string(), z.number()]) }), {
15406
+ create: method(z.object({ block: CoreBlockInputSchema }), z.object({ block: CoreBlockSchema }), {
15340
15407
  kind: "mutation",
15341
- auth: "admin"
15408
+ auth: "admin",
15409
+ caller: "required"
15342
15410
  }),
15343
- /** Insert a new record. */
15344
- insert: method(z.object({
15345
- namespace: z.string().optional(),
15346
- collection: z.string(),
15347
- record: z.object({
15348
- id: z.string().optional(),
15349
- data: z.record(z.string(), z.unknown())
15350
- })
15351
- }), z.object({
15352
- /**
15353
- * The id the row ACTUALLY got (D473): the one supplied, the UUID minted
15354
- * for an absent one, or the ROWID SQLite assigned on an `INTEGER`
15355
- * primary key — which is the only place an auto key is knowable.
15356
- */
15357
- id: z.union([z.string(), z.number()]) }), {
15411
+ update: method(z.object({
15412
+ blockId: z.string(),
15413
+ block: CoreBlockInputFieldsSchema.partial()
15414
+ }), z.object({ block: CoreBlockSchema }), {
15415
+ kind: "mutation",
15416
+ auth: "admin",
15417
+ caller: "required"
15418
+ }),
15419
+ delete: method(z.object({ blockId: z.string() }), z.object({ success: z.literal(true) }), {
15358
15420
  kind: "mutation",
15359
15421
  auth: "admin"
15360
15422
  }),
15361
- /**
15362
- * Insert MANY records in ONE transaction, returning how many landed.
15363
- *
15364
- * The write-side twin of {@link deleteWhere}, and it exists for the same
15365
- * reason: without it, appending a batch is N round trips and N COMMITs on
15366
- * the single shared connection that also serves every cluster-wide
15367
- * configuration read. The durable load series writes one process row per
15368
- * process per sample — 76 rows every 10 s on the live fleet — and the
15369
- * operator's rule for it is *one transaction per sample, never one per
15370
- * row*. `insert` cannot express that; nothing else could.
15371
- *
15372
- * **All or nothing.** A batch that fails on its fifth row leaves none of
15373
- * the five behind. A half-written sample is worse than a missing one: the
15374
- * missing one reads as "nobody reported", which is true, while the half
15375
- * one reads as "these were the only processes running", which is not.
15376
- *
15377
- * `id` is OPTIONAL per record, and that is the difference from
15378
- * {@link insert}. A collection whose primary key is an `INTEGER` rowid
15379
- * alias has no id to supply — SQLite assigns it, for free, and inventing a
15380
- * `randomUUID()` for such a column would write a 36-character string into
15381
- * an integer key. Omitted on a TEXT key, a uuid is generated exactly as
15382
- * `insert` does.
15383
- */
15384
- insertMany: method(z.object({
15385
- namespace: z.string().optional(),
15386
- collection: z.string(),
15387
- records: z.array(BulkRecordSchema).readonly()
15388
- }), z.object({ inserted: z.number().int() }), {
15423
+ setEnabled: method(z.object({
15424
+ blockId: z.string(),
15425
+ enabled: z.boolean()
15426
+ }), z.object({ block: CoreBlockSchema }), {
15389
15427
  kind: "mutation",
15390
15428
  auth: "admin"
15391
15429
  }),
15392
15430
  /**
15393
- * Several writes, ONE transaction, behind an optional precondition.
15394
- *
15395
- * The multi-collection twin of {@link insertMany}: a write that has to move
15396
- * a set of rows in one collection AND a revision in another cannot be
15397
- * expressed as separate calls without a window in which a reader (or a
15398
- * crash) sees half of it. The retrain annotation save replaces a frame's
15399
- * rows, its dismissed set and its revision this way.
15431
+ * Stop this block's runner and let the supervisor bring it back.
15400
15432
  *
15401
- * `guard`, when given, is read inside the transaction: if the row is
15402
- * missing or its column differs from `equals`, NOTHING is written and the
15403
- * answer is `{ applied: false, current }` with what was found — the
15404
- * compare-and-set a revisioned write needs, with no second reader able to
15405
- * slip between the check and the writes.
15433
+ * **It stores nothing.** There is no "restart requested" flag and no second
15434
+ * lifecycle field: the supervisor already stops and respawns a runner when
15435
+ * the code hash changes, and this exposes that same path deliberately
15436
+ * (D62 — a switch writes the authority that already owned the function).
15437
+ * The next reconcile pass remains the authority, so a restart that lost a
15438
+ * race is corrected within one pass rather than leaving a stale flag behind.
15406
15439
  *
15407
- * **All or nothing**, like {@link insertMany}: a throw in any op rolls the
15408
- * whole call back. Ops run in the order given (delete before insert to
15409
- * replace a set). `namespace` applies to every collection named.
15440
+ * Refused for a DISABLED block: nothing would come back, and a button that
15441
+ * silently does nothing is worse than one that says why.
15410
15442
  */
15411
- transact: method(z.object({
15412
- namespace: z.string().optional(),
15413
- guard: TransactGuardSchema.optional(),
15414
- ops: z.array(TransactOpSchema).readonly()
15415
- }), z.object({
15416
- applied: z.boolean(),
15417
- current: z.unknown().optional()
15418
- }), {
15443
+ restart: method(z.object({ blockId: z.string() }), z.object({ block: CoreBlockSchema }), {
15419
15444
  kind: "mutation",
15420
15445
  auth: "admin"
15421
15446
  }),
15422
- /** Update an existing record by ID. */
15423
- update: method(z.object({
15424
- namespace: z.string().optional(),
15425
- collection: z.string(),
15426
- id: z.string(),
15427
- data: z.record(z.string(), z.unknown())
15428
- }), z.void(), {
15447
+ /**
15448
+ * Type-check without saving — what the editor calls as the author types, so
15449
+ * the compiler's verdict is the same one the server will reach.
15450
+ * Accepts `{ code }` or `{ files, entry }` (multi-file project).
15451
+ */
15452
+ compile: method(CoreBlockCompileInputSchema, CoreBlockCompileResultSchema, {
15429
15453
  kind: "mutation",
15430
15454
  auth: "admin"
15431
15455
  }),
15432
- /** Delete a record by key/ID. */
15433
- delete: method(z.object({
15434
- namespace: z.string().optional(),
15435
- collection: z.string(),
15436
- key: z.string()
15437
- }), z.void(), {
15456
+ /**
15457
+ * Hydrated settings form for one block, or null until a `settingsSchema`
15458
+ * is known (extracted from the compiled entry's named export, or set on
15459
+ * the block). Values live in the `core-blocks:settings` collection.
15460
+ */
15461
+ getBlockSettings: method(z.object({ blockId: z.string() }), SettingsSchemaWithValuesSchema.nullable(), { auth: "admin" }),
15462
+ /**
15463
+ * Patch persisted preference values for one block. The schema is not
15464
+ * rewritten here — only values. Scripts read the same blob via
15465
+ * `ctx.settings.readAddonStore()` (mirrored into the block addon's
15466
+ * `addon-settings` namespace on every patch).
15467
+ */
15468
+ updateBlockSettings: method(z.object({
15469
+ blockId: z.string(),
15470
+ patch: SettingsPatchSchema
15471
+ }), SettingsUpdateResultSchema, {
15438
15472
  kind: "mutation",
15439
15473
  auth: "admin"
15440
15474
  }),
15441
15475
  /**
15442
- * Delete every record matching `filter`, in ONE statement, returning how
15443
- * many rows went. This exists because its absence made every retention
15444
- * path in the system an N+1 drain loop: `delete` takes a key, so a sweep
15445
- * had to SELECT a page of full rows — every column, including the fat
15446
- * ones — purely to learn their ids, then issue one call per row.
15476
+ * The declaration files the editor type-checks against.
15447
15477
  *
15448
- * **The filter is required and must resolve.** A predicate naming
15449
- * something the collection cannot express is an ERROR here, not a
15450
- * widening as it is on `query`, and a filter with no predicates is an
15451
- * error rather than "every row". Deleting a whole collection is a
15452
- * legitimate intent, but it must be asked for by name — not reached by
15453
- * an empty object.
15478
+ * Served rather than bundled: the graph is 3.4 MB across 344 files, and
15479
+ * bundling it would roughly double the admin remote. Served rather than
15480
+ * hand-stubbed: a block runs with the same `ctx` an addon gets, so a stub
15481
+ * would drift and the editor would confidently autocomplete methods that
15482
+ * do not exist.
15454
15483
  */
15455
- deleteWhere: method(z.object({
15456
- namespace: z.string().optional(),
15457
- collection: z.string(),
15458
- filter: MutationFilterSchema
15459
- }), z.object({ deleted: z.number().int() }), {
15484
+ getTypeDefs: method(z.object({}), z.object({ libs: z.array(z.object({
15485
+ filePath: z.string(),
15486
+ content: z.string()
15487
+ })) }), { auth: "admin" }),
15488
+ /**
15489
+ * Create a composition block (D659). VALIDATED first against the live
15490
+ * sources and every stored composition; a refusal names every problem by
15491
+ * path and reason (D391) and stores nothing.
15492
+ */
15493
+ createComposition: method(z.object({ block: CompositionBlockInputSchema }), z.object({ block: CoreBlockSchema }), {
15460
15494
  kind: "mutation",
15461
- auth: "admin"
15495
+ auth: "admin",
15496
+ caller: "required"
15462
15497
  }),
15463
15498
  /**
15464
- * Apply `data` to every record matching `filter`, in one statement,
15465
- * returning how many rows changed. Same filter contract as
15466
- * {@link deleteWhere} — an unresolvable predicate is an error.
15499
+ * Patch a composition block. A changed `composition` is validated exactly
15500
+ * as on create. `expectedUpdatedAt` is the `updatedAt` the caller READ: a
15501
+ * block changed since is refused by name, never silently overwritten.
15467
15502
  */
15468
- updateWhere: method(z.object({
15469
- namespace: z.string().optional(),
15470
- collection: z.string(),
15471
- filter: MutationFilterSchema,
15472
- data: z.record(z.string(), z.unknown())
15473
- }), z.object({ updated: z.number().int() }), {
15503
+ updateComposition: method(z.object({
15504
+ blockId: z.string(),
15505
+ expectedUpdatedAt: z.number(),
15506
+ block: CompositionBlockInputSchema.partial()
15507
+ }), z.object({ block: CoreBlockSchema }), {
15474
15508
  kind: "mutation",
15475
- auth: "admin"
15509
+ auth: "admin",
15510
+ caller: "required"
15476
15511
  }),
15477
- /** Count entries in a collection, optionally filtered. */
15478
- count: method(z.object({
15479
- namespace: z.string().optional(),
15480
- collection: z.string(),
15481
- filter: QueryFilterSchema.optional()
15482
- }), z.number(), { auth: "admin" }),
15512
+ /** One composition and the composer's state for it, or `not-loaded` (D315). */
15513
+ getComposition: method(z.object({ blockId: z.string() }), CompositionGetReadSchema, { auth: "admin" }),
15514
+ listCompositions: method(z.object({}), CompositionListReadSchema, { auth: "admin" }),
15483
15515
  /**
15484
- * `COUNT(*)` and one `SUM` / `MIN` / `MAX` per requested field, in ONE
15485
- * statement, over the rows `filter` selects.
15486
- *
15487
- * Exists because "how much is there" was being answered by materialising
15488
- * "what is there". The recorder's storage-pressure sweep asked its in-RAM
15489
- * footage index for bytes/count/oldest/newest across a set of storage
15490
- * locations twice a minute, and the only way to answer that from a map is
15491
- * to visit every row — 7.1 M of them on the live hub, ~15 M row visits a
15492
- * minute on the main thread, which is also why the whole archive had to
15493
- * stay resident to be visited. The question is a sum; nothing needs to be
15494
- * materialised to answer it.
15495
- *
15496
- * **The engine REFUSES a field it cannot serve**, exactly as
15497
- * `query.columns` does and unlike a PREDICATE, which is skipped when
15498
- * unresolvable. A dropped predicate over-matches and the caller sees extra
15499
- * rows; a dropped aggregate returns a NUMBER that is wrong and looks
15500
- * exactly like a real one. That asymmetry is what this repo has already
15501
- * paid for once in `count`.
15516
+ * The composition that customizes an existing device (D663), found by its
15517
+ * TARGET — never by the block's derived name. One per device at most.
15502
15518
  */
15503
- aggregate: method(z.object({
15504
- namespace: z.string().optional(),
15505
- collection: z.string(),
15506
- fields: z.array(AggregateFieldSchema).readonly(),
15507
- filter: QueryFilterSchema.optional()
15508
- }), AggregateResultSchema, { auth: "admin" }),
15509
- /** Grouped counts per ((field-origin)/bucketSize) bucket, filtered. */
15510
- histogram: method(z.object({
15511
- namespace: z.string().optional(),
15512
- collection: z.string(),
15513
- field: z.string(),
15514
- bucketSize: z.number().int().positive(),
15515
- origin: z.number().int(),
15516
- filter: QueryFilterSchema.optional()
15517
- }), z.array(z.object({
15518
- bucket: z.number().int(),
15519
- count: z.number().int()
15520
- })).readonly(), { auth: "admin" }),
15521
- /** Check if a collection is empty. */
15522
- isEmpty: method(z.object({
15523
- namespace: z.string().optional(),
15524
- collection: z.string()
15525
- }), z.boolean(), { auth: "admin" }),
15519
+ getCustomization: method(z.object({
15520
+ addonId: z.string().min(1),
15521
+ stableId: z.string().min(1)
15522
+ }), CompositionCustomizationReadSchema, { auth: "admin" }),
15526
15523
  /**
15527
- * Declare a typed (SQL-backed) collection with explicit columns +
15528
- * indexes. Idempotent: re-declaring an existing collection with the
15529
- * same shape is a no-op; shape changes (new columns, new indexes)
15530
- * are applied additively. Subsequent `insert` / `update` / `delete`
15531
- * / `query` calls on this collection use typed columns instead of
15532
- * JSON-blob storage — `record.data` fields are spread across
15533
- * columns, `query.filter.where` matches real columns (no
15534
- * `json_extract` overhead), `orderBy` uses column indexes.
15535
- *
15536
- * Addons call this in `onInitialize` before their first read/write.
15537
- * Collection names should be namespaced by addon (e.g.
15538
- * `pipeline-analytics:object-events`) to avoid cross-addon
15539
- * clashes — no automatic prefix is added.
15524
+ * The capabilities a composition may BUILD on a device of `deviceType`
15525
+ * (a new device, or added to an existing one), with their fields — the
15526
+ * editor's feature list and the presets' availability (G2, D676). Built
15527
+ * from the validator's own blockers; a replace of a BOUND cap is not
15528
+ * listed here (the device's bindings say what it has).
15540
15529
  */
15541
- declareCollection: method(z.object({
15542
- namespace: z.string().optional(),
15543
- collection: z.string(),
15544
- columns: z.array(CollectionColumnSchema).readonly(),
15545
- indexes: z.array(CollectionIndexSchema).readonly().optional()
15546
- }), z.void(), {
15530
+ listComposableCaps: method(z.object({ deviceType: z.enum(DeviceType) }), ComposableCapabilitiesSchema, { auth: "admin" }),
15531
+ /**
15532
+ * Validate without saving — the same verdict the save reaches. A mutation
15533
+ * for its body size; it writes nothing, so its access is `view`.
15534
+ */
15535
+ validateComposition: method(z.object({
15536
+ composition: CompositionSchema,
15537
+ blockId: z.string().optional()
15538
+ }), CompositionValidationSchema, {
15547
15539
  kind: "mutation",
15548
- auth: "admin"
15540
+ auth: "admin",
15541
+ access: "view"
15542
+ })
15543
+ }
15544
+ };
15545
+ /**
15546
+ * `custom-model-registry` — collection cap exposing operator-registered
15547
+ * custom detection models. Each provider (today: `addon-model-studio`)
15548
+ * contributes a list of `CustomModelDescriptor`s; the hub auto-concatenates
15549
+ * them across providers (`concatCollection`).
15550
+ *
15551
+ * The detection-pipeline is *aware* of this cap: when at least one provider
15552
+ * exists it unions these descriptors into the per-step model picker and the
15553
+ * runtime model-resolution path, alongside the static catalog. When no
15554
+ * provider exists the consumer no-ops entirely (identical to the catalog-only
15555
+ * behaviour).
15556
+ *
15557
+ * A descriptor carries a full `ModelCatalogEntry` directly — the same shape
15558
+ * the static catalog uses — so the existing download/resolution code consumes
15559
+ * it unchanged. `stepId` is the detection step the model targets
15560
+ * (e.g. `'object-detection'`).
15561
+ */
15562
+ var CustomModelDescriptorSchema = z.object({
15563
+ stepId: z.string(),
15564
+ entry: ModelCatalogEntrySchema
15565
+ });
15566
+ /** One regular file of an imported bundle, as the producer measured it. */
15567
+ var ModelBundleFileSchema = z.object({
15568
+ /** Relative path inside the bundle tar; an mlpackage member is `<x>.mlpackage/<member>`. */
15569
+ path: z.string().min(1),
15570
+ bytes: z.number().int().nonnegative(),
15571
+ sha256: z.string().regex(/^[0-9a-f]{64}$/)
15572
+ });
15573
+ var ImportModelBundleInputSchema = z.object({
15574
+ /** The registry provider that keeps the model (Model Studio). */
15575
+ addonId: z.string(),
15576
+ stepId: z.string().min(1),
15577
+ /**
15578
+ * The catalog rows to register, complete, every format URL already
15579
+ * `camstack-local://<modelId>/<file>` naming a file of the bundle. One
15580
+ * bundle may carry several rows (a base and its INT8 variant).
15581
+ */
15582
+ entries: z.array(ModelCatalogEntrySchema).min(1).max(4),
15583
+ /** The bundle tar, offered by the producer over `ctx.peerBytes` (same host). */
15584
+ bundle: z.object({
15585
+ ticket: PeerBytesTicketSchema,
15586
+ bytes: z.number().int().positive(),
15587
+ sha256: z.string().regex(/^[0-9a-f]{64}$/)
15588
+ }),
15589
+ /** Every file the tar must hold; anything missing, extra or different is refused. */
15590
+ files: z.array(ModelBundleFileSchema).min(1).max(64),
15591
+ /** Convert missing engine formats and push the model to every agent afterwards. */
15592
+ distribute: z.boolean()
15593
+ });
15594
+ var ImportModelBundleResultSchema = z.discriminatedUnion("kind", [z.object({
15595
+ kind: z.literal("imported"),
15596
+ modelIds: z.array(z.string()).readonly(),
15597
+ distributed: z.array(z.object({
15598
+ modelId: z.string(),
15599
+ nodeId: z.string(),
15600
+ format: z.enum(MODEL_FORMATS),
15601
+ ok: z.boolean(),
15602
+ error: z.string().optional()
15603
+ })).readonly()
15604
+ }), z.object({
15605
+ kind: z.literal("refused"),
15606
+ reason: z.enum([
15607
+ "transfer-failed",
15608
+ "checksum-mismatch",
15609
+ "bundle-mismatch",
15610
+ "invalid-entry",
15611
+ "id-taken"
15612
+ ]),
15613
+ detail: z.string()
15614
+ })]);
15615
+ var customModelRegistryCapability = {
15616
+ name: "custom-model-registry",
15617
+ scope: "system",
15618
+ mode: "collection",
15619
+ internal: true,
15620
+ methods: {
15621
+ /**
15622
+ * `internal: true` did not gate the mount (see the 2026-08-26 note on
15623
+ * `data-store-provider`) — this was reachable on the AppRouter by ANY
15624
+ * authenticated session at the default `auth: 'protected'`. The only
15625
+ * consumer, the detection-pipeline's model resolution
15626
+ * (`addon-pipeline/src/detection-pipeline/provider.ts`), calls
15627
+ * `ctx.api.customModelRegistry.listModels.query()` — UDS/Moleculer,
15628
+ * never tRPC — so `auth: 'admin'` costs it nothing.
15629
+ */
15630
+ listModels: method(z.void(), z.array(CustomModelDescriptorSchema).readonly(), { auth: "admin" }),
15631
+ /**
15632
+ * Register a model whose files arrive as ONE bundle tar (D806): the tar
15633
+ * is taken over `ctx.peerBytes`, checked against `bundle.sha256` and
15634
+ * every row of `files`, unpacked into the hub's flat modelsDir (directory
15635
+ * formats included), each format's `.revision` record written, the rows
15636
+ * upserted under the operator's name, the hub marked available and —
15637
+ * when asked — engine formats converted and the model distributed. A
15638
+ * model id already registered by another source is refused, never
15639
+ * overwritten.
15640
+ */
15641
+ importModelBundle: method(ImportModelBundleInputSchema, ImportModelBundleResultSchema, {
15642
+ kind: "mutation",
15643
+ auth: "admin",
15644
+ timeoutMs: 30 * 6e4
15549
15645
  })
15550
15646
  }
15551
15647
  };
@@ -15694,6 +15790,16 @@ id: z.union([z.string(), z.number()]) }), {
15694
15790
  kind: "mutation",
15695
15791
  auth: "admin"
15696
15792
  }),
15793
+ /** Upsert many records in ONE transaction; see the door's `upsertMany`. */
15794
+ upsertMany: method(z.object({
15795
+ namespace: z.string().optional(),
15796
+ collection: z.string(),
15797
+ conflict: z.array(z.string()).readonly(),
15798
+ records: z.array(BulkRecordSchema).readonly()
15799
+ }), z.object({ upserted: z.number().int() }), {
15800
+ kind: "mutation",
15801
+ auth: "admin"
15802
+ }),
15697
15803
  /** Insert many records in ONE transaction. All or nothing. */
15698
15804
  insertMany: method(z.object({
15699
15805
  namespace: z.string().optional(),
@@ -15786,12 +15892,7 @@ id: z.union([z.string(), z.number()]) }), {
15786
15892
  collection: z.string()
15787
15893
  }), z.boolean(), { auth: "admin" }),
15788
15894
  /** Declare a typed (SQL-backed) collection with columns + indexes. */
15789
- declareCollection: method(z.object({
15790
- namespace: z.string().optional(),
15791
- collection: z.string(),
15792
- columns: z.array(CollectionColumnSchema).readonly(),
15793
- indexes: z.array(CollectionIndexSchema).readonly().optional()
15794
- }), z.void(), {
15895
+ declareCollection: method(DeclareCollectionInputSchema, z.void(), {
15795
15896
  kind: "mutation",
15796
15897
  auth: "admin"
15797
15898
  })
@@ -53098,6 +53199,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
53098
53199
  addonId: null,
53099
53200
  access: "create"
53100
53201
  },
53202
+ "dataStoreProvider.upsertMany": {
53203
+ capName: "data-store-provider",
53204
+ capScope: "system",
53205
+ addonId: null,
53206
+ access: "create"
53207
+ },
53101
53208
  "dayNight.getOptions": {
53102
53209
  capName: "day-night",
53103
53210
  capScope: "device",
@@ -57946,6 +58053,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
57946
58053
  addonId: null,
57947
58054
  access: "create"
57948
58055
  },
58056
+ "settingsStore.upsertMany": {
58057
+ capName: "settings-store",
58058
+ capScope: "system",
58059
+ addonId: null,
58060
+ access: "create"
58061
+ },
57949
58062
  "smoke.getStatus": {
57950
58063
  capName: "smoke",
57951
58064
  capScope: "device",
@@ -65448,4 +65561,4 @@ function enumerateInferenceDevices(hw) {
65448
65561
  return out;
65449
65562
  }
65450
65563
  //#endregion
65451
- export { buildStreamParamsConfigSchema as $, compositionSliceKey as $n, transformSecretWrite as $r, mayReadLocation as $t, LocationIconIdSchema as A, siteZoneKey as An, formatSecretScope as Ar, extractNestedAddonId as At, StorageLocationModeSchema as B, validateComposition as Bn, normalizeSecretOwner as Br, isObjectInput as Bt, FieldClaimModeSchema as C, resolveMethodAuth as Cn, collectZodSecretPaths as Cr, enumerateInferenceDevices as Ct, KEYCHAIN_RESET_TRIGGER_ACTOR as D, scopesAllowDeviceCap as Dn, emitDownForOwnedCaps as Dr, evictionPolicyOfLocation as Dt, HUB_MDNS_TXT_KEYS as E, scopesAllowAddon as En, defineCustomActions as Er, evaluateCompositionField as Et, RecordingStatusSchema as F, storageProviderCapability as Fn, isSecretClear as Fr, isAppLinkBase as Ft, addonSettingsCapability as G, withLocationMode as Gn, resolveCapMount as Gr, legacyAutoLinkIds as Gt, StorageMigrationJobSchema as H, vectorDimFromBase64 as Hn, parseJsonUnknown as Hr, kebabToCamel as Ht, STORAGE_ACCESS_FALLBACK as I, streamCatalogCapability as In, isSecretMarker as Ir, isArrayOutputSchema as It, authProviderCapability as J, cloneStatefulExpressionMemory as Jn, secretTreeFromPaths as Jr, localNetworkCapability as Jt, addonWidgetsCapability as K, COMPOSER_ADDON_ID as Kn, resolveSecretMarkers as Kr, legacyModeOf as Kt, STREAM_PROFILE_META as L, streamQualityLabel as Ln, isSecretMarkerLike as Lr, isCollectionArrayMethod as Lt, MINUTES_PER_DAY as M, storageCapability as Mn, isDeviceConfigCap as Mr, foldSnapshotByFunction as Mt, MOTION_CLOSE_AFTER_MS as N, storageMigrationCapability as Nn, isEvent as Nr, formatMinutes as Nt, LOG_LEVEL_RANK as O, scoreRuntimes as On, emitReadiness as Or, expandContainer as Ot, RECORDING_SOURCE_CAMSTACK_ADDON as P, storageOccupancyCapability as Pn, isKeychainStoredField as Pr, gbToBytes as Pt, buildCapabilityLookup as Q, compositionItemFieldPath as Qn, toSecretFieldView as Qr, looseSchema as Qt, ScopedTokenSchema as R, supportedRuntimes as Rn, makeSecretMarker as Rr, isDefaultAppConnectionEndpoint as Rt, FIRST_LEVEL_MACRO_CLASSES as S, resolveLocationMode as Sn, collectSecretConfigKeys as Sr, deviceStatusCapability as St, HUB_MDNS_SERVICE_TYPE as T, runtimeStatePolicyFor as Tn, customAction as Tr, enumerateSchemaFields as Tt, UserRecordSchema as U, vectorIndexDimConflictError as Un, parseSecretRef as Ur, keychainAdminCapability as Ut, StorageLocationTypeSchema as V, validateCustomAddress as Vn, parseJsonObject as Vr, isVoidInput as Vt, addonPagesCapability as W, vectorStoreCapability as Wn, readinessKey as Wr, keychainCapability as Wt, bareAddonId as X, composedDeviceStableId as Xn, sleep as Xr, logDestinationCapability as Xt, backupCapability as Y, composedDeviceRef as Yn, secretTreeFromSchema as Yr, locationIconKey as Yt, batteryCapability as Z, compositionFeatureEnabled as Zn, toNodeId as Zr, logLevelAtMost as Zt, DATABASE_SNAPSHOT_TIMEOUT_MS as _, resolveAppConnections as _n, WELL_KNOWN_TAB_MAP as _r, deriveBatteryPresence as _t, BatteryStatusSchema as a, normalizeCoreBlockWrite as an, DeviceRole as ar, compositionSourceRefs as at, DeclaredDevices as b, resolveCoreBlockFiles as bn, asString$1 as br, deviceManagerCapability as bt, CAP_NAMES_WITH_STATUS as c, objectInputDeclaresRequiredDeviceId as cn, BaseAddon as cr, coreBlockIdFromAddonId as ct, CORE_BLOCKS_ADDON_ID as d, planComposition as dn, DEVICE_STATUS_METHOD as dr, createDeviceExtensionProvider as dt, EventCategory as ei, mayWriteToLocation as en, compositionSourceKey as er, calendarsCapability as et, CORE_BLOCK_ADDON_PREFIX as f, platformProbeCapability as fn, REDACTED_SECRET as fr, dataStoreProviderCapability as ft, DATABASE_SNAPSHOT_SUFFIX as g, replacedFieldKeys as gn, SECRET_CLEAR as gr, defineExtensionSlotProvider as gt, DATABASE_SNAPSHOT_PARTIAL_SUFFIX as h, reducePoints as hn, ReadinessTimeoutError as hr, decodeVectorBase64 as ht, BaseDevice as i, motionCapability as in, DeviceFeature as ir, compositionFieldKey as it, METHOD_ACCESS_MAP as j, snapshotCapability as jn, hydrateSchema as jr, filesystemBrowseCapability as jt, LegacyStorageLocationDefaultSchema as k, settingsStoreCapability as kn, expandCapMethods as kr, expressionContainsBuiltinCall as kt, COMPOSED_ITEM_FIXED_FIELDS as l, parseStreamParamsFormPatch as ln, DATAPLANE_SECRET_HEADER as lr, coreBlockSourceKind as lt, CoreBlockSchema as m, ptzAutotrackCapability as mn, ReadinessRegistry as mr, declarationOwnerNodeId as mt, AlertSchema as n, metricsProviderCapability as nn, disarmRoseMemory as nr, checkRoleAddress as nt, CAMERA_SWITCH_ORDER as o, normalizeUnit as on, DeviceType as or, coreBlockAddonId as ot, CalendarPreferencesSchema as p, procedureAuthKey as pn, RUNTIME_DEFAULTS as pr, databaseSnapshotCapability as pt, alertsCapability as q, buildFfmpegArgs as qn, scopeKey as qr, lifecycleJobSchema as qt, ApiKeyRecordSchema as r, modeMayWrite as rn, toExpressionValue as rr, composerCapability as rt, CAMSTACK_APP_LINK_ORIGIN as s, objectInputDeclaresAddonId as sn, errMsg as sr, coreBlockComposition as st, ALL_CAPABILITY_DEFINITIONS as t, memoizePinnedFfmpeg as tn, createStatefulExpressionMemory as tr, cameraGridLayoutCapability as tt, COMPOSER_RUNNER_ID as u, pickAppLinkHub as un, DEVICE_SETTINGS_CONTRIBUTION_METHODS as ur, coreBlocksCapability as ut, DAY_NAMES as v, resolveBucketMs as vn, asJsonObject as vr, describeComposableCaps as vt, FieldClaimSchema as w, resolveNotificationTapAddress as wn, createEvent as wr, enumerateItemArrayFields as wt, DeviceStatusSchema as x, resolveHubAddressRoles as xn, buildSecretRef as xr, deviceStateCapability as xt, DERIVED_CAMERA_SILENCED_CAP_NAMES as y, resolveCoreBlockEntry as yn, asNumber as yr, deviceExtensionCapability as yt, StorageCleanupJobSchema as z, userManagementCapability as zn, nodePin as zr, isLocationEnabled as zt };
65564
+ export { buildCapabilityLookup as $, compositionItemFieldPath as $n, toSecretFieldView as $r, looseSchema as $t, LegacyStorageLocationDefaultSchema as A, settingsStoreCapability as An, expandCapMethods as Ar, expressionContainsBuiltinCall as At, StorageCleanupJobSchema as B, userManagementCapability as Bn, nodePin as Br, isLocationEnabled as Bt, FIRST_LEVEL_MACRO_CLASSES as C, resolveLocationMode as Cn, collectSecretConfigKeys as Cr, deviceStatusCapability as Ct, HUB_MDNS_TXT_KEYS as D, scopesAllowAddon as Dn, defineCustomActions as Dr, evaluateCompositionField as Dt, HUB_MDNS_SERVICE_TYPE as E, runtimeStatePolicyFor as En, customAction as Er, enumerateSchemaFields as Et, RECORDING_SOURCE_CAMSTACK_ADDON as F, storageOccupancyCapability as Fn, isKeychainStoredField as Fr, gbToBytes as Ft, addonPagesCapability as G, vectorStoreCapability as Gn, readinessKey as Gr, keychainCapability as Gt, StorageLocationTypeSchema as H, validateCustomAddress as Hn, parseJsonObject as Hr, isVoidInput as Ht, RecordingStatusSchema as I, storageProviderCapability as In, isSecretClear as Ir, isAppLinkBase as It, alertsCapability as J, buildFfmpegArgs as Jn, scopeKey as Jr, lifecycleJobSchema as Jt, addonSettingsCapability as K, withLocationMode as Kn, resolveCapMount as Kr, legacyAutoLinkIds as Kt, STORAGE_ACCESS_FALLBACK as L, streamCatalogCapability as Ln, isSecretMarker as Lr, isArrayOutputSchema as Lt, METHOD_ACCESS_MAP as M, snapshotCapability as Mn, hydrateSchema as Mr, filesystemBrowseCapability as Mt, MINUTES_PER_DAY as N, storageCapability as Nn, isDeviceConfigCap as Nr, foldSnapshotByFunction as Nt, KEYCHAIN_RESET_TRIGGER_ACTOR as O, scopesAllowDeviceCap as On, emitDownForOwnedCaps as Or, evictionPolicyOfLocation as Ot, MOTION_CLOSE_AFTER_MS as P, storageMigrationCapability as Pn, isEvent as Pr, formatMinutes as Pt, batteryCapability as Q, compositionFeatureEnabled as Qn, toNodeId as Qr, logLevelAtMost as Qt, STREAM_PROFILE_META as R, streamQualityLabel as Rn, isSecretMarkerLike as Rr, isCollectionArrayMethod as Rt, DeviceStatusSchema as S, resolveHubAddressRoles as Sn, buildSecretRef as Sr, deviceStateCapability as St, FieldClaimSchema as T, resolveNotificationTapAddress as Tn, createEvent as Tr, enumerateItemArrayFields as Tt, StorageMigrationJobSchema as U, vectorDimFromBase64 as Un, parseJsonUnknown as Ur, kebabToCamel as Ut, StorageLocationModeSchema as V, validateComposition as Vn, normalizeSecretOwner as Vr, isObjectInput as Vt, UserRecordSchema as W, vectorIndexDimConflictError as Wn, parseSecretRef as Wr, keychainAdminCapability as Wt, backupCapability as X, composedDeviceRef as Xn, secretTreeFromSchema as Xr, locationIconKey as Xt, authProviderCapability as Y, cloneStatefulExpressionMemory as Yn, secretTreeFromPaths as Yr, localNetworkCapability as Yt, bareAddonId as Z, composedDeviceStableId as Zn, sleep as Zr, logDestinationCapability as Zt, DATABASE_SNAPSHOT_TIMEOUT_MS as _, replacedFieldKeys as _n, SECRET_CLEAR as _r, defineExtensionSlotProvider as _t, BatteryStatusSchema as a, motionCapability as an, DeviceFeature as ar, compositionFieldKey as at, DERIVED_CAMERA_SILENCED_CAP_NAMES as b, resolveCoreBlockEntry as bn, asNumber as br, deviceExtensionCapability as bt, CAP_NAMES_WITH_STATUS as c, objectInputDeclaresAddonId as cn, errMsg as cr, coreBlockComposition as ct, CORE_BLOCKS_ADDON_ID as d, pickAppLinkHub as dn, DEVICE_SETTINGS_CONTRIBUTION_METHODS as dr, coreBlocksCapability as dt, transformSecretWrite as ei, mayReadLocation as en, compositionSliceKey as er, buildStreamParamsConfigSchema as et, CORE_BLOCK_ADDON_PREFIX as f, planComposition as fn, DEVICE_STATUS_METHOD as fr, createDeviceExtensionProvider as ft, DATABASE_SNAPSHOT_SUFFIX as g, reducePoints as gn, ReadinessTimeoutError as gr, decodeVectorBase64 as gt, DATABASE_SNAPSHOT_PARTIAL_SUFFIX as h, ptzAutotrackCapability as hn, ReadinessRegistry as hr, declarationOwnerNodeId as ht, BaseDevice as i, modeMayWrite as in, toExpressionValue as ir, composerCapability as it, LocationIconIdSchema as j, siteZoneKey as jn, formatSecretScope as jr, extractNestedAddonId as jt, LOG_LEVEL_RANK as k, scoreRuntimes as kn, emitReadiness as kr, expandContainer as kt, COMPOSED_ITEM_FIXED_FIELDS as l, objectInputDeclaresRequiredDeviceId as ln, BaseAddon as lr, coreBlockIdFromAddonId as lt, CoreBlockSchema as m, procedureAuthKey as mn, RUNTIME_DEFAULTS as mr, databaseSnapshotCapability as mt, AlertSchema as n, memoizePinnedFfmpeg as nn, createStatefulExpressionMemory as nr, cameraGridLayoutCapability as nt, CAMERA_SWITCH_ORDER as o, normalizeCoreBlockWrite as on, DeviceRole as or, compositionSourceRefs as ot, CalendarPreferencesSchema as p, platformProbeCapability as pn, REDACTED_SECRET as pr, dataStoreProviderCapability as pt, addonWidgetsCapability as q, COMPOSER_ADDON_ID as qn, resolveSecretMarkers as qr, legacyModeOf as qt, ApiKeyRecordSchema as r, metricsProviderCapability as rn, disarmRoseMemory as rr, checkRoleAddress as rt, CAMSTACK_APP_LINK_ORIGIN as s, normalizeUnit as sn, DeviceType as sr, coreBlockAddonId as st, ALL_CAPABILITY_DEFINITIONS as t, EventCategory as ti, mayWriteToLocation as tn, compositionSourceKey as tr, calendarsCapability as tt, COMPOSER_RUNNER_ID as u, parseStreamParamsFormPatch as un, DATAPLANE_SECRET_HEADER as ur, coreBlockSourceKind as ut, DATA_STORE_DATABASES as v, resolveAppConnections as vn, WELL_KNOWN_TAB_MAP as vr, deriveBatteryPresence as vt, FieldClaimModeSchema as w, resolveMethodAuth as wn, collectZodSecretPaths as wr, enumerateInferenceDevices as wt, DeclaredDevices as x, resolveCoreBlockFiles as xn, asString$1 as xr, deviceManagerCapability as xt, DAY_NAMES as y, resolveBucketMs as yn, asJsonObject as yr, describeComposableCaps as yt, ScopedTokenSchema as z, supportedRuntimes as zn, makeSecretMarker as zr, isDefaultAppConnectionEndpoint as zt };