@camstack/addon-google-services 0.2.42 → 0.2.44
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/dist/google-services.addon.js +1116 -1244
- package/dist/google-services.addon.mjs +1117 -1245
- package/dist/index.mjs +1 -1
- package/package.json +2 -2
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createHash, randomBytes } from "node:crypto";
|
|
2
|
-
//#region ../types/dist/event-category-
|
|
2
|
+
//#region ../types/dist/event-category-78tcBemo.mjs
|
|
3
3
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
4
4
|
EventCategory["SystemBoot"] = "system.boot";
|
|
5
5
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -120,6 +120,23 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
120
120
|
*/
|
|
121
121
|
EventCategory["AddonLoadRecovered"] = "addon.load-recovered";
|
|
122
122
|
/**
|
|
123
|
+
* An addon is RUNNING although its installed package is below what the
|
|
124
|
+
* running server requires (`camstack.requires.addons` of the server, or the
|
|
125
|
+
* addon's own `requires.server`). Raised once per streak by the unsupported-
|
|
126
|
+
* addon tracker, on the hub and on agents; AlertCenter turns it into one
|
|
127
|
+
* operator alert per node and package. The addon is never held back for it.
|
|
128
|
+
*
|
|
129
|
+
* Payload: `{ packageName, addonId, nodeId, installedVersion, requiredMinimum, serverVersion, unmet }`.
|
|
130
|
+
*/
|
|
131
|
+
EventCategory["AddonUnsupportedVersion"] = "addon.unsupported-version";
|
|
132
|
+
/**
|
|
133
|
+
* The package of an {@link AddonUnsupportedVersion} alert reached a supported
|
|
134
|
+
* version, or is no longer installed on the node. AlertCenter dismisses the matching alert.
|
|
135
|
+
*
|
|
136
|
+
* Payload: `{ packageName, addonId, nodeId }`.
|
|
137
|
+
*/
|
|
138
|
+
EventCategory["AddonUnsupportedResolved"] = "addon.unsupported-resolved";
|
|
139
|
+
/**
|
|
123
140
|
* Monitor scheduled the next retry for a failed addon. Transient —
|
|
124
141
|
* surfaced to the UI for live-updating the "next retry in Ns"
|
|
125
142
|
* countdown on the Addons page row, NOT persisted as an alert.
|
|
@@ -230,7 +247,7 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
230
247
|
EventCategory["ProcessRestarted"] = "process.restarted";
|
|
231
248
|
/**
|
|
232
249
|
* The SET of storage locations changed — one was created, edited, enabled,
|
|
233
|
-
* disabled or deleted through
|
|
250
|
+
* disabled or deleted through the location instances or the forced-delete action.
|
|
234
251
|
*
|
|
235
252
|
* Telemetry, not a transaction (D8/D11): every consumer that re-resolves on
|
|
236
253
|
* it must also converge on its own periodic path, because a dropped event
|
|
@@ -785,7 +802,7 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
785
802
|
return EventCategory;
|
|
786
803
|
}({});
|
|
787
804
|
//#endregion
|
|
788
|
-
//#region ../types/dist/device-type-
|
|
805
|
+
//#region ../types/dist/device-type-DxCT0krO.mjs
|
|
789
806
|
/**
|
|
790
807
|
import { errMsg } from '@camstack/types'
|
|
791
808
|
* Extract a human-readable message from an unknown error value.
|
|
@@ -947,6 +964,13 @@ var DeviceFeature = /* @__PURE__ */ function(DeviceFeature) {
|
|
|
947
964
|
* filters that want "all devices with on-motion behaviour".
|
|
948
965
|
*/
|
|
949
966
|
DeviceFeature["MotionTrigger"] = "motion-trigger";
|
|
967
|
+
/**
|
|
968
|
+
* Device can be run for a chosen time and then stopped. Mirrors the
|
|
969
|
+
* `timed-run` wrapper cap — the cap is bound by the core-blocks addon, not by
|
|
970
|
+
* a driver, so the flag is derived from the device's bindings
|
|
971
|
+
* (`featuresOfBoundCaps`). Gates the quick-run control in the viewer.
|
|
972
|
+
*/
|
|
973
|
+
DeviceFeature["TimedRun"] = "timed-run";
|
|
950
974
|
/** Light supports rgb-triplet color via `color` cap. */
|
|
951
975
|
DeviceFeature["LightColorRgb"] = "light-color-rgb";
|
|
952
976
|
/** Light supports HSV color via `color` cap. */
|
|
@@ -5981,7 +6005,7 @@ var ZodIssueCode = {
|
|
|
5981
6005
|
var ZodFirstPartyTypeKind;
|
|
5982
6006
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5983
6007
|
//#endregion
|
|
5984
|
-
//#region ../types/dist/sleep-
|
|
6008
|
+
//#region ../types/dist/sleep-CGPZyzB5.mjs
|
|
5985
6009
|
/**
|
|
5986
6010
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5987
6011
|
* window to float samples (D455).
|
|
@@ -6345,6 +6369,59 @@ Object.fromEntries([
|
|
|
6345
6369
|
function isValuelessField(field) {
|
|
6346
6370
|
return field.type === "separator" || field.type === "info" || field.type === "qr-code" || field.type === "button" || field.type === "object-array" || field.type === "widget" || field.type === "addon-action-button" || field.type === "device-action-button" || field.type === "account-sign-in" || field.type === "secret-presence";
|
|
6347
6371
|
}
|
|
6372
|
+
/**
|
|
6373
|
+
* Base collector: flatten a hydrated `ConfigUISchemaWithValues` into
|
|
6374
|
+
* `key → { value, default }`, recursing through `group` and `sub-tabs`
|
|
6375
|
+
* layout fields. Keeping `value` and `default` SEPARATE (rather than
|
|
6376
|
+
* pre-resolving) lets callers both read the effective value AND detect
|
|
6377
|
+
* overrides (`value` differs from `default`). Structural over `unknown`;
|
|
6378
|
+
* malformed input yields an empty map, never throws.
|
|
6379
|
+
*/
|
|
6380
|
+
function collectHydratedFieldEntries(schema) {
|
|
6381
|
+
const out = /* @__PURE__ */ new Map();
|
|
6382
|
+
if (typeof schema !== "object" || schema === null) return out;
|
|
6383
|
+
const sections = schema.sections;
|
|
6384
|
+
if (!Array.isArray(sections)) return out;
|
|
6385
|
+
for (const section of sections) if (typeof section === "object" && section !== null) collectFieldEntriesInto(section.fields, out);
|
|
6386
|
+
return out;
|
|
6387
|
+
}
|
|
6388
|
+
/** Recursive field walker for {@link collectHydratedFieldEntries}. */
|
|
6389
|
+
function collectFieldEntriesInto(fields, into) {
|
|
6390
|
+
if (!Array.isArray(fields)) return;
|
|
6391
|
+
for (const field of fields) {
|
|
6392
|
+
if (typeof field !== "object" || field === null) continue;
|
|
6393
|
+
const type = field.type;
|
|
6394
|
+
if (type === "group") {
|
|
6395
|
+
collectFieldEntriesInto(field.fields, into);
|
|
6396
|
+
continue;
|
|
6397
|
+
}
|
|
6398
|
+
if (type === "sub-tabs") {
|
|
6399
|
+
const tabs = field.tabs;
|
|
6400
|
+
if (Array.isArray(tabs)) {
|
|
6401
|
+
for (const tab of tabs) if (typeof tab === "object" && tab !== null) collectFieldEntriesInto(tab.fields, into);
|
|
6402
|
+
}
|
|
6403
|
+
continue;
|
|
6404
|
+
}
|
|
6405
|
+
const key = field.key;
|
|
6406
|
+
if (typeof key !== "string" || key.length === 0) continue;
|
|
6407
|
+
if (!("value" in field)) continue;
|
|
6408
|
+
into.set(key, {
|
|
6409
|
+
value: field.value,
|
|
6410
|
+
default: field.default
|
|
6411
|
+
});
|
|
6412
|
+
}
|
|
6413
|
+
}
|
|
6414
|
+
/**
|
|
6415
|
+
* Flatten a hydrated settings payload into `key → EFFECTIVE value`
|
|
6416
|
+
* (`value ?? default`). The read-side inverse of `hydrateSchema` for the
|
|
6417
|
+
* common "just give me the resolved values" case. Built on
|
|
6418
|
+
* {@link collectHydratedFieldEntries}.
|
|
6419
|
+
*/
|
|
6420
|
+
function collectHydratedFieldValues(schema) {
|
|
6421
|
+
const out = /* @__PURE__ */ new Map();
|
|
6422
|
+
for (const [key, entry] of collectHydratedFieldEntries(schema)) out.set(key, entry.value ?? entry.default);
|
|
6423
|
+
return out;
|
|
6424
|
+
}
|
|
6348
6425
|
function hydrateSchema(schema, values, options = {}) {
|
|
6349
6426
|
return {
|
|
6350
6427
|
...schema.tabs ? { tabs: [...schema.tabs] } : {},
|
|
@@ -7145,6 +7222,7 @@ var RecordIntegrationInstances = class {
|
|
|
7145
7222
|
this.secretKeys = topLevelSecretKeys(kind.declaration.secretPaths);
|
|
7146
7223
|
this.secretMaps = secretMapKeys(kind.declaration.secretPaths);
|
|
7147
7224
|
this.nameField = kind.declaration.entry?.nameField ?? "name";
|
|
7225
|
+
if (hooks.kindOf === void 0 && hooks.description.kinds.length !== 1) throw new Error(`record kind '${kind.name}': describe().kinds has ${hooks.description.kinds.length} entries, so kindOf is required to say which one an instance is`);
|
|
7148
7226
|
}
|
|
7149
7227
|
/**
|
|
7150
7228
|
* One instance read for the addon's own runtime; null when absent. When the keychain is
|
|
@@ -7186,10 +7264,21 @@ var RecordIntegrationInstances = class {
|
|
|
7186
7264
|
}
|
|
7187
7265
|
return out;
|
|
7188
7266
|
}
|
|
7267
|
+
/** The kind an instance body is of: the provider's `kindOf`, else its one declared kind. */
|
|
7268
|
+
kindOfBody(body) {
|
|
7269
|
+
if (this.hooks.kindOf !== void 0) {
|
|
7270
|
+
const id = this.hooks.kindOf(body);
|
|
7271
|
+
if (!this.hooks.description.kinds.some((declared) => declared.id === id)) throw new Error(`record kind '${this.kind.name}': kindOf returned '${id}', which describe().kinds does not declare (D1013)`);
|
|
7272
|
+
return id;
|
|
7273
|
+
}
|
|
7274
|
+
const only = this.hooks.description.kinds[0];
|
|
7275
|
+
if (only === void 0) throw new Error(`record kind '${this.kind.name}' declares no kinds`);
|
|
7276
|
+
return only.id;
|
|
7277
|
+
}
|
|
7189
7278
|
viewOf(record) {
|
|
7190
7279
|
const shown = secretViewsOf(this.records.owner, this.kind.name, record.id, this.kind.declaration, record.data);
|
|
7191
7280
|
const rawName = record.data[this.nameField];
|
|
7192
|
-
const kind = this.
|
|
7281
|
+
const kind = this.kindOfBody(record.data);
|
|
7193
7282
|
const health = this.hooks.health?.(record.data, record.id);
|
|
7194
7283
|
return {
|
|
7195
7284
|
id: record.id,
|
|
@@ -7197,7 +7286,7 @@ var RecordIntegrationInstances = class {
|
|
|
7197
7286
|
configured: this.hooks.configured(record.data),
|
|
7198
7287
|
enabled: isInstanceEnabled(record.data),
|
|
7199
7288
|
formValues: shown,
|
|
7200
|
-
|
|
7289
|
+
kind,
|
|
7201
7290
|
...health?.status !== void 0 ? { status: health.status } : {},
|
|
7202
7291
|
...health?.lastCheckedAt !== void 0 ? { lastCheckedAt: health.lastCheckedAt } : {}
|
|
7203
7292
|
};
|
|
@@ -7230,17 +7319,35 @@ var RecordIntegrationInstances = class {
|
|
|
7230
7319
|
...kind !== void 0 ? { kind } : {}
|
|
7231
7320
|
});
|
|
7232
7321
|
if (minted === void 0) throw new Error("createInstance needs an id: this provider does not mint one");
|
|
7322
|
+
const initial = this.hooks.initialBody(name, kind);
|
|
7323
|
+
const patch = this.patchOf(values ?? {});
|
|
7324
|
+
if (Object.keys(patch).length > 0) Object.assign(patch, await this.hooks.validateWrite?.({
|
|
7325
|
+
kind,
|
|
7326
|
+
body: {
|
|
7327
|
+
...initial,
|
|
7328
|
+
...patch
|
|
7329
|
+
}
|
|
7330
|
+
}));
|
|
7233
7331
|
await this.handle.put({
|
|
7234
7332
|
id: minted,
|
|
7235
|
-
data:
|
|
7333
|
+
data: initial
|
|
7236
7334
|
}, { ifRev: 0 });
|
|
7237
|
-
const patch = this.patchOf(values ?? {});
|
|
7238
7335
|
if (Object.keys(patch).length > 0) await this.handle.patch(minted, patch);
|
|
7239
7336
|
await this.hooks.onChanged?.(minted, "created");
|
|
7240
7337
|
return { id: minted };
|
|
7241
7338
|
};
|
|
7242
7339
|
updateInstance = async ({ id, name, values }) => {
|
|
7243
7340
|
const patch = this.patchOf(values);
|
|
7341
|
+
if (this.hooks.validateWrite !== void 0 && Object.keys(patch).length > 0) {
|
|
7342
|
+
const stored = await this.handle.get(id);
|
|
7343
|
+
if (stored !== null) Object.assign(patch, await this.hooks.validateWrite({
|
|
7344
|
+
kind: void 0,
|
|
7345
|
+
body: {
|
|
7346
|
+
...stored.data,
|
|
7347
|
+
...patch
|
|
7348
|
+
}
|
|
7349
|
+
}));
|
|
7350
|
+
}
|
|
7244
7351
|
if (name !== void 0) patch[this.nameField] = name;
|
|
7245
7352
|
await this.handle.patch(id, patch);
|
|
7246
7353
|
await this.hooks.onChanged?.(id, "updated");
|
|
@@ -7551,6 +7658,21 @@ var SCOPED_SETTINGS_SCOPES = [
|
|
|
7551
7658
|
"device-defaults",
|
|
7552
7659
|
"node"
|
|
7553
7660
|
];
|
|
7661
|
+
/** The one refusal of a key a scope did not declare. */
|
|
7662
|
+
function assertDeclaredKeys(keys, declared) {
|
|
7663
|
+
const undeclared = keys.filter((key) => !declared.has(key));
|
|
7664
|
+
if (undeclared.length > 0) throw new Error(`scoped settings: [${undeclared.join(", ")}] not declared for this scope (declared: [${[...declared].join(", ")}])`);
|
|
7665
|
+
}
|
|
7666
|
+
/** Build the handle over an addon's scoped read, write and unset. */
|
|
7667
|
+
function createScopedSettings(deps) {
|
|
7668
|
+
return {
|
|
7669
|
+
async get() {
|
|
7670
|
+
return deps.schema.parse(await deps.read());
|
|
7671
|
+
},
|
|
7672
|
+
patch: (patch) => deps.write(Object.fromEntries(Object.entries(patch))),
|
|
7673
|
+
unset: (keys) => deps.unset(keys)
|
|
7674
|
+
};
|
|
7675
|
+
}
|
|
7554
7676
|
/** A write to a secret path could not be stored in the keychain, so it was refused. */
|
|
7555
7677
|
var KeychainWriteRefusedError = class extends Error {
|
|
7556
7678
|
fieldPath;
|
|
@@ -8126,7 +8248,16 @@ function createHandle(raw, opts) {
|
|
|
8126
8248
|
return blob;
|
|
8127
8249
|
}
|
|
8128
8250
|
},
|
|
8129
|
-
writeAddonStore: writeAddon
|
|
8251
|
+
writeAddonStore: writeAddon,
|
|
8252
|
+
removeClearedKeys: (keys) => serialize("addon", async () => {
|
|
8253
|
+
const stored = await readStoredAddonBlob(raw);
|
|
8254
|
+
index.seen("addon", stored);
|
|
8255
|
+
const removable = keys.filter((key) => collectSecretMarkerRefs(stored[key]).length === 0);
|
|
8256
|
+
if (removable.length === 0) return;
|
|
8257
|
+
const patch = Object.fromEntries(removable.map((key) => [key, void 0]));
|
|
8258
|
+
await raw.writeAddonStore(patch);
|
|
8259
|
+
index.wrote("addon", patch);
|
|
8260
|
+
})
|
|
8130
8261
|
};
|
|
8131
8262
|
}
|
|
8132
8263
|
/** The context the addon sees, plus the private raw view and write outcome. */
|
|
@@ -8256,7 +8387,7 @@ function boundOf(list) {
|
|
|
8256
8387
|
* Base class for CamStack addons. Eliminates settings boilerplate:
|
|
8257
8388
|
*
|
|
8258
8389
|
* - Typed `config` property with automatic resolution from store + defaults
|
|
8259
|
-
* -
|
|
8390
|
+
* - the scoped settings API (`clusterSettings` / `nodeSettings` / `deviceDefaults`) auto-implemented
|
|
8260
8391
|
* - `getAddonSettings()` / `updateAddonSettings()` auto-implemented
|
|
8261
8392
|
* - `getDeviceSettings()` / `updateDeviceSettings()` auto-implemented
|
|
8262
8393
|
* - `ctx` accessor for the AddonContext (no manual `this.ctxRef` storage)
|
|
@@ -8266,7 +8397,7 @@ function boundOf(list) {
|
|
|
8266
8397
|
* Subclasses override:
|
|
8267
8398
|
* - `onInitialize()` — addon-specific init logic, return ProviderRegistration[]
|
|
8268
8399
|
* - `onShutdown()` — cleanup
|
|
8269
|
-
* - `
|
|
8400
|
+
* - `clusterSettingsSchema()` / `nodeSettingsSchema()` / `deviceSettingsSchema()` — UI schemas
|
|
8270
8401
|
*
|
|
8271
8402
|
* @example
|
|
8272
8403
|
* ```ts
|
|
@@ -8280,7 +8411,7 @@ function boundOf(list) {
|
|
|
8280
8411
|
* super({ maxRetries: 3, endpoint: 'http://localhost' })
|
|
8281
8412
|
* }
|
|
8282
8413
|
*
|
|
8283
|
-
* protected
|
|
8414
|
+
* protected clusterSettingsSchema() {
|
|
8284
8415
|
* return this.schema({
|
|
8285
8416
|
* sections: [{
|
|
8286
8417
|
* id: 'main', title: 'Settings',
|
|
@@ -8323,7 +8454,7 @@ var BaseAddon = class {
|
|
|
8323
8454
|
defaults;
|
|
8324
8455
|
/**
|
|
8325
8456
|
* Hidden-state paths that hold secrets (D787) — values the addon writes
|
|
8326
|
-
* itself (`
|
|
8457
|
+
* itself (`state()`, the scoped writers) that no form field declares.
|
|
8327
8458
|
* Stored in the keychain exactly like a `password` field. Syntax:
|
|
8328
8459
|
* `'snapshotSigningKey'`, `'identity.pincode'`, `'tokens[userId].accessToken'`
|
|
8329
8460
|
* (`key[<id field>]` addresses array items by id, never by index).
|
|
@@ -8333,7 +8464,7 @@ var BaseAddon = class {
|
|
|
8333
8464
|
/**
|
|
8334
8465
|
* D986 M4: the scoped schemas this addon declared, resolved once per capability
|
|
8335
8466
|
* (`loadScopedSchemas`) so the sync readers (`perNodeKeys`, the secret tree, the restart check)
|
|
8336
|
-
* see them. Empty until loaded
|
|
8467
|
+
* see them. Empty until loaded.
|
|
8337
8468
|
*/
|
|
8338
8469
|
_scopedByCap = /* @__PURE__ */ new Map();
|
|
8339
8470
|
_nodeKeysByCap = /* @__PURE__ */ new Map();
|
|
@@ -8519,7 +8650,7 @@ var BaseAddon = class {
|
|
|
8519
8650
|
/** Addon-specific cleanup. Override if needed. */
|
|
8520
8651
|
async onShutdown() {}
|
|
8521
8652
|
/**
|
|
8522
|
-
* Called after config is resolved during
|
|
8653
|
+
* Called after config is resolved during a settings write.
|
|
8523
8654
|
* Override to react to config changes (e.g. restart a sampler, reconnect a service).
|
|
8524
8655
|
* Not called during initialize() — use onInitialize() for initial setup.
|
|
8525
8656
|
*/
|
|
@@ -8548,82 +8679,12 @@ var BaseAddon = class {
|
|
|
8548
8679
|
scopedSettingsCapabilities() {
|
|
8549
8680
|
return [];
|
|
8550
8681
|
}
|
|
8551
|
-
/** Override to provide global-level settings UI schema. */
|
|
8552
|
-
globalSettingsSchema(_cap) {
|
|
8553
|
-
return null;
|
|
8554
|
-
}
|
|
8555
8682
|
/** Override to provide device-level settings UI schema. */
|
|
8556
8683
|
deviceSettingsSchema() {
|
|
8557
8684
|
return null;
|
|
8558
8685
|
}
|
|
8559
8686
|
/**
|
|
8560
|
-
*
|
|
8561
|
-
* ARE the configuration of its integration.
|
|
8562
|
-
*
|
|
8563
|
-
* Return the `ConfigSection.id`s, from {@link globalSettingsSchema}, that an
|
|
8564
|
-
* operator should find on the addon's integration page (System →
|
|
8565
|
-
* Integrations → <name>) rather than only in the cluster-wide list of every
|
|
8566
|
-
* addon. Empty (the default) means the addon has no integration-level
|
|
8567
|
-
* settings and no such surface is offered — this is opt-in, because whether
|
|
8568
|
-
* an addon's configuration IS its integration's configuration depends on the
|
|
8569
|
-
* nature of the integration.
|
|
8570
|
-
*
|
|
8571
|
-
* WHAT THIS IS NOT. It is not a scope. The selected sections keep living in
|
|
8572
|
-
* the ONE global schema, in the ONE addon store, written by the ONE
|
|
8573
|
-
* `updateGlobalSettings` path. There is deliberately no
|
|
8574
|
-
* `updateIntegrationSettings`: a second write path is how a surface acquires
|
|
8575
|
-
* a second store key, and this repo has shipped that twice (`btmPath@hub`,
|
|
8576
|
-
* D266). Selecting sections cannot introduce a key that selecting cannot.
|
|
8577
|
-
*
|
|
8578
|
-
* WHY IT IS A LIST OF SECTION IDS AND NOT A MARKER ON THE SECTION.
|
|
8579
|
-
* `ConfigFieldBase` used to carry `scope?: 'device' | 'global'` and it was
|
|
8580
|
-
* removed with the reason recorded at
|
|
8581
|
-
* `packages/types/src/interfaces/config-ui.ts:249` — *"a field's scope is
|
|
8582
|
-
* determined by WHICH schema it lives in, not by a field-level marker."* A
|
|
8583
|
-
* marker sprinkled across sections also has to borrow a field that already
|
|
8584
|
-
* means something else; borrowing `section.tab` put the literal word
|
|
8585
|
-
* "integration" into an operator-facing tab bar, because `tab` means "how to
|
|
8586
|
-
* GROUP this visually" and cannot also mean "where this lives" (D269
|
|
8587
|
-
* supersedes D268). One declaration, in one place, next to the schema whose
|
|
8588
|
-
* ids it names.
|
|
8589
|
-
*/
|
|
8590
|
-
integrationSettingSections() {
|
|
8591
|
-
return [];
|
|
8592
|
-
}
|
|
8593
|
-
async getGlobalSettings(overlay, cap, nodeId) {
|
|
8594
|
-
await this.loadScopedSchemas(cap);
|
|
8595
|
-
const schema = this.globalSettingsSchema(cap) ?? this.scopedFormSchema(cap);
|
|
8596
|
-
if (!schema) return { sections: [] };
|
|
8597
|
-
const projected = await this.readRawProjectedStore(nodeId, cap);
|
|
8598
|
-
return hydrateSchema(schema, overlay ? await this.overlayKeepingMarkers(projected, overlay) : projected, { inlineSecretsAsViews: true });
|
|
8599
|
-
}
|
|
8600
|
-
/**
|
|
8601
|
-
* The integration-level view of this addon's settings: exactly the sections
|
|
8602
|
-
* named by {@link integrationSettingSections}, hydrated from the SAME store
|
|
8603
|
-
* `getGlobalSettings` reads, and narrowed to cluster-scoped fields.
|
|
8604
|
-
*
|
|
8605
|
-
* Returns `null` when the addon declared nothing — an addon that opts out has
|
|
8606
|
-
* no integration settings surface at all, rather than an empty one that reads
|
|
8607
|
-
* as a failed load.
|
|
8608
|
-
*
|
|
8609
|
-
* Three properties hold BY CONSTRUCTION, which is why they are here in core
|
|
8610
|
-
* and not in whichever UI happens to render this:
|
|
8611
|
-
*
|
|
8612
|
-
* 1. **One key.** The payload is a SUBSET of the global schema, so a field
|
|
8613
|
-
* shown here is the same field, with the same bare key, that the addon's
|
|
8614
|
-
* own page shows. There is no integration-specific writer — callers save
|
|
8615
|
-
* through `updateGlobalSettings` — so a second store key is unreachable,
|
|
8616
|
-
* not merely discouraged.
|
|
8617
|
-
* 2. **No node scope.** `perNode: true` fields are DROPPED. Their store key
|
|
8618
|
-
* is `<key>@<nodeId>` and an integration is not a node; whichever node
|
|
8619
|
-
* such a field silently picked would be a wrong answer for the operator
|
|
8620
|
-
* who opened the page (D266).
|
|
8621
|
-
* 3. **No silent typo.** A declared id that names no section throws. The
|
|
8622
|
-
* alternative — skip it — turns a rename into a surface that quietly
|
|
8623
|
-
* empties, which looks exactly like an addon with nothing to configure.
|
|
8624
|
-
*/
|
|
8625
|
-
/**
|
|
8626
|
-
* The form schema of ONE integration instance, or `null` to use {@link globalSettingsSchema}.
|
|
8687
|
+
* The form schema of ONE integration instance, or `null` to use the scoped form.
|
|
8627
8688
|
*
|
|
8628
8689
|
* Override it only when an `instanceMode: multiple` addon's instances differ: an NVR integration
|
|
8629
8690
|
* needs its connection fields, the default integration the addon's own sections. It is the
|
|
@@ -8671,37 +8732,178 @@ var BaseAddon = class {
|
|
|
8671
8732
|
}
|
|
8672
8733
|
}
|
|
8673
8734
|
/**
|
|
8735
|
+
* Hook: values layered over the stored ones when the FORM of one scope is served
|
|
8736
|
+
* ({@link getScopedSettings}) — a preview that derives dependent options without writing.
|
|
8737
|
+
* Never applied to {@link ScopedSettings.get} or to a write. `null` ⇒ no overlay.
|
|
8738
|
+
*/
|
|
8739
|
+
async scopedSettingsOverlay(_scope, _cap, _nodeId) {
|
|
8740
|
+
return null;
|
|
8741
|
+
}
|
|
8742
|
+
/**
|
|
8743
|
+
* Hook: a write of one scope changed stored values (not called when the store reports no change,
|
|
8744
|
+
* e.g. the write-back of a stored secret). `keys` are the bare field keys of the write, node keys included.
|
|
8745
|
+
*/
|
|
8746
|
+
async onScopedSettingsChanged(_scope, _cap, _keys) {}
|
|
8747
|
+
/** Typed handle over the CLUSTER settings `cap` declares (`clusterSettingsSchema`). */
|
|
8748
|
+
clusterSettings(cap, schema) {
|
|
8749
|
+
return this.scopedHandle("cluster", cap, schema);
|
|
8750
|
+
}
|
|
8751
|
+
/** Typed handle over the fleet defaults of the per-device settings `cap` declares. */
|
|
8752
|
+
deviceDefaults(cap, schema) {
|
|
8753
|
+
return this.scopedHandle("device-defaults", cap, schema);
|
|
8754
|
+
}
|
|
8755
|
+
/**
|
|
8756
|
+
* Typed handle over the settings `cap` owns PER NODE. `nodeId` omitted ⇒ the local node. A node
|
|
8757
|
+
* with no row yields the schema defaults — never a bare-key fallback.
|
|
8758
|
+
*/
|
|
8759
|
+
nodeSettings(cap, schema, nodeId) {
|
|
8760
|
+
return this.scopedHandle("node", cap, schema, nodeId);
|
|
8761
|
+
}
|
|
8762
|
+
/**
|
|
8763
|
+
* {@link state} for a value that is kept per node: stored under `<key>@<nodeId>`, and the
|
|
8764
|
+
* settings store carries `nodeId` in the row data (D986 §1), so a forgotten node's rows go in one
|
|
8765
|
+
* central delete. `nodeId` omitted ⇒ the local node.
|
|
8766
|
+
*/
|
|
8767
|
+
nodeState(key, schema, fallback, nodeId) {
|
|
8768
|
+
this._declaredStateKeys.add(key);
|
|
8769
|
+
return createDurableState({
|
|
8770
|
+
key: nodeScopedKey(key, nodeId ?? this._ctx?.kernel?.localNodeId ?? ""),
|
|
8771
|
+
schema,
|
|
8772
|
+
fallback,
|
|
8773
|
+
read: async () => this.resolveStoredSecrets(await this.readAddonStoreWithRetry()),
|
|
8774
|
+
write: async (patch) => {
|
|
8775
|
+
await this._ctx?.settings?.writeAddonStore(patch);
|
|
8776
|
+
},
|
|
8777
|
+
onParseError: (k, e) => this._ctx?.logger?.warn?.(`durable-state: stored "${k}" failed validation — using fallback`, { meta: {
|
|
8778
|
+
addonId: this._ctx?.id,
|
|
8779
|
+
key: k,
|
|
8780
|
+
error: String(e)
|
|
8781
|
+
} })
|
|
8782
|
+
});
|
|
8783
|
+
}
|
|
8784
|
+
/** The loaded schema `cap` declares for `scope`, or `null`. */
|
|
8785
|
+
async declaredScopedSchema(scope, cap) {
|
|
8786
|
+
await this.loadScopedSchemas(cap);
|
|
8787
|
+
return this.loadedScopedSchemas(cap).find((entry) => entry.scope === scope)?.schema ?? null;
|
|
8788
|
+
}
|
|
8789
|
+
async requireScopedSchema(scope, cap) {
|
|
8790
|
+
const schema = await this.declaredScopedSchema(scope, cap);
|
|
8791
|
+
if (schema === null) throw new Error(`${this.constructor.name}: cap "${cap}" declares no ${scope} settings`);
|
|
8792
|
+
return schema;
|
|
8793
|
+
}
|
|
8794
|
+
scopedKeys(schema) {
|
|
8795
|
+
return new Set(schema.sections.flatMap((section) => collectValueFieldKeys(section.fields)));
|
|
8796
|
+
}
|
|
8797
|
+
/** `store` narrowed to the keys `schema` declares. */
|
|
8798
|
+
narrowToScope(store, schema) {
|
|
8799
|
+
const keys = this.scopedKeys(schema);
|
|
8800
|
+
return Object.fromEntries(Object.entries(store).filter(([key]) => keys.has(key)));
|
|
8801
|
+
}
|
|
8802
|
+
scopedHandle(scope, cap, schema, nodeId) {
|
|
8803
|
+
return createScopedSettings({
|
|
8804
|
+
schema,
|
|
8805
|
+
read: async () => {
|
|
8806
|
+
const declared = await this.requireScopedSchema(scope, cap);
|
|
8807
|
+
const stored = this.narrowToScope(await this.resolveGlobalStore(nodeId, cap), declared);
|
|
8808
|
+
const effective = collectHydratedFieldValues(hydrateSchema(declared, stored));
|
|
8809
|
+
return {
|
|
8810
|
+
...Object.fromEntries([...effective].filter(([, value]) => value !== void 0)),
|
|
8811
|
+
...stored
|
|
8812
|
+
};
|
|
8813
|
+
},
|
|
8814
|
+
write: (patch) => this.writeScoped(scope, cap, patch, nodeId),
|
|
8815
|
+
unset: (keys) => this.unsetScoped(scope, cap, keys, nodeId)
|
|
8816
|
+
});
|
|
8817
|
+
}
|
|
8818
|
+
/** The one write path of the scoped API: declared keys only, then the global patch. */
|
|
8819
|
+
async writeScoped(scope, cap, patch, nodeId) {
|
|
8820
|
+
assertDeclaredKeys(Object.keys(patch), this.scopedKeys(await this.requireScopedSchema(scope, cap)));
|
|
8821
|
+
if (await this.applyGlobalPatch(patch, scope === "node" ? nodeId : void 0, cap)) await this.onScopedSettingsChanged(scope, cap, Object.keys(patch));
|
|
8822
|
+
}
|
|
8823
|
+
/**
|
|
8824
|
+
* Remove declared keys of one scope. A secret goes through {@link clearSecrets} — its keychain
|
|
8825
|
+
* value is released exactly as there — and the emptied row is then removed; every other key is
|
|
8826
|
+
* removed by an `undefined` patch (which a secret transform would read as "keep").
|
|
8827
|
+
*/
|
|
8828
|
+
async unsetScoped(scope, cap, keys, nodeId) {
|
|
8829
|
+
assertDeclaredKeys(keys, this.scopedKeys(await this.requireScopedSchema(scope, cap)));
|
|
8830
|
+
const target = scope === "node" ? nodeId : void 0;
|
|
8831
|
+
const tree = this.addonSecretTree();
|
|
8832
|
+
const secretKeys = keys.filter((key) => tree.has(key));
|
|
8833
|
+
const plainKeys = keys.filter((key) => !tree.has(key));
|
|
8834
|
+
let changed = false;
|
|
8835
|
+
if (plainKeys.length > 0) {
|
|
8836
|
+
const patch = Object.fromEntries(plainKeys.map((key) => [key, void 0]));
|
|
8837
|
+
changed = await this.applyGlobalPatch(patch, target, cap) || changed;
|
|
8838
|
+
}
|
|
8839
|
+
if (secretKeys.length > 0) {
|
|
8840
|
+
await this.clearSecretKeys(secretKeys, target, cap);
|
|
8841
|
+
const node = normalizeNodeId(target ?? this._ctx?.kernel?.localNodeId);
|
|
8842
|
+
const rows = secretKeys.map((key) => scope === "node" ? nodeScopedKey(key, node) : key);
|
|
8843
|
+
if (this._secretSettings !== null) await this._secretSettings.removeClearedKeys(rows);
|
|
8844
|
+
else await this._ctx?.settings?.writeAddonStore(Object.fromEntries(rows.map((row) => [row, void 0])));
|
|
8845
|
+
changed = true;
|
|
8846
|
+
}
|
|
8847
|
+
if (changed) await this.onScopedSettingsChanged(scope, cap, [...keys]);
|
|
8848
|
+
}
|
|
8849
|
+
/**
|
|
8850
|
+
* The hydrated form of one scope of one capability's settings (any
|
|
8851
|
+
* {@link scopedSettingsOverlay} applied), or `null` when the capability declares nothing there.
|
|
8852
|
+
*/
|
|
8853
|
+
async getScopedSettings(scope, cap, nodeId) {
|
|
8854
|
+
const schema = await this.declaredScopedSchema(scope, cap);
|
|
8855
|
+
if (schema === null) return null;
|
|
8856
|
+
const stored = this.narrowToScope(await this.readRawProjectedStore(nodeId, cap), schema);
|
|
8857
|
+
const overlay = await this.scopedSettingsOverlay(scope, cap, nodeId);
|
|
8858
|
+
return hydrateSchema(schema, overlay ? await this.overlayKeepingMarkers(stored, overlay) : stored, { inlineSecretsAsViews: true });
|
|
8859
|
+
}
|
|
8860
|
+
/**
|
|
8861
|
+
* The scoped schemas this addon serves: one entry per loaded (capability, scope), capabilities
|
|
8862
|
+
* in declaration order, scopes in {@link SCOPED_SETTINGS_SCOPES} order. `[]` when it declares
|
|
8863
|
+
* nothing.
|
|
8864
|
+
*/
|
|
8865
|
+
async listScopedSettings() {
|
|
8866
|
+
await this.loadScopedSchemas();
|
|
8867
|
+
return [...this._scopedByCap].flatMap(([cap, entries]) => entries.map((entry) => ({
|
|
8868
|
+
cap,
|
|
8869
|
+
scope: entry.scope,
|
|
8870
|
+
sectionIds: entry.schema.sections.map((section) => section.id)
|
|
8871
|
+
})));
|
|
8872
|
+
}
|
|
8873
|
+
/** The OPERATOR's write of declared keys of one scope (D787 secret semantics). */
|
|
8874
|
+
async updateScopedSettings(scope, cap, patch, nodeId) {
|
|
8875
|
+
this._operatorWriteDepth++;
|
|
8876
|
+
try {
|
|
8877
|
+
await this.writeScoped(scope, cap, patch, nodeId);
|
|
8878
|
+
} finally {
|
|
8879
|
+
this._operatorWriteDepth--;
|
|
8880
|
+
}
|
|
8881
|
+
}
|
|
8882
|
+
/**
|
|
8883
|
+
* The effective values (`stored ?? default`) of one scope, a secret as its `set` view — never
|
|
8884
|
+
* its value. `null` when the capability declares nothing for the scope.
|
|
8885
|
+
*/
|
|
8886
|
+
async readScopedValues(scope, cap, nodeId) {
|
|
8887
|
+
const schema = await this.declaredScopedSchema(scope, cap);
|
|
8888
|
+
if (schema === null) return null;
|
|
8889
|
+
const form = hydrateSchema(schema, this.narrowToScope(await this.readRawProjectedStore(nodeId, cap), schema), { inlineSecretsAsViews: true });
|
|
8890
|
+
return Object.fromEntries([...collectHydratedFieldValues(form)].filter(([, value]) => value !== void 0));
|
|
8891
|
+
}
|
|
8892
|
+
/**
|
|
8674
8893
|
* What the create wizard and the integration edit page render for one instance: the addon's
|
|
8675
8894
|
* per-instance schema when it declares one, else its global schema (what they always showed).
|
|
8676
8895
|
*/
|
|
8677
8896
|
async getIntegrationFormSchema(instance, nodeId) {
|
|
8678
8897
|
const scoped = await this.integrationFormSchema(instance);
|
|
8679
|
-
if (scoped === null) return this.
|
|
8898
|
+
if (scoped === null) return this.scopedForm(nodeId);
|
|
8680
8899
|
return hydrateSchema(scoped, {}, { inlineSecretsAsViews: true });
|
|
8681
8900
|
}
|
|
8682
|
-
|
|
8683
|
-
|
|
8684
|
-
|
|
8685
|
-
const schema = this.
|
|
8686
|
-
if (!schema)
|
|
8687
|
-
|
|
8688
|
-
const sections = [];
|
|
8689
|
-
for (const id of declared) {
|
|
8690
|
-
const section = byId.get(id);
|
|
8691
|
-
if (!section) throw new Error(`${this.constructor.name}: integrationSettingSections() names unknown section "${id}". Known sections: [${[...byId.keys()].join(", ")}].`);
|
|
8692
|
-
const fields = dropPerNodeFields(section.fields);
|
|
8693
|
-
if (fields.length === 0) continue;
|
|
8694
|
-
sections.push({
|
|
8695
|
-
...section,
|
|
8696
|
-
fields
|
|
8697
|
-
});
|
|
8698
|
-
}
|
|
8699
|
-
if (sections.length === 0) return null;
|
|
8700
|
-
const projected = await this.readRawProjectedStore(nodeId);
|
|
8701
|
-
return hydrateSchema({
|
|
8702
|
-
...schema,
|
|
8703
|
-
sections
|
|
8704
|
-
}, projected, { inlineSecretsAsViews: true });
|
|
8901
|
+
/** The form of the scoped schemas this addon declared, hydrated from its store. */
|
|
8902
|
+
async scopedForm(nodeId) {
|
|
8903
|
+
await this.loadScopedSchemas();
|
|
8904
|
+
const schema = this.scopedFormSchema();
|
|
8905
|
+
if (!schema) return { sections: [] };
|
|
8906
|
+
return hydrateSchema(schema, await this.readRawProjectedStore(nodeId), { inlineSecretsAsViews: true });
|
|
8705
8907
|
}
|
|
8706
8908
|
/**
|
|
8707
8909
|
* The raw addon store PROJECTED onto the target node's bare per-node keys:
|
|
@@ -8710,8 +8912,8 @@ var BaseAddon = class {
|
|
|
8710
8912
|
* bare fallback), all `@`-scoped and stray bare per-node keys are dropped.
|
|
8711
8913
|
* A no-op passthrough when the schema declares no `perNode` field.
|
|
8712
8914
|
*
|
|
8713
|
-
* This is the sanctioned way for
|
|
8714
|
-
* the store for custom
|
|
8915
|
+
* This is the sanctioned way for an addon that needs
|
|
8916
|
+
* the store for custom logic (option narrowing, value snapping) to
|
|
8715
8917
|
* read it per-node — never `ctx.settings.readAddonStore()` directly.
|
|
8716
8918
|
* `nodeId` omitted ⇒ the local node (node-blind injection from ctx).
|
|
8717
8919
|
*
|
|
@@ -8763,7 +8965,7 @@ var BaseAddon = class {
|
|
|
8763
8965
|
}
|
|
8764
8966
|
/**
|
|
8765
8967
|
* Whether ONE global key of this addon's store was written, read three-way
|
|
8766
|
-
* (D651). For a question a hydrated view cannot answer:
|
|
8968
|
+
* (D651). For a question a hydrated view cannot answer: a hydrated form
|
|
8767
8969
|
* reports `value ?? default`, so "the operator chose the default" and "nobody
|
|
8768
8970
|
* chose" look the same, and a failed read looks like both. A `perNode` key is
|
|
8769
8971
|
* not supported here: its stored name is scoped.
|
|
@@ -8797,7 +8999,7 @@ var BaseAddon = class {
|
|
|
8797
8999
|
}
|
|
8798
9000
|
/**
|
|
8799
9001
|
* The OPERATOR's write — a settings form or an admin API call, dispatched by
|
|
8800
|
-
* the kernel.
|
|
9002
|
+
* the kernel. The one in-process write of the addon blob that is not a scoped write; a secret
|
|
8801
9003
|
* the operator sends is stored as sent even when it equals a pre-keychain
|
|
8802
9004
|
* inline value: the operator re-entering a password is a change, an addon
|
|
8803
9005
|
* writing back what it read is not (D787).
|
|
@@ -8810,9 +9012,6 @@ var BaseAddon = class {
|
|
|
8810
9012
|
this._operatorWriteDepth--;
|
|
8811
9013
|
}
|
|
8812
9014
|
}
|
|
8813
|
-
async updateGlobalSettings(patch, nodeId) {
|
|
8814
|
-
await this.applyGlobalPatch(patch, nodeId);
|
|
8815
|
-
}
|
|
8816
9015
|
/**
|
|
8817
9016
|
* REMOVE stored secrets — their keychain values and their markers (D787).
|
|
8818
9017
|
*
|
|
@@ -8822,6 +9021,9 @@ var BaseAddon = class {
|
|
|
8822
9021
|
* a keychain (an older kernel) it writes `''`, as such code always did.
|
|
8823
9022
|
*/
|
|
8824
9023
|
async clearSecrets(keys, nodeId) {
|
|
9024
|
+
await this.clearSecretKeys(keys, nodeId);
|
|
9025
|
+
}
|
|
9026
|
+
async clearSecretKeys(keys, nodeId, cap) {
|
|
8825
9027
|
const tree = this.addonSecretTree();
|
|
8826
9028
|
const keychain = this._ctx?.secrets !== void 0;
|
|
8827
9029
|
const stored = keychain ? await this.readAddonStoreWithRetry() : {};
|
|
@@ -8834,25 +9036,26 @@ var BaseAddon = class {
|
|
|
8834
9036
|
const keychainStored = tree.has(key) || collectSecretMarkerRefs(stored[key]).length > 0;
|
|
8835
9037
|
patch[key] = keychain && keychainStored ? SECRET_CLEAR : "";
|
|
8836
9038
|
}
|
|
8837
|
-
await this.applyGlobalPatch(patch, nodeId);
|
|
9039
|
+
await this.applyGlobalPatch(patch, nodeId, cap);
|
|
8838
9040
|
}
|
|
8839
|
-
|
|
8840
|
-
|
|
8841
|
-
|
|
9041
|
+
/** Resolves `true` when the write changed stored values. */
|
|
9042
|
+
async applyGlobalPatch(barePatch, nodeId, cap) {
|
|
9043
|
+
await this.loadScopedSchemas(cap);
|
|
9044
|
+
const keys = this.perNodeKeys(cap);
|
|
8842
9045
|
const localNode = normalizeNodeId(this._ctx?.kernel?.localNodeId);
|
|
8843
9046
|
const target = normalizeNodeId(nodeId ?? this._ctx?.kernel?.localNodeId);
|
|
8844
9047
|
const scoped = keys.size > 0 ? scopePatch(barePatch, keys, target) : barePatch;
|
|
8845
9048
|
const handle = this._secretSettings;
|
|
8846
9049
|
if (handle !== null) {
|
|
8847
9050
|
const { changed } = await handle.writeAddonStore(scoped);
|
|
8848
|
-
if (!changed) return;
|
|
9051
|
+
if (!changed) return false;
|
|
8849
9052
|
} else await this._ctx?.settings?.writeAddonStore(scoped);
|
|
8850
|
-
if (target !== localNode) return;
|
|
9053
|
+
if (target !== localNode) return true;
|
|
8851
9054
|
await this.resolveConfig();
|
|
8852
9055
|
await this.onConfigChanged();
|
|
8853
9056
|
this.emitLifecycle(EventCategory.AddonUpdated, { level: "global" });
|
|
8854
|
-
|
|
8855
|
-
|
|
9057
|
+
this.maybeAutoRestart(Object.keys(barePatch), this.loadedScopedSchemas().map((entry) => entry.schema));
|
|
9058
|
+
return true;
|
|
8856
9059
|
}
|
|
8857
9060
|
/**
|
|
8858
9061
|
* The set of field keys the global settings schema declares `perNode: true`
|
|
@@ -8889,10 +9092,7 @@ var BaseAddon = class {
|
|
|
8889
9092
|
this._nodeKeysByCap = /* @__PURE__ */ new Map();
|
|
8890
9093
|
this._addonSecretTree = null;
|
|
8891
9094
|
}
|
|
8892
|
-
/**
|
|
8893
|
-
* The form the settings API serves while an addon declares no {@link globalSettingsSchema}: the
|
|
8894
|
-
* sections of its scoped schemas, so dropping the old hook does not blank the form.
|
|
8895
|
-
*/
|
|
9095
|
+
/** The form of an addon's scoped schemas: their sections, each shown once. */
|
|
8896
9096
|
scopedFormSchema(cap) {
|
|
8897
9097
|
const byId = /* @__PURE__ */ new Map();
|
|
8898
9098
|
for (const entry of this.loadedScopedSchemas(cap)) for (const section of entry.schema.sections) if (!byId.has(section.id)) byId.set(section.id, section);
|
|
@@ -8904,8 +9104,7 @@ var BaseAddon = class {
|
|
|
8904
9104
|
return [...this._scopedByCap.values()].flat();
|
|
8905
9105
|
}
|
|
8906
9106
|
/**
|
|
8907
|
-
* The field keys that are stored per node: every field of a {@link nodeSettingsSchema}
|
|
8908
|
-
* the fields the legacy {@link globalSettingsSchema} still marks `perNode: true`. Derived once
|
|
9107
|
+
* The field keys that are stored per node: every field of a {@link nodeSettingsSchema}. Derived once
|
|
8909
9108
|
* per `cap` argument and memoized (schemas are static declarations). Empty set ⇒ every
|
|
8910
9109
|
* per-node code path is bypassed and the settings API behaves like the node-agnostic one.
|
|
8911
9110
|
* Call {@link loadScopedSchemas} first (the async seams do).
|
|
@@ -8914,8 +9113,7 @@ var BaseAddon = class {
|
|
|
8914
9113
|
const cacheKey = cap ?? "";
|
|
8915
9114
|
const cached = this._nodeKeysByCap.get(cacheKey);
|
|
8916
9115
|
if (cached) return cached;
|
|
8917
|
-
const
|
|
8918
|
-
const keys = new Set(legacy ? legacy.sections.flatMap((section) => collectPerNodeFieldKeys(section.fields)) : []);
|
|
9116
|
+
const keys = /* @__PURE__ */ new Set();
|
|
8919
9117
|
for (const { scope, schema } of this.loadedScopedSchemas(cap)) {
|
|
8920
9118
|
if (scope !== "node") continue;
|
|
8921
9119
|
for (const section of schema.sections) for (const key of collectValueFieldKeys(section.fields)) keys.add(key);
|
|
@@ -9133,8 +9331,6 @@ var BaseAddon = class {
|
|
|
9133
9331
|
}
|
|
9134
9332
|
declaredKeySet() {
|
|
9135
9333
|
const keys = new Set(Object.keys(this.defaults));
|
|
9136
|
-
const schema = this.globalSettingsSchema();
|
|
9137
|
-
if (schema) for (const section of schema.sections) for (const key of collectFieldKeys(section.fields)) keys.add(key);
|
|
9138
9334
|
for (const { schema: scoped } of this.loadedScopedSchemas()) for (const section of scoped.sections) for (const key of collectFieldKeys(section.fields)) keys.add(key);
|
|
9139
9335
|
for (const key of this._declaredStateKeys) keys.add(key);
|
|
9140
9336
|
for (const path of this.secretStatePaths) {
|
|
@@ -9232,7 +9428,7 @@ var BaseAddon = class {
|
|
|
9232
9428
|
/** The addon store's secret tree: schema fields by TYPE, plus `secretStatePaths`. */
|
|
9233
9429
|
addonSecretTree() {
|
|
9234
9430
|
if (this._addonSecretTree === null) {
|
|
9235
|
-
const tree = new Map(
|
|
9431
|
+
const tree = /* @__PURE__ */ new Map();
|
|
9236
9432
|
for (const { schema } of this.loadedScopedSchemas()) for (const [key, node] of secretTreeFromSchema(schema)) tree.set(key, node);
|
|
9237
9433
|
this._addonSecretTree = mergeSecretStatePaths(tree, this.secretStatePaths);
|
|
9238
9434
|
}
|
|
@@ -9444,47 +9640,6 @@ function classifyStoreError(err) {
|
|
|
9444
9640
|
if (TRANSPORT_PHRASES.some((f) => message.includes(f))) return "transport";
|
|
9445
9641
|
return "permanent";
|
|
9446
9642
|
}
|
|
9447
|
-
/**
|
|
9448
|
-
* Collect the keys of every field marked `perNode: true`, recursing into
|
|
9449
|
-
* layout containers (`group` fields and `sub-tabs` tabs) the same way
|
|
9450
|
-
* `hydrateSchema` does. Valueless structural fields (separator/info/…)
|
|
9451
|
-
* don't declare `perNode` and are excluded by the `in` narrowing.
|
|
9452
|
-
*/
|
|
9453
|
-
/**
|
|
9454
|
-
* The same fields with every `perNode: true` one removed, recursing into layout
|
|
9455
|
-
* containers exactly as {@link collectPerNodeFieldKeys} does. A container left
|
|
9456
|
-
* with no child is dropped rather than rendered empty.
|
|
9457
|
-
*
|
|
9458
|
-
* Used by `getIntegrationSettings`: an integration is not a node, so a field
|
|
9459
|
-
* whose store key is `<key>@<nodeId>` has no node to belong to there.
|
|
9460
|
-
*/
|
|
9461
|
-
function dropPerNodeFields(fields) {
|
|
9462
|
-
const kept = [];
|
|
9463
|
-
for (const field of fields) {
|
|
9464
|
-
if (field.type === "group") {
|
|
9465
|
-
const inner = dropPerNodeFields(field.fields);
|
|
9466
|
-
if (inner.length > 0) kept.push({
|
|
9467
|
-
...field,
|
|
9468
|
-
fields: inner
|
|
9469
|
-
});
|
|
9470
|
-
continue;
|
|
9471
|
-
}
|
|
9472
|
-
if (field.type === "sub-tabs") {
|
|
9473
|
-
const tabs = field.tabs.map((tab) => ({
|
|
9474
|
-
...tab,
|
|
9475
|
-
fields: dropPerNodeFields(tab.fields)
|
|
9476
|
-
})).filter((tab) => tab.fields.length > 0);
|
|
9477
|
-
if (tabs.length > 0) kept.push({
|
|
9478
|
-
...field,
|
|
9479
|
-
tabs
|
|
9480
|
-
});
|
|
9481
|
-
continue;
|
|
9482
|
-
}
|
|
9483
|
-
if ("perNode" in field && field.perNode === true) continue;
|
|
9484
|
-
kept.push(field);
|
|
9485
|
-
}
|
|
9486
|
-
return kept;
|
|
9487
|
-
}
|
|
9488
9643
|
/** The keys of the value-holding fields, recursing into layout containers. */
|
|
9489
9644
|
function collectValueFieldKeys(fields) {
|
|
9490
9645
|
const collected = [];
|
|
@@ -9517,21 +9672,6 @@ function collectFieldKeys(fields) {
|
|
|
9517
9672
|
}
|
|
9518
9673
|
return collected;
|
|
9519
9674
|
}
|
|
9520
|
-
function collectPerNodeFieldKeys(fields) {
|
|
9521
|
-
const collected = [];
|
|
9522
|
-
for (const field of fields) {
|
|
9523
|
-
if (field.type === "group") {
|
|
9524
|
-
collected.push(...collectPerNodeFieldKeys(field.fields));
|
|
9525
|
-
continue;
|
|
9526
|
-
}
|
|
9527
|
-
if (field.type === "sub-tabs") {
|
|
9528
|
-
for (const tab of field.tabs) collected.push(...collectPerNodeFieldKeys(tab.fields));
|
|
9529
|
-
continue;
|
|
9530
|
-
}
|
|
9531
|
-
if ("perNode" in field && field.perNode === true) collected.push(field.key);
|
|
9532
|
-
}
|
|
9533
|
-
return collected;
|
|
9534
|
-
}
|
|
9535
9675
|
/**
|
|
9536
9676
|
* Normalize an `ICamstackAddon.initialize()` return value into the
|
|
9537
9677
|
* `AddonInitResult` envelope. Arrays are wrapped into `{ providers }`;
|
|
@@ -10582,7 +10722,6 @@ var CAP_NAMES = Object.freeze([
|
|
|
10582
10722
|
"notifier",
|
|
10583
10723
|
"numeric-sensor",
|
|
10584
10724
|
"oauth-integration",
|
|
10585
|
-
"oidc-connections",
|
|
10586
10725
|
"osd",
|
|
10587
10726
|
"osd-manager",
|
|
10588
10727
|
"pet-feeder",
|
|
@@ -12289,13 +12428,25 @@ Object.freeze({
|
|
|
12289
12428
|
"path": "temperature",
|
|
12290
12429
|
"valueType": "number"
|
|
12291
12430
|
}],
|
|
12292
|
-
"timed-run": [
|
|
12293
|
-
|
|
12294
|
-
|
|
12295
|
-
|
|
12296
|
-
|
|
12297
|
-
|
|
12298
|
-
|
|
12431
|
+
"timed-run": [
|
|
12432
|
+
{
|
|
12433
|
+
"path": "activeUntil",
|
|
12434
|
+
"valueType": "number"
|
|
12435
|
+
},
|
|
12436
|
+
{
|
|
12437
|
+
"path": "requestedBy",
|
|
12438
|
+
"valueType": "string"
|
|
12439
|
+
},
|
|
12440
|
+
{
|
|
12441
|
+
"path": "quickRun.duration",
|
|
12442
|
+
"valueType": "number"
|
|
12443
|
+
},
|
|
12444
|
+
{
|
|
12445
|
+
"path": "quickRun.unit",
|
|
12446
|
+
"valueType": "enum",
|
|
12447
|
+
"enumValues": ["s", "min"]
|
|
12448
|
+
}
|
|
12449
|
+
],
|
|
12299
12450
|
"update": [
|
|
12300
12451
|
{
|
|
12301
12452
|
"path": "currentVersion",
|
|
@@ -12474,8 +12625,7 @@ Object.freeze({
|
|
|
12474
12625
|
"device-provider": { "reloadDevice": 18e4 },
|
|
12475
12626
|
"llm": {
|
|
12476
12627
|
"generate": 6e5,
|
|
12477
|
-
"generateVision": 6e5
|
|
12478
|
-
"testProfile": 6e5
|
|
12628
|
+
"generateVision": 6e5
|
|
12479
12629
|
},
|
|
12480
12630
|
"llm-runtime": {
|
|
12481
12631
|
"complete": 6e5,
|
|
@@ -12534,7 +12684,7 @@ function userError(code, params, englishFallback) {
|
|
|
12534
12684
|
return new CamstackError(code, params, englishFallback);
|
|
12535
12685
|
}
|
|
12536
12686
|
//#endregion
|
|
12537
|
-
//#region ../types/dist/composition-
|
|
12687
|
+
//#region ../types/dist/composition-Bx0JvKUU.mjs
|
|
12538
12688
|
/**
|
|
12539
12689
|
* The ffmpeg build every CamStack node downloads, per platform and arch.
|
|
12540
12690
|
*
|
|
@@ -13696,6 +13846,387 @@ var NodeColorIdSchema = _enum([
|
|
|
13696
13846
|
"node-h"
|
|
13697
13847
|
]);
|
|
13698
13848
|
//#endregion
|
|
13849
|
+
//#region ../types/dist/convert-BAzH15HU.mjs
|
|
13850
|
+
/**
|
|
13851
|
+
* Frozen unit → spec table. `•` in the doc marks each dimension's canonical
|
|
13852
|
+
* unit (`factor: 1, offset: 0`). °F derives from `°C = (°F − 32) × 5/9` ⇒
|
|
13853
|
+
* `factor = 5/9`, `offset = -160/9` (kept as exact expressions, not rounded
|
|
13854
|
+
* decimals). K derives from `°C = K − 273.15`.
|
|
13855
|
+
*/
|
|
13856
|
+
var UNIT_TABLE = {
|
|
13857
|
+
"°C": {
|
|
13858
|
+
dimension: "temperature",
|
|
13859
|
+
factor: 1,
|
|
13860
|
+
offset: 0
|
|
13861
|
+
},
|
|
13862
|
+
"°F": {
|
|
13863
|
+
dimension: "temperature",
|
|
13864
|
+
factor: 5 / 9,
|
|
13865
|
+
offset: -160 / 9
|
|
13866
|
+
},
|
|
13867
|
+
K: {
|
|
13868
|
+
dimension: "temperature",
|
|
13869
|
+
factor: 1,
|
|
13870
|
+
offset: -273.15
|
|
13871
|
+
},
|
|
13872
|
+
hPa: {
|
|
13873
|
+
dimension: "pressure",
|
|
13874
|
+
factor: 1,
|
|
13875
|
+
offset: 0
|
|
13876
|
+
},
|
|
13877
|
+
kPa: {
|
|
13878
|
+
dimension: "pressure",
|
|
13879
|
+
factor: 10,
|
|
13880
|
+
offset: 0
|
|
13881
|
+
},
|
|
13882
|
+
Pa: {
|
|
13883
|
+
dimension: "pressure",
|
|
13884
|
+
factor: .01,
|
|
13885
|
+
offset: 0
|
|
13886
|
+
},
|
|
13887
|
+
mbar: {
|
|
13888
|
+
dimension: "pressure",
|
|
13889
|
+
factor: 1,
|
|
13890
|
+
offset: 0
|
|
13891
|
+
},
|
|
13892
|
+
bar: {
|
|
13893
|
+
dimension: "pressure",
|
|
13894
|
+
factor: 1e3,
|
|
13895
|
+
offset: 0
|
|
13896
|
+
},
|
|
13897
|
+
inHg: {
|
|
13898
|
+
dimension: "pressure",
|
|
13899
|
+
factor: 33.8639,
|
|
13900
|
+
offset: 0
|
|
13901
|
+
},
|
|
13902
|
+
mmHg: {
|
|
13903
|
+
dimension: "pressure",
|
|
13904
|
+
factor: 1.33322,
|
|
13905
|
+
offset: 0
|
|
13906
|
+
},
|
|
13907
|
+
psi: {
|
|
13908
|
+
dimension: "pressure",
|
|
13909
|
+
factor: 68.9476,
|
|
13910
|
+
offset: 0
|
|
13911
|
+
},
|
|
13912
|
+
"m/s": {
|
|
13913
|
+
dimension: "speed",
|
|
13914
|
+
factor: 1,
|
|
13915
|
+
offset: 0
|
|
13916
|
+
},
|
|
13917
|
+
"km/h": {
|
|
13918
|
+
dimension: "speed",
|
|
13919
|
+
factor: 1 / 3.6,
|
|
13920
|
+
offset: 0
|
|
13921
|
+
},
|
|
13922
|
+
mph: {
|
|
13923
|
+
dimension: "speed",
|
|
13924
|
+
factor: .44704,
|
|
13925
|
+
offset: 0
|
|
13926
|
+
},
|
|
13927
|
+
kn: {
|
|
13928
|
+
dimension: "speed",
|
|
13929
|
+
factor: .514444,
|
|
13930
|
+
offset: 0
|
|
13931
|
+
},
|
|
13932
|
+
"mm/h": {
|
|
13933
|
+
dimension: "precipitation-rate",
|
|
13934
|
+
factor: 1,
|
|
13935
|
+
offset: 0
|
|
13936
|
+
},
|
|
13937
|
+
"in/h": {
|
|
13938
|
+
dimension: "precipitation-rate",
|
|
13939
|
+
factor: 25.4,
|
|
13940
|
+
offset: 0
|
|
13941
|
+
},
|
|
13942
|
+
m: {
|
|
13943
|
+
dimension: "length",
|
|
13944
|
+
factor: 1,
|
|
13945
|
+
offset: 0
|
|
13946
|
+
},
|
|
13947
|
+
mm: {
|
|
13948
|
+
dimension: "length",
|
|
13949
|
+
factor: .001,
|
|
13950
|
+
offset: 0
|
|
13951
|
+
},
|
|
13952
|
+
cm: {
|
|
13953
|
+
dimension: "length",
|
|
13954
|
+
factor: .01,
|
|
13955
|
+
offset: 0
|
|
13956
|
+
},
|
|
13957
|
+
km: {
|
|
13958
|
+
dimension: "length",
|
|
13959
|
+
factor: 1e3,
|
|
13960
|
+
offset: 0
|
|
13961
|
+
},
|
|
13962
|
+
in: {
|
|
13963
|
+
dimension: "length",
|
|
13964
|
+
factor: .0254,
|
|
13965
|
+
offset: 0
|
|
13966
|
+
},
|
|
13967
|
+
ft: {
|
|
13968
|
+
dimension: "length",
|
|
13969
|
+
factor: .3048,
|
|
13970
|
+
offset: 0
|
|
13971
|
+
},
|
|
13972
|
+
mi: {
|
|
13973
|
+
dimension: "length",
|
|
13974
|
+
factor: 1609.344,
|
|
13975
|
+
offset: 0
|
|
13976
|
+
},
|
|
13977
|
+
"m²": {
|
|
13978
|
+
dimension: "area",
|
|
13979
|
+
factor: 1,
|
|
13980
|
+
offset: 0
|
|
13981
|
+
},
|
|
13982
|
+
lx: {
|
|
13983
|
+
dimension: "illuminance",
|
|
13984
|
+
factor: 1,
|
|
13985
|
+
offset: 0
|
|
13986
|
+
},
|
|
13987
|
+
"W/m²": {
|
|
13988
|
+
dimension: "irradiance",
|
|
13989
|
+
factor: 1,
|
|
13990
|
+
offset: 0
|
|
13991
|
+
},
|
|
13992
|
+
W: {
|
|
13993
|
+
dimension: "power",
|
|
13994
|
+
factor: 1,
|
|
13995
|
+
offset: 0
|
|
13996
|
+
},
|
|
13997
|
+
kW: {
|
|
13998
|
+
dimension: "power",
|
|
13999
|
+
factor: 1e3,
|
|
14000
|
+
offset: 0
|
|
14001
|
+
},
|
|
14002
|
+
VA: {
|
|
14003
|
+
dimension: "apparent-power",
|
|
14004
|
+
factor: 1,
|
|
14005
|
+
offset: 0
|
|
14006
|
+
},
|
|
14007
|
+
Wh: {
|
|
14008
|
+
dimension: "energy",
|
|
14009
|
+
factor: 1,
|
|
14010
|
+
offset: 0
|
|
14011
|
+
},
|
|
14012
|
+
kWh: {
|
|
14013
|
+
dimension: "energy",
|
|
14014
|
+
factor: 1e3,
|
|
14015
|
+
offset: 0
|
|
14016
|
+
},
|
|
14017
|
+
MWh: {
|
|
14018
|
+
dimension: "energy",
|
|
14019
|
+
factor: 1e6,
|
|
14020
|
+
offset: 0
|
|
14021
|
+
},
|
|
14022
|
+
V: {
|
|
14023
|
+
dimension: "voltage",
|
|
14024
|
+
factor: 1,
|
|
14025
|
+
offset: 0
|
|
14026
|
+
},
|
|
14027
|
+
mV: {
|
|
14028
|
+
dimension: "voltage",
|
|
14029
|
+
factor: .001,
|
|
14030
|
+
offset: 0
|
|
14031
|
+
},
|
|
14032
|
+
A: {
|
|
14033
|
+
dimension: "current",
|
|
14034
|
+
factor: 1,
|
|
14035
|
+
offset: 0
|
|
14036
|
+
},
|
|
14037
|
+
mA: {
|
|
14038
|
+
dimension: "current",
|
|
14039
|
+
factor: .001,
|
|
14040
|
+
offset: 0
|
|
14041
|
+
},
|
|
14042
|
+
ppm: {
|
|
14043
|
+
dimension: "concentration-volume",
|
|
14044
|
+
factor: 1,
|
|
14045
|
+
offset: 0
|
|
14046
|
+
},
|
|
14047
|
+
ppb: {
|
|
14048
|
+
dimension: "concentration-volume",
|
|
14049
|
+
factor: .001,
|
|
14050
|
+
offset: 0
|
|
14051
|
+
},
|
|
14052
|
+
"µg/m³": {
|
|
14053
|
+
dimension: "concentration-mass",
|
|
14054
|
+
factor: 1,
|
|
14055
|
+
offset: 0
|
|
14056
|
+
},
|
|
14057
|
+
"mg/m³": {
|
|
14058
|
+
dimension: "concentration-mass",
|
|
14059
|
+
factor: 1e3,
|
|
14060
|
+
offset: 0
|
|
14061
|
+
},
|
|
14062
|
+
kg: {
|
|
14063
|
+
dimension: "mass",
|
|
14064
|
+
factor: 1,
|
|
14065
|
+
offset: 0
|
|
14066
|
+
},
|
|
14067
|
+
g: {
|
|
14068
|
+
dimension: "mass",
|
|
14069
|
+
factor: .001,
|
|
14070
|
+
offset: 0
|
|
14071
|
+
},
|
|
14072
|
+
lb: {
|
|
14073
|
+
dimension: "mass",
|
|
14074
|
+
factor: .453592,
|
|
14075
|
+
offset: 0
|
|
14076
|
+
},
|
|
14077
|
+
oz: {
|
|
14078
|
+
dimension: "mass",
|
|
14079
|
+
factor: .0283495,
|
|
14080
|
+
offset: 0
|
|
14081
|
+
},
|
|
14082
|
+
"%": {
|
|
14083
|
+
dimension: "percentage",
|
|
14084
|
+
factor: 1,
|
|
14085
|
+
offset: 0
|
|
14086
|
+
},
|
|
14087
|
+
L: {
|
|
14088
|
+
dimension: "volume",
|
|
14089
|
+
factor: 1,
|
|
14090
|
+
offset: 0
|
|
14091
|
+
},
|
|
14092
|
+
mL: {
|
|
14093
|
+
dimension: "volume",
|
|
14094
|
+
factor: .001,
|
|
14095
|
+
offset: 0
|
|
14096
|
+
},
|
|
14097
|
+
gal: {
|
|
14098
|
+
dimension: "volume",
|
|
14099
|
+
factor: 3.785411784,
|
|
14100
|
+
offset: 0
|
|
14101
|
+
},
|
|
14102
|
+
s: {
|
|
14103
|
+
dimension: "duration",
|
|
14104
|
+
factor: 1,
|
|
14105
|
+
offset: 0
|
|
14106
|
+
},
|
|
14107
|
+
ms: {
|
|
14108
|
+
dimension: "duration",
|
|
14109
|
+
factor: .001,
|
|
14110
|
+
offset: 0
|
|
14111
|
+
},
|
|
14112
|
+
min: {
|
|
14113
|
+
dimension: "duration",
|
|
14114
|
+
factor: 60,
|
|
14115
|
+
offset: 0
|
|
14116
|
+
},
|
|
14117
|
+
h: {
|
|
14118
|
+
dimension: "duration",
|
|
14119
|
+
factor: 3600,
|
|
14120
|
+
offset: 0
|
|
14121
|
+
},
|
|
14122
|
+
d: {
|
|
14123
|
+
dimension: "duration",
|
|
14124
|
+
factor: 86400,
|
|
14125
|
+
offset: 0
|
|
14126
|
+
},
|
|
14127
|
+
B: {
|
|
14128
|
+
dimension: "information",
|
|
14129
|
+
factor: 1,
|
|
14130
|
+
offset: 0
|
|
14131
|
+
},
|
|
14132
|
+
KiB: {
|
|
14133
|
+
dimension: "information",
|
|
14134
|
+
factor: 1024,
|
|
14135
|
+
offset: 0
|
|
14136
|
+
},
|
|
14137
|
+
MiB: {
|
|
14138
|
+
dimension: "information",
|
|
14139
|
+
factor: 1024 ** 2,
|
|
14140
|
+
offset: 0
|
|
14141
|
+
},
|
|
14142
|
+
GiB: {
|
|
14143
|
+
dimension: "information",
|
|
14144
|
+
factor: 1024 ** 3,
|
|
14145
|
+
offset: 0
|
|
14146
|
+
},
|
|
14147
|
+
TiB: {
|
|
14148
|
+
dimension: "information",
|
|
14149
|
+
factor: 1024 ** 4,
|
|
14150
|
+
offset: 0
|
|
14151
|
+
},
|
|
14152
|
+
kB: {
|
|
14153
|
+
dimension: "information",
|
|
14154
|
+
factor: 1e3,
|
|
14155
|
+
offset: 0
|
|
14156
|
+
},
|
|
14157
|
+
MB: {
|
|
14158
|
+
dimension: "information",
|
|
14159
|
+
factor: 1e6,
|
|
14160
|
+
offset: 0
|
|
14161
|
+
},
|
|
14162
|
+
GB: {
|
|
14163
|
+
dimension: "information",
|
|
14164
|
+
factor: 1e9,
|
|
14165
|
+
offset: 0
|
|
14166
|
+
},
|
|
14167
|
+
"°": {
|
|
14168
|
+
dimension: "angle",
|
|
14169
|
+
factor: 1,
|
|
14170
|
+
offset: 0
|
|
14171
|
+
},
|
|
14172
|
+
dBFS: {
|
|
14173
|
+
dimension: "sound-level",
|
|
14174
|
+
factor: 1,
|
|
14175
|
+
offset: 0
|
|
14176
|
+
},
|
|
14177
|
+
dBm: {
|
|
14178
|
+
dimension: "signal-level",
|
|
14179
|
+
factor: 1,
|
|
14180
|
+
offset: 0
|
|
14181
|
+
},
|
|
14182
|
+
mired: {
|
|
14183
|
+
dimension: "colour-temperature",
|
|
14184
|
+
factor: 1,
|
|
14185
|
+
offset: 0
|
|
14186
|
+
},
|
|
14187
|
+
kbps: {
|
|
14188
|
+
dimension: "bitrate",
|
|
14189
|
+
factor: 1,
|
|
14190
|
+
offset: 0
|
|
14191
|
+
},
|
|
14192
|
+
Mbps: {
|
|
14193
|
+
dimension: "bitrate",
|
|
14194
|
+
factor: 1e3,
|
|
14195
|
+
offset: 0
|
|
14196
|
+
},
|
|
14197
|
+
fps: {
|
|
14198
|
+
dimension: "rate",
|
|
14199
|
+
factor: 1,
|
|
14200
|
+
offset: 0
|
|
14201
|
+
}
|
|
14202
|
+
};
|
|
14203
|
+
/** Resolve a unit's `UnitSpec`, or `undefined` when the spelling is unknown. */
|
|
14204
|
+
function specFor(unit) {
|
|
14205
|
+
return Object.hasOwn(UNIT_TABLE, unit) ? UNIT_TABLE[unit] : void 0;
|
|
14206
|
+
}
|
|
14207
|
+
/** Value in `spec`'s unit → its dimension's canonical unit. */
|
|
14208
|
+
function toCanonical(value, spec) {
|
|
14209
|
+
return value * spec.factor + spec.offset;
|
|
14210
|
+
}
|
|
14211
|
+
/** Canonical-unit value → the unit described by `spec`. */
|
|
14212
|
+
function fromCanonical(canonical, spec) {
|
|
14213
|
+
return (canonical - spec.offset) / spec.factor;
|
|
14214
|
+
}
|
|
14215
|
+
/**
|
|
14216
|
+
* Graceful variant for the render path: returns the converted value, or
|
|
14217
|
+
* `undefined` when the conversion is refused (unknown unit / cross-dimension).
|
|
14218
|
+
* Never throws — a render caller falls back to the raw value + source unit.
|
|
14219
|
+
*/
|
|
14220
|
+
function tryConvertUnit(value, from, to) {
|
|
14221
|
+
if (from === to) return value;
|
|
14222
|
+
const fromSpec = specFor(from);
|
|
14223
|
+
if (!fromSpec) return void 0;
|
|
14224
|
+
const toSpec = specFor(to);
|
|
14225
|
+
if (!toSpec) return void 0;
|
|
14226
|
+
if (fromSpec.dimension !== toSpec.dimension) return void 0;
|
|
14227
|
+
return fromCanonical(toCanonical(value, fromSpec), toSpec);
|
|
14228
|
+
}
|
|
14229
|
+
//#endregion
|
|
13699
14230
|
//#region ../types/dist/index.mjs
|
|
13700
14231
|
var SMTP_INBOUND_DEFAULT_PORT = 2525;
|
|
13701
14232
|
var SMTP_INBOUND_DEFAULT_DOMAIN = "camstack.local";
|
|
@@ -14100,17 +14631,18 @@ function composeInstanceKinds(parts, base) {
|
|
|
14100
14631
|
* message to what the kind supports — callers never special-case a service.
|
|
14101
14632
|
*
|
|
14102
14633
|
* DESIGN DECISIONS (locked):
|
|
14103
|
-
* -
|
|
14104
|
-
*
|
|
14105
|
-
*
|
|
14106
|
-
*
|
|
14107
|
-
*
|
|
14108
|
-
*
|
|
14109
|
-
*
|
|
14110
|
-
*
|
|
14111
|
-
*
|
|
14112
|
-
* routable. `send` / `testTarget` /
|
|
14113
|
-
* `
|
|
14634
|
+
* - A target is an INSTANCE of this function cap (epic #440, step 6): the
|
|
14635
|
+
* providers serve their targets as `integration-instances` records, one
|
|
14636
|
+
* record kind per target kind, and the admin lists, adds, edits, switches
|
|
14637
|
+
* and deletes them through that cap. This cap keeps what an instance cannot
|
|
14638
|
+
* say: the kind catalogue (`listTargetKinds`: capabilities, delivery
|
|
14639
|
+
* parameters, brand icon), dispatch (`send`, `testTarget`) and the form
|
|
14640
|
+
* helpers (`discoverTargets`, `probeTargetConfig`).
|
|
14641
|
+
* - `listTargetKinds` / `discoverTargets` return arrays → the generated
|
|
14642
|
+
* cap-mount auto-`concatCollection`-fans them across every registered
|
|
14643
|
+
* provider so one catalog is routable. `send` / `testTarget` /
|
|
14644
|
+
* `probeTargetConfig` route to ONE provider by the `addonId` the generated
|
|
14645
|
+
* collection router extracts from the call input.
|
|
14114
14646
|
* - `Attachment.bytes` is `Uint8Array`. Transport-safe: superjson (the tRPC
|
|
14115
14647
|
* transformer) + UDS MsgPack both round-trip typed arrays — already used by
|
|
14116
14648
|
* `storage` / `storage-provider` / `recording` caps over the same path. No
|
|
@@ -14355,7 +14887,7 @@ var TargetKindCapsSchema = object({
|
|
|
14355
14887
|
* the union is large and not meant for runtime validation here; the exported
|
|
14356
14888
|
* `TargetKind` type re-tightens `configSchema` to `ConfigUISchema`.
|
|
14357
14889
|
*/
|
|
14358
|
-
var ConfigSchemaPassthrough$
|
|
14890
|
+
var ConfigSchemaPassthrough$3 = unknown();
|
|
14359
14891
|
var TargetKindSchema = object({
|
|
14360
14892
|
kind: string(),
|
|
14361
14893
|
label: string(),
|
|
@@ -14392,7 +14924,7 @@ var TargetKindSchema = object({
|
|
|
14392
14924
|
* its raster path, which is the safe default for an unknown image.
|
|
14393
14925
|
*/
|
|
14394
14926
|
iconMediaType: string().optional(),
|
|
14395
|
-
configSchema: ConfigSchemaPassthrough$
|
|
14927
|
+
configSchema: ConfigSchemaPassthrough$3,
|
|
14396
14928
|
/**
|
|
14397
14929
|
* The config keys that decide WHERE this kind's secrets are sent (server,
|
|
14398
14930
|
* base URL, instance, chat, recipient). A save that changes any of them
|
|
@@ -14414,9 +14946,11 @@ var TargetKindSchema = object({
|
|
|
14414
14946
|
caps: TargetKindCapsSchema
|
|
14415
14947
|
});
|
|
14416
14948
|
/**
|
|
14417
|
-
* A
|
|
14418
|
-
*
|
|
14419
|
-
*
|
|
14949
|
+
* A target as a provider's own code sees it (the notification-center bridge, the
|
|
14950
|
+
* send path): the flat record body split into the name, the switch and the
|
|
14951
|
+
* kind's fields. `config` holds secrets; a reader that serves it to a client
|
|
14952
|
+
* REDACTS secret fields (a presence marker only) — never round-trip a stored
|
|
14953
|
+
* secret to the UI.
|
|
14420
14954
|
*/
|
|
14421
14955
|
var TargetSchema = object({
|
|
14422
14956
|
id: string(),
|
|
@@ -14459,13 +14993,13 @@ var ProbeTargetConfigResultSchema = object({
|
|
|
14459
14993
|
stateInstance: string().optional(),
|
|
14460
14994
|
error: string().optional()
|
|
14461
14995
|
});
|
|
14462
|
-
method(object({}), array(TargetKindSchema)), method(object({
|
|
14996
|
+
method(object({}), array(TargetKindSchema)), method(object({
|
|
14463
14997
|
kind: string(),
|
|
14464
14998
|
config: record(string(), unknown()).optional(),
|
|
14465
14999
|
/**
|
|
14466
15000
|
* When editing / duplicating, the blank password field never round-trips
|
|
14467
15001
|
* the stored token. Pass the source target id so the provider can restore
|
|
14468
|
-
* secrets server-side before dialling
|
|
15002
|
+
* secrets server-side before dialling.
|
|
14469
15003
|
*/
|
|
14470
15004
|
targetId: string().optional()
|
|
14471
15005
|
}), array(DiscoveredTargetSchema), { auth: "admin" }), method(object({
|
|
@@ -14488,27 +15022,6 @@ method(object({}), array(TargetKindSchema)), method(object({}), array(TargetSche
|
|
|
14488
15022
|
}), TestResultSchema, {
|
|
14489
15023
|
kind: "mutation",
|
|
14490
15024
|
auth: "admin"
|
|
14491
|
-
}), method(object({
|
|
14492
|
-
target: TargetSchema,
|
|
14493
|
-
/**
|
|
14494
|
-
* Duplicate flow: create a NEW target id while copying secrets from an
|
|
14495
|
-
* existing row. The UI never holds the stored token; blank / redacted
|
|
14496
|
-
* password fields are restored from this source (D634 still applies if
|
|
14497
|
-
* destinations diverge without a re-typed secret).
|
|
14498
|
-
*/
|
|
14499
|
-
cloneSecretsFrom: string().optional()
|
|
14500
|
-
}), TargetSchema, {
|
|
14501
|
-
kind: "mutation",
|
|
14502
|
-
auth: "admin"
|
|
14503
|
-
}), method(object({ targetId: string() }), _void(), {
|
|
14504
|
-
kind: "mutation",
|
|
14505
|
-
auth: "admin"
|
|
14506
|
-
}), method(object({
|
|
14507
|
-
targetId: string(),
|
|
14508
|
-
enabled: boolean()
|
|
14509
|
-
}), _void(), {
|
|
14510
|
-
kind: "mutation",
|
|
14511
|
-
auth: "admin"
|
|
14512
15025
|
});
|
|
14513
15026
|
looseObject({
|
|
14514
15027
|
name: string().min(1),
|
|
@@ -22776,7 +23289,6 @@ var SYSTEM_CAP_VOCABULARY = {
|
|
|
22776
23289
|
"notification-output": system("notification delivery — reached through notifier devices and rules"),
|
|
22777
23290
|
"notification-rules": system("notification rules — authored on their own page"),
|
|
22778
23291
|
"oauth-integration": system(IDENTITY),
|
|
22779
|
-
"oidc-connections": system(IDENTITY),
|
|
22780
23292
|
"osd-manager": system(PIPELINE),
|
|
22781
23293
|
"pipeline-executor": system(PIPELINE),
|
|
22782
23294
|
"pipeline-orchestrator": system(PIPELINE),
|
|
@@ -42797,6 +43309,7 @@ var ExpressionBindingSourceSchema = union([
|
|
|
42797
43309
|
object({
|
|
42798
43310
|
kind: literal("global"),
|
|
42799
43311
|
sourceStableId: string(),
|
|
43312
|
+
addonId: string().optional(),
|
|
42800
43313
|
cap: string(),
|
|
42801
43314
|
fieldPath: string()
|
|
42802
43315
|
})
|
|
@@ -42863,385 +43376,6 @@ var SourceInfoSchema = object({
|
|
|
42863
43376
|
raw: record(string(), unknown()).optional()
|
|
42864
43377
|
});
|
|
42865
43378
|
/**
|
|
42866
|
-
* Frozen unit → spec table. `•` in the doc marks each dimension's canonical
|
|
42867
|
-
* unit (`factor: 1, offset: 0`). °F derives from `°C = (°F − 32) × 5/9` ⇒
|
|
42868
|
-
* `factor = 5/9`, `offset = -160/9` (kept as exact expressions, not rounded
|
|
42869
|
-
* decimals). K derives from `°C = K − 273.15`.
|
|
42870
|
-
*/
|
|
42871
|
-
var UNIT_TABLE = {
|
|
42872
|
-
"°C": {
|
|
42873
|
-
dimension: "temperature",
|
|
42874
|
-
factor: 1,
|
|
42875
|
-
offset: 0
|
|
42876
|
-
},
|
|
42877
|
-
"°F": {
|
|
42878
|
-
dimension: "temperature",
|
|
42879
|
-
factor: 5 / 9,
|
|
42880
|
-
offset: -160 / 9
|
|
42881
|
-
},
|
|
42882
|
-
K: {
|
|
42883
|
-
dimension: "temperature",
|
|
42884
|
-
factor: 1,
|
|
42885
|
-
offset: -273.15
|
|
42886
|
-
},
|
|
42887
|
-
hPa: {
|
|
42888
|
-
dimension: "pressure",
|
|
42889
|
-
factor: 1,
|
|
42890
|
-
offset: 0
|
|
42891
|
-
},
|
|
42892
|
-
kPa: {
|
|
42893
|
-
dimension: "pressure",
|
|
42894
|
-
factor: 10,
|
|
42895
|
-
offset: 0
|
|
42896
|
-
},
|
|
42897
|
-
Pa: {
|
|
42898
|
-
dimension: "pressure",
|
|
42899
|
-
factor: .01,
|
|
42900
|
-
offset: 0
|
|
42901
|
-
},
|
|
42902
|
-
mbar: {
|
|
42903
|
-
dimension: "pressure",
|
|
42904
|
-
factor: 1,
|
|
42905
|
-
offset: 0
|
|
42906
|
-
},
|
|
42907
|
-
bar: {
|
|
42908
|
-
dimension: "pressure",
|
|
42909
|
-
factor: 1e3,
|
|
42910
|
-
offset: 0
|
|
42911
|
-
},
|
|
42912
|
-
inHg: {
|
|
42913
|
-
dimension: "pressure",
|
|
42914
|
-
factor: 33.8639,
|
|
42915
|
-
offset: 0
|
|
42916
|
-
},
|
|
42917
|
-
mmHg: {
|
|
42918
|
-
dimension: "pressure",
|
|
42919
|
-
factor: 1.33322,
|
|
42920
|
-
offset: 0
|
|
42921
|
-
},
|
|
42922
|
-
psi: {
|
|
42923
|
-
dimension: "pressure",
|
|
42924
|
-
factor: 68.9476,
|
|
42925
|
-
offset: 0
|
|
42926
|
-
},
|
|
42927
|
-
"m/s": {
|
|
42928
|
-
dimension: "speed",
|
|
42929
|
-
factor: 1,
|
|
42930
|
-
offset: 0
|
|
42931
|
-
},
|
|
42932
|
-
"km/h": {
|
|
42933
|
-
dimension: "speed",
|
|
42934
|
-
factor: 1 / 3.6,
|
|
42935
|
-
offset: 0
|
|
42936
|
-
},
|
|
42937
|
-
mph: {
|
|
42938
|
-
dimension: "speed",
|
|
42939
|
-
factor: .44704,
|
|
42940
|
-
offset: 0
|
|
42941
|
-
},
|
|
42942
|
-
kn: {
|
|
42943
|
-
dimension: "speed",
|
|
42944
|
-
factor: .514444,
|
|
42945
|
-
offset: 0
|
|
42946
|
-
},
|
|
42947
|
-
"mm/h": {
|
|
42948
|
-
dimension: "precipitation-rate",
|
|
42949
|
-
factor: 1,
|
|
42950
|
-
offset: 0
|
|
42951
|
-
},
|
|
42952
|
-
"in/h": {
|
|
42953
|
-
dimension: "precipitation-rate",
|
|
42954
|
-
factor: 25.4,
|
|
42955
|
-
offset: 0
|
|
42956
|
-
},
|
|
42957
|
-
m: {
|
|
42958
|
-
dimension: "length",
|
|
42959
|
-
factor: 1,
|
|
42960
|
-
offset: 0
|
|
42961
|
-
},
|
|
42962
|
-
mm: {
|
|
42963
|
-
dimension: "length",
|
|
42964
|
-
factor: .001,
|
|
42965
|
-
offset: 0
|
|
42966
|
-
},
|
|
42967
|
-
cm: {
|
|
42968
|
-
dimension: "length",
|
|
42969
|
-
factor: .01,
|
|
42970
|
-
offset: 0
|
|
42971
|
-
},
|
|
42972
|
-
km: {
|
|
42973
|
-
dimension: "length",
|
|
42974
|
-
factor: 1e3,
|
|
42975
|
-
offset: 0
|
|
42976
|
-
},
|
|
42977
|
-
in: {
|
|
42978
|
-
dimension: "length",
|
|
42979
|
-
factor: .0254,
|
|
42980
|
-
offset: 0
|
|
42981
|
-
},
|
|
42982
|
-
ft: {
|
|
42983
|
-
dimension: "length",
|
|
42984
|
-
factor: .3048,
|
|
42985
|
-
offset: 0
|
|
42986
|
-
},
|
|
42987
|
-
mi: {
|
|
42988
|
-
dimension: "length",
|
|
42989
|
-
factor: 1609.344,
|
|
42990
|
-
offset: 0
|
|
42991
|
-
},
|
|
42992
|
-
"m²": {
|
|
42993
|
-
dimension: "area",
|
|
42994
|
-
factor: 1,
|
|
42995
|
-
offset: 0
|
|
42996
|
-
},
|
|
42997
|
-
lx: {
|
|
42998
|
-
dimension: "illuminance",
|
|
42999
|
-
factor: 1,
|
|
43000
|
-
offset: 0
|
|
43001
|
-
},
|
|
43002
|
-
"W/m²": {
|
|
43003
|
-
dimension: "irradiance",
|
|
43004
|
-
factor: 1,
|
|
43005
|
-
offset: 0
|
|
43006
|
-
},
|
|
43007
|
-
W: {
|
|
43008
|
-
dimension: "power",
|
|
43009
|
-
factor: 1,
|
|
43010
|
-
offset: 0
|
|
43011
|
-
},
|
|
43012
|
-
kW: {
|
|
43013
|
-
dimension: "power",
|
|
43014
|
-
factor: 1e3,
|
|
43015
|
-
offset: 0
|
|
43016
|
-
},
|
|
43017
|
-
VA: {
|
|
43018
|
-
dimension: "apparent-power",
|
|
43019
|
-
factor: 1,
|
|
43020
|
-
offset: 0
|
|
43021
|
-
},
|
|
43022
|
-
Wh: {
|
|
43023
|
-
dimension: "energy",
|
|
43024
|
-
factor: 1,
|
|
43025
|
-
offset: 0
|
|
43026
|
-
},
|
|
43027
|
-
kWh: {
|
|
43028
|
-
dimension: "energy",
|
|
43029
|
-
factor: 1e3,
|
|
43030
|
-
offset: 0
|
|
43031
|
-
},
|
|
43032
|
-
MWh: {
|
|
43033
|
-
dimension: "energy",
|
|
43034
|
-
factor: 1e6,
|
|
43035
|
-
offset: 0
|
|
43036
|
-
},
|
|
43037
|
-
V: {
|
|
43038
|
-
dimension: "voltage",
|
|
43039
|
-
factor: 1,
|
|
43040
|
-
offset: 0
|
|
43041
|
-
},
|
|
43042
|
-
mV: {
|
|
43043
|
-
dimension: "voltage",
|
|
43044
|
-
factor: .001,
|
|
43045
|
-
offset: 0
|
|
43046
|
-
},
|
|
43047
|
-
A: {
|
|
43048
|
-
dimension: "current",
|
|
43049
|
-
factor: 1,
|
|
43050
|
-
offset: 0
|
|
43051
|
-
},
|
|
43052
|
-
mA: {
|
|
43053
|
-
dimension: "current",
|
|
43054
|
-
factor: .001,
|
|
43055
|
-
offset: 0
|
|
43056
|
-
},
|
|
43057
|
-
ppm: {
|
|
43058
|
-
dimension: "concentration-volume",
|
|
43059
|
-
factor: 1,
|
|
43060
|
-
offset: 0
|
|
43061
|
-
},
|
|
43062
|
-
ppb: {
|
|
43063
|
-
dimension: "concentration-volume",
|
|
43064
|
-
factor: .001,
|
|
43065
|
-
offset: 0
|
|
43066
|
-
},
|
|
43067
|
-
"µg/m³": {
|
|
43068
|
-
dimension: "concentration-mass",
|
|
43069
|
-
factor: 1,
|
|
43070
|
-
offset: 0
|
|
43071
|
-
},
|
|
43072
|
-
"mg/m³": {
|
|
43073
|
-
dimension: "concentration-mass",
|
|
43074
|
-
factor: 1e3,
|
|
43075
|
-
offset: 0
|
|
43076
|
-
},
|
|
43077
|
-
kg: {
|
|
43078
|
-
dimension: "mass",
|
|
43079
|
-
factor: 1,
|
|
43080
|
-
offset: 0
|
|
43081
|
-
},
|
|
43082
|
-
g: {
|
|
43083
|
-
dimension: "mass",
|
|
43084
|
-
factor: .001,
|
|
43085
|
-
offset: 0
|
|
43086
|
-
},
|
|
43087
|
-
lb: {
|
|
43088
|
-
dimension: "mass",
|
|
43089
|
-
factor: .453592,
|
|
43090
|
-
offset: 0
|
|
43091
|
-
},
|
|
43092
|
-
oz: {
|
|
43093
|
-
dimension: "mass",
|
|
43094
|
-
factor: .0283495,
|
|
43095
|
-
offset: 0
|
|
43096
|
-
},
|
|
43097
|
-
"%": {
|
|
43098
|
-
dimension: "percentage",
|
|
43099
|
-
factor: 1,
|
|
43100
|
-
offset: 0
|
|
43101
|
-
},
|
|
43102
|
-
L: {
|
|
43103
|
-
dimension: "volume",
|
|
43104
|
-
factor: 1,
|
|
43105
|
-
offset: 0
|
|
43106
|
-
},
|
|
43107
|
-
mL: {
|
|
43108
|
-
dimension: "volume",
|
|
43109
|
-
factor: .001,
|
|
43110
|
-
offset: 0
|
|
43111
|
-
},
|
|
43112
|
-
gal: {
|
|
43113
|
-
dimension: "volume",
|
|
43114
|
-
factor: 3.785411784,
|
|
43115
|
-
offset: 0
|
|
43116
|
-
},
|
|
43117
|
-
s: {
|
|
43118
|
-
dimension: "duration",
|
|
43119
|
-
factor: 1,
|
|
43120
|
-
offset: 0
|
|
43121
|
-
},
|
|
43122
|
-
ms: {
|
|
43123
|
-
dimension: "duration",
|
|
43124
|
-
factor: .001,
|
|
43125
|
-
offset: 0
|
|
43126
|
-
},
|
|
43127
|
-
min: {
|
|
43128
|
-
dimension: "duration",
|
|
43129
|
-
factor: 60,
|
|
43130
|
-
offset: 0
|
|
43131
|
-
},
|
|
43132
|
-
h: {
|
|
43133
|
-
dimension: "duration",
|
|
43134
|
-
factor: 3600,
|
|
43135
|
-
offset: 0
|
|
43136
|
-
},
|
|
43137
|
-
d: {
|
|
43138
|
-
dimension: "duration",
|
|
43139
|
-
factor: 86400,
|
|
43140
|
-
offset: 0
|
|
43141
|
-
},
|
|
43142
|
-
B: {
|
|
43143
|
-
dimension: "information",
|
|
43144
|
-
factor: 1,
|
|
43145
|
-
offset: 0
|
|
43146
|
-
},
|
|
43147
|
-
KiB: {
|
|
43148
|
-
dimension: "information",
|
|
43149
|
-
factor: 1024,
|
|
43150
|
-
offset: 0
|
|
43151
|
-
},
|
|
43152
|
-
MiB: {
|
|
43153
|
-
dimension: "information",
|
|
43154
|
-
factor: 1024 ** 2,
|
|
43155
|
-
offset: 0
|
|
43156
|
-
},
|
|
43157
|
-
GiB: {
|
|
43158
|
-
dimension: "information",
|
|
43159
|
-
factor: 1024 ** 3,
|
|
43160
|
-
offset: 0
|
|
43161
|
-
},
|
|
43162
|
-
TiB: {
|
|
43163
|
-
dimension: "information",
|
|
43164
|
-
factor: 1024 ** 4,
|
|
43165
|
-
offset: 0
|
|
43166
|
-
},
|
|
43167
|
-
kB: {
|
|
43168
|
-
dimension: "information",
|
|
43169
|
-
factor: 1e3,
|
|
43170
|
-
offset: 0
|
|
43171
|
-
},
|
|
43172
|
-
MB: {
|
|
43173
|
-
dimension: "information",
|
|
43174
|
-
factor: 1e6,
|
|
43175
|
-
offset: 0
|
|
43176
|
-
},
|
|
43177
|
-
GB: {
|
|
43178
|
-
dimension: "information",
|
|
43179
|
-
factor: 1e9,
|
|
43180
|
-
offset: 0
|
|
43181
|
-
},
|
|
43182
|
-
"°": {
|
|
43183
|
-
dimension: "angle",
|
|
43184
|
-
factor: 1,
|
|
43185
|
-
offset: 0
|
|
43186
|
-
},
|
|
43187
|
-
dBFS: {
|
|
43188
|
-
dimension: "sound-level",
|
|
43189
|
-
factor: 1,
|
|
43190
|
-
offset: 0
|
|
43191
|
-
},
|
|
43192
|
-
dBm: {
|
|
43193
|
-
dimension: "signal-level",
|
|
43194
|
-
factor: 1,
|
|
43195
|
-
offset: 0
|
|
43196
|
-
},
|
|
43197
|
-
mired: {
|
|
43198
|
-
dimension: "colour-temperature",
|
|
43199
|
-
factor: 1,
|
|
43200
|
-
offset: 0
|
|
43201
|
-
},
|
|
43202
|
-
kbps: {
|
|
43203
|
-
dimension: "bitrate",
|
|
43204
|
-
factor: 1,
|
|
43205
|
-
offset: 0
|
|
43206
|
-
},
|
|
43207
|
-
Mbps: {
|
|
43208
|
-
dimension: "bitrate",
|
|
43209
|
-
factor: 1e3,
|
|
43210
|
-
offset: 0
|
|
43211
|
-
},
|
|
43212
|
-
fps: {
|
|
43213
|
-
dimension: "rate",
|
|
43214
|
-
factor: 1,
|
|
43215
|
-
offset: 0
|
|
43216
|
-
}
|
|
43217
|
-
};
|
|
43218
|
-
/** Resolve a unit's `UnitSpec`, or `undefined` when the spelling is unknown. */
|
|
43219
|
-
function specFor(unit) {
|
|
43220
|
-
return Object.hasOwn(UNIT_TABLE, unit) ? UNIT_TABLE[unit] : void 0;
|
|
43221
|
-
}
|
|
43222
|
-
/** Value in `spec`'s unit → its dimension's canonical unit. */
|
|
43223
|
-
function toCanonical(value, spec) {
|
|
43224
|
-
return value * spec.factor + spec.offset;
|
|
43225
|
-
}
|
|
43226
|
-
/** Canonical-unit value → the unit described by `spec`. */
|
|
43227
|
-
function fromCanonical(canonical, spec) {
|
|
43228
|
-
return (canonical - spec.offset) / spec.factor;
|
|
43229
|
-
}
|
|
43230
|
-
/**
|
|
43231
|
-
* Graceful variant for the render path: returns the converted value, or
|
|
43232
|
-
* `undefined` when the conversion is refused (unknown unit / cross-dimension).
|
|
43233
|
-
* Never throws — a render caller falls back to the raw value + source unit.
|
|
43234
|
-
*/
|
|
43235
|
-
function tryConvertUnit(value, from, to) {
|
|
43236
|
-
if (from === to) return value;
|
|
43237
|
-
const fromSpec = specFor(from);
|
|
43238
|
-
if (!fromSpec) return void 0;
|
|
43239
|
-
const toSpec = specFor(to);
|
|
43240
|
-
if (!toSpec) return void 0;
|
|
43241
|
-
if (fromSpec.dimension !== toSpec.dimension) return void 0;
|
|
43242
|
-
return fromCanonical(toCanonical(value, fromSpec), toSpec);
|
|
43243
|
-
}
|
|
43244
|
-
/**
|
|
43245
43379
|
* A number a person types for a physical quantity — the input side of the
|
|
43246
43380
|
* value + unit contract (D972).
|
|
43247
43381
|
*
|
|
@@ -44937,15 +45071,28 @@ var SettingsSchemaWithValuesSchema = object({
|
|
|
44937
45071
|
});
|
|
44938
45072
|
/** Patch object — keys are field names, values are the new field values. */
|
|
44939
45073
|
var SettingsPatchSchema = record(string(), unknown());
|
|
45074
|
+
/** The scope of a scoped-settings call (D986): where the capability declared the values. */
|
|
45075
|
+
var ScopedSettingsScopeSchema = _enum(SCOPED_SETTINGS_SCOPES);
|
|
45076
|
+
/** One scoped schema an addon serves: its capability, scope and section ids. */
|
|
45077
|
+
var ScopedSettingsDeclarationSchema = object({
|
|
45078
|
+
cap: string(),
|
|
45079
|
+
scope: ScopedSettingsScopeSchema,
|
|
45080
|
+
sectionIds: array(string())
|
|
45081
|
+
});
|
|
44940
45082
|
/** Standard success response for update operations. */
|
|
44941
45083
|
var SettingsUpdateResultSchema = object({ success: literal(true) });
|
|
44942
45084
|
method(object({
|
|
44943
45085
|
addonId: string(),
|
|
44944
|
-
|
|
44945
|
-
|
|
44946
|
-
|
|
45086
|
+
cap: string(),
|
|
45087
|
+
scope: ScopedSettingsScopeSchema,
|
|
45088
|
+
nodeId: string().optional()
|
|
44947
45089
|
}), SettingsSchemaWithValuesSchema.nullable()), method(object({
|
|
44948
45090
|
addonId: string(),
|
|
45091
|
+
nodeId: string().optional()
|
|
45092
|
+
}), array(ScopedSettingsDeclarationSchema).nullable()), method(object({
|
|
45093
|
+
addonId: string(),
|
|
45094
|
+
cap: string(),
|
|
45095
|
+
scope: ScopedSettingsScopeSchema,
|
|
44949
45096
|
nodeId: string().optional(),
|
|
44950
45097
|
patch: SettingsPatchSchema
|
|
44951
45098
|
}), SettingsUpdateResultSchema, {
|
|
@@ -44953,8 +45100,10 @@ method(object({
|
|
|
44953
45100
|
auth: "admin"
|
|
44954
45101
|
}), method(object({
|
|
44955
45102
|
addonId: string(),
|
|
45103
|
+
cap: string(),
|
|
45104
|
+
scope: ScopedSettingsScopeSchema,
|
|
44956
45105
|
nodeId: string().optional()
|
|
44957
|
-
}),
|
|
45106
|
+
}), record(string(), unknown()).nullable()), method(object({
|
|
44958
45107
|
addonId: string(),
|
|
44959
45108
|
nodeId: string().optional(),
|
|
44960
45109
|
instance: IntegrationInstanceRefSchema
|
|
@@ -46294,7 +46443,7 @@ var BackupDestinationInfoSchema = object({
|
|
|
46294
46443
|
id: string(),
|
|
46295
46444
|
/**
|
|
46296
46445
|
* Manifest id of the owning addon. The Settings button on the
|
|
46297
|
-
* destination card opens that addon's
|
|
46446
|
+
* destination card opens that addon's scoped settings panel.
|
|
46298
46447
|
*/
|
|
46299
46448
|
addonId: string(),
|
|
46300
46449
|
/** Operator-toggled enable flag from the destination-policy table. */
|
|
@@ -48903,7 +49052,7 @@ DeviceType.MediaPlayer, method(deviceOnly, _void(), {
|
|
|
48903
49052
|
kind: "mutation",
|
|
48904
49053
|
auth: "protected"
|
|
48905
49054
|
});
|
|
48906
|
-
DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.PetFeeder, DeviceType.Container, DeviceType.Thermostat, DeviceType.EventEmitter, DeviceType.Camera, DeviceType.Hub, DeviceType.Light, DeviceType.Siren, DeviceType.Switch, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Fan, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder, DeviceType.PetFountain, DeviceType.Dishwasher, DeviceType.Washer, DeviceType.Heater, DeviceType.Dryer, DeviceType.Gateway, DeviceType.Camera, DeviceType.Fan, DeviceType.Lock, DeviceType.Camera, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Heater, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Heater, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Heater, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Heater, DeviceType.Gateway, DeviceType.Hub, DeviceType.Camera, DeviceType.Sensor, DeviceType.MediaPlayer, DeviceType.Vacuum, DeviceType.Generic, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.PetFountain, DeviceType.Fan, DeviceType.Humidifier, DeviceType.Climate, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder, DeviceType.Heater;
|
|
49055
|
+
DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.PetFeeder, DeviceType.Container, DeviceType.Thermostat, DeviceType.EventEmitter, DeviceType.Camera, DeviceType.Hub, DeviceType.Light, DeviceType.Siren, DeviceType.Switch, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Fan, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder, DeviceType.PetFountain, DeviceType.Dishwasher, DeviceType.Washer, DeviceType.Heater, DeviceType.Dryer, DeviceType.Gateway, DeviceType.Camera, DeviceType.Fan, DeviceType.Lock, DeviceType.Camera, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Heater, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Heater, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Heater, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Heater, DeviceType.Gateway, DeviceType.Hub, DeviceType.Camera, DeviceType.Sensor, DeviceType.MediaPlayer, DeviceType.Vacuum, DeviceType.Generic, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.PetFountain, DeviceType.Fan, DeviceType.Humidifier, DeviceType.Climate, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder, DeviceType.Heater, DeviceType.MediaPlayer;
|
|
48907
49056
|
var NUMBER = {
|
|
48908
49057
|
kind: "fixed",
|
|
48909
49058
|
result: ["number"]
|
|
@@ -50774,6 +50923,7 @@ method(InstancePinSchema, DeviceExportStatusSchema), method(_void(), array(Expor
|
|
|
50774
50923
|
kind: "mutation",
|
|
50775
50924
|
auth: "admin"
|
|
50776
50925
|
});
|
|
50926
|
+
var DeviceAliasSchema = string().max(64).regex(/^[a-z][a-z0-9_]*$/);
|
|
50777
50927
|
/**
|
|
50778
50928
|
* A SITE ZONE — a named part of the property that several locations belong to.
|
|
50779
50929
|
*
|
|
@@ -51167,6 +51317,12 @@ var DeviceInfoSchema = object({
|
|
|
51167
51317
|
addonId: string(),
|
|
51168
51318
|
type: _enum(DeviceType),
|
|
51169
51319
|
name: string(),
|
|
51320
|
+
/** The name a value template uses for this device (`{{ stufa_veranda.temperature }}`),
|
|
51321
|
+
* entity_id style. Generated once from the name at first registration, unique
|
|
51322
|
+
* cluster-wide, editable through `setAlias`, NOT changed by a rename (D1021).
|
|
51323
|
+
* Optional: a record produced by an older build omits it until the boot
|
|
51324
|
+
* backfill has run. */
|
|
51325
|
+
alias: DeviceAliasSchema.optional(),
|
|
51170
51326
|
/** Operator-organisational location label. `null` when unset. */
|
|
51171
51327
|
location: string().nullable(),
|
|
51172
51328
|
/** Soft-disabled flag. */
|
|
@@ -51486,6 +51642,25 @@ method(object({
|
|
|
51486
51642
|
}), _void(), {
|
|
51487
51643
|
kind: "mutation",
|
|
51488
51644
|
auth: "admin"
|
|
51645
|
+
}), method(object({
|
|
51646
|
+
deviceId: number(),
|
|
51647
|
+
alias: string()
|
|
51648
|
+
}), discriminatedUnion("ok", [object({
|
|
51649
|
+
ok: literal(true),
|
|
51650
|
+
alias: DeviceAliasSchema
|
|
51651
|
+
}), object({
|
|
51652
|
+
ok: literal(false),
|
|
51653
|
+
reason: _enum([
|
|
51654
|
+
"empty",
|
|
51655
|
+
"too-long",
|
|
51656
|
+
"grammar",
|
|
51657
|
+
"reserved",
|
|
51658
|
+
"taken"
|
|
51659
|
+
]),
|
|
51660
|
+
takenBy: number().optional()
|
|
51661
|
+
})]), {
|
|
51662
|
+
kind: "mutation",
|
|
51663
|
+
auth: "admin"
|
|
51489
51664
|
}), method(object({
|
|
51490
51665
|
deviceId: number(),
|
|
51491
51666
|
location: string().nullable()
|
|
@@ -54511,7 +54686,7 @@ method(_void(), array(IntegrationWithStateSchema)), method(object({ id: string()
|
|
|
54511
54686
|
* or the redaction token KEEPS the stored secret; `{ $secretClear: true }`
|
|
54512
54687
|
* clears it.
|
|
54513
54688
|
*/
|
|
54514
|
-
var ConfigSchemaPassthrough$
|
|
54689
|
+
var ConfigSchemaPassthrough$2 = custom();
|
|
54515
54690
|
var IntegrationInstanceIdSchema = string().min(1);
|
|
54516
54691
|
var IntegrationInstanceModeSchema = _enum(["single", "multiple"]);
|
|
54517
54692
|
/**
|
|
@@ -54557,7 +54732,16 @@ var IntegrationInstanceKindSchema = object({
|
|
|
54557
54732
|
/** Relative hub path to start an interactive account link of an instance of this kind. */
|
|
54558
54733
|
connectPath: string().min(1).optional(),
|
|
54559
54734
|
/** Relative hub path to disconnect that account. */
|
|
54560
|
-
disconnectPath: string().min(1).optional()
|
|
54735
|
+
disconnectPath: string().min(1).optional(),
|
|
54736
|
+
/**
|
|
54737
|
+
* Parts of the edit dialog the flat form cannot draw (a node picker, a model source), named by a
|
|
54738
|
+
* GENERIC widget id the client maps to a component; a client that knows none of them shows none.
|
|
54739
|
+
* `connection` widgets write connection values, `model` widgets own the model choice.
|
|
54740
|
+
*/
|
|
54741
|
+
widgets: array(object({
|
|
54742
|
+
id: string().min(1),
|
|
54743
|
+
placement: _enum(["connection", "model"])
|
|
54744
|
+
})).optional()
|
|
54561
54745
|
});
|
|
54562
54746
|
/**
|
|
54563
54747
|
* How devices of an instance are found. `none`: the operator adds them by hand; `lan`: the addon
|
|
@@ -54598,10 +54782,11 @@ var IntegrationInstanceDescriptionSchema = object({
|
|
|
54598
54782
|
/** True when `testInstance` really probes the remote. */
|
|
54599
54783
|
canTest: boolean(),
|
|
54600
54784
|
/**
|
|
54601
|
-
* The kinds an instance can be of
|
|
54602
|
-
* Add flow asks which first and sends it as
|
|
54785
|
+
* The kinds an instance can be of (D1013 rule 1), each naming its `functionCap`. One entry:
|
|
54786
|
+
* nothing to choose; more than one: the Add flow asks which first and sends it as
|
|
54787
|
+
* `createInstance.kind`. Never empty: every instance belongs to exactly one kind.
|
|
54603
54788
|
*/
|
|
54604
|
-
kinds: array(IntegrationInstanceKindSchema).
|
|
54789
|
+
kinds: array(IntegrationInstanceKindSchema).min(1),
|
|
54605
54790
|
/**
|
|
54606
54791
|
* The provider accepts `createInstance.id` for an id that once existed (an adopted id, because
|
|
54607
54792
|
* devices carry it). The UI then offers "restore under its old id" on Add. Absent means no.
|
|
@@ -54637,8 +54822,8 @@ var IntegrationInstanceSchema = object({
|
|
|
54637
54822
|
* the body is the one store, `setInstanceEnabled` the one writer (epic #440, step 3).
|
|
54638
54823
|
*/
|
|
54639
54824
|
enabled: boolean().optional(),
|
|
54640
|
-
/** The kind of this instance
|
|
54641
|
-
kind: string().
|
|
54825
|
+
/** The kind of this instance: exactly one of `describe().kinds[].id` (D1013 rule 2). */
|
|
54826
|
+
kind: string().min(1),
|
|
54642
54827
|
/** Values for the instance form; a secret is a `SecretFieldView`, never text. */
|
|
54643
54828
|
formValues: record(string(), unknown()),
|
|
54644
54829
|
status: IntegrationInstanceStatusSchema.optional(),
|
|
@@ -54662,7 +54847,7 @@ var integrationInstancesCapability = {
|
|
|
54662
54847
|
id: IntegrationInstanceIdSchema.nullable(),
|
|
54663
54848
|
/** The kind of the create form (`id: null`) of a provider with several. */
|
|
54664
54849
|
kind: string().min(1).optional()
|
|
54665
|
-
}), ConfigSchemaPassthrough$
|
|
54850
|
+
}), ConfigSchemaPassthrough$2, { auth: "admin" }),
|
|
54666
54851
|
listInstances: method(_void(), array(IntegrationInstanceSchema).readonly(), { auth: "admin" }),
|
|
54667
54852
|
getInstance: method(object({ id: IntegrationInstanceIdSchema }), IntegrationInstanceSchema.nullable(), { auth: "admin" }),
|
|
54668
54853
|
/**
|
|
@@ -55613,12 +55798,12 @@ var LlmModelInfoSchema = object({
|
|
|
55613
55798
|
});
|
|
55614
55799
|
/**
|
|
55615
55800
|
* The provider-specific part of a profile, validated by the provider that owns
|
|
55616
|
-
* the kind (
|
|
55801
|
+
* the kind (saving an instance refuses what it does not accept). A field its
|
|
55617
55802
|
* `connectionSchema` declares `type: 'password'` is a secret: it is held in the
|
|
55618
55803
|
* keychain, never in the row, and reads back as the redaction marker.
|
|
55619
55804
|
*/
|
|
55620
55805
|
var LlmProviderConfigSchema = record(string(), unknown());
|
|
55621
|
-
|
|
55806
|
+
object({
|
|
55622
55807
|
id: string(),
|
|
55623
55808
|
name: string(),
|
|
55624
55809
|
/** The provider-declared kind (`LlmProfileKindDescriptor.kind`). */
|
|
@@ -55712,8 +55897,8 @@ var LlmProviderWidgetSchema = object({
|
|
|
55712
55897
|
/** ConfigUISchema tree passed through untyped on the wire (the
|
|
55713
55898
|
* notification-output `ConfigSchemaPassthrough` precedent at
|
|
55714
55899
|
* notification-output.cap.ts:151); the exported TS type re-tightens it. */
|
|
55715
|
-
var ConfigSchemaPassthrough$
|
|
55716
|
-
|
|
55900
|
+
var ConfigSchemaPassthrough$1 = unknown();
|
|
55901
|
+
object({
|
|
55717
55902
|
kind: LlmProfileKindSchema,
|
|
55718
55903
|
label: string(),
|
|
55719
55904
|
/** A generic icon name (`cloud`, `plug`, `cpu`) — never a glyph or a logo. */
|
|
@@ -55721,9 +55906,9 @@ var LlmProfileKindDescriptorSchema = object({
|
|
|
55721
55906
|
/** Stamped by each provider so the concat-fanned catalog stays routable. */
|
|
55722
55907
|
addonId: string(),
|
|
55723
55908
|
/** The provider's own fields (`providerConfig`); `password` fields are keychain-held. */
|
|
55724
|
-
connectionSchema: ConfigSchemaPassthrough$
|
|
55909
|
+
connectionSchema: ConfigSchemaPassthrough$1,
|
|
55725
55910
|
/** Provider fields that belong under "Advanced" (extra headers, runtime tuning). */
|
|
55726
|
-
advancedSchema: ConfigSchemaPassthrough$
|
|
55911
|
+
advancedSchema: ConfigSchemaPassthrough$1.optional(),
|
|
55727
55912
|
/** The kind's defaults; a model from `listModels` may override any of them. */
|
|
55728
55913
|
features: LlmModelFeaturesSchema,
|
|
55729
55914
|
/** `false` = the provider stamps `supportsVision` itself (from what a node reports). */
|
|
@@ -55852,20 +56037,7 @@ method(LlmGenerateBaseInputSchema, LlmGenerateResultSchema, {
|
|
|
55852
56037
|
}), method(object({
|
|
55853
56038
|
addonId: string().optional(),
|
|
55854
56039
|
requestId: string()
|
|
55855
|
-
}), _void(), { kind: "mutation" }), method(
|
|
55856
|
-
kind: "mutation",
|
|
55857
|
-
auth: "admin"
|
|
55858
|
-
}), method(RawSecretMigrationInputSchema, RawSecretMigrationReportSchema, {
|
|
55859
|
-
kind: "mutation",
|
|
55860
|
-
auth: "admin"
|
|
55861
|
-
}), method(ProfileRefInputSchema, _void(), {
|
|
55862
|
-
kind: "mutation",
|
|
55863
|
-
auth: "admin"
|
|
55864
|
-
}), method(ProfileRefInputSchema, LlmGenerateResultSchema, {
|
|
55865
|
-
kind: "mutation",
|
|
55866
|
-
auth: "admin",
|
|
55867
|
-
timeoutMs: AI_CAP_TRANSPORT_TIMEOUT_MS
|
|
55868
|
-
}), method(LlmListModelsInputSchema, LlmListModelsResultSchema, {
|
|
56040
|
+
}), _void(), { kind: "mutation" }), method(LlmListModelsInputSchema, LlmListModelsResultSchema, {
|
|
55869
56041
|
kind: "mutation",
|
|
55870
56042
|
auth: "admin"
|
|
55871
56043
|
}), method(object({}), array(LlmDefaultSchema)), method(object({
|
|
@@ -56860,20 +57032,7 @@ method(_void(), MeshStatusSchema), method(object({
|
|
|
56860
57032
|
/** Optional hostname override the host should advertise once joined. */
|
|
56861
57033
|
hostname: string().optional() }), object({
|
|
56862
57034
|
/** Authentication URL the operator should open in a browser. */
|
|
56863
|
-
loginUrl: string() }), { kind: "mutation" }), method(_void(), object({ left: literal(true) }), { kind: "mutation" }), method(_void(), object({ loggedOut: literal(true) }), { kind: "mutation" }), method(_void(), object({ peers: array(MeshPeerSchema).readonly() }))
|
|
56864
|
-
/** Optional auth key — when provided, probes the key validity
|
|
56865
|
-
* against the provider's API. Omit when already joined to
|
|
56866
|
-
* just ping the daemon. */
|
|
56867
|
-
authKey: string().optional() }), object({
|
|
56868
|
-
ok: boolean(),
|
|
56869
|
-
/** Provider-side identifier resolved by the probe (tailnet
|
|
56870
|
-
* name for Tailscale, network id for ZeroTier, etc.). */
|
|
56871
|
-
tenant: string().optional(),
|
|
56872
|
-
/** Daemon binary version, when reachable. */
|
|
56873
|
-
daemonVersion: string().optional(),
|
|
56874
|
-
/** Human-readable error when `ok: false`. */
|
|
56875
|
-
error: string().optional()
|
|
56876
|
-
}), { kind: "mutation" });
|
|
57035
|
+
loginUrl: string() }), { kind: "mutation" }), method(_void(), object({ left: literal(true) }), { kind: "mutation" }), method(_void(), object({ loggedOut: literal(true) }), { kind: "mutation" }), method(_void(), object({ peers: array(MeshPeerSchema).readonly() }));
|
|
56877
57036
|
object({
|
|
56878
57037
|
value: number().nullable().meta(readingMeta("device", { label: "Total" })),
|
|
56879
57038
|
lastFetchedAt: number()
|
|
@@ -64234,6 +64393,11 @@ var NcScheduleSchema = object({
|
|
|
64234
64393
|
* as a STATE SUMMARY at the end of each window of `schedule`.
|
|
64235
64394
|
*/
|
|
64236
64395
|
var NcSystemEventDeliveryModeSchema = _enum(["instant", "summary"]);
|
|
64396
|
+
_enum([
|
|
64397
|
+
"activation",
|
|
64398
|
+
"deactivation",
|
|
64399
|
+
"schedule"
|
|
64400
|
+
]);
|
|
64237
64401
|
/**
|
|
64238
64402
|
* How a summary window is SENT (D698): `rule` (absent) = ONE notification with
|
|
64239
64403
|
* every section; `section` = one notification per section with something to
|
|
@@ -64250,11 +64414,26 @@ var NcStateSummarySplitSchema = _enum(["rule", "section"]);
|
|
|
64250
64414
|
* midnight crossing); the send time is each window's END. Refused on the
|
|
64251
64415
|
* `alarm` family, which stays instant (`systemEventDeliveryProblems`).
|
|
64252
64416
|
*/
|
|
64253
|
-
var NcSystemEventDeliverySchema = discriminatedUnion("mode", [
|
|
64254
|
-
mode: literal("
|
|
64255
|
-
|
|
64256
|
-
|
|
64257
|
-
|
|
64417
|
+
var NcSystemEventDeliverySchema = discriminatedUnion("mode", [
|
|
64418
|
+
object({ mode: literal("instant") }),
|
|
64419
|
+
object({
|
|
64420
|
+
mode: literal("summary"),
|
|
64421
|
+
schedule: NcScheduleSchema,
|
|
64422
|
+
split: NcStateSummarySplitSchema.optional()
|
|
64423
|
+
}),
|
|
64424
|
+
object({
|
|
64425
|
+
mode: literal("modes"),
|
|
64426
|
+
/** The bad edge, and every kind that has a single edge. */
|
|
64427
|
+
onActivation: boolean(),
|
|
64428
|
+
/** The recovery edges of the classes of the selected kinds (derived, never stored per kind). */
|
|
64429
|
+
onDeactivation: boolean(),
|
|
64430
|
+
/** A state summary at the end of each window; absent = no summary. */
|
|
64431
|
+
onSchedule: object({
|
|
64432
|
+
schedule: NcScheduleSchema,
|
|
64433
|
+
grouping: NcStateSummarySplitSchema
|
|
64434
|
+
}).optional()
|
|
64435
|
+
})
|
|
64436
|
+
]);
|
|
64258
64437
|
/** Fuzzy plate matcher — OCR noise makes exact match useless (spec row 12/13). */
|
|
64259
64438
|
var NcPlateMatcherSchema = object({
|
|
64260
64439
|
/**
|
|
@@ -66531,61 +66710,6 @@ var OauthIntegrationDescriptorSchema = object({
|
|
|
66531
66710
|
});
|
|
66532
66711
|
method(_void(), OauthIntegrationDescriptorSchema, { auth: "admin" });
|
|
66533
66712
|
/**
|
|
66534
|
-
* `oidc-connections` — CRUD for IdP rows under `auth-oidc` (D828 sibling).
|
|
66535
|
-
*
|
|
66536
|
-
* One hub-only singleton (`auth-oidc`). The Settings UI is a DataTable +
|
|
66537
|
-
* ItemFormDialog; there is no `editable-array` in `globalSettingsSchema`.
|
|
66538
|
-
* Operator-chosen `id` is the URL slug (`/addon/auth-oidc/<id>/…`) and is
|
|
66539
|
-
* immutable after create.
|
|
66540
|
-
*/
|
|
66541
|
-
var ConfigSchemaPassthrough$1 = unknown();
|
|
66542
|
-
var OidcConnectionSchema = object({
|
|
66543
|
-
id: string().min(1),
|
|
66544
|
-
displayName: string(),
|
|
66545
|
-
icon: string(),
|
|
66546
|
-
issuerUrl: string(),
|
|
66547
|
-
clientId: string(),
|
|
66548
|
-
/** Client id + secret present — never the secret value. */
|
|
66549
|
-
configured: boolean(),
|
|
66550
|
-
/**
|
|
66551
|
-
* Values for the connection form schema. `clientSecret` is a keychain
|
|
66552
|
-
* {@link SecretFieldView} or `null` / `''`, never plaintext (D789).
|
|
66553
|
-
*/
|
|
66554
|
-
formValues: record(string(), unknown()).optional()
|
|
66555
|
-
});
|
|
66556
|
-
/**
|
|
66557
|
-
* Patch one connection. Omitted or empty `clientSecret` keeps the stored
|
|
66558
|
-
* secret (D787). `{ $secretClear: true }` clears it. `id` is never renamed.
|
|
66559
|
-
*/
|
|
66560
|
-
var OidcConnectionUpdateInputSchema = object({
|
|
66561
|
-
id: string().min(1),
|
|
66562
|
-
displayName: string().min(1),
|
|
66563
|
-
icon: string().optional(),
|
|
66564
|
-
issuerUrl: string().optional(),
|
|
66565
|
-
clientId: string().optional(),
|
|
66566
|
-
clientSecret: union([string(), object({ $secretClear: literal(true) })]).optional(),
|
|
66567
|
-
redirectUri: string().optional(),
|
|
66568
|
-
scopes: string().optional(),
|
|
66569
|
-
usernameClaim: _enum([
|
|
66570
|
-
"preferred_username",
|
|
66571
|
-
"email",
|
|
66572
|
-
"sub"
|
|
66573
|
-
]).optional()
|
|
66574
|
-
});
|
|
66575
|
-
method(object({}), ConfigSchemaPassthrough$1, { auth: "admin" }), method(object({}), array(OidcConnectionSchema).readonly(), { auth: "admin" }), method(object({
|
|
66576
|
-
id: string().min(1).regex(/^[a-z0-9][a-z0-9-]{0,63}$/, "id must be a lowercase slug"),
|
|
66577
|
-
displayName: string().min(1)
|
|
66578
|
-
}), object({ id: string() }), {
|
|
66579
|
-
kind: "mutation",
|
|
66580
|
-
auth: "admin"
|
|
66581
|
-
}), method(OidcConnectionUpdateInputSchema, object({ ok: literal(true) }), {
|
|
66582
|
-
kind: "mutation",
|
|
66583
|
-
auth: "admin"
|
|
66584
|
-
}), method(object({ id: string().min(1) }), object({ ok: literal(true) }), {
|
|
66585
|
-
kind: "mutation",
|
|
66586
|
-
auth: "admin"
|
|
66587
|
-
});
|
|
66588
|
-
/**
|
|
66589
66713
|
* Generic on-screen-display (video overlay) cap. Each camera exposes
|
|
66590
66714
|
* a firmware-defined list of overlays (channel name, timestamp,
|
|
66591
66715
|
* watermark, logo, …); the cap models them as a homogeneous array of
|
|
@@ -71636,6 +71760,7 @@ var RemoteLayoutComponentSchema = object({
|
|
|
71636
71760
|
});
|
|
71637
71761
|
});
|
|
71638
71762
|
method(object({}), array(RemoteLayoutComponentSchema), { auth: "protected" });
|
|
71763
|
+
DeviceType.MediaPlayer;
|
|
71639
71764
|
var RunningStateSourceSchema = _enum(["native", "assigned"]);
|
|
71640
71765
|
object({
|
|
71641
71766
|
/** null = unknown — never coerced to false (D393). */
|
|
@@ -72771,21 +72896,6 @@ method(object({
|
|
|
72771
72896
|
*/
|
|
72772
72897
|
ttlSec: union([number().int().positive(), literal("never")]).optional()
|
|
72773
72898
|
}), object({ token: string() }), { auth: "admin" }), method(object({ token: string() }), SsoBridgeClaimsSchema.nullable(), { auth: "admin" });
|
|
72774
|
-
var ProviderListEntrySchema = discriminatedUnion("shouldSaveDiskSpace", [object({
|
|
72775
|
-
providerId: string().min(1),
|
|
72776
|
-
displayName: string().min(1),
|
|
72777
|
-
configSchema: unknown(),
|
|
72778
|
-
nodeLocal: boolean(),
|
|
72779
|
-
shouldSaveDiskSpace: literal(true),
|
|
72780
|
-
minFreePercent: number().min(0).max(100)
|
|
72781
|
-
}), object({
|
|
72782
|
-
providerId: string().min(1),
|
|
72783
|
-
displayName: string().min(1),
|
|
72784
|
-
configSchema: unknown(),
|
|
72785
|
-
nodeLocal: boolean(),
|
|
72786
|
-
shouldSaveDiskSpace: literal(false),
|
|
72787
|
-
minFreePercent: literal(null)
|
|
72788
|
-
})]);
|
|
72789
72899
|
method(object({
|
|
72790
72900
|
location: StorageLocationRefSchema,
|
|
72791
72901
|
relativePath: string()
|
|
@@ -72847,42 +72957,7 @@ method(object({
|
|
|
72847
72957
|
}), _instanceof(Uint8Array), { auth: "admin" }), method(object({ downloadId: string() }), _void(), {
|
|
72848
72958
|
kind: "mutation",
|
|
72849
72959
|
auth: "admin"
|
|
72850
|
-
}), method(object({ type: StorageLocationTypeSchema.optional() }), array(StorageLocationSchema).readonly()), method(_void(), array(StorageLocationDeclarationSchema).readonly()), method(
|
|
72851
|
-
createdAt: true,
|
|
72852
|
-
updatedAt: true
|
|
72853
|
-
}), StorageLocationSchema, {
|
|
72854
|
-
kind: "mutation",
|
|
72855
|
-
auth: "admin"
|
|
72856
|
-
}), method(object({
|
|
72857
|
-
id: string(),
|
|
72858
|
-
force: boolean().optional()
|
|
72859
|
-
}), _void(), {
|
|
72860
|
-
kind: "mutation",
|
|
72861
|
-
auth: "admin"
|
|
72862
|
-
}), method(_void(), array(StorageDrainProgressSchema).readonly()), method(object({ id: string() }), object({
|
|
72863
|
-
ok: boolean(),
|
|
72864
|
-
error: string().optional()
|
|
72865
|
-
}), { auth: "admin" }), method(_void(), array(ProviderListEntrySchema).readonly()), method(object({
|
|
72866
|
-
providerId: string(),
|
|
72867
|
-
/**
|
|
72868
|
-
* The location this config is an UNSAVED edit of, when there is one.
|
|
72869
|
-
*
|
|
72870
|
-
* `listLocations` replaces every declared secret with the redaction
|
|
72871
|
-
* sentinel, so the edit modal's form state holds the sentinel for any
|
|
72872
|
-
* credential the operator did not retype — and posting that here
|
|
72873
|
-
* without a way to resolve it makes the provider try to authenticate
|
|
72874
|
-
* as `__camstack_redacted__` and report the operator's own working
|
|
72875
|
-
* password as wrong. Given this id, the orchestrator restores each
|
|
72876
|
-
* sentinel from the stored config (same rule as `upsertLocation`)
|
|
72877
|
-
* before dispatching. Omitted by the "Add location" wizard, where
|
|
72878
|
-
* every value was typed just now and nothing is stored yet.
|
|
72879
|
-
*/
|
|
72880
|
-
locationId: string().optional(),
|
|
72881
|
-
config: record(string(), unknown())
|
|
72882
|
-
}), object({
|
|
72883
|
-
ok: boolean(),
|
|
72884
|
-
error: string().optional()
|
|
72885
|
-
}), { auth: "admin" });
|
|
72960
|
+
}), method(object({ type: StorageLocationTypeSchema.optional() }), array(StorageLocationSchema).readonly()), method(_void(), array(StorageLocationDeclarationSchema).readonly()), method(_void(), array(StorageDrainProgressSchema).readonly());
|
|
72886
72961
|
/** One table of the settings database. */
|
|
72887
72962
|
var StorageTableSchema = object({
|
|
72888
72963
|
/** The table's full name, e.g. `recorder:addon-settings` or `addon-device-settings`. */
|
|
@@ -74113,7 +74188,7 @@ var TerminalInstanceInfoSchema = object({
|
|
|
74113
74188
|
/**
|
|
74114
74189
|
* False while the node the instance is bound to is not in the cluster
|
|
74115
74190
|
* topology (forgotten, renamed, re-paired). The instance is kept; the
|
|
74116
|
-
* operator re-points it
|
|
74191
|
+
* operator re-points it on the Terminal page.
|
|
74117
74192
|
*/
|
|
74118
74193
|
nodeInCluster: boolean(),
|
|
74119
74194
|
profileId: string(),
|
|
@@ -74151,41 +74226,7 @@ var TerminalOutputBatchSchema = object({
|
|
|
74151
74226
|
snapshot: string().optional(),
|
|
74152
74227
|
events: array(TerminalOutputEventSchema).readonly()
|
|
74153
74228
|
});
|
|
74154
|
-
method(_void(), array(TerminalProfileInfoSchema).readonly(), { auth: "admin" }), method(_void(), array(
|
|
74155
|
-
targetNodeId: string().min(1),
|
|
74156
|
-
profileId: string().min(1),
|
|
74157
|
-
name: string().trim().min(1).max(160).optional(),
|
|
74158
|
-
executable: string().max(1024).optional(),
|
|
74159
|
-
args: array(string().max(2048)).max(64).optional(),
|
|
74160
|
-
cwd: string().max(1024).optional(),
|
|
74161
|
-
environment: array(string().max(4096)).max(64).optional(),
|
|
74162
|
-
profileSettings: ProfileSettingsBagSchema.optional()
|
|
74163
|
-
}), TerminalInstanceInfoSchema, {
|
|
74164
|
-
kind: "mutation",
|
|
74165
|
-
auth: "admin"
|
|
74166
|
-
}), method(object({
|
|
74167
|
-
instanceId: string().min(1),
|
|
74168
|
-
/** Re-point the instance to another node; the profile must exist there. */
|
|
74169
|
-
targetNodeId: string().min(1).max(256).optional(),
|
|
74170
|
-
name: string().trim().min(1).max(160).optional(),
|
|
74171
|
-
executable: string().max(1024).optional(),
|
|
74172
|
-
args: array(string().max(2048)).max(64).optional(),
|
|
74173
|
-
cwd: string().max(1024).optional(),
|
|
74174
|
-
environment: array(string().max(4096)).max(64).optional(),
|
|
74175
|
-
profileSettings: ProfileSettingsBagSchema.optional()
|
|
74176
|
-
}), TerminalInstanceInfoSchema, {
|
|
74177
|
-
kind: "mutation",
|
|
74178
|
-
auth: "admin"
|
|
74179
|
-
}), method(object({ instanceId: string().min(1) }), _void(), {
|
|
74180
|
-
kind: "mutation",
|
|
74181
|
-
auth: "admin"
|
|
74182
|
-
}), method(object({
|
|
74183
|
-
instanceId: string().min(1),
|
|
74184
|
-
enabled: boolean()
|
|
74185
|
-
}), TerminalInstanceInfoSchema, {
|
|
74186
|
-
kind: "mutation",
|
|
74187
|
-
auth: "admin"
|
|
74188
|
-
}), method(_void(), array(TerminalLegacyCameraSchema).readonly(), { auth: "admin" }), method(object({
|
|
74229
|
+
method(_void(), array(TerminalProfileInfoSchema).readonly(), { auth: "admin" }), method(_void(), array(TerminalLegacyCameraSchema).readonly(), { auth: "admin" }), method(object({
|
|
74189
74230
|
stableId: string().min(1),
|
|
74190
74231
|
name: string().trim().min(1).max(160).optional()
|
|
74191
74232
|
}), TerminalInstanceInfoSchema, {
|
|
@@ -74254,6 +74295,11 @@ var TimedRunUnitSchema = _enum(["s", "min"]);
|
|
|
74254
74295
|
_enum(["switch", "pet-fountain"]);
|
|
74255
74296
|
DeviceType.Heater, DeviceType.PetFountain;
|
|
74256
74297
|
DeviceType.Heater, DeviceType.PetFountain;
|
|
74298
|
+
/** One duration, as the one-tap run asks for it. */
|
|
74299
|
+
var TimedRunQuickRunSchema = object({
|
|
74300
|
+
duration: number().positive().finite(),
|
|
74301
|
+
unit: TimedRunUnitSchema
|
|
74302
|
+
});
|
|
74257
74303
|
/** Why a request was not carried out. Typed, so a caller can say it in words. */
|
|
74258
74304
|
var TimedRunRefusalSchema = _enum([
|
|
74259
74305
|
"unsupported-device",
|
|
@@ -74274,9 +74320,30 @@ object({
|
|
|
74274
74320
|
activeUntil: number().nullable(),
|
|
74275
74321
|
/** Who asked for the run (a user id or an addon id); `null` when nothing is armed or it did not say. */
|
|
74276
74322
|
requestedBy: string().nullable(),
|
|
74323
|
+
/**
|
|
74324
|
+
* The one-tap run of THIS device: what a "Run" button on any surface starts. `null` when
|
|
74325
|
+
* the device is gone or its type has no timed run; a status from before this field
|
|
74326
|
+
* existed has none, and a surface falls back to the type's default.
|
|
74327
|
+
*/
|
|
74328
|
+
quickRun: TimedRunQuickRunSchema.nullable(),
|
|
74277
74329
|
lastFetchedAt: number()
|
|
74278
74330
|
});
|
|
74279
|
-
|
|
74331
|
+
/** What the settings form needs: the unit, the bounds and the type's default. */
|
|
74332
|
+
var TimedRunOptionsSchema = object({
|
|
74333
|
+
unit: TimedRunUnitSchema,
|
|
74334
|
+
/** The longest run, in `unit`. */
|
|
74335
|
+
maxDuration: number(),
|
|
74336
|
+
defaultDuration: number()
|
|
74337
|
+
});
|
|
74338
|
+
/** The one-tap run duration, in the type's unit; `null` returns to the type's default. */
|
|
74339
|
+
var TimedRunSettingsPatchSchema = object({ quickRunDuration: number().positive().finite().nullable().optional() });
|
|
74340
|
+
method(object({ deviceId: number().int() }), TimedRunOptionsSchema), method(object({
|
|
74341
|
+
deviceId: number().int(),
|
|
74342
|
+
settings: TimedRunSettingsPatchSchema
|
|
74343
|
+
}), _void(), {
|
|
74344
|
+
kind: "mutation",
|
|
74345
|
+
auth: "admin"
|
|
74346
|
+
}), method(object({
|
|
74280
74347
|
deviceId: number().int(),
|
|
74281
74348
|
duration: number().positive().finite(),
|
|
74282
74349
|
unit: TimedRunUnitSchema
|
|
@@ -76982,21 +77049,28 @@ Object.freeze({
|
|
|
76982
77049
|
access: "view",
|
|
76983
77050
|
role: "admin"
|
|
76984
77051
|
},
|
|
76985
|
-
"addonSettings.
|
|
77052
|
+
"addonSettings.getIntegrationFormSchema": {
|
|
77053
|
+
capName: "addon-settings",
|
|
77054
|
+
capScope: "system",
|
|
77055
|
+
addonId: null,
|
|
77056
|
+
access: "view",
|
|
77057
|
+
role: "admin"
|
|
77058
|
+
},
|
|
77059
|
+
"addonSettings.getScopedSettings": {
|
|
76986
77060
|
capName: "addon-settings",
|
|
76987
77061
|
capScope: "system",
|
|
76988
77062
|
addonId: null,
|
|
76989
77063
|
access: "view",
|
|
76990
77064
|
role: "admin"
|
|
76991
77065
|
},
|
|
76992
|
-
"addonSettings.
|
|
77066
|
+
"addonSettings.listScopedSettings": {
|
|
76993
77067
|
capName: "addon-settings",
|
|
76994
77068
|
capScope: "system",
|
|
76995
77069
|
addonId: null,
|
|
76996
77070
|
access: "view",
|
|
76997
77071
|
role: "admin"
|
|
76998
77072
|
},
|
|
76999
|
-
"addonSettings.
|
|
77073
|
+
"addonSettings.readScopedValues": {
|
|
77000
77074
|
capName: "addon-settings",
|
|
77001
77075
|
capScope: "system",
|
|
77002
77076
|
addonId: null,
|
|
@@ -77017,7 +77091,7 @@ Object.freeze({
|
|
|
77017
77091
|
access: "create",
|
|
77018
77092
|
role: "admin"
|
|
77019
77093
|
},
|
|
77020
|
-
"addonSettings.
|
|
77094
|
+
"addonSettings.updateScopedSettings": {
|
|
77021
77095
|
capName: "addon-settings",
|
|
77022
77096
|
capScope: "system",
|
|
77023
77097
|
addonId: null,
|
|
@@ -79187,6 +79261,13 @@ Object.freeze({
|
|
|
79187
79261
|
access: "create",
|
|
79188
79262
|
role: "admin"
|
|
79189
79263
|
},
|
|
79264
|
+
"deviceManager.setAlias": {
|
|
79265
|
+
capName: "device-manager",
|
|
79266
|
+
capScope: "system",
|
|
79267
|
+
addonId: null,
|
|
79268
|
+
access: "create",
|
|
79269
|
+
role: "admin"
|
|
79270
|
+
},
|
|
79190
79271
|
"deviceManager.setChildLayout": {
|
|
79191
79272
|
capName: "device-manager",
|
|
79192
79273
|
capScope: "system",
|
|
@@ -80475,13 +80556,6 @@ Object.freeze({
|
|
|
80475
80556
|
access: "delete",
|
|
80476
80557
|
role: "admin"
|
|
80477
80558
|
},
|
|
80478
|
-
"llm.deleteProfile": {
|
|
80479
|
-
capName: "llm",
|
|
80480
|
-
capScope: "system",
|
|
80481
|
-
addonId: null,
|
|
80482
|
-
access: "delete",
|
|
80483
|
-
role: "admin"
|
|
80484
|
-
},
|
|
80485
80559
|
"llm.generate": {
|
|
80486
80560
|
capName: "llm",
|
|
80487
80561
|
capScope: "system",
|
|
@@ -80545,20 +80619,6 @@ Object.freeze({
|
|
|
80545
80619
|
access: "view",
|
|
80546
80620
|
role: "admin"
|
|
80547
80621
|
},
|
|
80548
|
-
"llm.listProfileKinds": {
|
|
80549
|
-
capName: "llm",
|
|
80550
|
-
capScope: "system",
|
|
80551
|
-
addonId: null,
|
|
80552
|
-
access: "view",
|
|
80553
|
-
role: "admin"
|
|
80554
|
-
},
|
|
80555
|
-
"llm.listProfiles": {
|
|
80556
|
-
capName: "llm",
|
|
80557
|
-
capScope: "system",
|
|
80558
|
-
addonId: null,
|
|
80559
|
-
access: "view",
|
|
80560
|
-
role: "admin"
|
|
80561
|
-
},
|
|
80562
80622
|
"llm.listRuntimeNodes": {
|
|
80563
80623
|
capName: "llm",
|
|
80564
80624
|
capScope: "system",
|
|
@@ -80566,13 +80626,6 @@ Object.freeze({
|
|
|
80566
80626
|
access: "view",
|
|
80567
80627
|
role: "admin"
|
|
80568
80628
|
},
|
|
80569
|
-
"llm.migrateRawSecrets": {
|
|
80570
|
-
capName: "llm",
|
|
80571
|
-
capScope: "system",
|
|
80572
|
-
addonId: null,
|
|
80573
|
-
access: "create",
|
|
80574
|
-
role: "admin"
|
|
80575
|
-
},
|
|
80576
80629
|
"llm.resolveModelRef": {
|
|
80577
80630
|
capName: "llm",
|
|
80578
80631
|
capScope: "system",
|
|
@@ -80601,20 +80654,6 @@ Object.freeze({
|
|
|
80601
80654
|
access: "create",
|
|
80602
80655
|
role: "admin"
|
|
80603
80656
|
},
|
|
80604
|
-
"llm.testProfile": {
|
|
80605
|
-
capName: "llm",
|
|
80606
|
-
capScope: "system",
|
|
80607
|
-
addonId: null,
|
|
80608
|
-
access: "create",
|
|
80609
|
-
role: "admin"
|
|
80610
|
-
},
|
|
80611
|
-
"llm.upsertProfile": {
|
|
80612
|
-
capName: "llm",
|
|
80613
|
-
capScope: "system",
|
|
80614
|
-
addonId: null,
|
|
80615
|
-
access: "create",
|
|
80616
|
-
role: "admin"
|
|
80617
|
-
},
|
|
80618
80657
|
"llmRuntime.appleAvailability": {
|
|
80619
80658
|
capName: "llm-runtime",
|
|
80620
80659
|
capScope: "system",
|
|
@@ -81119,13 +81158,6 @@ Object.freeze({
|
|
|
81119
81158
|
access: "create",
|
|
81120
81159
|
role: "admin"
|
|
81121
81160
|
},
|
|
81122
|
-
"meshNetwork.testConnection": {
|
|
81123
|
-
capName: "mesh-network",
|
|
81124
|
-
capScope: "system",
|
|
81125
|
-
addonId: null,
|
|
81126
|
-
access: "create",
|
|
81127
|
-
role: "admin"
|
|
81128
|
-
},
|
|
81129
81161
|
"meter.getStatus": {
|
|
81130
81162
|
capName: "meter",
|
|
81131
81163
|
capScope: "device",
|
|
@@ -81784,13 +81816,6 @@ Object.freeze({
|
|
|
81784
81816
|
access: "create",
|
|
81785
81817
|
role: "admin"
|
|
81786
81818
|
},
|
|
81787
|
-
"notificationOutput.deleteTarget": {
|
|
81788
|
-
capName: "notification-output",
|
|
81789
|
-
capScope: "system",
|
|
81790
|
-
addonId: null,
|
|
81791
|
-
access: "delete",
|
|
81792
|
-
role: "admin"
|
|
81793
|
-
},
|
|
81794
81819
|
"notificationOutput.discoverTargets": {
|
|
81795
81820
|
capName: "notification-output",
|
|
81796
81821
|
capScope: "system",
|
|
@@ -81798,13 +81823,6 @@ Object.freeze({
|
|
|
81798
81823
|
access: "view",
|
|
81799
81824
|
role: "admin"
|
|
81800
81825
|
},
|
|
81801
|
-
"notificationOutput.getTarget": {
|
|
81802
|
-
capName: "notification-output",
|
|
81803
|
-
capScope: "system",
|
|
81804
|
-
addonId: null,
|
|
81805
|
-
access: "view",
|
|
81806
|
-
role: "admin"
|
|
81807
|
-
},
|
|
81808
81826
|
"notificationOutput.listTargetKinds": {
|
|
81809
81827
|
capName: "notification-output",
|
|
81810
81828
|
capScope: "system",
|
|
@@ -81812,13 +81830,6 @@ Object.freeze({
|
|
|
81812
81830
|
access: "view",
|
|
81813
81831
|
role: "admin"
|
|
81814
81832
|
},
|
|
81815
|
-
"notificationOutput.listTargets": {
|
|
81816
|
-
capName: "notification-output",
|
|
81817
|
-
capScope: "system",
|
|
81818
|
-
addonId: null,
|
|
81819
|
-
access: "view",
|
|
81820
|
-
role: "admin"
|
|
81821
|
-
},
|
|
81822
81833
|
"notificationOutput.probeTargetConfig": {
|
|
81823
81834
|
capName: "notification-output",
|
|
81824
81835
|
capScope: "system",
|
|
@@ -81833,13 +81844,6 @@ Object.freeze({
|
|
|
81833
81844
|
access: "create",
|
|
81834
81845
|
role: "admin"
|
|
81835
81846
|
},
|
|
81836
|
-
"notificationOutput.setTargetEnabled": {
|
|
81837
|
-
capName: "notification-output",
|
|
81838
|
-
capScope: "system",
|
|
81839
|
-
addonId: null,
|
|
81840
|
-
access: "create",
|
|
81841
|
-
role: "admin"
|
|
81842
|
-
},
|
|
81843
81847
|
"notificationOutput.testTarget": {
|
|
81844
81848
|
capName: "notification-output",
|
|
81845
81849
|
capScope: "system",
|
|
@@ -81847,13 +81851,6 @@ Object.freeze({
|
|
|
81847
81851
|
access: "create",
|
|
81848
81852
|
role: "admin"
|
|
81849
81853
|
},
|
|
81850
|
-
"notificationOutput.upsertTarget": {
|
|
81851
|
-
capName: "notification-output",
|
|
81852
|
-
capScope: "system",
|
|
81853
|
-
addonId: null,
|
|
81854
|
-
access: "create",
|
|
81855
|
-
role: "admin"
|
|
81856
|
-
},
|
|
81857
81854
|
"notificationRules.activateAlarmProfile": {
|
|
81858
81855
|
capName: "notification-rules",
|
|
81859
81856
|
capScope: "system",
|
|
@@ -82113,41 +82110,6 @@ Object.freeze({
|
|
|
82113
82110
|
access: "view",
|
|
82114
82111
|
role: "admin"
|
|
82115
82112
|
},
|
|
82116
|
-
"oidcConnections.connectionFormSchema": {
|
|
82117
|
-
capName: "oidc-connections",
|
|
82118
|
-
capScope: "system",
|
|
82119
|
-
addonId: null,
|
|
82120
|
-
access: "view",
|
|
82121
|
-
role: "admin"
|
|
82122
|
-
},
|
|
82123
|
-
"oidcConnections.createConnection": {
|
|
82124
|
-
capName: "oidc-connections",
|
|
82125
|
-
capScope: "system",
|
|
82126
|
-
addonId: null,
|
|
82127
|
-
access: "create",
|
|
82128
|
-
role: "admin"
|
|
82129
|
-
},
|
|
82130
|
-
"oidcConnections.deleteConnection": {
|
|
82131
|
-
capName: "oidc-connections",
|
|
82132
|
-
capScope: "system",
|
|
82133
|
-
addonId: null,
|
|
82134
|
-
access: "delete",
|
|
82135
|
-
role: "admin"
|
|
82136
|
-
},
|
|
82137
|
-
"oidcConnections.listConnections": {
|
|
82138
|
-
capName: "oidc-connections",
|
|
82139
|
-
capScope: "system",
|
|
82140
|
-
addonId: null,
|
|
82141
|
-
access: "view",
|
|
82142
|
-
role: "admin"
|
|
82143
|
-
},
|
|
82144
|
-
"oidcConnections.updateConnection": {
|
|
82145
|
-
capName: "oidc-connections",
|
|
82146
|
-
capScope: "system",
|
|
82147
|
-
addonId: null,
|
|
82148
|
-
access: "create",
|
|
82149
|
-
role: "admin"
|
|
82150
|
-
},
|
|
82151
82113
|
"osd.getStatus": {
|
|
82152
82114
|
capName: "osd",
|
|
82153
82115
|
capScope: "device",
|
|
@@ -85179,13 +85141,6 @@ Object.freeze({
|
|
|
85179
85141
|
access: "delete",
|
|
85180
85142
|
role: "admin"
|
|
85181
85143
|
},
|
|
85182
|
-
"storage.deleteLocation": {
|
|
85183
|
-
capName: "storage",
|
|
85184
|
-
capScope: "system",
|
|
85185
|
-
addonId: null,
|
|
85186
|
-
access: "delete",
|
|
85187
|
-
role: "admin"
|
|
85188
|
-
},
|
|
85189
85144
|
"storage.endDownload": {
|
|
85190
85145
|
capName: "storage",
|
|
85191
85146
|
capScope: "system",
|
|
@@ -85242,13 +85197,6 @@ Object.freeze({
|
|
|
85242
85197
|
access: "view",
|
|
85243
85198
|
role: "admin"
|
|
85244
85199
|
},
|
|
85245
|
-
"storage.listProviders": {
|
|
85246
|
-
capName: "storage",
|
|
85247
|
-
capScope: "system",
|
|
85248
|
-
addonId: null,
|
|
85249
|
-
access: "view",
|
|
85250
|
-
role: "admin"
|
|
85251
|
-
},
|
|
85252
85200
|
"storage.read": {
|
|
85253
85201
|
capName: "storage",
|
|
85254
85202
|
capScope: "system",
|
|
@@ -85270,27 +85218,6 @@ Object.freeze({
|
|
|
85270
85218
|
access: "view",
|
|
85271
85219
|
role: "admin"
|
|
85272
85220
|
},
|
|
85273
|
-
"storage.testConfig": {
|
|
85274
|
-
capName: "storage",
|
|
85275
|
-
capScope: "system",
|
|
85276
|
-
addonId: null,
|
|
85277
|
-
access: "view",
|
|
85278
|
-
role: "admin"
|
|
85279
|
-
},
|
|
85280
|
-
"storage.testLocation": {
|
|
85281
|
-
capName: "storage",
|
|
85282
|
-
capScope: "system",
|
|
85283
|
-
addonId: null,
|
|
85284
|
-
access: "view",
|
|
85285
|
-
role: "admin"
|
|
85286
|
-
},
|
|
85287
|
-
"storage.upsertLocation": {
|
|
85288
|
-
capName: "storage",
|
|
85289
|
-
capScope: "system",
|
|
85290
|
-
addonId: null,
|
|
85291
|
-
access: "create",
|
|
85292
|
-
role: "admin"
|
|
85293
|
-
},
|
|
85294
85221
|
"storage.write": {
|
|
85295
85222
|
capName: "storage",
|
|
85296
85223
|
capScope: "system",
|
|
@@ -86068,27 +85995,6 @@ Object.freeze({
|
|
|
86068
85995
|
access: "create",
|
|
86069
85996
|
role: "admin"
|
|
86070
85997
|
},
|
|
86071
|
-
"terminalSession.createInstance": {
|
|
86072
|
-
capName: "terminal-session",
|
|
86073
|
-
capScope: "system",
|
|
86074
|
-
addonId: null,
|
|
86075
|
-
access: "create",
|
|
86076
|
-
role: "admin"
|
|
86077
|
-
},
|
|
86078
|
-
"terminalSession.deleteInstance": {
|
|
86079
|
-
capName: "terminal-session",
|
|
86080
|
-
capScope: "system",
|
|
86081
|
-
addonId: null,
|
|
86082
|
-
access: "delete",
|
|
86083
|
-
role: "admin"
|
|
86084
|
-
},
|
|
86085
|
-
"terminalSession.listInstances": {
|
|
86086
|
-
capName: "terminal-session",
|
|
86087
|
-
capScope: "system",
|
|
86088
|
-
addonId: null,
|
|
86089
|
-
access: "view",
|
|
86090
|
-
role: "admin"
|
|
86091
|
-
},
|
|
86092
85998
|
"terminalSession.listLegacyCameras": {
|
|
86093
85999
|
capName: "terminal-session",
|
|
86094
86000
|
capScope: "system",
|
|
@@ -86131,20 +86037,6 @@ Object.freeze({
|
|
|
86131
86037
|
access: "create",
|
|
86132
86038
|
role: "admin"
|
|
86133
86039
|
},
|
|
86134
|
-
"terminalSession.setInstanceEnabled": {
|
|
86135
|
-
capName: "terminal-session",
|
|
86136
|
-
capScope: "system",
|
|
86137
|
-
addonId: null,
|
|
86138
|
-
access: "create",
|
|
86139
|
-
role: "admin"
|
|
86140
|
-
},
|
|
86141
|
-
"terminalSession.updateInstance": {
|
|
86142
|
-
capName: "terminal-session",
|
|
86143
|
-
capScope: "system",
|
|
86144
|
-
addonId: null,
|
|
86145
|
-
access: "create",
|
|
86146
|
-
role: "admin"
|
|
86147
|
-
},
|
|
86148
86040
|
"terminalSession.writeInput": {
|
|
86149
86041
|
capName: "terminal-session",
|
|
86150
86042
|
capScope: "system",
|
|
@@ -86159,6 +86051,13 @@ Object.freeze({
|
|
|
86159
86051
|
access: "create",
|
|
86160
86052
|
role: "viewer"
|
|
86161
86053
|
},
|
|
86054
|
+
"timedRun.getOptions": {
|
|
86055
|
+
capName: "timed-run",
|
|
86056
|
+
capScope: "device",
|
|
86057
|
+
addonId: null,
|
|
86058
|
+
access: "view",
|
|
86059
|
+
role: "viewer"
|
|
86060
|
+
},
|
|
86162
86061
|
"timedRun.getStatus": {
|
|
86163
86062
|
capName: "timed-run",
|
|
86164
86063
|
capScope: "device",
|
|
@@ -86173,6 +86072,13 @@ Object.freeze({
|
|
|
86173
86072
|
access: "create",
|
|
86174
86073
|
role: "viewer"
|
|
86175
86074
|
},
|
|
86075
|
+
"timedRun.setSettings": {
|
|
86076
|
+
capName: "timed-run",
|
|
86077
|
+
capScope: "device",
|
|
86078
|
+
addonId: null,
|
|
86079
|
+
access: "create",
|
|
86080
|
+
role: "admin"
|
|
86081
|
+
},
|
|
86176
86082
|
"toast.onToast": {
|
|
86177
86083
|
capName: "toast",
|
|
86178
86084
|
capScope: "system",
|
|
@@ -87103,6 +87009,7 @@ function offered(received) {
|
|
|
87103
87009
|
};
|
|
87104
87010
|
}
|
|
87105
87011
|
offered(HA_AS), withheld(HOMEKIT_REASON), withheld(ALEXA_REASON), withheld(GOOGLE_REASON), withheld(MATTER_REASON);
|
|
87012
|
+
string().min(1).max(4096);
|
|
87106
87013
|
Object.freeze({
|
|
87107
87014
|
"accessories.getStatus": [{
|
|
87108
87015
|
name: "deviceId",
|
|
@@ -87786,6 +87693,11 @@ Object.freeze({
|
|
|
87786
87693
|
form: "single",
|
|
87787
87694
|
optional: false
|
|
87788
87695
|
}],
|
|
87696
|
+
"deviceManager.setAlias": [{
|
|
87697
|
+
name: "deviceId",
|
|
87698
|
+
form: "single",
|
|
87699
|
+
optional: false
|
|
87700
|
+
}],
|
|
87789
87701
|
"deviceManager.setChildLayout": [{
|
|
87790
87702
|
name: "deviceId",
|
|
87791
87703
|
form: "single",
|
|
@@ -89850,6 +89762,11 @@ Object.freeze({
|
|
|
89850
89762
|
form: "single",
|
|
89851
89763
|
optional: false
|
|
89852
89764
|
}],
|
|
89765
|
+
"timedRun.getOptions": [{
|
|
89766
|
+
name: "deviceId",
|
|
89767
|
+
form: "single",
|
|
89768
|
+
optional: false
|
|
89769
|
+
}],
|
|
89853
89770
|
"timedRun.getStatus": [{
|
|
89854
89771
|
name: "deviceId",
|
|
89855
89772
|
form: "single",
|
|
@@ -89860,6 +89777,11 @@ Object.freeze({
|
|
|
89860
89777
|
form: "single",
|
|
89861
89778
|
optional: false
|
|
89862
89779
|
}],
|
|
89780
|
+
"timedRun.setSettings": [{
|
|
89781
|
+
name: "deviceId",
|
|
89782
|
+
form: "single",
|
|
89783
|
+
optional: false
|
|
89784
|
+
}],
|
|
89863
89785
|
"update.getStatus": [{
|
|
89864
89786
|
name: "deviceId",
|
|
89865
89787
|
form: "single",
|
|
@@ -90722,6 +90644,7 @@ var STATE_SUMMARY_VARS = [
|
|
|
90722
90644
|
[...RULE_TEXT],
|
|
90723
90645
|
[...RULE_TEXT],
|
|
90724
90646
|
[...RULE_TEXT],
|
|
90647
|
+
[...RULE_TEXT],
|
|
90725
90648
|
[...RULE_BODY_ONLY],
|
|
90726
90649
|
[...RULE_TEXT],
|
|
90727
90650
|
([...RULE_TEXT], [...DEVICE_EVENTS]),
|
|
@@ -91843,222 +91766,6 @@ var GoogleBrokerRegistry = class {
|
|
|
91843
91766
|
}
|
|
91844
91767
|
};
|
|
91845
91768
|
//#endregion
|
|
91846
|
-
//#region src/google-settings-copy.ts
|
|
91847
|
-
/**
|
|
91848
|
-
* Operator-facing setup copy for Connectivity → Calendars / Email.
|
|
91849
|
-
* Keep Connect as a same-origin relative link so the admin session cookie
|
|
91850
|
-
* rides along (an absolute Public URL from a LAN admin tab drops the cookie).
|
|
91851
|
-
* Root-relative hrefs must survive `sanitizeInfoHtml` in ui-library.
|
|
91852
|
-
*/
|
|
91853
|
-
/** Enable APIs library in Google Cloud Console. */
|
|
91854
|
-
var GOOGLE_CONSOLE_APIS_URL = "https://console.cloud.google.com/apis/library";
|
|
91855
|
-
/** Create / manage OAuth Web clients. */
|
|
91856
|
-
var GOOGLE_CONSOLE_CREDENTIALS_URL = "https://console.cloud.google.com/apis/credentials";
|
|
91857
|
-
function redirectUriDisplay(publicOrigin) {
|
|
91858
|
-
if (publicOrigin === null || publicOrigin.length === 0) return `<public-hub>${OAUTH_CALLBACK_SUFFIX}`;
|
|
91859
|
-
return `${publicOrigin.replace(/\/$/, "")}${OAUTH_CALLBACK_SUFFIX}`;
|
|
91860
|
-
}
|
|
91861
|
-
function consoleLinksHtml$1() {
|
|
91862
|
-
return [
|
|
91863
|
-
`<a href="${GOOGLE_CONSOLE_APIS_URL}">API library</a>`,
|
|
91864
|
-
` · `,
|
|
91865
|
-
`<a href="${GOOGLE_CONSOLE_CREDENTIALS_URL}">Credentials</a>`
|
|
91866
|
-
].join("");
|
|
91867
|
-
}
|
|
91868
|
-
function introHtml(cap, publicOrigin) {
|
|
91869
|
-
const redirect = escapeHtml$1(redirectUriDisplay(publicOrigin));
|
|
91870
|
-
const console = consoleLinksHtml$1();
|
|
91871
|
-
if (cap === "smtp-provider") return [
|
|
91872
|
-
"<ol>",
|
|
91873
|
-
`<li>Open Google Cloud Console (${console}) and enable the <strong>Gmail API</strong> (and Calendar API if you also use Calendars).</li>`,
|
|
91874
|
-
"<li>Under Credentials, create an OAuth client of type <strong>Web application</strong>.</li>",
|
|
91875
|
-
`<li>Add this authorized redirect URI (Network → <strong>Public endpoint</strong>, not Internal): <code>${redirect}</code></li>`,
|
|
91876
|
-
"<li>Paste Client ID and Client secret below, then <strong>Save</strong>.</li>",
|
|
91877
|
-
`<li>Open <a href="${OAUTH_START_PATH}">Connect Google</a> while signed in as admin (same browser tab as this hub).</li>`,
|
|
91878
|
-
"<li>Set From address (connected account or a verified send-as). Turn this integration off with the page <strong>Enable</strong> toggle when you do not want Gmail send — Calendar can stay connected.</li>",
|
|
91879
|
-
"</ol>"
|
|
91880
|
-
].join("");
|
|
91881
|
-
if (cap === "calendar-source") return [
|
|
91882
|
-
"<ol>",
|
|
91883
|
-
`<li>Open Google Cloud Console (${console}) and enable the <strong>Google Calendar API</strong> (and Gmail API if you also use Email).</li>`,
|
|
91884
|
-
"<li>Under Credentials, create an OAuth client of type <strong>Web application</strong>.</li>",
|
|
91885
|
-
`<li>Add this authorized redirect URI (Network → <strong>Public endpoint</strong>, not Internal): <code>${redirect}</code></li>`,
|
|
91886
|
-
"<li>Paste Client ID and Client secret below, then <strong>Save</strong>.</li>",
|
|
91887
|
-
`<li>Open <a href="${OAUTH_START_PATH}">Connect Google</a> while signed in as admin (same browser tab as this hub).</li>`,
|
|
91888
|
-
"<li>Optionally restrict which calendars are exposed with the filter below.</li>",
|
|
91889
|
-
"</ol>"
|
|
91890
|
-
].join("");
|
|
91891
|
-
return [
|
|
91892
|
-
"<ol>",
|
|
91893
|
-
`<li>Open Google Cloud Console (${console}) and enable <strong>Google Calendar API</strong> and <strong>Gmail API</strong>.</li>`,
|
|
91894
|
-
"<li>Create a <strong>Web application</strong> OAuth client under Credentials.</li>",
|
|
91895
|
-
`<li>Register redirect URI: <code>${redirect}</code> (Network → Public endpoint).</li>`,
|
|
91896
|
-
`<li>Paste Client ID / secret, Save, then <a href="${OAUTH_START_PATH}">Connect Google</a>.</li>`,
|
|
91897
|
-
"<li>Calendars and Email share one Google account; use each page’s <strong>Enable</strong> toggle to turn a capability off without revoking OAuth.</li>",
|
|
91898
|
-
"</ol>"
|
|
91899
|
-
].join("");
|
|
91900
|
-
}
|
|
91901
|
-
function connectHtml(cap, publicOrigin) {
|
|
91902
|
-
const redirect = escapeHtml$1(redirectUriDisplay(publicOrigin));
|
|
91903
|
-
if (cap === "smtp-provider") return [
|
|
91904
|
-
`After Save, open <a href="${OAUTH_START_PATH}">Connect Google</a> in this hub (admin session required). `,
|
|
91905
|
-
"Connect requests <code>gmail.send</code> (and Calendar read for the Calendars page). ",
|
|
91906
|
-
`Google must list exactly: <code>${redirect}</code>. `,
|
|
91907
|
-
"If an older Connect predates Gmail send, revoke CamStack in Google Account → Security and Connect again. ",
|
|
91908
|
-
`Console: ${consoleLinksHtml$1()}.`
|
|
91909
|
-
].join("");
|
|
91910
|
-
if (cap === "calendar-source") return [
|
|
91911
|
-
`After Save, open <a href="${OAUTH_START_PATH}">Connect Google</a> in this hub (admin session required). `,
|
|
91912
|
-
"Connect requests <code>calendar.readonly</code> (and Gmail send for the Email page). ",
|
|
91913
|
-
`Google must list exactly: <code>${redirect}</code>. `,
|
|
91914
|
-
`Console: ${consoleLinksHtml$1()}.`
|
|
91915
|
-
].join("");
|
|
91916
|
-
return [
|
|
91917
|
-
`After Save, open <a href="${OAUTH_START_PATH}">Connect Google</a>. `,
|
|
91918
|
-
`Redirect URI registered in Google Cloud must be <code>${redirect}</code>. `,
|
|
91919
|
-
`Console: ${consoleLinksHtml$1()}.`
|
|
91920
|
-
].join("");
|
|
91921
|
-
}
|
|
91922
|
-
function escapeHtml$1(s) {
|
|
91923
|
-
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
91924
|
-
}
|
|
91925
|
-
//#endregion
|
|
91926
|
-
//#region src/google-broker-settings-schema.ts
|
|
91927
|
-
/**
|
|
91928
|
-
* Per-kind broker creation/edit form for kind=`google`.
|
|
91929
|
-
* Account linking (Sign in) is driven by the kind's `connectPath`
|
|
91930
|
-
* on the instances page — not a hard-coded Connect link in this form.
|
|
91931
|
-
*/
|
|
91932
|
-
function consoleLinksHtml() {
|
|
91933
|
-
return [
|
|
91934
|
-
`<a href="${GOOGLE_CONSOLE_APIS_URL}">API library</a>`,
|
|
91935
|
-
` · `,
|
|
91936
|
-
`<a href="${GOOGLE_CONSOLE_CREDENTIALS_URL}">Credentials</a>`
|
|
91937
|
-
].join("");
|
|
91938
|
-
}
|
|
91939
|
-
/** Setup steps shown on Add / Edit — includes Audience / Test users. */
|
|
91940
|
-
function googleBrokerSetupHtml(publicOrigin) {
|
|
91941
|
-
const redirect = escapeHtml(redirectUriDisplay(publicOrigin));
|
|
91942
|
-
return [
|
|
91943
|
-
"<ol>",
|
|
91944
|
-
`<li>Open Google Cloud Console (${consoleLinksHtml()}). Create a <strong>new project</strong> (or pick an existing one) from the project picker at the top.</li>`,
|
|
91945
|
-
"<li>In that project, enable <strong>Google Calendar API</strong> and/or <strong>Gmail API</strong> (API library).</li>",
|
|
91946
|
-
"<li>Open <strong>Google Auth Platform → Audience</strong> (or APIs & Services → OAuth consent screen → <strong>Audience</strong>). User type <strong>External</strong> + publishing status <strong>Testing</strong> is fine for a personal hub. Under <strong>Test users</strong>, add the Google account(s) that will Sign in — otherwise Google returns <code>403: access_denied</code>. (If you only see Branding / Data Access, open the <strong>Audience</strong> tab in the left sidebar of Google Auth Platform.) Publishing / verification is optional for a private hub.</li>",
|
|
91947
|
-
"<li>Under Credentials, create an OAuth client of type <strong>Web application</strong>.</li>",
|
|
91948
|
-
`<li>Add this authorized redirect URI (Network → <strong>Public endpoint</strong>, not Internal): <code>${redirect}</code></li>`,
|
|
91949
|
-
"<li>Paste Client ID and Client secret below. <strong>Test connection</strong> checks those with Google (not the account yet).</li>",
|
|
91950
|
-
"<li>Add the broker — the hub then opens Google sign-in in a popup to link the account (Calendar + Gmail). Use <strong>Sign in</strong> on the row if you skip or cancel.</li>",
|
|
91951
|
-
"</ol>"
|
|
91952
|
-
].join("");
|
|
91953
|
-
}
|
|
91954
|
-
function buildGoogleBrokerSettingsSchema(publicOrigin) {
|
|
91955
|
-
return { sections: [
|
|
91956
|
-
{
|
|
91957
|
-
id: "setup-intro",
|
|
91958
|
-
title: "Setup",
|
|
91959
|
-
titleKey: "google-services:googleBrokerSettings.s_setup-intro.title",
|
|
91960
|
-
description: "Google Cloud Console — register the hub redirect before Add / Sign in.",
|
|
91961
|
-
descriptionKey: "google-services:googleBrokerSettings.s_setup-intro.description",
|
|
91962
|
-
columns: 1,
|
|
91963
|
-
fields: [{
|
|
91964
|
-
type: "info",
|
|
91965
|
-
key: "_setupSteps",
|
|
91966
|
-
label: "Steps",
|
|
91967
|
-
labelKey: "google-services:googleBrokerSettings.s_setup-intro._setupSteps.label",
|
|
91968
|
-
format: "html",
|
|
91969
|
-
content: googleBrokerSetupHtml(publicOrigin)
|
|
91970
|
-
}]
|
|
91971
|
-
},
|
|
91972
|
-
{
|
|
91973
|
-
id: "google-oauth-client",
|
|
91974
|
-
title: "Google OAuth client",
|
|
91975
|
-
titleKey: "google-services:googleBrokerSettings.s_google-oauth-client.title",
|
|
91976
|
-
description: "Web application client from Google Cloud Console. The same Cloud project can be reused across Google brokers.",
|
|
91977
|
-
descriptionKey: "google-services:googleBrokerSettings.s_google-oauth-client.description",
|
|
91978
|
-
columns: 1,
|
|
91979
|
-
fields: [{
|
|
91980
|
-
type: "text",
|
|
91981
|
-
key: "clientId",
|
|
91982
|
-
label: "Client ID",
|
|
91983
|
-
labelKey: "google-services:googleBrokerSettings.s_google-oauth-client.clientId.label"
|
|
91984
|
-
}, {
|
|
91985
|
-
type: "password",
|
|
91986
|
-
key: "clientSecret",
|
|
91987
|
-
label: "Client secret",
|
|
91988
|
-
labelKey: "google-services:googleBrokerSettings.s_google-oauth-client.clientSecret.label",
|
|
91989
|
-
showToggle: true
|
|
91990
|
-
}]
|
|
91991
|
-
},
|
|
91992
|
-
{
|
|
91993
|
-
id: "gmail-send",
|
|
91994
|
-
title: "Gmail send",
|
|
91995
|
-
titleKey: "google-services:googleBrokerSettings.s_gmail-send.title",
|
|
91996
|
-
description: "From must be this connected account or a verified send-as. Disable Email on Connectivity to turn Gmail off without removing the broker.",
|
|
91997
|
-
descriptionKey: "google-services:googleBrokerSettings.s_gmail-send.description",
|
|
91998
|
-
columns: 1,
|
|
91999
|
-
fields: [{
|
|
92000
|
-
type: "text",
|
|
92001
|
-
key: "fromAddress",
|
|
92002
|
-
label: "From address",
|
|
92003
|
-
labelKey: "google-services:googleBrokerSettings.s_gmail-send.fromAddress.label",
|
|
92004
|
-
description: "Defaults to the connected Google account email when empty.",
|
|
92005
|
-
descriptionKey: "google-services:googleBrokerSettings.s_gmail-send.fromAddress.description"
|
|
92006
|
-
}, {
|
|
92007
|
-
type: "text",
|
|
92008
|
-
key: "fromName",
|
|
92009
|
-
label: "From display name (optional)",
|
|
92010
|
-
labelKey: "google-services:googleBrokerSettings.s_gmail-send.fromName.label"
|
|
92011
|
-
}]
|
|
92012
|
-
}
|
|
92013
|
-
] };
|
|
92014
|
-
}
|
|
92015
|
-
/** Connectivity Calendars / Email pages — the calendar import picker is on each broker. */
|
|
92016
|
-
function buildGoogleFeatureSettingsSchema(cap, publicOrigin) {
|
|
92017
|
-
const redirect = escapeHtml(redirectUriDisplay(publicOrigin));
|
|
92018
|
-
if (cap === "calendar-source") return { sections: [{
|
|
92019
|
-
id: "setup-intro",
|
|
92020
|
-
title: "Google brokers",
|
|
92021
|
-
titleKey: "google-services:googleFeatureSettings.s_setup-intro.title",
|
|
92022
|
-
columns: 1,
|
|
92023
|
-
fields: [{
|
|
92024
|
-
type: "info",
|
|
92025
|
-
key: "_setupSteps",
|
|
92026
|
-
label: "Setup",
|
|
92027
|
-
labelKey: "google-services:googleFeatureSettings.s_setup-intro._setupSteps.label",
|
|
92028
|
-
format: "html",
|
|
92029
|
-
content: [
|
|
92030
|
-
"<p>Link a Google account under Connectivity → <strong>Brokers</strong> ",
|
|
92031
|
-
"(Client ID / secret + Sign in), then add a calendar under Connectivity → <strong>Calendars</strong>. ",
|
|
92032
|
-
`OAuth redirect URI: <code>${redirect}</code>.</p>`
|
|
92033
|
-
].join("")
|
|
92034
|
-
}]
|
|
92035
|
-
}] };
|
|
92036
|
-
return { sections: [{
|
|
92037
|
-
id: "setup-intro",
|
|
92038
|
-
title: cap === "smtp-provider" ? "Gmail send uses Google brokers" : "Google brokers",
|
|
92039
|
-
columns: 1,
|
|
92040
|
-
fields: [{
|
|
92041
|
-
type: "info",
|
|
92042
|
-
key: "_setupSteps",
|
|
92043
|
-
label: "Setup",
|
|
92044
|
-
labelKey: "google-services:googleFeatureSettings._setupSteps.label",
|
|
92045
|
-
format: "html",
|
|
92046
|
-
content: cap === "smtp-provider" ? [
|
|
92047
|
-
"<p>Add or edit a <strong>Google</strong> broker under Connectivity → <strong>Brokers</strong> ",
|
|
92048
|
-
"(Client ID / secret + Sign in). From address and send-as live on that broker. ",
|
|
92049
|
-
`OAuth redirect URI: <code>${redirect}</code>.</p>`
|
|
92050
|
-
].join("") : [
|
|
92051
|
-
"<p>Add or edit a <strong>Google</strong> broker under Connectivity → <strong>Brokers</strong> ",
|
|
92052
|
-
"(Client ID / secret + Sign in). ",
|
|
92053
|
-
`OAuth redirect URI: <code>${redirect}</code>.</p>`
|
|
92054
|
-
].join("")
|
|
92055
|
-
}]
|
|
92056
|
-
}] };
|
|
92057
|
-
}
|
|
92058
|
-
function escapeHtml(s) {
|
|
92059
|
-
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
92060
|
-
}
|
|
92061
|
-
//#endregion
|
|
92062
91769
|
//#region src/google-calendar-source.ts
|
|
92063
91770
|
function parseGoogleInstant(value) {
|
|
92064
91771
|
const ms = Date.parse(value);
|
|
@@ -92555,7 +92262,13 @@ function buildGoogleCalendarInstances(records, deps) {
|
|
|
92555
92262
|
role: "services",
|
|
92556
92263
|
instanceMode: "multiple",
|
|
92557
92264
|
kind: GOOGLE_CALENDAR_INSTANCE_KIND,
|
|
92558
|
-
canTest: false
|
|
92265
|
+
canTest: false,
|
|
92266
|
+
kinds: [{
|
|
92267
|
+
id: GOOGLE_CALENDAR_INSTANCE_KIND,
|
|
92268
|
+
label: "Google calendar",
|
|
92269
|
+
functionCap: "calendar-source",
|
|
92270
|
+
role: "services"
|
|
92271
|
+
}]
|
|
92559
92272
|
},
|
|
92560
92273
|
labels: { accountId: {
|
|
92561
92274
|
label: "Google account",
|
|
@@ -92579,6 +92292,179 @@ function buildGoogleCalendarInstances(records, deps) {
|
|
|
92579
92292
|
});
|
|
92580
92293
|
}
|
|
92581
92294
|
//#endregion
|
|
92295
|
+
//#region src/google-settings-copy.ts
|
|
92296
|
+
/**
|
|
92297
|
+
* Operator-facing setup copy for Connectivity → Calendars / Email.
|
|
92298
|
+
* Keep Connect as a same-origin relative link so the admin session cookie
|
|
92299
|
+
* rides along (an absolute Public URL from a LAN admin tab drops the cookie).
|
|
92300
|
+
* Root-relative hrefs must survive `sanitizeInfoHtml` in ui-library.
|
|
92301
|
+
*/
|
|
92302
|
+
/** Enable APIs library in Google Cloud Console. */
|
|
92303
|
+
var GOOGLE_CONSOLE_APIS_URL = "https://console.cloud.google.com/apis/library";
|
|
92304
|
+
/** Create / manage OAuth Web clients. */
|
|
92305
|
+
var GOOGLE_CONSOLE_CREDENTIALS_URL = "https://console.cloud.google.com/apis/credentials";
|
|
92306
|
+
function redirectUriDisplay(publicOrigin) {
|
|
92307
|
+
if (publicOrigin === null || publicOrigin.length === 0) return `<public-hub>${OAUTH_CALLBACK_SUFFIX}`;
|
|
92308
|
+
return `${publicOrigin.replace(/\/$/, "")}${OAUTH_CALLBACK_SUFFIX}`;
|
|
92309
|
+
}
|
|
92310
|
+
function consoleLinksHtml$1() {
|
|
92311
|
+
return [
|
|
92312
|
+
`<a href="${GOOGLE_CONSOLE_APIS_URL}">API library</a>`,
|
|
92313
|
+
` · `,
|
|
92314
|
+
`<a href="${GOOGLE_CONSOLE_CREDENTIALS_URL}">Credentials</a>`
|
|
92315
|
+
].join("");
|
|
92316
|
+
}
|
|
92317
|
+
function introHtml(cap, publicOrigin) {
|
|
92318
|
+
const redirect = escapeHtml$1(redirectUriDisplay(publicOrigin));
|
|
92319
|
+
const console = consoleLinksHtml$1();
|
|
92320
|
+
if (cap === "smtp-provider") return [
|
|
92321
|
+
"<ol>",
|
|
92322
|
+
`<li>Open Google Cloud Console (${console}) and enable the <strong>Gmail API</strong> (and Calendar API if you also use Calendars).</li>`,
|
|
92323
|
+
"<li>Under Credentials, create an OAuth client of type <strong>Web application</strong>.</li>",
|
|
92324
|
+
`<li>Add this authorized redirect URI (Network → <strong>Public endpoint</strong>, not Internal): <code>${redirect}</code></li>`,
|
|
92325
|
+
"<li>Paste Client ID and Client secret below, then <strong>Save</strong>.</li>",
|
|
92326
|
+
`<li>Open <a href="${OAUTH_START_PATH}">Connect Google</a> while signed in as admin (same browser tab as this hub).</li>`,
|
|
92327
|
+
"<li>Set From address (connected account or a verified send-as). Turn this integration off with the page <strong>Enable</strong> toggle when you do not want Gmail send — Calendar can stay connected.</li>",
|
|
92328
|
+
"</ol>"
|
|
92329
|
+
].join("");
|
|
92330
|
+
if (cap === "calendar-source") return [
|
|
92331
|
+
"<ol>",
|
|
92332
|
+
`<li>Open Google Cloud Console (${console}) and enable the <strong>Google Calendar API</strong> (and Gmail API if you also use Email).</li>`,
|
|
92333
|
+
"<li>Under Credentials, create an OAuth client of type <strong>Web application</strong>.</li>",
|
|
92334
|
+
`<li>Add this authorized redirect URI (Network → <strong>Public endpoint</strong>, not Internal): <code>${redirect}</code></li>`,
|
|
92335
|
+
"<li>Paste Client ID and Client secret below, then <strong>Save</strong>.</li>",
|
|
92336
|
+
`<li>Open <a href="${OAUTH_START_PATH}">Connect Google</a> while signed in as admin (same browser tab as this hub).</li>`,
|
|
92337
|
+
"<li>Optionally restrict which calendars are exposed with the filter below.</li>",
|
|
92338
|
+
"</ol>"
|
|
92339
|
+
].join("");
|
|
92340
|
+
return [
|
|
92341
|
+
"<ol>",
|
|
92342
|
+
`<li>Open Google Cloud Console (${console}) and enable <strong>Google Calendar API</strong> and <strong>Gmail API</strong>.</li>`,
|
|
92343
|
+
"<li>Create a <strong>Web application</strong> OAuth client under Credentials.</li>",
|
|
92344
|
+
`<li>Register redirect URI: <code>${redirect}</code> (Network → Public endpoint).</li>`,
|
|
92345
|
+
`<li>Paste Client ID / secret, Save, then <a href="${OAUTH_START_PATH}">Connect Google</a>.</li>`,
|
|
92346
|
+
"<li>Calendars and Email share one Google account; use each page’s <strong>Enable</strong> toggle to turn a capability off without revoking OAuth.</li>",
|
|
92347
|
+
"</ol>"
|
|
92348
|
+
].join("");
|
|
92349
|
+
}
|
|
92350
|
+
function connectHtml(cap, publicOrigin) {
|
|
92351
|
+
const redirect = escapeHtml$1(redirectUriDisplay(publicOrigin));
|
|
92352
|
+
if (cap === "smtp-provider") return [
|
|
92353
|
+
`After Save, open <a href="${OAUTH_START_PATH}">Connect Google</a> in this hub (admin session required). `,
|
|
92354
|
+
"Connect requests <code>gmail.send</code> (and Calendar read for the Calendars page). ",
|
|
92355
|
+
`Google must list exactly: <code>${redirect}</code>. `,
|
|
92356
|
+
"If an older Connect predates Gmail send, revoke CamStack in Google Account → Security and Connect again. ",
|
|
92357
|
+
`Console: ${consoleLinksHtml$1()}.`
|
|
92358
|
+
].join("");
|
|
92359
|
+
if (cap === "calendar-source") return [
|
|
92360
|
+
`After Save, open <a href="${OAUTH_START_PATH}">Connect Google</a> in this hub (admin session required). `,
|
|
92361
|
+
"Connect requests <code>calendar.readonly</code> (and Gmail send for the Email page). ",
|
|
92362
|
+
`Google must list exactly: <code>${redirect}</code>. `,
|
|
92363
|
+
`Console: ${consoleLinksHtml$1()}.`
|
|
92364
|
+
].join("");
|
|
92365
|
+
return [
|
|
92366
|
+
`After Save, open <a href="${OAUTH_START_PATH}">Connect Google</a>. `,
|
|
92367
|
+
`Redirect URI registered in Google Cloud must be <code>${redirect}</code>. `,
|
|
92368
|
+
`Console: ${consoleLinksHtml$1()}.`
|
|
92369
|
+
].join("");
|
|
92370
|
+
}
|
|
92371
|
+
function escapeHtml$1(s) {
|
|
92372
|
+
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
92373
|
+
}
|
|
92374
|
+
//#endregion
|
|
92375
|
+
//#region src/google-broker-settings-schema.ts
|
|
92376
|
+
/**
|
|
92377
|
+
* Per-kind broker creation/edit form for kind=`google`.
|
|
92378
|
+
* Account linking (Sign in) is driven by the kind's `connectPath`
|
|
92379
|
+
* on the instances page — not a hard-coded Connect link in this form.
|
|
92380
|
+
*/
|
|
92381
|
+
function consoleLinksHtml() {
|
|
92382
|
+
return [
|
|
92383
|
+
`<a href="${GOOGLE_CONSOLE_APIS_URL}">API library</a>`,
|
|
92384
|
+
` · `,
|
|
92385
|
+
`<a href="${GOOGLE_CONSOLE_CREDENTIALS_URL}">Credentials</a>`
|
|
92386
|
+
].join("");
|
|
92387
|
+
}
|
|
92388
|
+
/** Setup steps shown on Add / Edit — includes Audience / Test users. */
|
|
92389
|
+
function googleBrokerSetupHtml(publicOrigin) {
|
|
92390
|
+
const redirect = escapeHtml(redirectUriDisplay(publicOrigin));
|
|
92391
|
+
return [
|
|
92392
|
+
"<ol>",
|
|
92393
|
+
`<li>Open Google Cloud Console (${consoleLinksHtml()}). Create a <strong>new project</strong> (or pick an existing one) from the project picker at the top.</li>`,
|
|
92394
|
+
"<li>In that project, enable <strong>Google Calendar API</strong> and/or <strong>Gmail API</strong> (API library).</li>",
|
|
92395
|
+
"<li>Open <strong>Google Auth Platform → Audience</strong> (or APIs & Services → OAuth consent screen → <strong>Audience</strong>). User type <strong>External</strong> + publishing status <strong>Testing</strong> is fine for a personal hub. Under <strong>Test users</strong>, add the Google account(s) that will Sign in — otherwise Google returns <code>403: access_denied</code>. (If you only see Branding / Data Access, open the <strong>Audience</strong> tab in the left sidebar of Google Auth Platform.) Publishing / verification is optional for a private hub.</li>",
|
|
92396
|
+
"<li>Under Credentials, create an OAuth client of type <strong>Web application</strong>.</li>",
|
|
92397
|
+
`<li>Add this authorized redirect URI (Network → <strong>Public endpoint</strong>, not Internal): <code>${redirect}</code></li>`,
|
|
92398
|
+
"<li>Paste Client ID and Client secret below. <strong>Test connection</strong> checks those with Google (not the account yet).</li>",
|
|
92399
|
+
"<li>Add the broker — the hub then opens Google sign-in in a popup to link the account (Calendar + Gmail). Use <strong>Sign in</strong> on the row if you skip or cancel.</li>",
|
|
92400
|
+
"</ol>"
|
|
92401
|
+
].join("");
|
|
92402
|
+
}
|
|
92403
|
+
function buildGoogleBrokerSettingsSchema(publicOrigin) {
|
|
92404
|
+
return { sections: [
|
|
92405
|
+
{
|
|
92406
|
+
id: "setup-intro",
|
|
92407
|
+
title: "Setup",
|
|
92408
|
+
titleKey: "google-services:googleBrokerSettings.s_setup-intro.title",
|
|
92409
|
+
description: "Google Cloud Console — register the hub redirect before Add / Sign in.",
|
|
92410
|
+
descriptionKey: "google-services:googleBrokerSettings.s_setup-intro.description",
|
|
92411
|
+
columns: 1,
|
|
92412
|
+
fields: [{
|
|
92413
|
+
type: "info",
|
|
92414
|
+
key: "_setupSteps",
|
|
92415
|
+
label: "Steps",
|
|
92416
|
+
labelKey: "google-services:googleBrokerSettings.s_setup-intro._setupSteps.label",
|
|
92417
|
+
format: "html",
|
|
92418
|
+
content: googleBrokerSetupHtml(publicOrigin)
|
|
92419
|
+
}]
|
|
92420
|
+
},
|
|
92421
|
+
{
|
|
92422
|
+
id: "google-oauth-client",
|
|
92423
|
+
title: "Google OAuth client",
|
|
92424
|
+
titleKey: "google-services:googleBrokerSettings.s_google-oauth-client.title",
|
|
92425
|
+
description: "Web application client from Google Cloud Console. The same Cloud project can be reused across Google brokers.",
|
|
92426
|
+
descriptionKey: "google-services:googleBrokerSettings.s_google-oauth-client.description",
|
|
92427
|
+
columns: 1,
|
|
92428
|
+
fields: [{
|
|
92429
|
+
type: "text",
|
|
92430
|
+
key: "clientId",
|
|
92431
|
+
label: "Client ID",
|
|
92432
|
+
labelKey: "google-services:googleBrokerSettings.s_google-oauth-client.clientId.label"
|
|
92433
|
+
}, {
|
|
92434
|
+
type: "password",
|
|
92435
|
+
key: "clientSecret",
|
|
92436
|
+
label: "Client secret",
|
|
92437
|
+
labelKey: "google-services:googleBrokerSettings.s_google-oauth-client.clientSecret.label",
|
|
92438
|
+
showToggle: true
|
|
92439
|
+
}]
|
|
92440
|
+
},
|
|
92441
|
+
{
|
|
92442
|
+
id: "gmail-send",
|
|
92443
|
+
title: "Gmail send",
|
|
92444
|
+
titleKey: "google-services:googleBrokerSettings.s_gmail-send.title",
|
|
92445
|
+
description: "From must be this connected account or a verified send-as. Disable Email on Connectivity to turn Gmail off without removing the broker.",
|
|
92446
|
+
descriptionKey: "google-services:googleBrokerSettings.s_gmail-send.description",
|
|
92447
|
+
columns: 1,
|
|
92448
|
+
fields: [{
|
|
92449
|
+
type: "text",
|
|
92450
|
+
key: "fromAddress",
|
|
92451
|
+
label: "From address",
|
|
92452
|
+
labelKey: "google-services:googleBrokerSettings.s_gmail-send.fromAddress.label",
|
|
92453
|
+
description: "Defaults to the connected Google account email when empty.",
|
|
92454
|
+
descriptionKey: "google-services:googleBrokerSettings.s_gmail-send.fromAddress.description"
|
|
92455
|
+
}, {
|
|
92456
|
+
type: "text",
|
|
92457
|
+
key: "fromName",
|
|
92458
|
+
label: "From display name (optional)",
|
|
92459
|
+
labelKey: "google-services:googleBrokerSettings.s_gmail-send.fromName.label"
|
|
92460
|
+
}]
|
|
92461
|
+
}
|
|
92462
|
+
] };
|
|
92463
|
+
}
|
|
92464
|
+
function escapeHtml(s) {
|
|
92465
|
+
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
92466
|
+
}
|
|
92467
|
+
//#endregion
|
|
92582
92468
|
//#region src/google-instances.ts
|
|
92583
92469
|
/**
|
|
92584
92470
|
* The Google accounts as `integration-instances` (planning#408 P3): one instance per broker
|
|
@@ -92615,7 +92501,8 @@ function buildGoogleInstances(records, deps) {
|
|
|
92615
92501
|
instanceMode: "multiple",
|
|
92616
92502
|
kind: "account",
|
|
92617
92503
|
canTest: true,
|
|
92618
|
-
allowRestoreId: true
|
|
92504
|
+
allowRestoreId: true,
|
|
92505
|
+
kinds: [googleAccountKind(deps)]
|
|
92619
92506
|
},
|
|
92620
92507
|
formSchema: () => buildGoogleBrokerSettingsSchema(deps.publicOrigin()),
|
|
92621
92508
|
initialBody: (name) => ({
|
|
@@ -93865,21 +93752,6 @@ var GoogleServicesAddon = class extends BaseAddon {
|
|
|
93865
93752
|
this.publicOrigin = null;
|
|
93866
93753
|
}
|
|
93867
93754
|
}
|
|
93868
|
-
/**
|
|
93869
|
-
* Connectivity Calendars / Email: point at Brokers (no duplicate OAuth fields).
|
|
93870
|
-
* Addon page without cap: same pointer + note.
|
|
93871
|
-
*/
|
|
93872
|
-
globalSettingsSchema(cap) {
|
|
93873
|
-
const scoped = asSettingsCap(cap);
|
|
93874
|
-
return this.schema(buildGoogleFeatureSettingsSchema(scoped, this.publicOrigin));
|
|
93875
|
-
}
|
|
93876
|
-
async getGlobalSettings(overlay, cap, nodeId) {
|
|
93877
|
-
await this.refreshPublicOrigin();
|
|
93878
|
-
return super.getGlobalSettings(overlay, cap, nodeId);
|
|
93879
|
-
}
|
|
93880
93755
|
};
|
|
93881
|
-
function asSettingsCap(cap) {
|
|
93882
|
-
if (cap === "calendar-source" || cap === "smtp-provider") return cap;
|
|
93883
|
-
}
|
|
93884
93756
|
//#endregion
|
|
93885
|
-
export { GOOGLE_OAUTH_SCOPES as C, GoogleServicesAddon, GoogleServicesAddon as default, GOOGLE_GMAIL_SEND_SCOPE as S, OAUTH_START_PATH as T, GoogleBrokerRegistry as _,
|
|
93757
|
+
export { GOOGLE_OAUTH_SCOPES as C, GoogleServicesAddon, GoogleServicesAddon as default, GOOGLE_GMAIL_SEND_SCOPE as S, OAUTH_START_PATH as T, GoogleBrokerRegistry as _, redirectUriDisplay as a, DEFAULT_GOOGLE_CONFIG as b, exchangeCode as c, buildRawMime as d, createGmailSmtpProvider as f, mapGoogleEvent as g, createGoogleCalendarSource as h, introHtml as i, needsRefresh as l, createGoogleCalendarApi as m, GOOGLE_CONSOLE_CREDENTIALS_URL as n, applyTokenResponse as o, selectGmailAccount as p, connectHtml as r, buildAuthorizeUrl as s, GOOGLE_CONSOLE_APIS_URL as t, refreshAccessToken as u, parseStampedCalendarId as v, GoogleServicesConfigSchema as w, GOOGLE_BROKER_KIND as x, stampCalendarId as y };
|