@camstack/system 1.2.29 → 1.2.31
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/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 +135 -92
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +135 -92
- package/dist/builtins/backup-orchestrator/destination-policy.d.ts +12 -14
- package/dist/builtins/backup-orchestrator/schedule-store.d.ts +6 -6
- package/dist/builtins/console-logging/index.js +1 -1
- package/dist/builtins/console-logging/index.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/local-auth/local-auth.addon.js +1 -1
- package/dist/builtins/local-auth/local-auth.addon.mjs +1 -1
- 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/filter-compiler.d.ts +61 -0
- package/dist/builtins/sqlite-storage/integration-registry.d.ts +3 -3
- package/dist/builtins/sqlite-storage/sqlite-settings-backend.d.ts +49 -8
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +117 -85
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +117 -85
- package/dist/builtins/storage-orchestrator/location-store.d.ts +17 -24
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.d.ts +0 -6
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +132 -121
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +132 -121
- 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-CPmFYLqq.js → dist-CDv5YTHQ.js} +93 -1
- package/dist/{dist-B7hOpr5i.mjs → dist-CNmXITJ-.mjs} +93 -1
- package/dist/index.js +406 -224
- package/dist/index.mjs +406 -224
- package/dist/kernel/addon-installer.d.ts +38 -0
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { a as __toCommonJS, i as __require, n as __esmMin, o as __toESM$1, r as __exportAll, t as __commonJSMin$1 } from "./chunk-CNf5ZN-e.mjs";
|
|
2
|
-
import { A as extractNestedAddonId, At as scopeKey, Dt as parseJsonUnknown$1, Et as parseJsonObject, F as isObjectInput, G as objectInputDeclaresAddonId, H as looseSchema, I as isVoidInput, J as procedureAuthKey, L as kebabToCamel, Mt as EventCategory$1, N as isArrayOutputSchema, Ot as readinessKey, P as isCollectionArrayMethod, R as lifecycleJobSchema, St as expandCapMethods, V as logLevelAtMost, _t as asNumber, at as errMsg$1, bt as emitDownForOwnedCaps, c as RUNTIME_DEFAULTS, ct as DEVICE_SETTINGS_CONTRIBUTION_METHODS, gt as asJsonObject$1, kt as resolveCapMount, lt as DEVICE_STATUS_METHOD, m as addonSettingsCapability, mt as ReadinessTimeoutError, pt as ReadinessRegistry, s as METHOD_ACCESS_MAP, st as DATAPLANE_SECRET_HEADER$1, t as ALL_CAPABILITY_DEFINITIONS, vt as asString$1, yt as createEvent } from "./dist-
|
|
2
|
+
import { A as extractNestedAddonId, At as scopeKey, Dt as parseJsonUnknown$1, Et as parseJsonObject, F as isObjectInput, G as objectInputDeclaresAddonId, H as looseSchema, I as isVoidInput, J as procedureAuthKey, L as kebabToCamel, Mt as EventCategory$1, N as isArrayOutputSchema, Ot as readinessKey, P as isCollectionArrayMethod, R as lifecycleJobSchema, St as expandCapMethods, V as logLevelAtMost, _t as asNumber, at as errMsg$1, bt as emitDownForOwnedCaps, c as RUNTIME_DEFAULTS, ct as DEVICE_SETTINGS_CONTRIBUTION_METHODS, gt as asJsonObject$1, kt as resolveCapMount, lt as DEVICE_STATUS_METHOD, m as addonSettingsCapability, mt as ReadinessTimeoutError, pt as ReadinessRegistry, s as METHOD_ACCESS_MAP, st as DATAPLANE_SECRET_HEADER$1, t as ALL_CAPABILITY_DEFINITIONS, vt as asString$1, yt as createEvent } from "./dist-CNmXITJ-.mjs";
|
|
3
3
|
import { a as downloadModel, c as getModelFilePath, d as contentTypeFor, f as createAuthenticatedFileServer, h as resolveFilePath, i as downloadFile, l as isModelDownloaded, m as parseTokenizedUrl, n as collectModelFiles, o as ensureModel, p as parseRangeHeader, r as deleteModelFromDisk, s as fetchJson, t as ModelDownloadService, u as createFileDataPlaneHandler } from "./model-download-service-Cp9f4dk6.mjs";
|
|
4
4
|
import { $ as buildNativeCapProxy, A as createHubCapForwardService, B as AGENT_CAP_FWD_ACTION, C as brokerTransportLink, Ct as resolveAddonClass, D as localProviderLink, E as ipcParentLink, F as createUdsLogger, G as callWithServiceDiscovery, H as CapRouteResolver, I as createUdsLoggerWithControl, J as UdsLocalTransportServer, K as createLocalTransport, L as LocalChildClient, M as createUdsEventBridge, N as createUdsEventBus, O as HUB_CAP_FWD_ACTION, P as udsChildLogToWorkerEntry, Q as encodeFrame, R as LocalChildRegistry, S as brokerCallForCap, St as runNpm, T as ipcChildLink, U as CapRouteError, V as AGENT_CAP_FWD_SERVICE, W as classifyCapRoute, X as localEndpointPath, Y as SocketChannel, Z as FrameDecoder, _ as createKernelHwAccel, _t as CapabilityHandle, a as getWorkerDeviceRegistry, b as __resetCapUsageRegistryForTests, bt as installManifestNativeDeps, c as setHubConnected, ct as NATIVE_PROVIDER_SERVICE_INFIX, d as getBrokerEventBus, dt as capBareAction, et as buildUdsNativeCapProxy, f as getMoleculerEventStats, ft as capServiceName, g as AddonDepsManager, gt as DeviceRegistry, h as subscribePassthrough, ht as serializeTypedArrays, i as createUdsAddonContext, it as mountNativeCapService, j as createParentUnownedCallHandler, k as HUB_CAP_FWD_SERVICE, l as EVENT_TOPIC_PREFIX, lt as capActionName, m as setNodeEventInterest, mt as deserializeTypedArrays, n as adaptBrokerToCluster, o as getOrInitReadinessRegistry, ot as createAddonService, p as registerEventBusService, pt as parseCapAction, q as UdsLocalTransportClient, r as createAddonContext, s as getOrInitReadinessRegistryForClient, st as validateProviderRegistrations, t as installManifestPythonDeps, tt as createBrokerDeviceManagerApi, u as clusterEventTopic, ut as capActionSuffix, v as resolveHwAccel, vt as CapabilityUnavailableError, w as buildLinkChain, wt as createAddonDataPlaneFacility, x as getCapUsageRegistry, xt as resolveNpmInvocation, y as CapUsageRegistry, yt as copyBundledNativeModules, z as UDS_NO_ROUTE_PREFIX } from "./manifest-python-deps-Ck4-9K9m.mjs";
|
|
5
5
|
import { n as getSinglePidStats, t as getPidStats } from "./resource-monitor-BkP504Vq.mjs";
|
|
@@ -2069,18 +2069,47 @@ function serializeSetting(value) {
|
|
|
2069
2069
|
valueType: "json"
|
|
2070
2070
|
};
|
|
2071
2071
|
}
|
|
2072
|
-
|
|
2072
|
+
/**
|
|
2073
|
+
* Decode a settings row back to its value.
|
|
2074
|
+
*
|
|
2075
|
+
* `raw` is `unknown`, not `string`, on purpose: the collection surface parses
|
|
2076
|
+
* any TEXT column whose value starts with `{` or `[`, so a `json` setting
|
|
2077
|
+
* arrives here ALREADY an object. Coercing it with `String(...)` first — which
|
|
2078
|
+
* is what a straight port of the `table*` version did — produced the literal
|
|
2079
|
+
* `"[object Object]"`.
|
|
2080
|
+
*/
|
|
2081
|
+
function deserializeSetting(raw, valueType) {
|
|
2082
|
+
if (valueType === "json") {
|
|
2083
|
+
if (typeof raw !== "string") return raw;
|
|
2084
|
+
try {
|
|
2085
|
+
return JSON.parse(raw);
|
|
2086
|
+
} catch {
|
|
2087
|
+
return raw;
|
|
2088
|
+
}
|
|
2089
|
+
}
|
|
2090
|
+
const value = String(raw);
|
|
2073
2091
|
switch (valueType) {
|
|
2074
2092
|
case "number": return Number(value);
|
|
2075
2093
|
case "boolean": return value === "true";
|
|
2076
|
-
case "json": try {
|
|
2077
|
-
return JSON.parse(value);
|
|
2078
|
-
} catch {
|
|
2079
|
-
return value;
|
|
2080
|
-
}
|
|
2081
2094
|
default: return value;
|
|
2082
2095
|
}
|
|
2083
2096
|
}
|
|
2097
|
+
/**
|
|
2098
|
+
* Read an `info` blob off a row.
|
|
2099
|
+
*
|
|
2100
|
+
* The column is declared `JSON`, so the surface hands back a parsed object —
|
|
2101
|
+
* but rows written before B2 by an older build are still raw strings on disk
|
|
2102
|
+
* for as long as they go un-rewritten, and a string that fails to parse must
|
|
2103
|
+
* not take the whole record down.
|
|
2104
|
+
*/
|
|
2105
|
+
function isPlainObject(value) {
|
|
2106
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
2107
|
+
}
|
|
2108
|
+
function readInfo(raw) {
|
|
2109
|
+
if (typeof raw === "string") return parseJsonObject(raw) ?? {};
|
|
2110
|
+
if (isPlainObject(raw)) return { ...raw };
|
|
2111
|
+
return {};
|
|
2112
|
+
}
|
|
2084
2113
|
var integrationCounter = 0;
|
|
2085
2114
|
var deviceCounter = 0;
|
|
2086
2115
|
function nextIntegrationId() {
|
|
@@ -2089,52 +2118,50 @@ function nextIntegrationId() {
|
|
|
2089
2118
|
function nextDeviceId() {
|
|
2090
2119
|
return `dev_${String(++deviceCounter).padStart(4, "0")}`;
|
|
2091
2120
|
}
|
|
2092
|
-
var
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
};
|
|
2137
|
-
var INTEGRATION_SETTINGS_SCHEMA = { columns: [
|
|
2121
|
+
var INTEGRATIONS_COLUMNS = [
|
|
2122
|
+
{
|
|
2123
|
+
name: "id",
|
|
2124
|
+
type: "TEXT",
|
|
2125
|
+
primaryKey: true
|
|
2126
|
+
},
|
|
2127
|
+
{
|
|
2128
|
+
name: "addon_id",
|
|
2129
|
+
type: "TEXT",
|
|
2130
|
+
notNull: true
|
|
2131
|
+
},
|
|
2132
|
+
{
|
|
2133
|
+
name: "name",
|
|
2134
|
+
type: "TEXT",
|
|
2135
|
+
notNull: true
|
|
2136
|
+
},
|
|
2137
|
+
{
|
|
2138
|
+
name: "enabled",
|
|
2139
|
+
type: "INTEGER",
|
|
2140
|
+
notNull: true,
|
|
2141
|
+
defaultValue: 1
|
|
2142
|
+
},
|
|
2143
|
+
{
|
|
2144
|
+
name: "info",
|
|
2145
|
+
type: "JSON",
|
|
2146
|
+
notNull: true,
|
|
2147
|
+
defaultValue: "{}"
|
|
2148
|
+
},
|
|
2149
|
+
{
|
|
2150
|
+
name: "created_at",
|
|
2151
|
+
type: "INTEGER",
|
|
2152
|
+
notNull: true
|
|
2153
|
+
},
|
|
2154
|
+
{
|
|
2155
|
+
name: "updated_at",
|
|
2156
|
+
type: "INTEGER",
|
|
2157
|
+
notNull: true
|
|
2158
|
+
}
|
|
2159
|
+
];
|
|
2160
|
+
var INTEGRATIONS_INDEXES = [{
|
|
2161
|
+
name: "idx_integrations_addon",
|
|
2162
|
+
columns: ["addon_id"]
|
|
2163
|
+
}];
|
|
2164
|
+
var INTEGRATION_SETTINGS_COLUMNS = [
|
|
2138
2165
|
{
|
|
2139
2166
|
name: "integration_id",
|
|
2140
2167
|
type: "TEXT",
|
|
@@ -2156,76 +2183,74 @@ var INTEGRATION_SETTINGS_SCHEMA = { columns: [
|
|
|
2156
2183
|
notNull: true,
|
|
2157
2184
|
defaultValue: "string"
|
|
2158
2185
|
}
|
|
2159
|
-
]
|
|
2160
|
-
var
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
};
|
|
2228
|
-
var DEVICE_SETTINGS_SCHEMA = { columns: [
|
|
2186
|
+
];
|
|
2187
|
+
var DEVICES_COLUMNS = [
|
|
2188
|
+
{
|
|
2189
|
+
name: "id",
|
|
2190
|
+
type: "TEXT",
|
|
2191
|
+
primaryKey: true
|
|
2192
|
+
},
|
|
2193
|
+
{
|
|
2194
|
+
name: "integration_id",
|
|
2195
|
+
type: "TEXT",
|
|
2196
|
+
notNull: true
|
|
2197
|
+
},
|
|
2198
|
+
{
|
|
2199
|
+
name: "stable_id",
|
|
2200
|
+
type: "TEXT",
|
|
2201
|
+
notNull: true,
|
|
2202
|
+
unique: true
|
|
2203
|
+
},
|
|
2204
|
+
{
|
|
2205
|
+
name: "type",
|
|
2206
|
+
type: "TEXT",
|
|
2207
|
+
notNull: true,
|
|
2208
|
+
defaultValue: "camera"
|
|
2209
|
+
},
|
|
2210
|
+
{
|
|
2211
|
+
name: "name",
|
|
2212
|
+
type: "TEXT",
|
|
2213
|
+
notNull: true
|
|
2214
|
+
},
|
|
2215
|
+
{
|
|
2216
|
+
name: "enabled",
|
|
2217
|
+
type: "INTEGER",
|
|
2218
|
+
notNull: true,
|
|
2219
|
+
defaultValue: 1
|
|
2220
|
+
},
|
|
2221
|
+
{
|
|
2222
|
+
name: "info",
|
|
2223
|
+
type: "JSON",
|
|
2224
|
+
notNull: true,
|
|
2225
|
+
defaultValue: "{}"
|
|
2226
|
+
},
|
|
2227
|
+
{
|
|
2228
|
+
name: "created_at",
|
|
2229
|
+
type: "INTEGER",
|
|
2230
|
+
notNull: true
|
|
2231
|
+
},
|
|
2232
|
+
{
|
|
2233
|
+
name: "updated_at",
|
|
2234
|
+
type: "INTEGER",
|
|
2235
|
+
notNull: true
|
|
2236
|
+
}
|
|
2237
|
+
];
|
|
2238
|
+
var DEVICES_INDEXES = [
|
|
2239
|
+
{
|
|
2240
|
+
name: "idx_devices_integration",
|
|
2241
|
+
columns: ["integration_id"]
|
|
2242
|
+
},
|
|
2243
|
+
{
|
|
2244
|
+
name: "idx_devices_stable",
|
|
2245
|
+
columns: ["stable_id"],
|
|
2246
|
+
unique: true
|
|
2247
|
+
},
|
|
2248
|
+
{
|
|
2249
|
+
name: "idx_devices_type",
|
|
2250
|
+
columns: ["type"]
|
|
2251
|
+
}
|
|
2252
|
+
];
|
|
2253
|
+
var DEVICE_SETTINGS_COLUMNS = [
|
|
2229
2254
|
{
|
|
2230
2255
|
name: "device_id",
|
|
2231
2256
|
type: "TEXT",
|
|
@@ -2247,51 +2272,80 @@ var DEVICE_SETTINGS_SCHEMA = { columns: [
|
|
|
2247
2272
|
notNull: true,
|
|
2248
2273
|
defaultValue: "string"
|
|
2249
2274
|
}
|
|
2250
|
-
]
|
|
2275
|
+
];
|
|
2276
|
+
var INTEGRATIONS = "integrations";
|
|
2277
|
+
var INTEGRATION_SETTINGS = "integration_settings";
|
|
2278
|
+
var DEVICES = "devices";
|
|
2279
|
+
var DEVICE_SETTINGS = "device_settings_kv";
|
|
2251
2280
|
var IntegrationRegistry = class {
|
|
2252
|
-
|
|
2281
|
+
store;
|
|
2253
2282
|
constructor(backend) {
|
|
2254
|
-
this.
|
|
2283
|
+
this.store = backend;
|
|
2255
2284
|
}
|
|
2256
2285
|
async initialize() {
|
|
2257
|
-
await this.
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2286
|
+
await this.store.declareCollection({
|
|
2287
|
+
collection: INTEGRATIONS,
|
|
2288
|
+
columns: INTEGRATIONS_COLUMNS,
|
|
2289
|
+
indexes: INTEGRATIONS_INDEXES
|
|
2290
|
+
});
|
|
2291
|
+
await this.store.declareCollection({
|
|
2292
|
+
collection: INTEGRATION_SETTINGS,
|
|
2293
|
+
columns: INTEGRATION_SETTINGS_COLUMNS
|
|
2294
|
+
});
|
|
2295
|
+
await this.store.declareCollection({
|
|
2296
|
+
collection: DEVICES,
|
|
2297
|
+
columns: DEVICES_COLUMNS,
|
|
2298
|
+
indexes: DEVICES_INDEXES
|
|
2299
|
+
});
|
|
2300
|
+
await this.store.declareCollection({
|
|
2301
|
+
collection: DEVICE_SETTINGS,
|
|
2302
|
+
columns: DEVICE_SETTINGS_COLUMNS
|
|
2303
|
+
});
|
|
2304
|
+
const ints = await this.store.query({
|
|
2305
|
+
collection: INTEGRATIONS,
|
|
2306
|
+
filter: {
|
|
2307
|
+
orderBy: {
|
|
2308
|
+
field: "id",
|
|
2309
|
+
direction: "desc"
|
|
2310
|
+
},
|
|
2311
|
+
limit: 1
|
|
2312
|
+
}
|
|
2313
|
+
});
|
|
2268
2314
|
if (ints[0]) {
|
|
2269
|
-
const num = parseInt(
|
|
2315
|
+
const num = parseInt(ints[0].id.replace("int_", ""), 10);
|
|
2270
2316
|
if (!isNaN(num)) integrationCounter = num;
|
|
2271
2317
|
}
|
|
2272
|
-
const devs = await this.
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2318
|
+
const devs = await this.store.query({
|
|
2319
|
+
collection: DEVICES,
|
|
2320
|
+
filter: {
|
|
2321
|
+
orderBy: {
|
|
2322
|
+
field: "id",
|
|
2323
|
+
direction: "desc"
|
|
2324
|
+
},
|
|
2325
|
+
limit: 1
|
|
2326
|
+
}
|
|
2327
|
+
});
|
|
2279
2328
|
if (devs[0]) {
|
|
2280
|
-
const num = parseInt(
|
|
2329
|
+
const num = parseInt(devs[0].id.replace("dev_", ""), 10);
|
|
2281
2330
|
if (!isNaN(num)) deviceCounter = num;
|
|
2282
2331
|
}
|
|
2283
2332
|
}
|
|
2284
2333
|
async createIntegration(input) {
|
|
2285
2334
|
const id = nextIntegrationId();
|
|
2286
2335
|
const now = Math.floor(Date.now() / 1e3);
|
|
2287
|
-
await this.
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2336
|
+
await this.store.insert({
|
|
2337
|
+
collection: INTEGRATIONS,
|
|
2338
|
+
record: {
|
|
2339
|
+
id,
|
|
2340
|
+
data: {
|
|
2341
|
+
addon_id: input.addonId,
|
|
2342
|
+
name: input.name,
|
|
2343
|
+
enabled: input.enabled !== false ? 1 : 0,
|
|
2344
|
+
info: input.info ?? {},
|
|
2345
|
+
created_at: now,
|
|
2346
|
+
updated_at: now
|
|
2347
|
+
}
|
|
2348
|
+
}
|
|
2295
2349
|
});
|
|
2296
2350
|
if (input.settings) await this.setIntegrationSettings(id, input.settings);
|
|
2297
2351
|
return {
|
|
@@ -2305,52 +2359,95 @@ var IntegrationRegistry = class {
|
|
|
2305
2359
|
};
|
|
2306
2360
|
}
|
|
2307
2361
|
async getIntegration(id) {
|
|
2308
|
-
const
|
|
2309
|
-
|
|
2362
|
+
const rows = await this.store.query({
|
|
2363
|
+
collection: INTEGRATIONS,
|
|
2364
|
+
filter: {
|
|
2365
|
+
where: { id },
|
|
2366
|
+
limit: 1
|
|
2367
|
+
}
|
|
2368
|
+
});
|
|
2369
|
+
return rows[0] ? this.mapIntegration(rows[0].data) : null;
|
|
2310
2370
|
}
|
|
2311
2371
|
async getIntegrationByAddonId(addonId) {
|
|
2312
|
-
const
|
|
2313
|
-
|
|
2372
|
+
const rows = await this.store.query({
|
|
2373
|
+
collection: INTEGRATIONS,
|
|
2374
|
+
filter: {
|
|
2375
|
+
where: { addon_id: addonId },
|
|
2376
|
+
limit: 1
|
|
2377
|
+
}
|
|
2378
|
+
});
|
|
2379
|
+
return rows[0] ? this.mapIntegration(rows[0].data) : null;
|
|
2314
2380
|
}
|
|
2315
2381
|
async listIntegrations() {
|
|
2316
|
-
return (await this.
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2382
|
+
return (await this.store.query({
|
|
2383
|
+
collection: INTEGRATIONS,
|
|
2384
|
+
filter: { orderBy: {
|
|
2385
|
+
field: "created_at",
|
|
2386
|
+
direction: "asc"
|
|
2387
|
+
} }
|
|
2388
|
+
})).map((r) => this.mapIntegration(r.data));
|
|
2320
2389
|
}
|
|
2321
2390
|
async updateIntegration(id, updates) {
|
|
2322
2391
|
const updateRow = { updated_at: Math.floor(Date.now() / 1e3) };
|
|
2323
2392
|
if (updates.name !== void 0) updateRow["name"] = updates.name;
|
|
2324
2393
|
if (updates.enabled !== void 0) updateRow["enabled"] = updates.enabled ? 1 : 0;
|
|
2325
|
-
if (updates.info !== void 0) updateRow["info"] =
|
|
2326
|
-
await this.
|
|
2394
|
+
if (updates.info !== void 0) updateRow["info"] = updates.info;
|
|
2395
|
+
await this.store.updateWhere({
|
|
2396
|
+
collection: INTEGRATIONS,
|
|
2397
|
+
filter: { where: { id } },
|
|
2398
|
+
data: updateRow
|
|
2399
|
+
});
|
|
2327
2400
|
return this.getIntegration(id);
|
|
2328
2401
|
}
|
|
2329
2402
|
async deleteIntegration(id) {
|
|
2330
2403
|
const devices = await this.listDevices(id);
|
|
2331
|
-
for (const d of devices) await this.
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2404
|
+
for (const d of devices) await this.store.deleteWhere({
|
|
2405
|
+
collection: DEVICE_SETTINGS,
|
|
2406
|
+
filter: { where: { device_id: d.id } }
|
|
2407
|
+
});
|
|
2408
|
+
await this.store.deleteWhere({
|
|
2409
|
+
collection: DEVICES,
|
|
2410
|
+
filter: { where: { integration_id: id } }
|
|
2411
|
+
});
|
|
2412
|
+
await this.store.deleteWhere({
|
|
2413
|
+
collection: INTEGRATION_SETTINGS,
|
|
2414
|
+
filter: { where: { integration_id: id } }
|
|
2415
|
+
});
|
|
2416
|
+
await this.store.deleteWhere({
|
|
2417
|
+
collection: INTEGRATIONS,
|
|
2418
|
+
filter: { where: { id } }
|
|
2419
|
+
});
|
|
2335
2420
|
return true;
|
|
2336
2421
|
}
|
|
2337
2422
|
async getIntegrationSettings(integrationId) {
|
|
2338
2423
|
const result = {};
|
|
2339
|
-
const rows = await this.
|
|
2340
|
-
|
|
2424
|
+
const rows = await this.store.query({
|
|
2425
|
+
collection: INTEGRATION_SETTINGS,
|
|
2426
|
+
filter: { where: { integration_id: integrationId } }
|
|
2427
|
+
});
|
|
2428
|
+
for (const row of rows) result[String(row.data["key"])] = deserializeSetting(row.data["value"], String(row.data["value_type"]));
|
|
2341
2429
|
return result;
|
|
2342
2430
|
}
|
|
2343
2431
|
async setIntegrationSetting(integrationId, key, value) {
|
|
2344
2432
|
const s = serializeSetting(value);
|
|
2345
|
-
await this.
|
|
2346
|
-
|
|
2347
|
-
|
|
2433
|
+
await this.store.deleteWhere({
|
|
2434
|
+
collection: INTEGRATION_SETTINGS,
|
|
2435
|
+
filter: { where: {
|
|
2436
|
+
integration_id: integrationId,
|
|
2437
|
+
key
|
|
2438
|
+
} }
|
|
2348
2439
|
});
|
|
2349
|
-
await this.
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2440
|
+
await this.store.insert({
|
|
2441
|
+
collection: INTEGRATION_SETTINGS,
|
|
2442
|
+
record: {
|
|
2443
|
+
id: `${integrationId}:${key}`,
|
|
2444
|
+
data: {
|
|
2445
|
+
integration_id: integrationId,
|
|
2446
|
+
key,
|
|
2447
|
+
value: s.value,
|
|
2448
|
+
value_type: s.valueType
|
|
2449
|
+
}
|
|
2450
|
+
}
|
|
2354
2451
|
});
|
|
2355
2452
|
}
|
|
2356
2453
|
async setIntegrationSettings(integrationId, settings) {
|
|
@@ -2359,16 +2456,21 @@ var IntegrationRegistry = class {
|
|
|
2359
2456
|
async createDevice(input) {
|
|
2360
2457
|
const id = nextDeviceId();
|
|
2361
2458
|
const now = Math.floor(Date.now() / 1e3);
|
|
2362
|
-
await this.
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2459
|
+
await this.store.insert({
|
|
2460
|
+
collection: DEVICES,
|
|
2461
|
+
record: {
|
|
2462
|
+
id,
|
|
2463
|
+
data: {
|
|
2464
|
+
integration_id: input.integrationId,
|
|
2465
|
+
stable_id: input.stableId,
|
|
2466
|
+
type: input.type,
|
|
2467
|
+
name: input.name,
|
|
2468
|
+
enabled: input.enabled !== false ? 1 : 0,
|
|
2469
|
+
info: input.info ?? {},
|
|
2470
|
+
created_at: now,
|
|
2471
|
+
updated_at: now
|
|
2472
|
+
}
|
|
2473
|
+
}
|
|
2372
2474
|
});
|
|
2373
2475
|
if (input.settings) await this.setDeviceSettings(id, input.settings);
|
|
2374
2476
|
return {
|
|
@@ -2384,65 +2486,101 @@ var IntegrationRegistry = class {
|
|
|
2384
2486
|
};
|
|
2385
2487
|
}
|
|
2386
2488
|
async getDevice(id) {
|
|
2387
|
-
const
|
|
2388
|
-
|
|
2489
|
+
const rows = await this.store.query({
|
|
2490
|
+
collection: DEVICES,
|
|
2491
|
+
filter: {
|
|
2492
|
+
where: { id },
|
|
2493
|
+
limit: 1
|
|
2494
|
+
}
|
|
2495
|
+
});
|
|
2496
|
+
return rows[0] ? this.mapDevice(rows[0].data) : null;
|
|
2389
2497
|
}
|
|
2390
2498
|
async getDeviceByStableId(stableId) {
|
|
2391
|
-
const
|
|
2392
|
-
|
|
2499
|
+
const rows = await this.store.query({
|
|
2500
|
+
collection: DEVICES,
|
|
2501
|
+
filter: {
|
|
2502
|
+
where: { stable_id: stableId },
|
|
2503
|
+
limit: 1
|
|
2504
|
+
}
|
|
2505
|
+
});
|
|
2506
|
+
return rows[0] ? this.mapDevice(rows[0].data) : null;
|
|
2393
2507
|
}
|
|
2394
2508
|
async listDevices(integrationId) {
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2509
|
+
return (await this.store.query({
|
|
2510
|
+
collection: DEVICES,
|
|
2511
|
+
filter: {
|
|
2512
|
+
...integrationId ? { where: { integration_id: integrationId } } : {},
|
|
2513
|
+
orderBy: {
|
|
2514
|
+
field: "created_at",
|
|
2515
|
+
direction: "asc"
|
|
2516
|
+
}
|
|
2400
2517
|
}
|
|
2401
|
-
}
|
|
2402
|
-
field: "created_at",
|
|
2403
|
-
direction: "asc"
|
|
2404
|
-
} };
|
|
2405
|
-
return (await this.backend.tableQuery?.("devices", options) ?? []).map((r) => this.mapDevice(r));
|
|
2518
|
+
})).map((r) => this.mapDevice(r.data));
|
|
2406
2519
|
}
|
|
2407
2520
|
async listCameras() {
|
|
2408
|
-
return (await this.
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
2521
|
+
return (await this.store.query({
|
|
2522
|
+
collection: DEVICES,
|
|
2523
|
+
filter: {
|
|
2524
|
+
where: { type: "camera" },
|
|
2525
|
+
orderBy: {
|
|
2526
|
+
field: "created_at",
|
|
2527
|
+
direction: "asc"
|
|
2528
|
+
}
|
|
2413
2529
|
}
|
|
2414
|
-
})
|
|
2530
|
+
})).map((r) => this.mapDevice(r.data));
|
|
2415
2531
|
}
|
|
2416
2532
|
async updateDevice(id, updates) {
|
|
2417
2533
|
const updateRow = { updated_at: Math.floor(Date.now() / 1e3) };
|
|
2418
2534
|
if (updates.name !== void 0) updateRow["name"] = updates.name;
|
|
2419
2535
|
if (updates.enabled !== void 0) updateRow["enabled"] = updates.enabled ? 1 : 0;
|
|
2420
|
-
if (updates.info !== void 0) updateRow["info"] =
|
|
2421
|
-
await this.
|
|
2536
|
+
if (updates.info !== void 0) updateRow["info"] = updates.info;
|
|
2537
|
+
await this.store.updateWhere({
|
|
2538
|
+
collection: DEVICES,
|
|
2539
|
+
filter: { where: { id } },
|
|
2540
|
+
data: updateRow
|
|
2541
|
+
});
|
|
2422
2542
|
return this.getDevice(id);
|
|
2423
2543
|
}
|
|
2424
2544
|
async deleteDevice(id) {
|
|
2425
|
-
await this.
|
|
2426
|
-
|
|
2545
|
+
await this.store.deleteWhere({
|
|
2546
|
+
collection: DEVICE_SETTINGS,
|
|
2547
|
+
filter: { where: { device_id: id } }
|
|
2548
|
+
});
|
|
2549
|
+
await this.store.deleteWhere({
|
|
2550
|
+
collection: DEVICES,
|
|
2551
|
+
filter: { where: { id } }
|
|
2552
|
+
});
|
|
2427
2553
|
return true;
|
|
2428
2554
|
}
|
|
2429
2555
|
async getDeviceSettings(deviceId) {
|
|
2430
2556
|
const result = {};
|
|
2431
|
-
const rows = await this.
|
|
2432
|
-
|
|
2557
|
+
const rows = await this.store.query({
|
|
2558
|
+
collection: DEVICE_SETTINGS,
|
|
2559
|
+
filter: { where: { device_id: deviceId } }
|
|
2560
|
+
});
|
|
2561
|
+
for (const row of rows) result[String(row.data["key"])] = deserializeSetting(row.data["value"], String(row.data["value_type"]));
|
|
2433
2562
|
return result;
|
|
2434
2563
|
}
|
|
2435
2564
|
async setDeviceSetting(deviceId, key, value) {
|
|
2436
2565
|
const s = serializeSetting(value);
|
|
2437
|
-
await this.
|
|
2438
|
-
|
|
2439
|
-
|
|
2566
|
+
await this.store.deleteWhere({
|
|
2567
|
+
collection: DEVICE_SETTINGS,
|
|
2568
|
+
filter: { where: {
|
|
2569
|
+
device_id: deviceId,
|
|
2570
|
+
key
|
|
2571
|
+
} }
|
|
2440
2572
|
});
|
|
2441
|
-
await this.
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2573
|
+
await this.store.insert({
|
|
2574
|
+
collection: DEVICE_SETTINGS,
|
|
2575
|
+
record: {
|
|
2576
|
+
id: `${deviceId}:${key}`,
|
|
2577
|
+
data: {
|
|
2578
|
+
device_id: deviceId,
|
|
2579
|
+
key,
|
|
2580
|
+
value: s.value,
|
|
2581
|
+
value_type: s.valueType
|
|
2582
|
+
}
|
|
2583
|
+
}
|
|
2446
2584
|
});
|
|
2447
2585
|
}
|
|
2448
2586
|
async setDeviceSettings(deviceId, settings) {
|
|
@@ -2454,7 +2592,7 @@ var IntegrationRegistry = class {
|
|
|
2454
2592
|
addonId: String(row["addon_id"]),
|
|
2455
2593
|
name: String(row["name"]),
|
|
2456
2594
|
enabled: row["enabled"] === 1,
|
|
2457
|
-
info:
|
|
2595
|
+
info: readInfo(row["info"]),
|
|
2458
2596
|
createdAt: Number(row["created_at"]),
|
|
2459
2597
|
updatedAt: Number(row["updated_at"])
|
|
2460
2598
|
};
|
|
@@ -2467,7 +2605,7 @@ var IntegrationRegistry = class {
|
|
|
2467
2605
|
type: String(row["type"]),
|
|
2468
2606
|
name: String(row["name"]),
|
|
2469
2607
|
enabled: row["enabled"] === 1,
|
|
2470
|
-
info:
|
|
2608
|
+
info: readInfo(row["info"]),
|
|
2471
2609
|
createdAt: Number(row["created_at"]),
|
|
2472
2610
|
updatedAt: Number(row["updated_at"])
|
|
2473
2611
|
};
|
|
@@ -3566,6 +3704,25 @@ function readPackageJson(pkgJsonPath) {
|
|
|
3566
3704
|
camstackAddons: Array.isArray(addonsField) ? addonsField : null
|
|
3567
3705
|
};
|
|
3568
3706
|
}
|
|
3707
|
+
/**
|
|
3708
|
+
* Should the bootstrap SKIP seeding `packageName` into /data/addons?
|
|
3709
|
+
*
|
|
3710
|
+
* True only for the package the closure provides, and only when it actually
|
|
3711
|
+
* resolves. Both halves are load-bearing:
|
|
3712
|
+
*
|
|
3713
|
+
* - seeding a copy the closure already provides creates one that WINS over
|
|
3714
|
+
* the closure and is never refreshed (bootstrap is seed-only, and
|
|
3715
|
+
* `camstack deploy` of a framework package is rejected on an image hub), so
|
|
3716
|
+
* the node runs first-boot builtins forever while reporting the new
|
|
3717
|
+
* version;
|
|
3718
|
+
* - skipping it when it does NOT resolve is how a fresh deployment was once
|
|
3719
|
+
* made unbootable ("No addon provides required infrastructure capability
|
|
3720
|
+
* storage-provider"). That is why the guard is resolvability rather than a
|
|
3721
|
+
* blanket removal from the bootstrap list.
|
|
3722
|
+
*/
|
|
3723
|
+
function shouldSkipClosureProvidedSeed(packageName, isResolvable) {
|
|
3724
|
+
return packageName === "@camstack/system" && isResolvable;
|
|
3725
|
+
}
|
|
3569
3726
|
/** Minimal no-op logger for default parameter */
|
|
3570
3727
|
var noopLogger = {
|
|
3571
3728
|
debug() {},
|
|
@@ -3585,6 +3742,7 @@ var AddonInstaller = class AddonInstaller {
|
|
|
3585
3742
|
workspaceDir;
|
|
3586
3743
|
installSource;
|
|
3587
3744
|
logger;
|
|
3745
|
+
isPackageResolvable;
|
|
3588
3746
|
/**
|
|
3589
3747
|
* Central manifest of installed addons. Tracks version + source +
|
|
3590
3748
|
* timestamps + last-backup pointer per package, written atomically
|
|
@@ -3600,6 +3758,7 @@ var AddonInstaller = class AddonInstaller {
|
|
|
3600
3758
|
this.workspaceDir = config.workspacePackagesDir;
|
|
3601
3759
|
this.logger = logger;
|
|
3602
3760
|
this.manifest = new AddonManifest(config.addonsDir);
|
|
3761
|
+
this.isPackageResolvable = config.isPackageResolvable;
|
|
3603
3762
|
if (config.installSource) this.installSource = config.installSource;
|
|
3604
3763
|
else this.installSource = "npm";
|
|
3605
3764
|
}
|
|
@@ -3628,6 +3787,25 @@ var AddonInstaller = class AddonInstaller {
|
|
|
3628
3787
|
* hardcoded lists — see design spec
|
|
3629
3788
|
* docs/superpowers/specs/2026-05-20-docker-install-from-npm-design.md.
|
|
3630
3789
|
*/
|
|
3790
|
+
/**
|
|
3791
|
+
* Is `packageName` reachable through normal resolution — i.e. does the
|
|
3792
|
+
* running closure already provide it?
|
|
3793
|
+
*
|
|
3794
|
+
* Overridable via `AddonInstallerConfig.isPackageResolvable` so a spec can
|
|
3795
|
+
* exercise BOTH sides. That matters more than it looks: the branch that
|
|
3796
|
+
* still seeds is the one protecting a fresh deployment from an unbootable
|
|
3797
|
+
* node, and it is unreachable in a test process where `@camstack/system`
|
|
3798
|
+
* always resolves.
|
|
3799
|
+
*/
|
|
3800
|
+
isResolvableFromClosure(packageName) {
|
|
3801
|
+
if (this.isPackageResolvable) return this.isPackageResolvable(packageName);
|
|
3802
|
+
try {
|
|
3803
|
+
__require.resolve(`${packageName}/package.json`);
|
|
3804
|
+
return true;
|
|
3805
|
+
} catch {
|
|
3806
|
+
return false;
|
|
3807
|
+
}
|
|
3808
|
+
}
|
|
3631
3809
|
static deriveBootstrapList(metaPackageName) {
|
|
3632
3810
|
const pkgJsonId = `${metaPackageName}/package.json`;
|
|
3633
3811
|
let pkgPath;
|
|
@@ -3710,6 +3888,10 @@ var AddonInstaller = class AddonInstaller {
|
|
|
3710
3888
|
this.logger.debug(`${packageName} — already installed, skipping`);
|
|
3711
3889
|
continue;
|
|
3712
3890
|
}
|
|
3891
|
+
if (shouldSkipClosureProvidedSeed(packageName, this.isResolvableFromClosure(packageName))) {
|
|
3892
|
+
this.logger.info(`${packageName} — provided by the server closure, not seeding a copy that would shadow it`);
|
|
3893
|
+
continue;
|
|
3894
|
+
}
|
|
3713
3895
|
try {
|
|
3714
3896
|
if (isLocal) {
|
|
3715
3897
|
const pkgDir = this.findLocalPackage(packageName);
|