@camstack/addon-remote-storage 1.1.12 → 1.1.14
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/s3.addon.js +1 -1
- package/dist/s3.addon.mjs +1 -1
- package/dist/sftp.addon.js +1 -1
- package/dist/sftp.addon.mjs +1 -1
- package/dist/{shared-fV3ZB0lu.mjs → shared-D9u4CXu8.mjs} +247 -17
- package/dist/{shared-BpumIDGo.js → shared-N5OfEciV.js} +247 -17
- package/dist/webdav.addon.js +1 -1
- package/dist/webdav.addon.mjs +1 -1
- package/package.json +10 -1
package/dist/s3.addon.js
CHANGED
|
@@ -2,7 +2,7 @@ Object.defineProperties(exports, {
|
|
|
2
2
|
__esModule: { value: true },
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
|
-
const require_shared = require("./shared-
|
|
5
|
+
const require_shared = require("./shared-N5OfEciV.js");
|
|
6
6
|
let node_stream = require("node:stream");
|
|
7
7
|
let _aws_sdk_client_s3 = require("@aws-sdk/client-s3");
|
|
8
8
|
let _aws_sdk_lib_storage = require("@aws-sdk/lib-storage");
|
package/dist/s3.addon.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { c as BaseAddon, i as rearmIdleAbort, n as getOptionalBasePath, o as scheduleIdleAbort, s as storageProviderCapability, t as createSessionId } from "./shared-
|
|
1
|
+
import { c as BaseAddon, i as rearmIdleAbort, n as getOptionalBasePath, o as scheduleIdleAbort, s as storageProviderCapability, t as createSessionId } from "./shared-D9u4CXu8.mjs";
|
|
2
2
|
import { PassThrough } from "node:stream";
|
|
3
3
|
import { DeleteObjectCommand, GetObjectCommand, HeadBucketCommand, HeadObjectCommand, ListObjectsV2Command, PutObjectCommand, S3Client } from "@aws-sdk/client-s3";
|
|
4
4
|
import { Upload } from "@aws-sdk/lib-storage";
|
package/dist/sftp.addon.js
CHANGED
|
@@ -2,7 +2,7 @@ Object.defineProperties(exports, {
|
|
|
2
2
|
__esModule: { value: true },
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
|
-
const require_shared = require("./shared-
|
|
5
|
+
const require_shared = require("./shared-N5OfEciV.js");
|
|
6
6
|
let ssh2 = require("ssh2");
|
|
7
7
|
let node_path = require("node:path");
|
|
8
8
|
node_path = require_shared.__toESM(node_path);
|
package/dist/sftp.addon.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as safeJoinRemotePath, c as BaseAddon, i as rearmIdleAbort, o as scheduleIdleAbort, r as getRequiredBasePath, s as storageProviderCapability, t as createSessionId } from "./shared-
|
|
1
|
+
import { a as safeJoinRemotePath, c as BaseAddon, i as rearmIdleAbort, o as scheduleIdleAbort, r as getRequiredBasePath, s as storageProviderCapability, t as createSessionId } from "./shared-D9u4CXu8.mjs";
|
|
2
2
|
import { Client } from "ssh2";
|
|
3
3
|
import * as path from "node:path";
|
|
4
4
|
//#region src/providers/sftp/sftp-config-schema.ts
|
|
@@ -4629,7 +4629,7 @@ function _instanceof(cls, params = {}) {
|
|
|
4629
4629
|
return inst;
|
|
4630
4630
|
}
|
|
4631
4631
|
//#endregion
|
|
4632
|
-
//#region ../types/dist/sleep-
|
|
4632
|
+
//#region ../types/dist/sleep-MHm--th-.mjs
|
|
4633
4633
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
4634
4634
|
EventCategory["SystemBoot"] = "system.boot";
|
|
4635
4635
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -5891,6 +5891,7 @@ var CamStreamKindSchema = _enum([
|
|
|
5891
5891
|
"pull-rtsp",
|
|
5892
5892
|
"pull-rtmp",
|
|
5893
5893
|
"pull-http",
|
|
5894
|
+
"pull-flv",
|
|
5894
5895
|
"pull-rfc4571",
|
|
5895
5896
|
"push-annexb",
|
|
5896
5897
|
"derived"
|
|
@@ -7034,7 +7035,21 @@ var StorageLocationDeclarationSchema = object({
|
|
|
7034
7035
|
* slots (e.g. `recordingsLow` → `recordings`) so operators only need to
|
|
7035
7036
|
* configure the primary location.
|
|
7036
7037
|
*/
|
|
7037
|
-
defaultsTo: string().optional()
|
|
7038
|
+
defaultsTo: string().optional(),
|
|
7039
|
+
/**
|
|
7040
|
+
* Which node root the seeded `<id>:default` instance is placed under on a
|
|
7041
|
+
* FRESH install:
|
|
7042
|
+
* - `'data'` (default) — the node's data dir (`CAMSTACK_DATA` / boot dir),
|
|
7043
|
+
* the appData volume. Right for small/durable data (backups, logs, models).
|
|
7044
|
+
* - `'media'` — the dedicated media volume (`CAMSTACK_MEDIA_ROOT`) when that
|
|
7045
|
+
* env is set, else falls back to the data root. Right for bulky, hot media
|
|
7046
|
+
* (recordings, event media) that should stay off the appData disk.
|
|
7047
|
+
*
|
|
7048
|
+
* Only affects the seeded default's `basePath`; operators can repoint any
|
|
7049
|
+
* location afterwards, and a `defaultsTo` slot inherits its parent's root
|
|
7050
|
+
* regardless of this field. Absent (the common case) is treated as `'data'`.
|
|
7051
|
+
*/
|
|
7052
|
+
defaultRoot: _enum(["data", "media"]).optional()
|
|
7038
7053
|
});
|
|
7039
7054
|
var DecoderStatsSchema = object({
|
|
7040
7055
|
inputFps: number(),
|
|
@@ -7881,6 +7896,10 @@ var RtspRestreamEntrySchema = object({
|
|
|
7881
7896
|
var BrokerRtspClientSchema = object({
|
|
7882
7897
|
sessionId: string(),
|
|
7883
7898
|
remoteAddr: string(),
|
|
7899
|
+
/** Client `User-Agent` (e.g. `recorder` for the recorder's RTSP pull), or
|
|
7900
|
+
* null/absent when the client sent none. Lets the UI label a consumer by
|
|
7901
|
+
* purpose. Optional so a client built against an older schema stays valid. */
|
|
7902
|
+
userAgent: string().nullish(),
|
|
7884
7903
|
playing: boolean(),
|
|
7885
7904
|
muted: boolean(),
|
|
7886
7905
|
connectedAt: number(),
|
|
@@ -13170,7 +13189,7 @@ var AddBrokerInputSchema = object({
|
|
|
13170
13189
|
});
|
|
13171
13190
|
var AddBrokerResultSchema = object({ id: string() });
|
|
13172
13191
|
var IdInputSchema = object({ id: string() });
|
|
13173
|
-
var TestResultSchema = discriminatedUnion("ok", [object({
|
|
13192
|
+
var TestResultSchema$1 = discriminatedUnion("ok", [object({
|
|
13174
13193
|
ok: literal(true),
|
|
13175
13194
|
latencyMs: number()
|
|
13176
13195
|
}), object({
|
|
@@ -13193,7 +13212,7 @@ var StatusSchema = object({
|
|
|
13193
13212
|
brokerCount: number(),
|
|
13194
13213
|
embeddedRunning: boolean()
|
|
13195
13214
|
});
|
|
13196
|
-
method(_void(), array(BrokerInfoSchema)), method(IdInputSchema, BrokerConnectionDetailsSchema), method(AddBrokerInputSchema, AddBrokerResultSchema, { kind: "mutation" }), method(IdInputSchema, _void(), { kind: "mutation" }), method(IdInputSchema, TestResultSchema, { kind: "mutation" }), method(StartEmbeddedInputSchema, StartEmbeddedResultSchema, { kind: "mutation" }), method(IdInputSchema, _void(), { kind: "mutation" }), method(_void(), StatusSchema);
|
|
13215
|
+
method(_void(), array(BrokerInfoSchema)), method(IdInputSchema, BrokerConnectionDetailsSchema), method(AddBrokerInputSchema, AddBrokerResultSchema, { kind: "mutation" }), method(IdInputSchema, _void(), { kind: "mutation" }), method(IdInputSchema, TestResultSchema$1, { kind: "mutation" }), method(StartEmbeddedInputSchema, StartEmbeddedResultSchema, { kind: "mutation" }), method(IdInputSchema, _void(), { kind: "mutation" }), method(_void(), StatusSchema);
|
|
13197
13216
|
var NetworkEndpointSchema = object({
|
|
13198
13217
|
url: string(),
|
|
13199
13218
|
hostname: string(),
|
|
@@ -13227,23 +13246,198 @@ var NetworkEndpointEntrySchema = NetworkEndpointSchema.extend({
|
|
|
13227
13246
|
sourcePort: number().optional()
|
|
13228
13247
|
});
|
|
13229
13248
|
method(_void(), NetworkEndpointSchema, { kind: "mutation" }), method(_void(), _void(), { kind: "mutation" }), method(_void(), NetworkEndpointSchema.nullable()), method(_void(), NetworkAccessStatusSchema), method(_void(), array(NetworkEndpointEntrySchema).readonly());
|
|
13230
|
-
|
|
13231
|
-
|
|
13249
|
+
/**
|
|
13250
|
+
* notification-output — canonical, capability-gated notification delivery.
|
|
13251
|
+
*
|
|
13252
|
+
* Apprise-derived model (see
|
|
13253
|
+
* `docs/superpowers/specs/2026-07-03-notification-output-notifier-matrix.md`):
|
|
13254
|
+
* callers emit ONE canonical `Notification`; each provider declares a
|
|
13255
|
+
* per-kind capability descriptor (`TargetKind`), and the pure degrade
|
|
13256
|
+
* engine (`@camstack/types` `prepareNotification`) transcodes / degrades the
|
|
13257
|
+
* message to what the kind supports — callers never special-case a service.
|
|
13258
|
+
*
|
|
13259
|
+
* DESIGN DECISIONS (locked):
|
|
13260
|
+
* - Target CRUD lives on THIS cap (`upsertTarget` / `deleteTarget` /
|
|
13261
|
+
* `setTargetEnabled`), each provider persisting via the `settings-store`
|
|
13262
|
+
* cap. Rationale: the admin UI needs one uniform surface across the
|
|
13263
|
+
* notifiers addon AND the HA addon; the addon-`globalSettingsSchema`-array
|
|
13264
|
+
* alternative would fork the UI per addon and cannot host the
|
|
13265
|
+
* discovery→adopt flow.
|
|
13266
|
+
* - `listTargetKinds` / `listTargets` / `discoverTargets` return arrays →
|
|
13267
|
+
* the generated cap-mount auto-`concatCollection`-fans them across every
|
|
13268
|
+
* registered provider (notifiers addon + HA addon) so one catalog is
|
|
13269
|
+
* routable. `send` / `testTarget` / CRUD route to ONE provider by the
|
|
13270
|
+
* `addonId` the generated collection router extracts from the call input.
|
|
13271
|
+
* - `Attachment.bytes` is `Uint8Array`. Transport-safe: superjson (the tRPC
|
|
13272
|
+
* transformer) + UDS MsgPack both round-trip typed arrays — already used by
|
|
13273
|
+
* `storage` / `storage-provider` / `recording` caps over the same path. No
|
|
13274
|
+
* base64 fallback needed.
|
|
13275
|
+
*
|
|
13276
|
+
* TODO (deferred, closed-set change — separate decision): add
|
|
13277
|
+
* `providerKind: 'notify'` so notification providers surface on the unified
|
|
13278
|
+
* admin "Integrations" page.
|
|
13279
|
+
*/
|
|
13280
|
+
/**
|
|
13281
|
+
* Zentik-derived typed-media enum — the superset across every kind. Each
|
|
13282
|
+
* adapter picks what it supports and the degrade engine filters the rest.
|
|
13283
|
+
*/
|
|
13284
|
+
var AttachmentMediaTypeSchema = _enum([
|
|
13285
|
+
"image",
|
|
13286
|
+
"video",
|
|
13287
|
+
"gif",
|
|
13288
|
+
"audio",
|
|
13289
|
+
"icon"
|
|
13290
|
+
]);
|
|
13291
|
+
/**
|
|
13292
|
+
* A single attachment. Exactly one of `url` (remote source, most adapters
|
|
13293
|
+
* prefer this) or `bytes` (inline source; required for Pushover-style
|
|
13294
|
+
* bytes-only kinds) MUST be present — the degrade engine expresses a
|
|
13295
|
+
* url→bytes fetch as a `needsFetch` directive the adapter executes.
|
|
13296
|
+
*/
|
|
13297
|
+
var AttachmentSchema = object({
|
|
13298
|
+
mediaType: AttachmentMediaTypeSchema,
|
|
13299
|
+
url: string().optional(),
|
|
13300
|
+
bytes: _instanceof(Uint8Array).optional(),
|
|
13301
|
+
mime: string().optional(),
|
|
13302
|
+
name: string().optional()
|
|
13303
|
+
}).refine((a) => a.url !== void 0 || a.bytes !== void 0, { message: "Attachment requires either `url` or `bytes`" });
|
|
13304
|
+
var NotificationFormatSchema = _enum([
|
|
13305
|
+
"text",
|
|
13306
|
+
"markdown",
|
|
13307
|
+
"html"
|
|
13308
|
+
]);
|
|
13309
|
+
/** A single tap-through action button. */
|
|
13310
|
+
var NotificationActionSchema = object({
|
|
13311
|
+
id: string(),
|
|
13312
|
+
label: string(),
|
|
13313
|
+
url: string().optional()
|
|
13314
|
+
});
|
|
13315
|
+
/**
|
|
13316
|
+
* The canonical notification. `body` is the only hard field (Apprise model).
|
|
13317
|
+
* `priority` is a 5-level ORDINAL (1=lowest … 3=normal(default) … 5=urgent),
|
|
13318
|
+
* NOT a fixed severity enum — each kind declares its own `caps.levels` and
|
|
13319
|
+
* the adapter maps this ordinal onto its native level. `level?` is an
|
|
13320
|
+
* optional kind-native level id (`emergency`, `silent`, …) that overrides
|
|
13321
|
+
* `priority` for that one target.
|
|
13322
|
+
*/
|
|
13323
|
+
var NotificationSchema = object({
|
|
13232
13324
|
body: string(),
|
|
13233
|
-
|
|
13325
|
+
title: string().optional(),
|
|
13326
|
+
format: NotificationFormatSchema.default("text"),
|
|
13327
|
+
priority: number().int().min(1).max(5).default(3),
|
|
13328
|
+
level: string().optional(),
|
|
13329
|
+
attachments: array(AttachmentSchema).optional(),
|
|
13330
|
+
clickUrl: string().optional(),
|
|
13331
|
+
actions: array(NotificationActionSchema).optional(),
|
|
13332
|
+
sound: string().optional(),
|
|
13333
|
+
ttl: number().optional(),
|
|
13334
|
+
tag: string().optional(),
|
|
13234
13335
|
deviceId: number().optional(),
|
|
13235
13336
|
eventId: string().optional(),
|
|
13236
|
-
priority: _enum([
|
|
13237
|
-
"low",
|
|
13238
|
-
"normal",
|
|
13239
|
-
"high",
|
|
13240
|
-
"critical"
|
|
13241
|
-
]).default("normal"),
|
|
13242
13337
|
metadata: record(string(), unknown()).optional()
|
|
13243
|
-
})
|
|
13338
|
+
});
|
|
13339
|
+
/** One declared native severity/priority level for a kind. */
|
|
13340
|
+
var TargetKindLevelSchema = object({
|
|
13341
|
+
id: string(),
|
|
13342
|
+
label: string(),
|
|
13343
|
+
/** Which canonical priority (1..5) this level maps to. `null` = qualitative-only. */
|
|
13344
|
+
ordinal: number().int().min(1).max(5).nullable(),
|
|
13345
|
+
flags: object({
|
|
13346
|
+
critical: boolean().optional(),
|
|
13347
|
+
silent: boolean().optional(),
|
|
13348
|
+
noPush: boolean().optional()
|
|
13349
|
+
}).optional(),
|
|
13350
|
+
/** e.g. Pushover `emergency` requires `retry` / `expire`. */
|
|
13351
|
+
requires: array(string()).optional(),
|
|
13352
|
+
description: string().optional()
|
|
13353
|
+
});
|
|
13354
|
+
/** The full capability block consulted before dispatch. */
|
|
13355
|
+
var TargetKindCapsSchema = object({
|
|
13356
|
+
attachments: object({
|
|
13357
|
+
mediaTypes: array(AttachmentMediaTypeSchema),
|
|
13358
|
+
mode: _enum([
|
|
13359
|
+
"url",
|
|
13360
|
+
"bytes",
|
|
13361
|
+
"both"
|
|
13362
|
+
]),
|
|
13363
|
+
max: number().int().nonnegative(),
|
|
13364
|
+
maxBytes: number().int().positive().optional()
|
|
13365
|
+
}),
|
|
13366
|
+
/** Max action buttons (0 = none). */
|
|
13367
|
+
actions: number().int().nonnegative(),
|
|
13368
|
+
levels: array(TargetKindLevelSchema),
|
|
13369
|
+
format: array(NotificationFormatSchema),
|
|
13370
|
+
clickUrl: boolean(),
|
|
13371
|
+
sound: boolean(),
|
|
13372
|
+
ttl: boolean(),
|
|
13373
|
+
bodyMaxLen: number().int().positive()
|
|
13374
|
+
});
|
|
13375
|
+
/**
|
|
13376
|
+
* `configSchema` is a `ConfigUISchema` tree passed through to the admin
|
|
13377
|
+
* FormBuilder. Stored as `z.unknown()` at the cap seam (mirrors
|
|
13378
|
+
* `device-provider.getChildCreationSchema` `CreationSchemaOutputSchema`) —
|
|
13379
|
+
* the union is large and not meant for runtime validation here; the exported
|
|
13380
|
+
* `TargetKind` type re-tightens `configSchema` to `ConfigUISchema`.
|
|
13381
|
+
*/
|
|
13382
|
+
var ConfigSchemaPassthrough = unknown();
|
|
13383
|
+
var TargetKindSchema = object({
|
|
13384
|
+
kind: string(),
|
|
13385
|
+
label: string(),
|
|
13386
|
+
icon: string(),
|
|
13387
|
+
/** Stamped by each provider so the concat-fanned catalog stays routable. */
|
|
13388
|
+
addonId: string(),
|
|
13389
|
+
configSchema: ConfigSchemaPassthrough,
|
|
13390
|
+
supportsDiscovery: boolean(),
|
|
13391
|
+
caps: TargetKindCapsSchema
|
|
13392
|
+
});
|
|
13393
|
+
/**
|
|
13394
|
+
* A persisted target. `config` holds secrets; providers REDACT secret fields
|
|
13395
|
+
* (return a presence marker only) when serving `listTargets` — never
|
|
13396
|
+
* round-trip a stored secret to the UI.
|
|
13397
|
+
*/
|
|
13398
|
+
var TargetSchema = object({
|
|
13399
|
+
id: string(),
|
|
13400
|
+
name: string(),
|
|
13401
|
+
kind: string(),
|
|
13402
|
+
addonId: string(),
|
|
13403
|
+
enabled: boolean(),
|
|
13404
|
+
config: record(string(), unknown())
|
|
13405
|
+
});
|
|
13406
|
+
/** A discovery-surfaced candidate (config is partial + non-secret). */
|
|
13407
|
+
var DiscoveredTargetSchema = object({
|
|
13408
|
+
kind: string(),
|
|
13409
|
+
suggestedName: string(),
|
|
13410
|
+
config: record(string(), unknown())
|
|
13411
|
+
});
|
|
13412
|
+
/** The degrade engine's report — what was resolved / dropped / degraded. */
|
|
13413
|
+
var RenderedAsSchema = object({
|
|
13414
|
+
level: string(),
|
|
13415
|
+
format: NotificationFormatSchema,
|
|
13416
|
+
attachmentsSent: number().int().nonnegative(),
|
|
13417
|
+
actionsSent: number().int().nonnegative(),
|
|
13418
|
+
truncated: boolean(),
|
|
13419
|
+
dropped: array(string())
|
|
13420
|
+
});
|
|
13421
|
+
var SendResultSchema = object({
|
|
13244
13422
|
success: boolean(),
|
|
13245
|
-
error: string().optional()
|
|
13246
|
-
|
|
13423
|
+
error: string().optional(),
|
|
13424
|
+
renderedAs: RenderedAsSchema.optional()
|
|
13425
|
+
});
|
|
13426
|
+
/** Same shape as SendResult — kept as a distinct name for the test panel. */
|
|
13427
|
+
var TestResultSchema = SendResultSchema;
|
|
13428
|
+
method(object({}), array(TargetKindSchema)), method(object({}), array(TargetSchema)), method(object({
|
|
13429
|
+
kind: string(),
|
|
13430
|
+
config: record(string(), unknown()).optional()
|
|
13431
|
+
}), array(DiscoveredTargetSchema)), method(object({
|
|
13432
|
+
targetId: string(),
|
|
13433
|
+
notification: NotificationSchema
|
|
13434
|
+
}), SendResultSchema, { kind: "mutation" }), method(object({
|
|
13435
|
+
targetId: string(),
|
|
13436
|
+
sample: NotificationSchema.optional()
|
|
13437
|
+
}), TestResultSchema, { kind: "mutation" }), method(object({ target: TargetSchema }), TargetSchema, { kind: "mutation" }), method(object({ targetId: string() }), _void(), { kind: "mutation" }), method(object({
|
|
13438
|
+
targetId: string(),
|
|
13439
|
+
enabled: boolean()
|
|
13440
|
+
}), _void(), { kind: "mutation" });
|
|
13247
13441
|
/**
|
|
13248
13442
|
* Zod schemas for persisted record types.
|
|
13249
13443
|
*
|
|
@@ -19283,13 +19477,49 @@ Object.freeze({
|
|
|
19283
19477
|
addonId: null,
|
|
19284
19478
|
access: "create"
|
|
19285
19479
|
},
|
|
19480
|
+
"notificationOutput.deleteTarget": {
|
|
19481
|
+
capName: "notification-output",
|
|
19482
|
+
capScope: "system",
|
|
19483
|
+
addonId: null,
|
|
19484
|
+
access: "delete"
|
|
19485
|
+
},
|
|
19486
|
+
"notificationOutput.discoverTargets": {
|
|
19487
|
+
capName: "notification-output",
|
|
19488
|
+
capScope: "system",
|
|
19489
|
+
addonId: null,
|
|
19490
|
+
access: "view"
|
|
19491
|
+
},
|
|
19492
|
+
"notificationOutput.listTargetKinds": {
|
|
19493
|
+
capName: "notification-output",
|
|
19494
|
+
capScope: "system",
|
|
19495
|
+
addonId: null,
|
|
19496
|
+
access: "view"
|
|
19497
|
+
},
|
|
19498
|
+
"notificationOutput.listTargets": {
|
|
19499
|
+
capName: "notification-output",
|
|
19500
|
+
capScope: "system",
|
|
19501
|
+
addonId: null,
|
|
19502
|
+
access: "view"
|
|
19503
|
+
},
|
|
19286
19504
|
"notificationOutput.send": {
|
|
19287
19505
|
capName: "notification-output",
|
|
19288
19506
|
capScope: "system",
|
|
19289
19507
|
addonId: null,
|
|
19290
19508
|
access: "create"
|
|
19291
19509
|
},
|
|
19292
|
-
"notificationOutput.
|
|
19510
|
+
"notificationOutput.setTargetEnabled": {
|
|
19511
|
+
capName: "notification-output",
|
|
19512
|
+
capScope: "system",
|
|
19513
|
+
addonId: null,
|
|
19514
|
+
access: "create"
|
|
19515
|
+
},
|
|
19516
|
+
"notificationOutput.testTarget": {
|
|
19517
|
+
capName: "notification-output",
|
|
19518
|
+
capScope: "system",
|
|
19519
|
+
addonId: null,
|
|
19520
|
+
access: "create"
|
|
19521
|
+
},
|
|
19522
|
+
"notificationOutput.upsertTarget": {
|
|
19293
19523
|
capName: "notification-output",
|
|
19294
19524
|
capScope: "system",
|
|
19295
19525
|
addonId: null,
|
|
@@ -4652,7 +4652,7 @@ function _instanceof(cls, params = {}) {
|
|
|
4652
4652
|
return inst;
|
|
4653
4653
|
}
|
|
4654
4654
|
//#endregion
|
|
4655
|
-
//#region ../types/dist/sleep-
|
|
4655
|
+
//#region ../types/dist/sleep-MHm--th-.mjs
|
|
4656
4656
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
4657
4657
|
EventCategory["SystemBoot"] = "system.boot";
|
|
4658
4658
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -5914,6 +5914,7 @@ var CamStreamKindSchema = _enum([
|
|
|
5914
5914
|
"pull-rtsp",
|
|
5915
5915
|
"pull-rtmp",
|
|
5916
5916
|
"pull-http",
|
|
5917
|
+
"pull-flv",
|
|
5917
5918
|
"pull-rfc4571",
|
|
5918
5919
|
"push-annexb",
|
|
5919
5920
|
"derived"
|
|
@@ -7057,7 +7058,21 @@ var StorageLocationDeclarationSchema = object({
|
|
|
7057
7058
|
* slots (e.g. `recordingsLow` → `recordings`) so operators only need to
|
|
7058
7059
|
* configure the primary location.
|
|
7059
7060
|
*/
|
|
7060
|
-
defaultsTo: string().optional()
|
|
7061
|
+
defaultsTo: string().optional(),
|
|
7062
|
+
/**
|
|
7063
|
+
* Which node root the seeded `<id>:default` instance is placed under on a
|
|
7064
|
+
* FRESH install:
|
|
7065
|
+
* - `'data'` (default) — the node's data dir (`CAMSTACK_DATA` / boot dir),
|
|
7066
|
+
* the appData volume. Right for small/durable data (backups, logs, models).
|
|
7067
|
+
* - `'media'` — the dedicated media volume (`CAMSTACK_MEDIA_ROOT`) when that
|
|
7068
|
+
* env is set, else falls back to the data root. Right for bulky, hot media
|
|
7069
|
+
* (recordings, event media) that should stay off the appData disk.
|
|
7070
|
+
*
|
|
7071
|
+
* Only affects the seeded default's `basePath`; operators can repoint any
|
|
7072
|
+
* location afterwards, and a `defaultsTo` slot inherits its parent's root
|
|
7073
|
+
* regardless of this field. Absent (the common case) is treated as `'data'`.
|
|
7074
|
+
*/
|
|
7075
|
+
defaultRoot: _enum(["data", "media"]).optional()
|
|
7061
7076
|
});
|
|
7062
7077
|
var DecoderStatsSchema = object({
|
|
7063
7078
|
inputFps: number(),
|
|
@@ -7904,6 +7919,10 @@ var RtspRestreamEntrySchema = object({
|
|
|
7904
7919
|
var BrokerRtspClientSchema = object({
|
|
7905
7920
|
sessionId: string(),
|
|
7906
7921
|
remoteAddr: string(),
|
|
7922
|
+
/** Client `User-Agent` (e.g. `recorder` for the recorder's RTSP pull), or
|
|
7923
|
+
* null/absent when the client sent none. Lets the UI label a consumer by
|
|
7924
|
+
* purpose. Optional so a client built against an older schema stays valid. */
|
|
7925
|
+
userAgent: string().nullish(),
|
|
7907
7926
|
playing: boolean(),
|
|
7908
7927
|
muted: boolean(),
|
|
7909
7928
|
connectedAt: number(),
|
|
@@ -13193,7 +13212,7 @@ var AddBrokerInputSchema = object({
|
|
|
13193
13212
|
});
|
|
13194
13213
|
var AddBrokerResultSchema = object({ id: string() });
|
|
13195
13214
|
var IdInputSchema = object({ id: string() });
|
|
13196
|
-
var TestResultSchema = discriminatedUnion("ok", [object({
|
|
13215
|
+
var TestResultSchema$1 = discriminatedUnion("ok", [object({
|
|
13197
13216
|
ok: literal(true),
|
|
13198
13217
|
latencyMs: number()
|
|
13199
13218
|
}), object({
|
|
@@ -13216,7 +13235,7 @@ var StatusSchema = object({
|
|
|
13216
13235
|
brokerCount: number(),
|
|
13217
13236
|
embeddedRunning: boolean()
|
|
13218
13237
|
});
|
|
13219
|
-
method(_void(), array(BrokerInfoSchema)), method(IdInputSchema, BrokerConnectionDetailsSchema), method(AddBrokerInputSchema, AddBrokerResultSchema, { kind: "mutation" }), method(IdInputSchema, _void(), { kind: "mutation" }), method(IdInputSchema, TestResultSchema, { kind: "mutation" }), method(StartEmbeddedInputSchema, StartEmbeddedResultSchema, { kind: "mutation" }), method(IdInputSchema, _void(), { kind: "mutation" }), method(_void(), StatusSchema);
|
|
13238
|
+
method(_void(), array(BrokerInfoSchema)), method(IdInputSchema, BrokerConnectionDetailsSchema), method(AddBrokerInputSchema, AddBrokerResultSchema, { kind: "mutation" }), method(IdInputSchema, _void(), { kind: "mutation" }), method(IdInputSchema, TestResultSchema$1, { kind: "mutation" }), method(StartEmbeddedInputSchema, StartEmbeddedResultSchema, { kind: "mutation" }), method(IdInputSchema, _void(), { kind: "mutation" }), method(_void(), StatusSchema);
|
|
13220
13239
|
var NetworkEndpointSchema = object({
|
|
13221
13240
|
url: string(),
|
|
13222
13241
|
hostname: string(),
|
|
@@ -13250,23 +13269,198 @@ var NetworkEndpointEntrySchema = NetworkEndpointSchema.extend({
|
|
|
13250
13269
|
sourcePort: number().optional()
|
|
13251
13270
|
});
|
|
13252
13271
|
method(_void(), NetworkEndpointSchema, { kind: "mutation" }), method(_void(), _void(), { kind: "mutation" }), method(_void(), NetworkEndpointSchema.nullable()), method(_void(), NetworkAccessStatusSchema), method(_void(), array(NetworkEndpointEntrySchema).readonly());
|
|
13253
|
-
|
|
13254
|
-
|
|
13272
|
+
/**
|
|
13273
|
+
* notification-output — canonical, capability-gated notification delivery.
|
|
13274
|
+
*
|
|
13275
|
+
* Apprise-derived model (see
|
|
13276
|
+
* `docs/superpowers/specs/2026-07-03-notification-output-notifier-matrix.md`):
|
|
13277
|
+
* callers emit ONE canonical `Notification`; each provider declares a
|
|
13278
|
+
* per-kind capability descriptor (`TargetKind`), and the pure degrade
|
|
13279
|
+
* engine (`@camstack/types` `prepareNotification`) transcodes / degrades the
|
|
13280
|
+
* message to what the kind supports — callers never special-case a service.
|
|
13281
|
+
*
|
|
13282
|
+
* DESIGN DECISIONS (locked):
|
|
13283
|
+
* - Target CRUD lives on THIS cap (`upsertTarget` / `deleteTarget` /
|
|
13284
|
+
* `setTargetEnabled`), each provider persisting via the `settings-store`
|
|
13285
|
+
* cap. Rationale: the admin UI needs one uniform surface across the
|
|
13286
|
+
* notifiers addon AND the HA addon; the addon-`globalSettingsSchema`-array
|
|
13287
|
+
* alternative would fork the UI per addon and cannot host the
|
|
13288
|
+
* discovery→adopt flow.
|
|
13289
|
+
* - `listTargetKinds` / `listTargets` / `discoverTargets` return arrays →
|
|
13290
|
+
* the generated cap-mount auto-`concatCollection`-fans them across every
|
|
13291
|
+
* registered provider (notifiers addon + HA addon) so one catalog is
|
|
13292
|
+
* routable. `send` / `testTarget` / CRUD route to ONE provider by the
|
|
13293
|
+
* `addonId` the generated collection router extracts from the call input.
|
|
13294
|
+
* - `Attachment.bytes` is `Uint8Array`. Transport-safe: superjson (the tRPC
|
|
13295
|
+
* transformer) + UDS MsgPack both round-trip typed arrays — already used by
|
|
13296
|
+
* `storage` / `storage-provider` / `recording` caps over the same path. No
|
|
13297
|
+
* base64 fallback needed.
|
|
13298
|
+
*
|
|
13299
|
+
* TODO (deferred, closed-set change — separate decision): add
|
|
13300
|
+
* `providerKind: 'notify'` so notification providers surface on the unified
|
|
13301
|
+
* admin "Integrations" page.
|
|
13302
|
+
*/
|
|
13303
|
+
/**
|
|
13304
|
+
* Zentik-derived typed-media enum — the superset across every kind. Each
|
|
13305
|
+
* adapter picks what it supports and the degrade engine filters the rest.
|
|
13306
|
+
*/
|
|
13307
|
+
var AttachmentMediaTypeSchema = _enum([
|
|
13308
|
+
"image",
|
|
13309
|
+
"video",
|
|
13310
|
+
"gif",
|
|
13311
|
+
"audio",
|
|
13312
|
+
"icon"
|
|
13313
|
+
]);
|
|
13314
|
+
/**
|
|
13315
|
+
* A single attachment. Exactly one of `url` (remote source, most adapters
|
|
13316
|
+
* prefer this) or `bytes` (inline source; required for Pushover-style
|
|
13317
|
+
* bytes-only kinds) MUST be present — the degrade engine expresses a
|
|
13318
|
+
* url→bytes fetch as a `needsFetch` directive the adapter executes.
|
|
13319
|
+
*/
|
|
13320
|
+
var AttachmentSchema = object({
|
|
13321
|
+
mediaType: AttachmentMediaTypeSchema,
|
|
13322
|
+
url: string().optional(),
|
|
13323
|
+
bytes: _instanceof(Uint8Array).optional(),
|
|
13324
|
+
mime: string().optional(),
|
|
13325
|
+
name: string().optional()
|
|
13326
|
+
}).refine((a) => a.url !== void 0 || a.bytes !== void 0, { message: "Attachment requires either `url` or `bytes`" });
|
|
13327
|
+
var NotificationFormatSchema = _enum([
|
|
13328
|
+
"text",
|
|
13329
|
+
"markdown",
|
|
13330
|
+
"html"
|
|
13331
|
+
]);
|
|
13332
|
+
/** A single tap-through action button. */
|
|
13333
|
+
var NotificationActionSchema = object({
|
|
13334
|
+
id: string(),
|
|
13335
|
+
label: string(),
|
|
13336
|
+
url: string().optional()
|
|
13337
|
+
});
|
|
13338
|
+
/**
|
|
13339
|
+
* The canonical notification. `body` is the only hard field (Apprise model).
|
|
13340
|
+
* `priority` is a 5-level ORDINAL (1=lowest … 3=normal(default) … 5=urgent),
|
|
13341
|
+
* NOT a fixed severity enum — each kind declares its own `caps.levels` and
|
|
13342
|
+
* the adapter maps this ordinal onto its native level. `level?` is an
|
|
13343
|
+
* optional kind-native level id (`emergency`, `silent`, …) that overrides
|
|
13344
|
+
* `priority` for that one target.
|
|
13345
|
+
*/
|
|
13346
|
+
var NotificationSchema = object({
|
|
13255
13347
|
body: string(),
|
|
13256
|
-
|
|
13348
|
+
title: string().optional(),
|
|
13349
|
+
format: NotificationFormatSchema.default("text"),
|
|
13350
|
+
priority: number().int().min(1).max(5).default(3),
|
|
13351
|
+
level: string().optional(),
|
|
13352
|
+
attachments: array(AttachmentSchema).optional(),
|
|
13353
|
+
clickUrl: string().optional(),
|
|
13354
|
+
actions: array(NotificationActionSchema).optional(),
|
|
13355
|
+
sound: string().optional(),
|
|
13356
|
+
ttl: number().optional(),
|
|
13357
|
+
tag: string().optional(),
|
|
13257
13358
|
deviceId: number().optional(),
|
|
13258
13359
|
eventId: string().optional(),
|
|
13259
|
-
priority: _enum([
|
|
13260
|
-
"low",
|
|
13261
|
-
"normal",
|
|
13262
|
-
"high",
|
|
13263
|
-
"critical"
|
|
13264
|
-
]).default("normal"),
|
|
13265
13360
|
metadata: record(string(), unknown()).optional()
|
|
13266
|
-
})
|
|
13361
|
+
});
|
|
13362
|
+
/** One declared native severity/priority level for a kind. */
|
|
13363
|
+
var TargetKindLevelSchema = object({
|
|
13364
|
+
id: string(),
|
|
13365
|
+
label: string(),
|
|
13366
|
+
/** Which canonical priority (1..5) this level maps to. `null` = qualitative-only. */
|
|
13367
|
+
ordinal: number().int().min(1).max(5).nullable(),
|
|
13368
|
+
flags: object({
|
|
13369
|
+
critical: boolean().optional(),
|
|
13370
|
+
silent: boolean().optional(),
|
|
13371
|
+
noPush: boolean().optional()
|
|
13372
|
+
}).optional(),
|
|
13373
|
+
/** e.g. Pushover `emergency` requires `retry` / `expire`. */
|
|
13374
|
+
requires: array(string()).optional(),
|
|
13375
|
+
description: string().optional()
|
|
13376
|
+
});
|
|
13377
|
+
/** The full capability block consulted before dispatch. */
|
|
13378
|
+
var TargetKindCapsSchema = object({
|
|
13379
|
+
attachments: object({
|
|
13380
|
+
mediaTypes: array(AttachmentMediaTypeSchema),
|
|
13381
|
+
mode: _enum([
|
|
13382
|
+
"url",
|
|
13383
|
+
"bytes",
|
|
13384
|
+
"both"
|
|
13385
|
+
]),
|
|
13386
|
+
max: number().int().nonnegative(),
|
|
13387
|
+
maxBytes: number().int().positive().optional()
|
|
13388
|
+
}),
|
|
13389
|
+
/** Max action buttons (0 = none). */
|
|
13390
|
+
actions: number().int().nonnegative(),
|
|
13391
|
+
levels: array(TargetKindLevelSchema),
|
|
13392
|
+
format: array(NotificationFormatSchema),
|
|
13393
|
+
clickUrl: boolean(),
|
|
13394
|
+
sound: boolean(),
|
|
13395
|
+
ttl: boolean(),
|
|
13396
|
+
bodyMaxLen: number().int().positive()
|
|
13397
|
+
});
|
|
13398
|
+
/**
|
|
13399
|
+
* `configSchema` is a `ConfigUISchema` tree passed through to the admin
|
|
13400
|
+
* FormBuilder. Stored as `z.unknown()` at the cap seam (mirrors
|
|
13401
|
+
* `device-provider.getChildCreationSchema` `CreationSchemaOutputSchema`) —
|
|
13402
|
+
* the union is large and not meant for runtime validation here; the exported
|
|
13403
|
+
* `TargetKind` type re-tightens `configSchema` to `ConfigUISchema`.
|
|
13404
|
+
*/
|
|
13405
|
+
var ConfigSchemaPassthrough = unknown();
|
|
13406
|
+
var TargetKindSchema = object({
|
|
13407
|
+
kind: string(),
|
|
13408
|
+
label: string(),
|
|
13409
|
+
icon: string(),
|
|
13410
|
+
/** Stamped by each provider so the concat-fanned catalog stays routable. */
|
|
13411
|
+
addonId: string(),
|
|
13412
|
+
configSchema: ConfigSchemaPassthrough,
|
|
13413
|
+
supportsDiscovery: boolean(),
|
|
13414
|
+
caps: TargetKindCapsSchema
|
|
13415
|
+
});
|
|
13416
|
+
/**
|
|
13417
|
+
* A persisted target. `config` holds secrets; providers REDACT secret fields
|
|
13418
|
+
* (return a presence marker only) when serving `listTargets` — never
|
|
13419
|
+
* round-trip a stored secret to the UI.
|
|
13420
|
+
*/
|
|
13421
|
+
var TargetSchema = object({
|
|
13422
|
+
id: string(),
|
|
13423
|
+
name: string(),
|
|
13424
|
+
kind: string(),
|
|
13425
|
+
addonId: string(),
|
|
13426
|
+
enabled: boolean(),
|
|
13427
|
+
config: record(string(), unknown())
|
|
13428
|
+
});
|
|
13429
|
+
/** A discovery-surfaced candidate (config is partial + non-secret). */
|
|
13430
|
+
var DiscoveredTargetSchema = object({
|
|
13431
|
+
kind: string(),
|
|
13432
|
+
suggestedName: string(),
|
|
13433
|
+
config: record(string(), unknown())
|
|
13434
|
+
});
|
|
13435
|
+
/** The degrade engine's report — what was resolved / dropped / degraded. */
|
|
13436
|
+
var RenderedAsSchema = object({
|
|
13437
|
+
level: string(),
|
|
13438
|
+
format: NotificationFormatSchema,
|
|
13439
|
+
attachmentsSent: number().int().nonnegative(),
|
|
13440
|
+
actionsSent: number().int().nonnegative(),
|
|
13441
|
+
truncated: boolean(),
|
|
13442
|
+
dropped: array(string())
|
|
13443
|
+
});
|
|
13444
|
+
var SendResultSchema = object({
|
|
13267
13445
|
success: boolean(),
|
|
13268
|
-
error: string().optional()
|
|
13269
|
-
|
|
13446
|
+
error: string().optional(),
|
|
13447
|
+
renderedAs: RenderedAsSchema.optional()
|
|
13448
|
+
});
|
|
13449
|
+
/** Same shape as SendResult — kept as a distinct name for the test panel. */
|
|
13450
|
+
var TestResultSchema = SendResultSchema;
|
|
13451
|
+
method(object({}), array(TargetKindSchema)), method(object({}), array(TargetSchema)), method(object({
|
|
13452
|
+
kind: string(),
|
|
13453
|
+
config: record(string(), unknown()).optional()
|
|
13454
|
+
}), array(DiscoveredTargetSchema)), method(object({
|
|
13455
|
+
targetId: string(),
|
|
13456
|
+
notification: NotificationSchema
|
|
13457
|
+
}), SendResultSchema, { kind: "mutation" }), method(object({
|
|
13458
|
+
targetId: string(),
|
|
13459
|
+
sample: NotificationSchema.optional()
|
|
13460
|
+
}), TestResultSchema, { kind: "mutation" }), method(object({ target: TargetSchema }), TargetSchema, { kind: "mutation" }), method(object({ targetId: string() }), _void(), { kind: "mutation" }), method(object({
|
|
13461
|
+
targetId: string(),
|
|
13462
|
+
enabled: boolean()
|
|
13463
|
+
}), _void(), { kind: "mutation" });
|
|
13270
13464
|
/**
|
|
13271
13465
|
* Zod schemas for persisted record types.
|
|
13272
13466
|
*
|
|
@@ -19306,13 +19500,49 @@ Object.freeze({
|
|
|
19306
19500
|
addonId: null,
|
|
19307
19501
|
access: "create"
|
|
19308
19502
|
},
|
|
19503
|
+
"notificationOutput.deleteTarget": {
|
|
19504
|
+
capName: "notification-output",
|
|
19505
|
+
capScope: "system",
|
|
19506
|
+
addonId: null,
|
|
19507
|
+
access: "delete"
|
|
19508
|
+
},
|
|
19509
|
+
"notificationOutput.discoverTargets": {
|
|
19510
|
+
capName: "notification-output",
|
|
19511
|
+
capScope: "system",
|
|
19512
|
+
addonId: null,
|
|
19513
|
+
access: "view"
|
|
19514
|
+
},
|
|
19515
|
+
"notificationOutput.listTargetKinds": {
|
|
19516
|
+
capName: "notification-output",
|
|
19517
|
+
capScope: "system",
|
|
19518
|
+
addonId: null,
|
|
19519
|
+
access: "view"
|
|
19520
|
+
},
|
|
19521
|
+
"notificationOutput.listTargets": {
|
|
19522
|
+
capName: "notification-output",
|
|
19523
|
+
capScope: "system",
|
|
19524
|
+
addonId: null,
|
|
19525
|
+
access: "view"
|
|
19526
|
+
},
|
|
19309
19527
|
"notificationOutput.send": {
|
|
19310
19528
|
capName: "notification-output",
|
|
19311
19529
|
capScope: "system",
|
|
19312
19530
|
addonId: null,
|
|
19313
19531
|
access: "create"
|
|
19314
19532
|
},
|
|
19315
|
-
"notificationOutput.
|
|
19533
|
+
"notificationOutput.setTargetEnabled": {
|
|
19534
|
+
capName: "notification-output",
|
|
19535
|
+
capScope: "system",
|
|
19536
|
+
addonId: null,
|
|
19537
|
+
access: "create"
|
|
19538
|
+
},
|
|
19539
|
+
"notificationOutput.testTarget": {
|
|
19540
|
+
capName: "notification-output",
|
|
19541
|
+
capScope: "system",
|
|
19542
|
+
addonId: null,
|
|
19543
|
+
access: "create"
|
|
19544
|
+
},
|
|
19545
|
+
"notificationOutput.upsertTarget": {
|
|
19316
19546
|
capName: "notification-output",
|
|
19317
19547
|
capScope: "system",
|
|
19318
19548
|
addonId: null,
|
package/dist/webdav.addon.js
CHANGED
|
@@ -2,7 +2,7 @@ Object.defineProperties(exports, {
|
|
|
2
2
|
__esModule: { value: true },
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
|
-
const require_shared = require("./shared-
|
|
5
|
+
const require_shared = require("./shared-N5OfEciV.js");
|
|
6
6
|
let node_stream = require("node:stream");
|
|
7
7
|
let webdav = require("webdav");
|
|
8
8
|
//#region src/providers/webdav/webdav-config-schema.ts
|
package/dist/webdav.addon.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as safeJoinRemotePath, c as BaseAddon, i as rearmIdleAbort, o as scheduleIdleAbort, r as getRequiredBasePath, s as storageProviderCapability, t as createSessionId } from "./shared-
|
|
1
|
+
import { a as safeJoinRemotePath, c as BaseAddon, i as rearmIdleAbort, o as scheduleIdleAbort, r as getRequiredBasePath, s as storageProviderCapability, t as createSessionId } from "./shared-D9u4CXu8.mjs";
|
|
2
2
|
import { PassThrough } from "node:stream";
|
|
3
3
|
import { AuthType, createClient } from "webdav";
|
|
4
4
|
//#region src/providers/webdav/webdav-config-schema.ts
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@camstack/addon-remote-storage",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.14",
|
|
4
4
|
"description": "Remote storage providers (SFTP, S3, WebDAV) — unifies remote backends behind the storage-provider cap",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"camstack",
|
|
@@ -36,6 +36,9 @@
|
|
|
36
36
|
"addons": [
|
|
37
37
|
{
|
|
38
38
|
"id": "sftp-storage",
|
|
39
|
+
"execution": {
|
|
40
|
+
"group": "remote-storage"
|
|
41
|
+
},
|
|
39
42
|
"category": "system",
|
|
40
43
|
"name": "SFTP Storage",
|
|
41
44
|
"version": "0.1.1",
|
|
@@ -52,6 +55,9 @@
|
|
|
52
55
|
},
|
|
53
56
|
{
|
|
54
57
|
"id": "s3-storage",
|
|
58
|
+
"execution": {
|
|
59
|
+
"group": "remote-storage"
|
|
60
|
+
},
|
|
55
61
|
"category": "system",
|
|
56
62
|
"name": "S3 Storage",
|
|
57
63
|
"version": "0.1.1",
|
|
@@ -68,6 +74,9 @@
|
|
|
68
74
|
},
|
|
69
75
|
{
|
|
70
76
|
"id": "webdav-storage",
|
|
77
|
+
"execution": {
|
|
78
|
+
"group": "remote-storage"
|
|
79
|
+
},
|
|
71
80
|
"category": "system",
|
|
72
81
|
"name": "WebDAV Storage",
|
|
73
82
|
"version": "0.1.1",
|