@camstack/system 1.2.70 → 1.2.71
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/addon-runner.js +1 -1
- package/dist/addon-runner.mjs +1 -1
- package/dist/auth/auth-manager.d.ts +13 -29
- package/dist/auth/scope-matcher.d.ts +6 -5
- package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js +1 -1
- package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +1 -1
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +1 -1
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +1 -1
- package/dist/builtins/alerts/alerts.addon.js +1 -1
- package/dist/builtins/alerts/alerts.addon.mjs +1 -1
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +1 -1
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +1 -1
- package/dist/builtins/console-logging/index.js +1 -1
- package/dist/builtins/console-logging/index.mjs +1 -1
- package/dist/builtins/core-blocks/core-blocks.addon.js +1 -1
- package/dist/builtins/core-blocks/core-blocks.addon.mjs +1 -1
- package/dist/builtins/device-manager/device-manager.addon.js +1 -1
- package/dist/builtins/device-manager/device-manager.addon.mjs +1 -1
- package/dist/builtins/doorbell/virtual-doorbell.addon.js +1 -1
- package/dist/builtins/doorbell/virtual-doorbell.addon.mjs +1 -1
- package/dist/builtins/hub-forwarder/index.js +1 -1
- package/dist/builtins/hub-forwarder/index.mjs +1 -1
- package/dist/builtins/liveness-monitor/liveness-monitor.addon.js +1 -1
- package/dist/builtins/liveness-monitor/liveness-monitor.addon.mjs +1 -1
- package/dist/builtins/local-auth/local-auth.addon.js +4756 -4717
- package/dist/builtins/local-auth/local-auth.addon.mjs +4747 -4708
- package/dist/builtins/local-auth/oauth-grants.d.ts +15 -0
- package/dist/builtins/local-network/local-network.addon.js +1 -1
- package/dist/builtins/local-network/local-network.addon.mjs +1 -1
- package/dist/builtins/loki-logging/index.js +1 -1
- package/dist/builtins/loki-logging/index.mjs +1 -1
- package/dist/builtins/native-metrics/native-metrics.addon.js +1 -1
- package/dist/builtins/native-metrics/native-metrics.addon.mjs +1 -1
- package/dist/builtins/platform-probe/index.js +1 -1
- package/dist/builtins/platform-probe/index.mjs +1 -1
- package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +1 -1
- package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +1 -1
- package/dist/builtins/snapshot/index.js +1 -1
- package/dist/builtins/snapshot/index.mjs +1 -1
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +1 -1
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +1 -1
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +1 -1
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +1 -1
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +1 -1
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +1 -1
- package/dist/builtins/system-config/system-config.addon.js +1 -1
- package/dist/builtins/system-config/system-config.addon.mjs +1 -1
- package/dist/builtins/winston-logging/index.js +1 -1
- package/dist/builtins/winston-logging/index.mjs +1 -1
- package/dist/{dist-CnQXXnK1.mjs → dist-Daxx9CB0.mjs} +92 -17
- package/dist/{dist-DCLoJf2T.js → dist-I0WgqQQ-.js} +103 -16
- package/dist/index.d.ts +1 -1
- package/dist/index.js +4 -13
- package/dist/index.mjs +3 -13
- package/dist/kernel/transport/parent-unowned-call.d.ts +27 -0
- package/dist/{manifest-python-deps-DKrHcUZj.mjs → manifest-python-deps-BdWxKNvu.mjs} +2 -0
- package/dist/{manifest-python-deps-DafB-1hp.js → manifest-python-deps-BqIpg0C7.js} +2 -0
- package/package.json +1 -1
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
import { ISsoBridgeProvider, TokenScope } from '@camstack/types';
|
|
2
2
|
import { OauthSessionManager } from './oauth-session-manager.js';
|
|
3
|
+
/**
|
|
4
|
+
* The refresh lifetime for an integration whose descriptor declares none.
|
|
5
|
+
* 30 days — the value every link used before `refreshTokenTtlSec` existed, kept
|
|
6
|
+
* as the default so an integration that says nothing is unchanged.
|
|
7
|
+
*/
|
|
8
|
+
export declare const DEFAULT_REFRESH_TTL_SEC = 2592000;
|
|
9
|
+
/** Seconds, or `'never'` for a refresh token minted with no `exp` claim. */
|
|
10
|
+
export type RefreshTtl = number | 'never';
|
|
3
11
|
interface IssueCodeInput {
|
|
4
12
|
integrationId: string;
|
|
5
13
|
userId: string;
|
|
@@ -8,6 +16,13 @@ interface IssueCodeInput {
|
|
|
8
16
|
redirectUri: string;
|
|
9
17
|
hubUrl: string;
|
|
10
18
|
codeChallenge?: string;
|
|
19
|
+
/**
|
|
20
|
+
* From the integration's `OauthIntegrationDescriptor.refreshTokenTtlSec`.
|
|
21
|
+
* Baked into the CODE so it travels with the link: re-reading the descriptor
|
|
22
|
+
* at refresh time would let an edit retroactively change the lifetime of a
|
|
23
|
+
* grant the operator already consented to.
|
|
24
|
+
*/
|
|
25
|
+
refreshTtlSec?: RefreshTtl;
|
|
11
26
|
}
|
|
12
27
|
/**
|
|
13
28
|
* PKCE S256 check (RFC 7636 §4.6): `BASE64URL(SHA256(verifier)) === challenge`.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
const require_chunk = require("../../chunk-Cek0wNdY.js");
|
|
3
|
-
const require_dist = require("../../dist-
|
|
3
|
+
const require_dist = require("../../dist-I0WgqQQ-.js");
|
|
4
4
|
let node_os = require("node:os");
|
|
5
5
|
node_os = require_chunk.__toESM(node_os);
|
|
6
6
|
//#region src/builtins/local-network/local-network.addon.ts
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Bt as EventCategory, K as localNetworkCapability, mt as BaseAddon } from "../../dist-Daxx9CB0.mjs";
|
|
2
2
|
import * as os from "node:os";
|
|
3
3
|
//#region src/builtins/local-network/local-network.addon.ts
|
|
4
4
|
/**
|
|
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
require("../../chunk-Cek0wNdY.js");
|
|
6
|
-
const require_dist = require("../../dist-
|
|
6
|
+
const require_dist = require("../../dist-I0WgqQQ-.js");
|
|
7
7
|
//#region src/builtins/loki-logging/loki-payload.ts
|
|
8
8
|
/**
|
|
9
9
|
* Loki rejects a label name that is not a valid Prometheus label
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { mt as BaseAddon, q as logDestinationCapability } from "../../dist-Daxx9CB0.mjs";
|
|
2
2
|
//#region src/builtins/loki-logging/loki-payload.ts
|
|
3
3
|
/**
|
|
4
4
|
* Loki rejects a label name that is not a valid Prometheus label
|
|
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
const require_chunk = require("../../chunk-Cek0wNdY.js");
|
|
6
|
-
const require_dist = require("../../dist-
|
|
6
|
+
const require_dist = require("../../dist-I0WgqQQ-.js");
|
|
7
7
|
let node_child_process = require("node:child_process");
|
|
8
8
|
let node_util = require("node:util");
|
|
9
9
|
let node_os = require("node:os");
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Bt as EventCategory, Dt as createEvent, X as metricsProviderCapability, mt as BaseAddon } from "../../dist-Daxx9CB0.mjs";
|
|
2
2
|
import { execFile, execFileSync } from "node:child_process";
|
|
3
3
|
import { promisify } from "node:util";
|
|
4
4
|
import * as os from "node:os";
|
|
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
const require_chunk = require("../../chunk-Cek0wNdY.js");
|
|
6
|
-
const require_dist = require("../../dist-
|
|
6
|
+
const require_dist = require("../../dist-I0WgqQQ-.js");
|
|
7
7
|
let node_child_process = require("node:child_process");
|
|
8
8
|
let node_util = require("node:util");
|
|
9
9
|
let node_os = require("node:os");
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { o as __toESM } from "../../chunk-CNf5ZN-e.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import { Bt as EventCategory, P as enumerateInferenceDevices, et as platformProbeCapability, it as scoreRuntimes, kt as emitReadiness, mt as BaseAddon, pt as errMsg } from "../../dist-Daxx9CB0.mjs";
|
|
3
3
|
import { execFile } from "node:child_process";
|
|
4
4
|
import { promisify } from "node:util";
|
|
5
5
|
import * as os from "node:os";
|
|
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
require("../../chunk-Cek0wNdY.js");
|
|
6
|
-
const require_dist = require("../../dist-
|
|
6
|
+
const require_dist = require("../../dist-I0WgqQQ-.js");
|
|
7
7
|
//#region src/builtins/remote-access-orchestrator/enabled-providers-reconcile.ts
|
|
8
8
|
/**
|
|
9
9
|
* Reconcile the durable `enabledProviders` set against authoritative
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Bt as EventCategory, mt as BaseAddon } from "../../dist-Daxx9CB0.mjs";
|
|
2
2
|
//#region src/builtins/remote-access-orchestrator/enabled-providers-reconcile.ts
|
|
3
3
|
/**
|
|
4
4
|
* Reconcile the durable `enabledProviders` set against authoritative
|
|
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
require("../../chunk-Cek0wNdY.js");
|
|
6
|
-
const require_dist = require("../../dist-
|
|
6
|
+
const require_dist = require("../../dist-I0WgqQQ-.js");
|
|
7
7
|
let zod = require("zod");
|
|
8
8
|
let node_crypto = require("node:crypto");
|
|
9
9
|
let _camstack_types_node = require("@camstack/types/node");
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { C as bareAddonId,
|
|
1
|
+
import { C as bareAddonId, Nt as nodePin, bt as DeviceType, i as BatteryStatusSchema, lt as streamQualityLabel, mt as BaseAddon, ot as snapshotCapability, pt as errMsg, vt as DeviceFeature } from "../../dist-Daxx9CB0.mjs";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import { randomUUID } from "node:crypto";
|
|
4
4
|
import { signExpiringUrl, verifyExpiringUrl } from "@camstack/types/node";
|
|
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
const require_chunk = require("../../chunk-Cek0wNdY.js");
|
|
6
|
-
const require_dist = require("../../dist-
|
|
6
|
+
const require_dist = require("../../dist-I0WgqQQ-.js");
|
|
7
7
|
let node_crypto = require("node:crypto");
|
|
8
8
|
let node_fs_promises = require("node:fs/promises");
|
|
9
9
|
let node_path = require("node:path");
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { R as filesystemBrowseCapability,
|
|
1
|
+
import { R as filesystemBrowseCapability, ct as storageProviderCapability, mt as BaseAddon } from "../../dist-Daxx9CB0.mjs";
|
|
2
2
|
import { randomUUID } from "node:crypto";
|
|
3
3
|
import { mkdir, readdir, realpath, statfs } from "node:fs/promises";
|
|
4
4
|
import * as path$1 from "node:path";
|
|
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
const require_chunk = require("../../chunk-Cek0wNdY.js");
|
|
6
|
-
const require_dist = require("../../dist-
|
|
6
|
+
const require_dist = require("../../dist-I0WgqQQ-.js");
|
|
7
7
|
let node_crypto = require("node:crypto");
|
|
8
8
|
let node_fs = require("node:fs");
|
|
9
9
|
let node_module = require("node:module");
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { C as bareAddonId,
|
|
1
|
+
import { C as bareAddonId, Ft as parseJsonUnknown, O as dataStoreProviderCapability, dt as vectorDimFromBase64, f as RUNTIME_DEFAULTS, ft as vectorStoreCapability, k as decodeVectorBase64, mt as BaseAddon, pt as errMsg, wt as asJsonObject } from "../../dist-Daxx9CB0.mjs";
|
|
2
2
|
import { createRequire } from "node:module";
|
|
3
3
|
import { randomUUID } from "node:crypto";
|
|
4
4
|
import { statSync } from "node:fs";
|
|
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
const require_chunk = require("../../chunk-Cek0wNdY.js");
|
|
6
|
-
const require_dist = require("../../dist-
|
|
6
|
+
const require_dist = require("../../dist-I0WgqQQ-.js");
|
|
7
7
|
let node_fs_promises = require("node:fs/promises");
|
|
8
8
|
node_fs_promises = require_chunk.__toESM(node_fs_promises);
|
|
9
9
|
let node_path = require("node:path");
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Pt as parseJsonObject, at as settingsStoreCapability, h as StorageLocationTypeSchema, mt as BaseAddon, st as storageCapability } from "../../dist-Daxx9CB0.mjs";
|
|
2
2
|
import * as fs from "node:fs/promises";
|
|
3
3
|
import * as path$1 from "node:path";
|
|
4
4
|
import { buildStorageLocationRegistry } from "@camstack/system";
|
|
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
require("../../chunk-Cek0wNdY.js");
|
|
6
|
-
const require_dist = require("../../dist-
|
|
6
|
+
const require_dist = require("../../dist-I0WgqQQ-.js");
|
|
7
7
|
//#region src/builtins/system-config/system-config.addon.ts
|
|
8
8
|
/**
|
|
9
9
|
* Built-in `system-config` addon — Phase 4 of the settings redesign.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { jt as hydrateSchema, mt as BaseAddon, pt as errMsg } from "../../dist-Daxx9CB0.mjs";
|
|
2
2
|
//#region src/builtins/system-config/system-config.addon.ts
|
|
3
3
|
/**
|
|
4
4
|
* Built-in `system-config` addon — Phase 4 of the settings redesign.
|
|
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
const require_chunk = require("../../chunk-Cek0wNdY.js");
|
|
6
|
-
const require_dist = require("../../dist-
|
|
6
|
+
const require_dist = require("../../dist-I0WgqQQ-.js");
|
|
7
7
|
const require_formatter = require("../../formatter-DqAKDlvN.js");
|
|
8
8
|
let node_path = require("node:path");
|
|
9
9
|
node_path = require_chunk.__toESM(node_path);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { mt as BaseAddon, q as logDestinationCapability } from "../../dist-Daxx9CB0.mjs";
|
|
2
2
|
import { t as formatLogLine } from "../../formatter-B7qW8bPJ.mjs";
|
|
3
3
|
import * as path$1 from "node:path";
|
|
4
4
|
import path from "node:path";
|
|
@@ -4148,6 +4148,24 @@ var ConvertResultSchema = z.object({
|
|
|
4148
4148
|
artifacts: z.array(ConvertArtifactSchema).readonly()
|
|
4149
4149
|
});
|
|
4150
4150
|
/**
|
|
4151
|
+
* True if the scope set grants `access` on device-scoped capabilities.
|
|
4152
|
+
* A `category:device` grant covers every device cap (the broad grant).
|
|
4153
|
+
*/
|
|
4154
|
+
function scopesAllowDeviceCap(scopes, access) {
|
|
4155
|
+
return scopes.some((s) => s.type === "category" && s.target === "device" && s.access.includes(access));
|
|
4156
|
+
}
|
|
4157
|
+
/**
|
|
4158
|
+
* True if the scope set names this addon with at least `access`.
|
|
4159
|
+
*
|
|
4160
|
+
* Deliberately NOT satisfied by `category:device`: a grant over per-camera
|
|
4161
|
+
* capabilities says nothing about an addon's own HTTP surface, and conflating
|
|
4162
|
+
* the two is precisely the confusion that let an Alexa token drive Home
|
|
4163
|
+
* Assistant's command route.
|
|
4164
|
+
*/
|
|
4165
|
+
function scopesAllowAddon(scopes, addonId, access) {
|
|
4166
|
+
return scopes.some((s) => s.type === "addon" && s.target === addonId && s.access.includes(access));
|
|
4167
|
+
}
|
|
4168
|
+
/**
|
|
4151
4169
|
* Error types for the safe expression engine. Two distinct classes so callers
|
|
4152
4170
|
* can tell a compile-time (grammar) failure from a runtime (evaluation)
|
|
4153
4171
|
* failure — both are non-fatal to the host: read paths degrade to "skip link".
|
|
@@ -13056,21 +13074,32 @@ var ScopedTokenSchema = z.object({
|
|
|
13056
13074
|
* core, and no per-integration branch anywhere: `/api/oauth2/authorize` and
|
|
13057
13075
|
* `/api/oauth2/integrations` are built from this collection alone.
|
|
13058
13076
|
*
|
|
13059
|
-
* **Scopes
|
|
13060
|
-
*
|
|
13061
|
-
*
|
|
13062
|
-
*
|
|
13063
|
-
*
|
|
13077
|
+
* **Scopes. `requestedScopes` has exactly ONE meaning: what the integration
|
|
13078
|
+
* NEEDS to function.** Not a blast radius, not a conservative
|
|
13079
|
+
* under-declaration, not a description of some other path the addon happens to
|
|
13080
|
+
* have. Derive it from what the client actually calls **with this token** —
|
|
13081
|
+
* every tRPC path against `METHOD_ACCESS_MAP`, plus an `addon:` grant for every
|
|
13082
|
+
* addon HTTP route it posts to — and write the call that justifies each entry
|
|
13083
|
+
* next to it. Two integrations once used this field to mean two different
|
|
13084
|
+
* things; the operator ruled there is one meaning, and any third integration
|
|
13085
|
+
* inherits it (2026-08-09).
|
|
13086
|
+
*
|
|
13087
|
+
* This is not documentation, it is the ENFORCEMENT INPUT. Since
|
|
13088
|
+
* [D103](../../../../docs/decisions/adr-0103.md) the `/addon/:addonId/*` gate
|
|
13089
|
+
* checks an integration token's grant before letting it reach an
|
|
13090
|
+
* `access: 'authenticated'` route, so an **under-declaration is an integration
|
|
13091
|
+
* that stops working** — a missing `addon:` entry means `403 Token scope
|
|
13092
|
+
* mismatch` on every control the client tries to actuate. Widen the descriptor
|
|
13093
|
+
* honestly rather than weakening a check to make a route pass.
|
|
13094
|
+
*
|
|
13095
|
+
* Prefer a narrow `capability:` scope to a `category:` one unless the client
|
|
13096
|
+
* genuinely needs a whole family; a category scope grants every future member
|
|
13064
13097
|
* of that category too. `category:system [create]` has been rejected once and
|
|
13065
13098
|
* should stay rejected: it hands `addons.installPackage` to an integration.
|
|
13066
13099
|
*
|
|
13067
|
-
*
|
|
13068
|
-
*
|
|
13069
|
-
*
|
|
13070
|
-
* the addon does the work, while the Home Assistant component calls tRPC
|
|
13071
|
-
* directly with the token. So `requestedScopes` describes the blast radius of
|
|
13072
|
-
* the GRANT, not the reach of the integration; do not widen one to describe the
|
|
13073
|
-
* other.
|
|
13100
|
+
* Calls the ADDON itself makes over `ctx.api` run as the addon and are not
|
|
13101
|
+
* scope-checked, so they are not what this field describes — but reaching the
|
|
13102
|
+
* addon's route in the first place IS, and that is the entry to declare.
|
|
13074
13103
|
*
|
|
13075
13104
|
* **The boot window.** An addon registers its provider after its runner forks
|
|
13076
13105
|
* and initialises, so between hub start and that moment this collection is
|
|
@@ -13111,7 +13140,30 @@ var OauthIntegrationDescriptorSchema = z.object({
|
|
|
13111
13140
|
* present, /api/oauth2/authorize bakes THIS into the code instead of the
|
|
13112
13141
|
* hub-global `publicHubUrl()`, so a forked exporter addon (which can't set
|
|
13113
13142
|
* the hub's env) drives the claim that its cloud Lambda routes back on. */
|
|
13114
|
-
hubUrl: z.string().optional()
|
|
13143
|
+
hubUrl: z.string().optional(),
|
|
13144
|
+
/**
|
|
13145
|
+
* How long a REFRESH token issued for this integration lives — seconds, or
|
|
13146
|
+
* `'never'` for a token minted with no `exp` claim at all. Omit to keep the
|
|
13147
|
+
* 30-day default, which is what every link used before this field existed.
|
|
13148
|
+
*
|
|
13149
|
+
* Declared here for the same reason `requestedScopes` is: the integration
|
|
13150
|
+
* knows what it needs. Amazon's account linking and a Home Assistant config
|
|
13151
|
+
* entry are both meant to survive indefinitely, and re-linking is a manual
|
|
13152
|
+
* user action, so a 30-day expiry silently unlinks a working integration.
|
|
13153
|
+
*
|
|
13154
|
+
* **The security posture, stated so it is owned deliberately.** A refresh
|
|
13155
|
+
* token that never expires is permanent access if it leaks. What bounds it is
|
|
13156
|
+
* revocation, not time: `oauthRefresh` re-reads the session on every use and
|
|
13157
|
+
* returns `null` once `revokedAt` is set, as does `oauthVerifyAccessToken`.
|
|
13158
|
+
* The one gap is the ACCESS token — it is a plain signed JWT that nothing
|
|
13159
|
+
* re-checks against the session on the `/trpc` and `/addon/*` paths, so
|
|
13160
|
+
* revoking a link takes effect there only after its remaining hour. That hour
|
|
13161
|
+
* is why the access TTL is not configurable.
|
|
13162
|
+
*
|
|
13163
|
+
* The value is baked into the authorization code at `/authorize` and travels
|
|
13164
|
+
* on the tokens, so editing this field changes FUTURE links only.
|
|
13165
|
+
*/
|
|
13166
|
+
refreshTokenTtlSec: z.union([z.number().int().positive(), z.literal("never")]).optional()
|
|
13115
13167
|
});
|
|
13116
13168
|
var oauthIntegrationCapability = {
|
|
13117
13169
|
name: "oauth-integration",
|
|
@@ -17416,7 +17468,16 @@ var SsoBridgeClaimsSchema = z.object({
|
|
|
17416
17468
|
codeChallenge: z.string().optional(),
|
|
17417
17469
|
/** OAuth session registry id — set on `oauth-access`/`oauth-refresh`
|
|
17418
17470
|
* tokens so the verify path can check the session is not revoked. */
|
|
17419
|
-
sessionId: z.string().optional()
|
|
17471
|
+
sessionId: z.string().optional(),
|
|
17472
|
+
/**
|
|
17473
|
+
* The refresh lifetime this LINK was created with, in seconds, or `'never'`.
|
|
17474
|
+
* Baked into the code at `/authorize` from the integration's descriptor and
|
|
17475
|
+
* carried forward so `oauthRefresh` re-mints with the same lifetime. It rides
|
|
17476
|
+
* on the token rather than being re-read from the descriptor on purpose:
|
|
17477
|
+
* editing a descriptor must not retroactively extend or shorten a link the
|
|
17478
|
+
* operator already consented to.
|
|
17479
|
+
*/
|
|
17480
|
+
refreshTtl: z.union([z.number().int().positive(), z.literal("never")]).optional()
|
|
17420
17481
|
});
|
|
17421
17482
|
var ssoBridgeCapability = {
|
|
17422
17483
|
name: "sso-bridge",
|
|
@@ -17426,7 +17487,16 @@ var ssoBridgeCapability = {
|
|
|
17426
17487
|
methods: {
|
|
17427
17488
|
signBridgeToken: method(z.object({
|
|
17428
17489
|
claims: SsoBridgeClaimsSchema,
|
|
17429
|
-
|
|
17490
|
+
/**
|
|
17491
|
+
* Seconds, or `'never'` for a token minted with NO `exp` claim.
|
|
17492
|
+
*
|
|
17493
|
+
* `'never'` is a literal rather than `undefined`/`0` because omitting
|
|
17494
|
+
* this field already means "the 5-minute SSO hand-off default", and
|
|
17495
|
+
* `jwt.sign` THROWS on `{ expiresIn: undefined }` — a "no expiry" that
|
|
17496
|
+
* went through the numeric path would fail at mint time and break
|
|
17497
|
+
* linking rather than produce an eternal token.
|
|
17498
|
+
*/
|
|
17499
|
+
ttlSec: z.union([z.number().int().positive(), z.literal("never")]).optional()
|
|
17430
17500
|
}), z.object({ token: z.string() })),
|
|
17431
17501
|
verifyBridgeToken: method(z.object({ token: z.string() }), SsoBridgeClaimsSchema.nullable())
|
|
17432
17502
|
}
|
|
@@ -26222,7 +26292,12 @@ var userManagementCapability = {
|
|
|
26222
26292
|
hubUrl: z.string(),
|
|
26223
26293
|
/** PKCE (RFC 7636) S256 challenge. Baked into the signed code; a code
|
|
26224
26294
|
* that carries one can ONLY be exchanged with the matching verifier. */
|
|
26225
|
-
codeChallenge: z.string().optional()
|
|
26295
|
+
codeChallenge: z.string().optional(),
|
|
26296
|
+
/** The integration's declared refresh lifetime — seconds, or `'never'`.
|
|
26297
|
+
* From `OauthIntegrationDescriptor.refreshTokenTtlSec`. Baked into the
|
|
26298
|
+
* code so the link carries its own lifetime; omit for the 30-day
|
|
26299
|
+
* default. */
|
|
26300
|
+
refreshTtlSec: z.union([z.number().int().positive(), z.literal("never")]).optional()
|
|
26226
26301
|
}), z.object({ code: z.string() }), {
|
|
26227
26302
|
kind: "mutation",
|
|
26228
26303
|
access: "create"
|
|
@@ -33238,4 +33313,4 @@ function enumerateInferenceDevices(hw) {
|
|
|
33238
33313
|
return out;
|
|
33239
33314
|
}
|
|
33240
33315
|
//#endregion
|
|
33241
|
-
export { parseStreamParamsFormPatch as $, deviceManagerCapability as A,
|
|
33316
|
+
export { parseStreamParamsFormPatch as $, deviceManagerCapability as A, expandCapMethods as At, isCollectionArrayMethod as B, EventCategory as Bt, bareAddonId as C, WELL_KNOWN_TAB_MAP as Ct, coreBlocksCapability as D, createEvent as Dt, coreBlockIdFromAddonId as E, asString as Et, enumerateItemArrayFields as F, parseJsonUnknown as Ft, lifecycleJobSchema as G, isSameAddonId as H, enumerateSchemaFields as I, readinessKey as It, logLevelAtMost as J, localNetworkCapability as K, extractNestedAddonId as L, resolveCapMount as Lt, deviceStatusCapability as M, isDeviceConfigCap as Mt, doorbellCapability as N, nodePin as Nt, dataStoreProviderCapability as O, emitDownForOwnedCaps as Ot, enumerateInferenceDevices as P, parseJsonObject as Pt, objectInputDeclaresAddonId as Q, filesystemBrowseCapability as R, scopeKey as Rt, backupCapability as S, ReadinessTimeoutError as St, coreBlockAddonId as T, asNumber as Tt, isVoidInput as U, isObjectInput as V, kebabToCamel as W, metricsProviderCapability as X, looseSchema as Y, normalizeUnit as Z, addonPagesCapability as _, DEVICE_STATUS_METHOD as _t, CAP_NAMES_WITH_STATUS as a, settingsStoreCapability as at, alertsCapability as b, DeviceType as bt, CoreBlockSchema as c, storageProviderCapability as ct, METHOD_ACCESS_MAP as d, vectorDimFromBase64 as dt, platformProbeCapability as et, RUNTIME_DEFAULTS as f, vectorStoreCapability as ft, UserRecordSchema as g, DEVICE_SETTINGS_CONTRIBUTION_METHODS as gt, StorageLocationTypeSchema as h, DATAPLANE_SECRET_HEADER as ht, BatteryStatusSchema as i, scoreRuntimes as it, deviceStateCapability as j, hydrateSchema as jt, decodeVectorBase64 as k, emitReadiness as kt, DeclaredDevices as l, streamQualityLabel as lt, ScopedTokenSchema as m, BaseAddon as mt, AlertSchema as n, scopesAllowAddon as nt, CORE_BLOCKS_ADDON_ID as o, snapshotCapability as ot, STREAM_PROFILE_META as p, errMsg as pt, logDestinationCapability as q, ApiKeyRecordSchema as r, scopesAllowDeviceCap as rt, CORE_BLOCK_ADDON_PREFIX as s, storageCapability as st, ALL_CAPABILITY_DEFINITIONS as t, procedureAuthKey as tt, DeviceStatusSchema as u, userManagementCapability as ut, addonSettingsCapability as v, DeviceFeature as vt, buildStreamParamsConfigSchema as w, asJsonObject as wt, authProviderCapability as x, ReadinessRegistry as xt, addonWidgetsCapability as y, DeviceRole as yt, isArrayOutputSchema as z, sleep as zt };
|
|
@@ -4148,6 +4148,24 @@ var ConvertResultSchema = zod.z.object({
|
|
|
4148
4148
|
artifacts: zod.z.array(ConvertArtifactSchema).readonly()
|
|
4149
4149
|
});
|
|
4150
4150
|
/**
|
|
4151
|
+
* True if the scope set grants `access` on device-scoped capabilities.
|
|
4152
|
+
* A `category:device` grant covers every device cap (the broad grant).
|
|
4153
|
+
*/
|
|
4154
|
+
function scopesAllowDeviceCap(scopes, access) {
|
|
4155
|
+
return scopes.some((s) => s.type === "category" && s.target === "device" && s.access.includes(access));
|
|
4156
|
+
}
|
|
4157
|
+
/**
|
|
4158
|
+
* True if the scope set names this addon with at least `access`.
|
|
4159
|
+
*
|
|
4160
|
+
* Deliberately NOT satisfied by `category:device`: a grant over per-camera
|
|
4161
|
+
* capabilities says nothing about an addon's own HTTP surface, and conflating
|
|
4162
|
+
* the two is precisely the confusion that let an Alexa token drive Home
|
|
4163
|
+
* Assistant's command route.
|
|
4164
|
+
*/
|
|
4165
|
+
function scopesAllowAddon(scopes, addonId, access) {
|
|
4166
|
+
return scopes.some((s) => s.type === "addon" && s.target === addonId && s.access.includes(access));
|
|
4167
|
+
}
|
|
4168
|
+
/**
|
|
4151
4169
|
* Error types for the safe expression engine. Two distinct classes so callers
|
|
4152
4170
|
* can tell a compile-time (grammar) failure from a runtime (evaluation)
|
|
4153
4171
|
* failure — both are non-fatal to the host: read paths degrade to "skip link".
|
|
@@ -13056,21 +13074,32 @@ var ScopedTokenSchema = zod.z.object({
|
|
|
13056
13074
|
* core, and no per-integration branch anywhere: `/api/oauth2/authorize` and
|
|
13057
13075
|
* `/api/oauth2/integrations` are built from this collection alone.
|
|
13058
13076
|
*
|
|
13059
|
-
* **Scopes
|
|
13060
|
-
*
|
|
13061
|
-
*
|
|
13062
|
-
*
|
|
13063
|
-
*
|
|
13077
|
+
* **Scopes. `requestedScopes` has exactly ONE meaning: what the integration
|
|
13078
|
+
* NEEDS to function.** Not a blast radius, not a conservative
|
|
13079
|
+
* under-declaration, not a description of some other path the addon happens to
|
|
13080
|
+
* have. Derive it from what the client actually calls **with this token** —
|
|
13081
|
+
* every tRPC path against `METHOD_ACCESS_MAP`, plus an `addon:` grant for every
|
|
13082
|
+
* addon HTTP route it posts to — and write the call that justifies each entry
|
|
13083
|
+
* next to it. Two integrations once used this field to mean two different
|
|
13084
|
+
* things; the operator ruled there is one meaning, and any third integration
|
|
13085
|
+
* inherits it (2026-08-09).
|
|
13086
|
+
*
|
|
13087
|
+
* This is not documentation, it is the ENFORCEMENT INPUT. Since
|
|
13088
|
+
* [D103](../../../../docs/decisions/adr-0103.md) the `/addon/:addonId/*` gate
|
|
13089
|
+
* checks an integration token's grant before letting it reach an
|
|
13090
|
+
* `access: 'authenticated'` route, so an **under-declaration is an integration
|
|
13091
|
+
* that stops working** — a missing `addon:` entry means `403 Token scope
|
|
13092
|
+
* mismatch` on every control the client tries to actuate. Widen the descriptor
|
|
13093
|
+
* honestly rather than weakening a check to make a route pass.
|
|
13094
|
+
*
|
|
13095
|
+
* Prefer a narrow `capability:` scope to a `category:` one unless the client
|
|
13096
|
+
* genuinely needs a whole family; a category scope grants every future member
|
|
13064
13097
|
* of that category too. `category:system [create]` has been rejected once and
|
|
13065
13098
|
* should stay rejected: it hands `addons.installPackage` to an integration.
|
|
13066
13099
|
*
|
|
13067
|
-
*
|
|
13068
|
-
*
|
|
13069
|
-
*
|
|
13070
|
-
* the addon does the work, while the Home Assistant component calls tRPC
|
|
13071
|
-
* directly with the token. So `requestedScopes` describes the blast radius of
|
|
13072
|
-
* the GRANT, not the reach of the integration; do not widen one to describe the
|
|
13073
|
-
* other.
|
|
13100
|
+
* Calls the ADDON itself makes over `ctx.api` run as the addon and are not
|
|
13101
|
+
* scope-checked, so they are not what this field describes — but reaching the
|
|
13102
|
+
* addon's route in the first place IS, and that is the entry to declare.
|
|
13074
13103
|
*
|
|
13075
13104
|
* **The boot window.** An addon registers its provider after its runner forks
|
|
13076
13105
|
* and initialises, so between hub start and that moment this collection is
|
|
@@ -13111,7 +13140,30 @@ var OauthIntegrationDescriptorSchema = zod.z.object({
|
|
|
13111
13140
|
* present, /api/oauth2/authorize bakes THIS into the code instead of the
|
|
13112
13141
|
* hub-global `publicHubUrl()`, so a forked exporter addon (which can't set
|
|
13113
13142
|
* the hub's env) drives the claim that its cloud Lambda routes back on. */
|
|
13114
|
-
hubUrl: zod.z.string().optional()
|
|
13143
|
+
hubUrl: zod.z.string().optional(),
|
|
13144
|
+
/**
|
|
13145
|
+
* How long a REFRESH token issued for this integration lives — seconds, or
|
|
13146
|
+
* `'never'` for a token minted with no `exp` claim at all. Omit to keep the
|
|
13147
|
+
* 30-day default, which is what every link used before this field existed.
|
|
13148
|
+
*
|
|
13149
|
+
* Declared here for the same reason `requestedScopes` is: the integration
|
|
13150
|
+
* knows what it needs. Amazon's account linking and a Home Assistant config
|
|
13151
|
+
* entry are both meant to survive indefinitely, and re-linking is a manual
|
|
13152
|
+
* user action, so a 30-day expiry silently unlinks a working integration.
|
|
13153
|
+
*
|
|
13154
|
+
* **The security posture, stated so it is owned deliberately.** A refresh
|
|
13155
|
+
* token that never expires is permanent access if it leaks. What bounds it is
|
|
13156
|
+
* revocation, not time: `oauthRefresh` re-reads the session on every use and
|
|
13157
|
+
* returns `null` once `revokedAt` is set, as does `oauthVerifyAccessToken`.
|
|
13158
|
+
* The one gap is the ACCESS token — it is a plain signed JWT that nothing
|
|
13159
|
+
* re-checks against the session on the `/trpc` and `/addon/*` paths, so
|
|
13160
|
+
* revoking a link takes effect there only after its remaining hour. That hour
|
|
13161
|
+
* is why the access TTL is not configurable.
|
|
13162
|
+
*
|
|
13163
|
+
* The value is baked into the authorization code at `/authorize` and travels
|
|
13164
|
+
* on the tokens, so editing this field changes FUTURE links only.
|
|
13165
|
+
*/
|
|
13166
|
+
refreshTokenTtlSec: zod.z.union([zod.z.number().int().positive(), zod.z.literal("never")]).optional()
|
|
13115
13167
|
});
|
|
13116
13168
|
var oauthIntegrationCapability = {
|
|
13117
13169
|
name: "oauth-integration",
|
|
@@ -17416,7 +17468,16 @@ var SsoBridgeClaimsSchema = zod.z.object({
|
|
|
17416
17468
|
codeChallenge: zod.z.string().optional(),
|
|
17417
17469
|
/** OAuth session registry id — set on `oauth-access`/`oauth-refresh`
|
|
17418
17470
|
* tokens so the verify path can check the session is not revoked. */
|
|
17419
|
-
sessionId: zod.z.string().optional()
|
|
17471
|
+
sessionId: zod.z.string().optional(),
|
|
17472
|
+
/**
|
|
17473
|
+
* The refresh lifetime this LINK was created with, in seconds, or `'never'`.
|
|
17474
|
+
* Baked into the code at `/authorize` from the integration's descriptor and
|
|
17475
|
+
* carried forward so `oauthRefresh` re-mints with the same lifetime. It rides
|
|
17476
|
+
* on the token rather than being re-read from the descriptor on purpose:
|
|
17477
|
+
* editing a descriptor must not retroactively extend or shorten a link the
|
|
17478
|
+
* operator already consented to.
|
|
17479
|
+
*/
|
|
17480
|
+
refreshTtl: zod.z.union([zod.z.number().int().positive(), zod.z.literal("never")]).optional()
|
|
17420
17481
|
});
|
|
17421
17482
|
var ssoBridgeCapability = {
|
|
17422
17483
|
name: "sso-bridge",
|
|
@@ -17426,7 +17487,16 @@ var ssoBridgeCapability = {
|
|
|
17426
17487
|
methods: {
|
|
17427
17488
|
signBridgeToken: method(zod.z.object({
|
|
17428
17489
|
claims: SsoBridgeClaimsSchema,
|
|
17429
|
-
|
|
17490
|
+
/**
|
|
17491
|
+
* Seconds, or `'never'` for a token minted with NO `exp` claim.
|
|
17492
|
+
*
|
|
17493
|
+
* `'never'` is a literal rather than `undefined`/`0` because omitting
|
|
17494
|
+
* this field already means "the 5-minute SSO hand-off default", and
|
|
17495
|
+
* `jwt.sign` THROWS on `{ expiresIn: undefined }` — a "no expiry" that
|
|
17496
|
+
* went through the numeric path would fail at mint time and break
|
|
17497
|
+
* linking rather than produce an eternal token.
|
|
17498
|
+
*/
|
|
17499
|
+
ttlSec: zod.z.union([zod.z.number().int().positive(), zod.z.literal("never")]).optional()
|
|
17430
17500
|
}), zod.z.object({ token: zod.z.string() })),
|
|
17431
17501
|
verifyBridgeToken: method(zod.z.object({ token: zod.z.string() }), SsoBridgeClaimsSchema.nullable())
|
|
17432
17502
|
}
|
|
@@ -26222,7 +26292,12 @@ var userManagementCapability = {
|
|
|
26222
26292
|
hubUrl: zod.z.string(),
|
|
26223
26293
|
/** PKCE (RFC 7636) S256 challenge. Baked into the signed code; a code
|
|
26224
26294
|
* that carries one can ONLY be exchanged with the matching verifier. */
|
|
26225
|
-
codeChallenge: zod.z.string().optional()
|
|
26295
|
+
codeChallenge: zod.z.string().optional(),
|
|
26296
|
+
/** The integration's declared refresh lifetime — seconds, or `'never'`.
|
|
26297
|
+
* From `OauthIntegrationDescriptor.refreshTokenTtlSec`. Baked into the
|
|
26298
|
+
* code so the link carries its own lifetime; omit for the 30-day
|
|
26299
|
+
* default. */
|
|
26300
|
+
refreshTtlSec: zod.z.union([zod.z.number().int().positive(), zod.z.literal("never")]).optional()
|
|
26226
26301
|
}), zod.z.object({ code: zod.z.string() }), {
|
|
26227
26302
|
kind: "mutation",
|
|
26228
26303
|
access: "create"
|
|
@@ -33730,6 +33805,18 @@ Object.defineProperty(exports, "scopeKey", {
|
|
|
33730
33805
|
return scopeKey;
|
|
33731
33806
|
}
|
|
33732
33807
|
});
|
|
33808
|
+
Object.defineProperty(exports, "scopesAllowAddon", {
|
|
33809
|
+
enumerable: true,
|
|
33810
|
+
get: function() {
|
|
33811
|
+
return scopesAllowAddon;
|
|
33812
|
+
}
|
|
33813
|
+
});
|
|
33814
|
+
Object.defineProperty(exports, "scopesAllowDeviceCap", {
|
|
33815
|
+
enumerable: true,
|
|
33816
|
+
get: function() {
|
|
33817
|
+
return scopesAllowDeviceCap;
|
|
33818
|
+
}
|
|
33819
|
+
});
|
|
33733
33820
|
Object.defineProperty(exports, "scoreRuntimes", {
|
|
33734
33821
|
enumerable: true,
|
|
33735
33822
|
get: function() {
|
package/dist/index.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ export type { ApiKeyRecord, ApiKeyStorageAccess } from './auth/api-key-manager.j
|
|
|
8
8
|
export { ApiKeyManager } from './auth/api-key-manager.js';
|
|
9
9
|
export type { AuthConfigReader, TokenPayload } from './auth/auth-manager.js';
|
|
10
10
|
export { AuthManager } from './auth/auth-manager.js';
|
|
11
|
-
export { scopesAllowDeviceCap } from './auth/scope-matcher.js';
|
|
11
|
+
export { scopesAllowAddon, scopesAllowDeviceCap } from './auth/scope-matcher.js';
|
|
12
12
|
export { ScopedTokenManager } from './auth/scoped-token-manager.js';
|
|
13
13
|
export type { UserConfigReader, UserRecord, UserStorageAccess } from './auth/user-manager.js';
|
|
14
14
|
export { UserManager } from './auth/user-manager.js';
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
const require_chunk = require("./chunk-Cek0wNdY.js");
|
|
3
|
-
const require_dist = require("./dist-
|
|
3
|
+
const require_dist = require("./dist-I0WgqQQ-.js");
|
|
4
4
|
const require_builtins_alerts_alerts_addon = require("./builtins/alerts/alerts.addon.js");
|
|
5
5
|
require("./builtins/alerts/index.js");
|
|
6
6
|
const require_formatter = require("./formatter-DqAKDlvN.js");
|
|
@@ -25,7 +25,7 @@ const require_builtins_system_config_system_config_addon = require("./builtins/s
|
|
|
25
25
|
require("./builtins/system-config/index.js");
|
|
26
26
|
const require_builtins_winston_logging_index = require("./builtins/winston-logging/index.js");
|
|
27
27
|
const require_file_data_plane = require("./file-data-plane-DUHPHa-Y.js");
|
|
28
|
-
const require_manifest_python_deps = require("./manifest-python-deps-
|
|
28
|
+
const require_manifest_python_deps = require("./manifest-python-deps-BqIpg0C7.js");
|
|
29
29
|
const require_resource_monitor = require("./resource-monitor-CdnzxBLP.js");
|
|
30
30
|
const require_custom_action_registry = require("./custom-action-registry-jY0NOZK8.js");
|
|
31
31
|
let zod = require("zod");
|
|
@@ -183,16 +183,6 @@ function matchPath(pattern, path) {
|
|
|
183
183
|
return params;
|
|
184
184
|
}
|
|
185
185
|
//#endregion
|
|
186
|
-
//#region src/auth/scope-matcher.ts
|
|
187
|
-
/**
|
|
188
|
-
* True if the scope set grants `access` on device-scoped capabilities.
|
|
189
|
-
* A `category:device` grant covers every device cap (the broad grant).
|
|
190
|
-
* Mirrors the OR-semantics of the existing token scope matcher.
|
|
191
|
-
*/
|
|
192
|
-
function scopesAllowDeviceCap(scopes, access) {
|
|
193
|
-
return scopes.some((s) => s.type === "category" && s.target === "device" && s.access.includes(access));
|
|
194
|
-
}
|
|
195
|
-
//#endregion
|
|
196
186
|
//#region src/events/event-bus.ts
|
|
197
187
|
var EventBus = class {
|
|
198
188
|
listeners = /* @__PURE__ */ new Map();
|
|
@@ -95239,7 +95229,8 @@ exports.resolveNpmInvocation = require_manifest_python_deps.resolveNpmInvocation
|
|
|
95239
95229
|
exports.runNpm = require_manifest_python_deps.runNpm;
|
|
95240
95230
|
exports.scheduleSelfRestart = scheduleSelfRestart;
|
|
95241
95231
|
exports.scopeKey = require_dist.scopeKey;
|
|
95242
|
-
exports.
|
|
95232
|
+
exports.scopesAllowAddon = require_dist.scopesAllowAddon;
|
|
95233
|
+
exports.scopesAllowDeviceCap = require_dist.scopesAllowDeviceCap;
|
|
95243
95234
|
exports.selectAddonResidue = selectAddonResidue;
|
|
95244
95235
|
exports.serializeTypedArrays = require_manifest_python_deps.serializeTypedArrays;
|
|
95245
95236
|
exports.setHubConnected = require_manifest_python_deps.setHubConnected;
|