@camstack/addon-waste-collections 0.1.36 → 0.1.37
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/dist/waste-collections.addon.js +113 -703
- package/dist/waste-collections.addon.mjs +113 -703
- package/package.json +2 -2
|
@@ -2,7 +2,7 @@ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
|
2
2
|
import { dirname, join } from "node:path";
|
|
3
3
|
import { spawn } from "node:child_process";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
|
-
//#region ../types/dist/event-category-
|
|
5
|
+
//#region ../types/dist/event-category-78tcBemo.mjs
|
|
6
6
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
7
7
|
EventCategory["SystemBoot"] = "system.boot";
|
|
8
8
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -123,6 +123,23 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
123
123
|
*/
|
|
124
124
|
EventCategory["AddonLoadRecovered"] = "addon.load-recovered";
|
|
125
125
|
/**
|
|
126
|
+
* An addon is RUNNING although its installed package is below what the
|
|
127
|
+
* running server requires (`camstack.requires.addons` of the server, or the
|
|
128
|
+
* addon's own `requires.server`). Raised once per streak by the unsupported-
|
|
129
|
+
* addon tracker, on the hub and on agents; AlertCenter turns it into one
|
|
130
|
+
* operator alert per node and package. The addon is never held back for it.
|
|
131
|
+
*
|
|
132
|
+
* Payload: `{ packageName, addonId, nodeId, installedVersion, requiredMinimum, serverVersion, unmet }`.
|
|
133
|
+
*/
|
|
134
|
+
EventCategory["AddonUnsupportedVersion"] = "addon.unsupported-version";
|
|
135
|
+
/**
|
|
136
|
+
* The package of an {@link AddonUnsupportedVersion} alert reached a supported
|
|
137
|
+
* version, or is no longer installed on the node. AlertCenter dismisses the matching alert.
|
|
138
|
+
*
|
|
139
|
+
* Payload: `{ packageName, addonId, nodeId }`.
|
|
140
|
+
*/
|
|
141
|
+
EventCategory["AddonUnsupportedResolved"] = "addon.unsupported-resolved";
|
|
142
|
+
/**
|
|
126
143
|
* Monitor scheduled the next retry for a failed addon. Transient —
|
|
127
144
|
* surfaced to the UI for live-updating the "next retry in Ns"
|
|
128
145
|
* countdown on the Addons page row, NOT persisted as an alert.
|
|
@@ -233,7 +250,7 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
233
250
|
EventCategory["ProcessRestarted"] = "process.restarted";
|
|
234
251
|
/**
|
|
235
252
|
* The SET of storage locations changed — one was created, edited, enabled,
|
|
236
|
-
* disabled or deleted through
|
|
253
|
+
* disabled or deleted through the location instances or the forced-delete action.
|
|
237
254
|
*
|
|
238
255
|
* Telemetry, not a transaction (D8/D11): every consumer that re-resolves on
|
|
239
256
|
* it must also converge on its own periodic path, because a dropped event
|
|
@@ -5984,7 +6001,7 @@ var ZodIssueCode = {
|
|
|
5984
6001
|
var ZodFirstPartyTypeKind;
|
|
5985
6002
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5986
6003
|
//#endregion
|
|
5987
|
-
//#region ../types/dist/sleep-
|
|
6004
|
+
//#region ../types/dist/sleep-AEnTN3b4.mjs
|
|
5988
6005
|
/**
|
|
5989
6006
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5990
6007
|
* window to float samples (D455).
|
|
@@ -6079,16 +6096,6 @@ var AddonMigrationsBlockedError = class extends Error {
|
|
|
6079
6096
|
this.migrationIds = migrationIds;
|
|
6080
6097
|
}
|
|
6081
6098
|
};
|
|
6082
|
-
/**
|
|
6083
|
-
* The value a redacted secret is replaced with on every read surface.
|
|
6084
|
-
*
|
|
6085
|
-
* It is also the WRITE-BACK token: an `upsertLocation` that sends this value
|
|
6086
|
-
* back for a key means "keep what is stored", which is what lets an operator
|
|
6087
|
-
* rename a location without retyping its password. A literal an operator could
|
|
6088
|
-
* plausibly choose as a real password would turn that convenience into a way
|
|
6089
|
-
* to lock yourself out, hence the sentinel shape.
|
|
6090
|
-
*/
|
|
6091
|
-
var REDACTED_SECRET = "__camstack_redacted__";
|
|
6092
6099
|
/** Is this field's stored value a credential? */
|
|
6093
6100
|
function isSecretConfigField(field) {
|
|
6094
6101
|
if (field.type === "password") return true;
|
|
@@ -7399,17 +7406,35 @@ var RecordIntegrationInstances = class {
|
|
|
7399
7406
|
...kind !== void 0 ? { kind } : {}
|
|
7400
7407
|
});
|
|
7401
7408
|
if (minted === void 0) throw new Error("createInstance needs an id: this provider does not mint one");
|
|
7409
|
+
const initial = this.hooks.initialBody(name, kind);
|
|
7410
|
+
const patch = this.patchOf(values ?? {});
|
|
7411
|
+
if (Object.keys(patch).length > 0) Object.assign(patch, await this.hooks.validateWrite?.({
|
|
7412
|
+
kind,
|
|
7413
|
+
body: {
|
|
7414
|
+
...initial,
|
|
7415
|
+
...patch
|
|
7416
|
+
}
|
|
7417
|
+
}));
|
|
7402
7418
|
await this.handle.put({
|
|
7403
7419
|
id: minted,
|
|
7404
|
-
data:
|
|
7420
|
+
data: initial
|
|
7405
7421
|
}, { ifRev: 0 });
|
|
7406
|
-
const patch = this.patchOf(values ?? {});
|
|
7407
7422
|
if (Object.keys(patch).length > 0) await this.handle.patch(minted, patch);
|
|
7408
7423
|
await this.hooks.onChanged?.(minted, "created");
|
|
7409
7424
|
return { id: minted };
|
|
7410
7425
|
};
|
|
7411
7426
|
updateInstance = async ({ id, name, values }) => {
|
|
7412
7427
|
const patch = this.patchOf(values);
|
|
7428
|
+
if (this.hooks.validateWrite !== void 0 && Object.keys(patch).length > 0) {
|
|
7429
|
+
const stored = await this.handle.get(id);
|
|
7430
|
+
if (stored !== null) Object.assign(patch, await this.hooks.validateWrite({
|
|
7431
|
+
kind: void 0,
|
|
7432
|
+
body: {
|
|
7433
|
+
...stored.data,
|
|
7434
|
+
...patch
|
|
7435
|
+
}
|
|
7436
|
+
}));
|
|
7437
|
+
}
|
|
7413
7438
|
if (name !== void 0) patch[this.nameField] = name;
|
|
7414
7439
|
await this.handle.patch(id, patch);
|
|
7415
7440
|
await this.hooks.onChanged?.(id, "updated");
|
|
@@ -10773,7 +10798,6 @@ var CAP_NAMES = Object.freeze([
|
|
|
10773
10798
|
"notifier",
|
|
10774
10799
|
"numeric-sensor",
|
|
10775
10800
|
"oauth-integration",
|
|
10776
|
-
"oidc-connections",
|
|
10777
10801
|
"osd",
|
|
10778
10802
|
"osd-manager",
|
|
10779
10803
|
"pet-feeder",
|
|
@@ -12665,8 +12689,7 @@ Object.freeze({
|
|
|
12665
12689
|
"device-provider": { "reloadDevice": 18e4 },
|
|
12666
12690
|
"llm": {
|
|
12667
12691
|
"generate": 6e5,
|
|
12668
|
-
"generateVision": 6e5
|
|
12669
|
-
"testProfile": 6e5
|
|
12692
|
+
"generateVision": 6e5
|
|
12670
12693
|
},
|
|
12671
12694
|
"llm-runtime": {
|
|
12672
12695
|
"complete": 6e5,
|
|
@@ -14069,17 +14092,18 @@ var IntegrationInstanceRefSchema = object({
|
|
|
14069
14092
|
* message to what the kind supports — callers never special-case a service.
|
|
14070
14093
|
*
|
|
14071
14094
|
* DESIGN DECISIONS (locked):
|
|
14072
|
-
* -
|
|
14073
|
-
*
|
|
14074
|
-
*
|
|
14075
|
-
*
|
|
14076
|
-
*
|
|
14077
|
-
*
|
|
14078
|
-
*
|
|
14079
|
-
*
|
|
14080
|
-
*
|
|
14081
|
-
* routable. `send` / `testTarget` /
|
|
14082
|
-
* `
|
|
14095
|
+
* - A target is an INSTANCE of this function cap (epic #440, step 6): the
|
|
14096
|
+
* providers serve their targets as `integration-instances` records, one
|
|
14097
|
+
* record kind per target kind, and the admin lists, adds, edits, switches
|
|
14098
|
+
* and deletes them through that cap. This cap keeps what an instance cannot
|
|
14099
|
+
* say: the kind catalogue (`listTargetKinds`: capabilities, delivery
|
|
14100
|
+
* parameters, brand icon), dispatch (`send`, `testTarget`) and the form
|
|
14101
|
+
* helpers (`discoverTargets`, `probeTargetConfig`).
|
|
14102
|
+
* - `listTargetKinds` / `discoverTargets` return arrays → the generated
|
|
14103
|
+
* cap-mount auto-`concatCollection`-fans them across every registered
|
|
14104
|
+
* provider so one catalog is routable. `send` / `testTarget` /
|
|
14105
|
+
* `probeTargetConfig` route to ONE provider by the `addonId` the generated
|
|
14106
|
+
* collection router extracts from the call input.
|
|
14083
14107
|
* - `Attachment.bytes` is `Uint8Array`. Transport-safe: superjson (the tRPC
|
|
14084
14108
|
* transformer) + UDS MsgPack both round-trip typed arrays — already used by
|
|
14085
14109
|
* `storage` / `storage-provider` / `recording` caps over the same path. No
|
|
@@ -14324,7 +14348,7 @@ var TargetKindCapsSchema = object({
|
|
|
14324
14348
|
* the union is large and not meant for runtime validation here; the exported
|
|
14325
14349
|
* `TargetKind` type re-tightens `configSchema` to `ConfigUISchema`.
|
|
14326
14350
|
*/
|
|
14327
|
-
var ConfigSchemaPassthrough$
|
|
14351
|
+
var ConfigSchemaPassthrough$3 = unknown();
|
|
14328
14352
|
var TargetKindSchema = object({
|
|
14329
14353
|
kind: string(),
|
|
14330
14354
|
label: string(),
|
|
@@ -14361,7 +14385,7 @@ var TargetKindSchema = object({
|
|
|
14361
14385
|
* its raster path, which is the safe default for an unknown image.
|
|
14362
14386
|
*/
|
|
14363
14387
|
iconMediaType: string().optional(),
|
|
14364
|
-
configSchema: ConfigSchemaPassthrough$
|
|
14388
|
+
configSchema: ConfigSchemaPassthrough$3,
|
|
14365
14389
|
/**
|
|
14366
14390
|
* The config keys that decide WHERE this kind's secrets are sent (server,
|
|
14367
14391
|
* base URL, instance, chat, recipient). A save that changes any of them
|
|
@@ -14383,9 +14407,11 @@ var TargetKindSchema = object({
|
|
|
14383
14407
|
caps: TargetKindCapsSchema
|
|
14384
14408
|
});
|
|
14385
14409
|
/**
|
|
14386
|
-
* A
|
|
14387
|
-
*
|
|
14388
|
-
*
|
|
14410
|
+
* A target as a provider's own code sees it (the notification-center bridge, the
|
|
14411
|
+
* send path): the flat record body split into the name, the switch and the
|
|
14412
|
+
* kind's fields. `config` holds secrets; a reader that serves it to a client
|
|
14413
|
+
* REDACTS secret fields (a presence marker only) — never round-trip a stored
|
|
14414
|
+
* secret to the UI.
|
|
14389
14415
|
*/
|
|
14390
14416
|
var TargetSchema = object({
|
|
14391
14417
|
id: string(),
|
|
@@ -14428,13 +14454,13 @@ var ProbeTargetConfigResultSchema = object({
|
|
|
14428
14454
|
stateInstance: string().optional(),
|
|
14429
14455
|
error: string().optional()
|
|
14430
14456
|
});
|
|
14431
|
-
method(object({}), array(TargetKindSchema)), method(object({
|
|
14457
|
+
method(object({}), array(TargetKindSchema)), method(object({
|
|
14432
14458
|
kind: string(),
|
|
14433
14459
|
config: record(string(), unknown()).optional(),
|
|
14434
14460
|
/**
|
|
14435
14461
|
* When editing / duplicating, the blank password field never round-trips
|
|
14436
14462
|
* the stored token. Pass the source target id so the provider can restore
|
|
14437
|
-
* secrets server-side before dialling
|
|
14463
|
+
* secrets server-side before dialling.
|
|
14438
14464
|
*/
|
|
14439
14465
|
targetId: string().optional()
|
|
14440
14466
|
}), array(DiscoveredTargetSchema), { auth: "admin" }), method(object({
|
|
@@ -14457,27 +14483,6 @@ method(object({}), array(TargetKindSchema)), method(object({}), array(TargetSche
|
|
|
14457
14483
|
}), TestResultSchema, {
|
|
14458
14484
|
kind: "mutation",
|
|
14459
14485
|
auth: "admin"
|
|
14460
|
-
}), method(object({
|
|
14461
|
-
target: TargetSchema,
|
|
14462
|
-
/**
|
|
14463
|
-
* Duplicate flow: create a NEW target id while copying secrets from an
|
|
14464
|
-
* existing row. The UI never holds the stored token; blank / redacted
|
|
14465
|
-
* password fields are restored from this source (D634 still applies if
|
|
14466
|
-
* destinations diverge without a re-typed secret).
|
|
14467
|
-
*/
|
|
14468
|
-
cloneSecretsFrom: string().optional()
|
|
14469
|
-
}), TargetSchema, {
|
|
14470
|
-
kind: "mutation",
|
|
14471
|
-
auth: "admin"
|
|
14472
|
-
}), method(object({ targetId: string() }), _void(), {
|
|
14473
|
-
kind: "mutation",
|
|
14474
|
-
auth: "admin"
|
|
14475
|
-
}), method(object({
|
|
14476
|
-
targetId: string(),
|
|
14477
|
-
enabled: boolean()
|
|
14478
|
-
}), _void(), {
|
|
14479
|
-
kind: "mutation",
|
|
14480
|
-
auth: "admin"
|
|
14481
14486
|
});
|
|
14482
14487
|
looseObject({
|
|
14483
14488
|
name: string().min(1),
|
|
@@ -22735,7 +22740,6 @@ var SYSTEM_CAP_VOCABULARY = {
|
|
|
22735
22740
|
"notification-output": system("notification delivery — reached through notifier devices and rules"),
|
|
22736
22741
|
"notification-rules": system("notification rules — authored on their own page"),
|
|
22737
22742
|
"oauth-integration": system(IDENTITY),
|
|
22738
|
-
"oidc-connections": system(IDENTITY),
|
|
22739
22743
|
"osd-manager": system(PIPELINE),
|
|
22740
22744
|
"pipeline-executor": system(PIPELINE),
|
|
22741
22745
|
"pipeline-orchestrator": system(PIPELINE),
|
|
@@ -54423,7 +54427,7 @@ method(_void(), array(IntegrationWithStateSchema)), method(object({ id: string()
|
|
|
54423
54427
|
* or the redaction token KEEPS the stored secret; `{ $secretClear: true }`
|
|
54424
54428
|
* clears it.
|
|
54425
54429
|
*/
|
|
54426
|
-
var ConfigSchemaPassthrough$
|
|
54430
|
+
var ConfigSchemaPassthrough$2 = custom();
|
|
54427
54431
|
var IntegrationInstanceIdSchema = string().min(1);
|
|
54428
54432
|
var IntegrationInstanceModeSchema = _enum(["single", "multiple"]);
|
|
54429
54433
|
/**
|
|
@@ -54469,7 +54473,16 @@ var IntegrationInstanceKindSchema = object({
|
|
|
54469
54473
|
/** Relative hub path to start an interactive account link of an instance of this kind. */
|
|
54470
54474
|
connectPath: string().min(1).optional(),
|
|
54471
54475
|
/** Relative hub path to disconnect that account. */
|
|
54472
|
-
disconnectPath: string().min(1).optional()
|
|
54476
|
+
disconnectPath: string().min(1).optional(),
|
|
54477
|
+
/**
|
|
54478
|
+
* Parts of the edit dialog the flat form cannot draw (a node picker, a model source), named by a
|
|
54479
|
+
* GENERIC widget id the client maps to a component; a client that knows none of them shows none.
|
|
54480
|
+
* `connection` widgets write connection values, `model` widgets own the model choice.
|
|
54481
|
+
*/
|
|
54482
|
+
widgets: array(object({
|
|
54483
|
+
id: string().min(1),
|
|
54484
|
+
placement: _enum(["connection", "model"])
|
|
54485
|
+
})).optional()
|
|
54473
54486
|
});
|
|
54474
54487
|
/**
|
|
54475
54488
|
* How devices of an instance are found. `none`: the operator adds them by hand; `lan`: the addon
|
|
@@ -54574,7 +54587,7 @@ var integrationInstancesCapability = {
|
|
|
54574
54587
|
id: IntegrationInstanceIdSchema.nullable(),
|
|
54575
54588
|
/** The kind of the create form (`id: null`) of a provider with several. */
|
|
54576
54589
|
kind: string().min(1).optional()
|
|
54577
|
-
}), ConfigSchemaPassthrough$
|
|
54590
|
+
}), ConfigSchemaPassthrough$2, { auth: "admin" }),
|
|
54578
54591
|
listInstances: method(_void(), array(IntegrationInstanceSchema).readonly(), { auth: "admin" }),
|
|
54579
54592
|
getInstance: method(object({ id: IntegrationInstanceIdSchema }), IntegrationInstanceSchema.nullable(), { auth: "admin" }),
|
|
54580
54593
|
/**
|
|
@@ -55525,12 +55538,12 @@ var LlmModelInfoSchema = object({
|
|
|
55525
55538
|
});
|
|
55526
55539
|
/**
|
|
55527
55540
|
* The provider-specific part of a profile, validated by the provider that owns
|
|
55528
|
-
* the kind (
|
|
55541
|
+
* the kind (saving an instance refuses what it does not accept). A field its
|
|
55529
55542
|
* `connectionSchema` declares `type: 'password'` is a secret: it is held in the
|
|
55530
55543
|
* keychain, never in the row, and reads back as the redaction marker.
|
|
55531
55544
|
*/
|
|
55532
55545
|
var LlmProviderConfigSchema = record(string(), unknown());
|
|
55533
|
-
|
|
55546
|
+
object({
|
|
55534
55547
|
id: string(),
|
|
55535
55548
|
name: string(),
|
|
55536
55549
|
/** The provider-declared kind (`LlmProfileKindDescriptor.kind`). */
|
|
@@ -55624,8 +55637,8 @@ var LlmProviderWidgetSchema = object({
|
|
|
55624
55637
|
/** ConfigUISchema tree passed through untyped on the wire (the
|
|
55625
55638
|
* notification-output `ConfigSchemaPassthrough` precedent at
|
|
55626
55639
|
* notification-output.cap.ts:151); the exported TS type re-tightens it. */
|
|
55627
|
-
var ConfigSchemaPassthrough$
|
|
55628
|
-
|
|
55640
|
+
var ConfigSchemaPassthrough$1 = unknown();
|
|
55641
|
+
object({
|
|
55629
55642
|
kind: LlmProfileKindSchema,
|
|
55630
55643
|
label: string(),
|
|
55631
55644
|
/** A generic icon name (`cloud`, `plug`, `cpu`) — never a glyph or a logo. */
|
|
@@ -55633,9 +55646,9 @@ var LlmProfileKindDescriptorSchema = object({
|
|
|
55633
55646
|
/** Stamped by each provider so the concat-fanned catalog stays routable. */
|
|
55634
55647
|
addonId: string(),
|
|
55635
55648
|
/** The provider's own fields (`providerConfig`); `password` fields are keychain-held. */
|
|
55636
|
-
connectionSchema: ConfigSchemaPassthrough$
|
|
55649
|
+
connectionSchema: ConfigSchemaPassthrough$1,
|
|
55637
55650
|
/** Provider fields that belong under "Advanced" (extra headers, runtime tuning). */
|
|
55638
|
-
advancedSchema: ConfigSchemaPassthrough$
|
|
55651
|
+
advancedSchema: ConfigSchemaPassthrough$1.optional(),
|
|
55639
55652
|
/** The kind's defaults; a model from `listModels` may override any of them. */
|
|
55640
55653
|
features: LlmModelFeaturesSchema,
|
|
55641
55654
|
/** `false` = the provider stamps `supportsVision` itself (from what a node reports). */
|
|
@@ -55764,20 +55777,7 @@ method(LlmGenerateBaseInputSchema, LlmGenerateResultSchema, {
|
|
|
55764
55777
|
}), method(object({
|
|
55765
55778
|
addonId: string().optional(),
|
|
55766
55779
|
requestId: string()
|
|
55767
|
-
}), _void(), { kind: "mutation" }), method(
|
|
55768
|
-
kind: "mutation",
|
|
55769
|
-
auth: "admin"
|
|
55770
|
-
}), method(RawSecretMigrationInputSchema, RawSecretMigrationReportSchema, {
|
|
55771
|
-
kind: "mutation",
|
|
55772
|
-
auth: "admin"
|
|
55773
|
-
}), method(ProfileRefInputSchema, _void(), {
|
|
55774
|
-
kind: "mutation",
|
|
55775
|
-
auth: "admin"
|
|
55776
|
-
}), method(ProfileRefInputSchema, LlmGenerateResultSchema, {
|
|
55777
|
-
kind: "mutation",
|
|
55778
|
-
auth: "admin",
|
|
55779
|
-
timeoutMs: AI_CAP_TRANSPORT_TIMEOUT_MS
|
|
55780
|
-
}), method(LlmListModelsInputSchema, LlmListModelsResultSchema, {
|
|
55780
|
+
}), _void(), { kind: "mutation" }), method(LlmListModelsInputSchema, LlmListModelsResultSchema, {
|
|
55781
55781
|
kind: "mutation",
|
|
55782
55782
|
auth: "admin"
|
|
55783
55783
|
}), method(object({}), array(LlmDefaultSchema)), method(object({
|
|
@@ -56772,20 +56772,7 @@ method(_void(), MeshStatusSchema), method(object({
|
|
|
56772
56772
|
/** Optional hostname override the host should advertise once joined. */
|
|
56773
56773
|
hostname: string().optional() }), object({
|
|
56774
56774
|
/** Authentication URL the operator should open in a browser. */
|
|
56775
|
-
loginUrl: string() }), { kind: "mutation" }), method(_void(), object({ left: literal(true) }), { kind: "mutation" }), method(_void(), object({ loggedOut: literal(true) }), { kind: "mutation" }), method(_void(), object({ peers: array(MeshPeerSchema).readonly() }))
|
|
56776
|
-
/** Optional auth key — when provided, probes the key validity
|
|
56777
|
-
* against the provider's API. Omit when already joined to
|
|
56778
|
-
* just ping the daemon. */
|
|
56779
|
-
authKey: string().optional() }), object({
|
|
56780
|
-
ok: boolean(),
|
|
56781
|
-
/** Provider-side identifier resolved by the probe (tailnet
|
|
56782
|
-
* name for Tailscale, network id for ZeroTier, etc.). */
|
|
56783
|
-
tenant: string().optional(),
|
|
56784
|
-
/** Daemon binary version, when reachable. */
|
|
56785
|
-
daemonVersion: string().optional(),
|
|
56786
|
-
/** Human-readable error when `ok: false`. */
|
|
56787
|
-
error: string().optional()
|
|
56788
|
-
}), { kind: "mutation" });
|
|
56775
|
+
loginUrl: string() }), { kind: "mutation" }), method(_void(), object({ left: literal(true) }), { kind: "mutation" }), method(_void(), object({ loggedOut: literal(true) }), { kind: "mutation" }), method(_void(), object({ peers: array(MeshPeerSchema).readonly() }));
|
|
56789
56776
|
object({
|
|
56790
56777
|
value: number().nullable().meta(readingMeta("device", { label: "Total" })),
|
|
56791
56778
|
lastFetchedAt: number()
|
|
@@ -66443,61 +66430,6 @@ var OauthIntegrationDescriptorSchema = object({
|
|
|
66443
66430
|
});
|
|
66444
66431
|
method(_void(), OauthIntegrationDescriptorSchema, { auth: "admin" });
|
|
66445
66432
|
/**
|
|
66446
|
-
* `oidc-connections` — CRUD for IdP rows under `auth-oidc` (D828 sibling).
|
|
66447
|
-
*
|
|
66448
|
-
* One hub-only singleton (`auth-oidc`). The Settings UI is a DataTable +
|
|
66449
|
-
* ItemFormDialog; there is no `editable-array` in `globalSettingsSchema`.
|
|
66450
|
-
* Operator-chosen `id` is the URL slug (`/addon/auth-oidc/<id>/…`) and is
|
|
66451
|
-
* immutable after create.
|
|
66452
|
-
*/
|
|
66453
|
-
var ConfigSchemaPassthrough$1 = unknown();
|
|
66454
|
-
var OidcConnectionSchema = object({
|
|
66455
|
-
id: string().min(1),
|
|
66456
|
-
displayName: string(),
|
|
66457
|
-
icon: string(),
|
|
66458
|
-
issuerUrl: string(),
|
|
66459
|
-
clientId: string(),
|
|
66460
|
-
/** Client id + secret present — never the secret value. */
|
|
66461
|
-
configured: boolean(),
|
|
66462
|
-
/**
|
|
66463
|
-
* Values for the connection form schema. `clientSecret` is a keychain
|
|
66464
|
-
* {@link SecretFieldView} or `null` / `''`, never plaintext (D789).
|
|
66465
|
-
*/
|
|
66466
|
-
formValues: record(string(), unknown()).optional()
|
|
66467
|
-
});
|
|
66468
|
-
/**
|
|
66469
|
-
* Patch one connection. Omitted or empty `clientSecret` keeps the stored
|
|
66470
|
-
* secret (D787). `{ $secretClear: true }` clears it. `id` is never renamed.
|
|
66471
|
-
*/
|
|
66472
|
-
var OidcConnectionUpdateInputSchema = object({
|
|
66473
|
-
id: string().min(1),
|
|
66474
|
-
displayName: string().min(1),
|
|
66475
|
-
icon: string().optional(),
|
|
66476
|
-
issuerUrl: string().optional(),
|
|
66477
|
-
clientId: string().optional(),
|
|
66478
|
-
clientSecret: union([string(), object({ $secretClear: literal(true) })]).optional(),
|
|
66479
|
-
redirectUri: string().optional(),
|
|
66480
|
-
scopes: string().optional(),
|
|
66481
|
-
usernameClaim: _enum([
|
|
66482
|
-
"preferred_username",
|
|
66483
|
-
"email",
|
|
66484
|
-
"sub"
|
|
66485
|
-
]).optional()
|
|
66486
|
-
});
|
|
66487
|
-
method(object({}), ConfigSchemaPassthrough$1, { auth: "admin" }), method(object({}), array(OidcConnectionSchema).readonly(), { auth: "admin" }), method(object({
|
|
66488
|
-
id: string().min(1).regex(/^[a-z0-9][a-z0-9-]{0,63}$/, "id must be a lowercase slug"),
|
|
66489
|
-
displayName: string().min(1)
|
|
66490
|
-
}), object({ id: string() }), {
|
|
66491
|
-
kind: "mutation",
|
|
66492
|
-
auth: "admin"
|
|
66493
|
-
}), method(OidcConnectionUpdateInputSchema, object({ ok: literal(true) }), {
|
|
66494
|
-
kind: "mutation",
|
|
66495
|
-
auth: "admin"
|
|
66496
|
-
}), method(object({ id: string().min(1) }), object({ ok: literal(true) }), {
|
|
66497
|
-
kind: "mutation",
|
|
66498
|
-
auth: "admin"
|
|
66499
|
-
});
|
|
66500
|
-
/**
|
|
66501
66433
|
* Generic on-screen-display (video overlay) cap. Each camera exposes
|
|
66502
66434
|
* a firmware-defined list of overlays (channel name, timestamp,
|
|
66503
66435
|
* watermark, logo, …); the cap models them as a homogeneous array of
|
|
@@ -72670,21 +72602,6 @@ method(object({
|
|
|
72670
72602
|
*/
|
|
72671
72603
|
ttlSec: union([number().int().positive(), literal("never")]).optional()
|
|
72672
72604
|
}), object({ token: string() }), { auth: "admin" }), method(object({ token: string() }), SsoBridgeClaimsSchema.nullable(), { auth: "admin" });
|
|
72673
|
-
var ProviderListEntrySchema = discriminatedUnion("shouldSaveDiskSpace", [object({
|
|
72674
|
-
providerId: string().min(1),
|
|
72675
|
-
displayName: string().min(1),
|
|
72676
|
-
configSchema: unknown(),
|
|
72677
|
-
nodeLocal: boolean(),
|
|
72678
|
-
shouldSaveDiskSpace: literal(true),
|
|
72679
|
-
minFreePercent: number().min(0).max(100)
|
|
72680
|
-
}), object({
|
|
72681
|
-
providerId: string().min(1),
|
|
72682
|
-
displayName: string().min(1),
|
|
72683
|
-
configSchema: unknown(),
|
|
72684
|
-
nodeLocal: boolean(),
|
|
72685
|
-
shouldSaveDiskSpace: literal(false),
|
|
72686
|
-
minFreePercent: literal(null)
|
|
72687
|
-
})]);
|
|
72688
72605
|
method(object({
|
|
72689
72606
|
location: StorageLocationRefSchema,
|
|
72690
72607
|
relativePath: string()
|
|
@@ -72746,42 +72663,7 @@ method(object({
|
|
|
72746
72663
|
}), _instanceof(Uint8Array), { auth: "admin" }), method(object({ downloadId: string() }), _void(), {
|
|
72747
72664
|
kind: "mutation",
|
|
72748
72665
|
auth: "admin"
|
|
72749
|
-
}), method(object({ type: StorageLocationTypeSchema.optional() }), array(StorageLocationSchema).readonly()), method(_void(), array(StorageLocationDeclarationSchema).readonly()), method(
|
|
72750
|
-
createdAt: true,
|
|
72751
|
-
updatedAt: true
|
|
72752
|
-
}), StorageLocationSchema, {
|
|
72753
|
-
kind: "mutation",
|
|
72754
|
-
auth: "admin"
|
|
72755
|
-
}), method(object({
|
|
72756
|
-
id: string(),
|
|
72757
|
-
force: boolean().optional()
|
|
72758
|
-
}), _void(), {
|
|
72759
|
-
kind: "mutation",
|
|
72760
|
-
auth: "admin"
|
|
72761
|
-
}), method(_void(), array(StorageDrainProgressSchema).readonly()), method(object({ id: string() }), object({
|
|
72762
|
-
ok: boolean(),
|
|
72763
|
-
error: string().optional()
|
|
72764
|
-
}), { auth: "admin" }), method(_void(), array(ProviderListEntrySchema).readonly()), method(object({
|
|
72765
|
-
providerId: string(),
|
|
72766
|
-
/**
|
|
72767
|
-
* The location this config is an UNSAVED edit of, when there is one.
|
|
72768
|
-
*
|
|
72769
|
-
* `listLocations` replaces every declared secret with the redaction
|
|
72770
|
-
* sentinel, so the edit modal's form state holds the sentinel for any
|
|
72771
|
-
* credential the operator did not retype — and posting that here
|
|
72772
|
-
* without a way to resolve it makes the provider try to authenticate
|
|
72773
|
-
* as `__camstack_redacted__` and report the operator's own working
|
|
72774
|
-
* password as wrong. Given this id, the orchestrator restores each
|
|
72775
|
-
* sentinel from the stored config (same rule as `upsertLocation`)
|
|
72776
|
-
* before dispatching. Omitted by the "Add location" wizard, where
|
|
72777
|
-
* every value was typed just now and nothing is stored yet.
|
|
72778
|
-
*/
|
|
72779
|
-
locationId: string().optional(),
|
|
72780
|
-
config: record(string(), unknown())
|
|
72781
|
-
}), object({
|
|
72782
|
-
ok: boolean(),
|
|
72783
|
-
error: string().optional()
|
|
72784
|
-
}), { auth: "admin" });
|
|
72666
|
+
}), method(object({ type: StorageLocationTypeSchema.optional() }), array(StorageLocationSchema).readonly()), method(_void(), array(StorageLocationDeclarationSchema).readonly()), method(_void(), array(StorageDrainProgressSchema).readonly());
|
|
72785
72667
|
/** One table of the settings database. */
|
|
72786
72668
|
var StorageTableSchema = object({
|
|
72787
72669
|
/** The table's full name, e.g. `recorder:addon-settings` or `addon-device-settings`. */
|
|
@@ -80374,13 +80256,6 @@ Object.freeze({
|
|
|
80374
80256
|
access: "delete",
|
|
80375
80257
|
role: "admin"
|
|
80376
80258
|
},
|
|
80377
|
-
"llm.deleteProfile": {
|
|
80378
|
-
capName: "llm",
|
|
80379
|
-
capScope: "system",
|
|
80380
|
-
addonId: null,
|
|
80381
|
-
access: "delete",
|
|
80382
|
-
role: "admin"
|
|
80383
|
-
},
|
|
80384
80259
|
"llm.generate": {
|
|
80385
80260
|
capName: "llm",
|
|
80386
80261
|
capScope: "system",
|
|
@@ -80444,20 +80319,6 @@ Object.freeze({
|
|
|
80444
80319
|
access: "view",
|
|
80445
80320
|
role: "admin"
|
|
80446
80321
|
},
|
|
80447
|
-
"llm.listProfileKinds": {
|
|
80448
|
-
capName: "llm",
|
|
80449
|
-
capScope: "system",
|
|
80450
|
-
addonId: null,
|
|
80451
|
-
access: "view",
|
|
80452
|
-
role: "admin"
|
|
80453
|
-
},
|
|
80454
|
-
"llm.listProfiles": {
|
|
80455
|
-
capName: "llm",
|
|
80456
|
-
capScope: "system",
|
|
80457
|
-
addonId: null,
|
|
80458
|
-
access: "view",
|
|
80459
|
-
role: "admin"
|
|
80460
|
-
},
|
|
80461
80322
|
"llm.listRuntimeNodes": {
|
|
80462
80323
|
capName: "llm",
|
|
80463
80324
|
capScope: "system",
|
|
@@ -80465,13 +80326,6 @@ Object.freeze({
|
|
|
80465
80326
|
access: "view",
|
|
80466
80327
|
role: "admin"
|
|
80467
80328
|
},
|
|
80468
|
-
"llm.migrateRawSecrets": {
|
|
80469
|
-
capName: "llm",
|
|
80470
|
-
capScope: "system",
|
|
80471
|
-
addonId: null,
|
|
80472
|
-
access: "create",
|
|
80473
|
-
role: "admin"
|
|
80474
|
-
},
|
|
80475
80329
|
"llm.resolveModelRef": {
|
|
80476
80330
|
capName: "llm",
|
|
80477
80331
|
capScope: "system",
|
|
@@ -80500,20 +80354,6 @@ Object.freeze({
|
|
|
80500
80354
|
access: "create",
|
|
80501
80355
|
role: "admin"
|
|
80502
80356
|
},
|
|
80503
|
-
"llm.testProfile": {
|
|
80504
|
-
capName: "llm",
|
|
80505
|
-
capScope: "system",
|
|
80506
|
-
addonId: null,
|
|
80507
|
-
access: "create",
|
|
80508
|
-
role: "admin"
|
|
80509
|
-
},
|
|
80510
|
-
"llm.upsertProfile": {
|
|
80511
|
-
capName: "llm",
|
|
80512
|
-
capScope: "system",
|
|
80513
|
-
addonId: null,
|
|
80514
|
-
access: "create",
|
|
80515
|
-
role: "admin"
|
|
80516
|
-
},
|
|
80517
80357
|
"llmRuntime.appleAvailability": {
|
|
80518
80358
|
capName: "llm-runtime",
|
|
80519
80359
|
capScope: "system",
|
|
@@ -81018,13 +80858,6 @@ Object.freeze({
|
|
|
81018
80858
|
access: "create",
|
|
81019
80859
|
role: "admin"
|
|
81020
80860
|
},
|
|
81021
|
-
"meshNetwork.testConnection": {
|
|
81022
|
-
capName: "mesh-network",
|
|
81023
|
-
capScope: "system",
|
|
81024
|
-
addonId: null,
|
|
81025
|
-
access: "create",
|
|
81026
|
-
role: "admin"
|
|
81027
|
-
},
|
|
81028
80861
|
"meter.getStatus": {
|
|
81029
80862
|
capName: "meter",
|
|
81030
80863
|
capScope: "device",
|
|
@@ -81683,13 +81516,6 @@ Object.freeze({
|
|
|
81683
81516
|
access: "create",
|
|
81684
81517
|
role: "admin"
|
|
81685
81518
|
},
|
|
81686
|
-
"notificationOutput.deleteTarget": {
|
|
81687
|
-
capName: "notification-output",
|
|
81688
|
-
capScope: "system",
|
|
81689
|
-
addonId: null,
|
|
81690
|
-
access: "delete",
|
|
81691
|
-
role: "admin"
|
|
81692
|
-
},
|
|
81693
81519
|
"notificationOutput.discoverTargets": {
|
|
81694
81520
|
capName: "notification-output",
|
|
81695
81521
|
capScope: "system",
|
|
@@ -81697,13 +81523,6 @@ Object.freeze({
|
|
|
81697
81523
|
access: "view",
|
|
81698
81524
|
role: "admin"
|
|
81699
81525
|
},
|
|
81700
|
-
"notificationOutput.getTarget": {
|
|
81701
|
-
capName: "notification-output",
|
|
81702
|
-
capScope: "system",
|
|
81703
|
-
addonId: null,
|
|
81704
|
-
access: "view",
|
|
81705
|
-
role: "admin"
|
|
81706
|
-
},
|
|
81707
81526
|
"notificationOutput.listTargetKinds": {
|
|
81708
81527
|
capName: "notification-output",
|
|
81709
81528
|
capScope: "system",
|
|
@@ -81711,13 +81530,6 @@ Object.freeze({
|
|
|
81711
81530
|
access: "view",
|
|
81712
81531
|
role: "admin"
|
|
81713
81532
|
},
|
|
81714
|
-
"notificationOutput.listTargets": {
|
|
81715
|
-
capName: "notification-output",
|
|
81716
|
-
capScope: "system",
|
|
81717
|
-
addonId: null,
|
|
81718
|
-
access: "view",
|
|
81719
|
-
role: "admin"
|
|
81720
|
-
},
|
|
81721
81533
|
"notificationOutput.probeTargetConfig": {
|
|
81722
81534
|
capName: "notification-output",
|
|
81723
81535
|
capScope: "system",
|
|
@@ -81732,13 +81544,6 @@ Object.freeze({
|
|
|
81732
81544
|
access: "create",
|
|
81733
81545
|
role: "admin"
|
|
81734
81546
|
},
|
|
81735
|
-
"notificationOutput.setTargetEnabled": {
|
|
81736
|
-
capName: "notification-output",
|
|
81737
|
-
capScope: "system",
|
|
81738
|
-
addonId: null,
|
|
81739
|
-
access: "create",
|
|
81740
|
-
role: "admin"
|
|
81741
|
-
},
|
|
81742
81547
|
"notificationOutput.testTarget": {
|
|
81743
81548
|
capName: "notification-output",
|
|
81744
81549
|
capScope: "system",
|
|
@@ -81746,13 +81551,6 @@ Object.freeze({
|
|
|
81746
81551
|
access: "create",
|
|
81747
81552
|
role: "admin"
|
|
81748
81553
|
},
|
|
81749
|
-
"notificationOutput.upsertTarget": {
|
|
81750
|
-
capName: "notification-output",
|
|
81751
|
-
capScope: "system",
|
|
81752
|
-
addonId: null,
|
|
81753
|
-
access: "create",
|
|
81754
|
-
role: "admin"
|
|
81755
|
-
},
|
|
81756
81554
|
"notificationRules.activateAlarmProfile": {
|
|
81757
81555
|
capName: "notification-rules",
|
|
81758
81556
|
capScope: "system",
|
|
@@ -82012,41 +81810,6 @@ Object.freeze({
|
|
|
82012
81810
|
access: "view",
|
|
82013
81811
|
role: "admin"
|
|
82014
81812
|
},
|
|
82015
|
-
"oidcConnections.connectionFormSchema": {
|
|
82016
|
-
capName: "oidc-connections",
|
|
82017
|
-
capScope: "system",
|
|
82018
|
-
addonId: null,
|
|
82019
|
-
access: "view",
|
|
82020
|
-
role: "admin"
|
|
82021
|
-
},
|
|
82022
|
-
"oidcConnections.createConnection": {
|
|
82023
|
-
capName: "oidc-connections",
|
|
82024
|
-
capScope: "system",
|
|
82025
|
-
addonId: null,
|
|
82026
|
-
access: "create",
|
|
82027
|
-
role: "admin"
|
|
82028
|
-
},
|
|
82029
|
-
"oidcConnections.deleteConnection": {
|
|
82030
|
-
capName: "oidc-connections",
|
|
82031
|
-
capScope: "system",
|
|
82032
|
-
addonId: null,
|
|
82033
|
-
access: "delete",
|
|
82034
|
-
role: "admin"
|
|
82035
|
-
},
|
|
82036
|
-
"oidcConnections.listConnections": {
|
|
82037
|
-
capName: "oidc-connections",
|
|
82038
|
-
capScope: "system",
|
|
82039
|
-
addonId: null,
|
|
82040
|
-
access: "view",
|
|
82041
|
-
role: "admin"
|
|
82042
|
-
},
|
|
82043
|
-
"oidcConnections.updateConnection": {
|
|
82044
|
-
capName: "oidc-connections",
|
|
82045
|
-
capScope: "system",
|
|
82046
|
-
addonId: null,
|
|
82047
|
-
access: "create",
|
|
82048
|
-
role: "admin"
|
|
82049
|
-
},
|
|
82050
81813
|
"osd.getStatus": {
|
|
82051
81814
|
capName: "osd",
|
|
82052
81815
|
capScope: "device",
|
|
@@ -85078,13 +84841,6 @@ Object.freeze({
|
|
|
85078
84841
|
access: "delete",
|
|
85079
84842
|
role: "admin"
|
|
85080
84843
|
},
|
|
85081
|
-
"storage.deleteLocation": {
|
|
85082
|
-
capName: "storage",
|
|
85083
|
-
capScope: "system",
|
|
85084
|
-
addonId: null,
|
|
85085
|
-
access: "delete",
|
|
85086
|
-
role: "admin"
|
|
85087
|
-
},
|
|
85088
84844
|
"storage.endDownload": {
|
|
85089
84845
|
capName: "storage",
|
|
85090
84846
|
capScope: "system",
|
|
@@ -85141,13 +84897,6 @@ Object.freeze({
|
|
|
85141
84897
|
access: "view",
|
|
85142
84898
|
role: "admin"
|
|
85143
84899
|
},
|
|
85144
|
-
"storage.listProviders": {
|
|
85145
|
-
capName: "storage",
|
|
85146
|
-
capScope: "system",
|
|
85147
|
-
addonId: null,
|
|
85148
|
-
access: "view",
|
|
85149
|
-
role: "admin"
|
|
85150
|
-
},
|
|
85151
84900
|
"storage.read": {
|
|
85152
84901
|
capName: "storage",
|
|
85153
84902
|
capScope: "system",
|
|
@@ -85169,27 +84918,6 @@ Object.freeze({
|
|
|
85169
84918
|
access: "view",
|
|
85170
84919
|
role: "admin"
|
|
85171
84920
|
},
|
|
85172
|
-
"storage.testConfig": {
|
|
85173
|
-
capName: "storage",
|
|
85174
|
-
capScope: "system",
|
|
85175
|
-
addonId: null,
|
|
85176
|
-
access: "view",
|
|
85177
|
-
role: "admin"
|
|
85178
|
-
},
|
|
85179
|
-
"storage.testLocation": {
|
|
85180
|
-
capName: "storage",
|
|
85181
|
-
capScope: "system",
|
|
85182
|
-
addonId: null,
|
|
85183
|
-
access: "view",
|
|
85184
|
-
role: "admin"
|
|
85185
|
-
},
|
|
85186
|
-
"storage.upsertLocation": {
|
|
85187
|
-
capName: "storage",
|
|
85188
|
-
capScope: "system",
|
|
85189
|
-
addonId: null,
|
|
85190
|
-
access: "create",
|
|
85191
|
-
role: "admin"
|
|
85192
|
-
},
|
|
85193
84921
|
"storage.write": {
|
|
85194
84922
|
capName: "storage",
|
|
85195
84923
|
capScope: "system",
|
|
@@ -91342,20 +91070,6 @@ object({
|
|
|
91342
91070
|
});
|
|
91343
91071
|
//#endregion
|
|
91344
91072
|
//#region src/custom-actions.ts
|
|
91345
|
-
var SourceIdSchema = string().min(1).regex(/^[a-z0-9][a-z0-9-]{0,63}$/, "id must be a lowercase slug");
|
|
91346
|
-
/**
|
|
91347
|
-
* A source as the admin list shows it. No `args`: a credential never leaves the
|
|
91348
|
-
* addon - `formValues` carries the redaction token where one is stored (D880).
|
|
91349
|
-
*/
|
|
91350
|
-
var WasteSourceRowSchema = object({
|
|
91351
|
-
id: string(),
|
|
91352
|
-
label: string(),
|
|
91353
|
-
module: string(),
|
|
91354
|
-
enabled: boolean(),
|
|
91355
|
-
formValues: record(string(), unknown()).optional(),
|
|
91356
|
-
serviceId: string().optional(),
|
|
91357
|
-
countryId: string().optional()
|
|
91358
|
-
});
|
|
91359
91073
|
var wasteCollectionsActions = defineCustomActions({
|
|
91360
91074
|
fetchNow: customAction(object({
|
|
91361
91075
|
/** When set, refresh only this configured source id; otherwise all enabled. */
|
|
@@ -91370,10 +91084,6 @@ sourceId: string().min(1).optional() }).optional(), object({
|
|
|
91370
91084
|
kind: "mutation",
|
|
91371
91085
|
auth: "admin"
|
|
91372
91086
|
}),
|
|
91373
|
-
listSources: customAction(object({}), array(WasteSourceRowSchema).readonly(), {
|
|
91374
|
-
kind: "mutation",
|
|
91375
|
-
auth: "admin"
|
|
91376
|
-
}),
|
|
91377
91087
|
listCountries: customAction(object({}), array(object({
|
|
91378
91088
|
id: string(),
|
|
91379
91089
|
label: string()
|
|
@@ -91391,43 +91101,6 @@ sourceId: string().min(1).optional() }).optional(), object({
|
|
|
91391
91101
|
})).readonly(), {
|
|
91392
91102
|
kind: "mutation",
|
|
91393
91103
|
auth: "admin"
|
|
91394
|
-
}),
|
|
91395
|
-
serviceFormSchema: customAction(object({ serviceId: string().min(1) }), unknown(), {
|
|
91396
|
-
kind: "mutation",
|
|
91397
|
-
auth: "admin"
|
|
91398
|
-
}),
|
|
91399
|
-
createSource: customAction(object({
|
|
91400
|
-
/** Optional override; when omitted the id is derived from `label`. */
|
|
91401
|
-
id: SourceIdSchema.optional(),
|
|
91402
|
-
label: string().min(1),
|
|
91403
|
-
serviceId: string().min(1),
|
|
91404
|
-
args: record(string(), unknown()).default({}),
|
|
91405
|
-
enabled: boolean().optional()
|
|
91406
|
-
}), object({ id: string() }), {
|
|
91407
|
-
kind: "mutation",
|
|
91408
|
-
auth: "admin"
|
|
91409
|
-
}),
|
|
91410
|
-
updateSource: customAction(object({
|
|
91411
|
-
id: string().min(1),
|
|
91412
|
-
label: string().min(1),
|
|
91413
|
-
serviceId: string().min(1).optional(),
|
|
91414
|
-
args: record(string(), unknown()).optional(),
|
|
91415
|
-
enabled: boolean().optional()
|
|
91416
|
-
}), object({ ok: literal(true) }), {
|
|
91417
|
-
kind: "mutation",
|
|
91418
|
-
auth: "admin"
|
|
91419
|
-
}),
|
|
91420
|
-
/**
|
|
91421
|
-
* D880: rewrite every legacy source (free `argsJson`) as typed `args`, moving its
|
|
91422
|
-
* credentials into the keychain. Dry run unless `apply`; idempotent; counts only.
|
|
91423
|
-
*/
|
|
91424
|
-
migrateSources: customAction(RawSecretMigrationInputSchema, RawSecretMigrationReportSchema, {
|
|
91425
|
-
kind: "mutation",
|
|
91426
|
-
auth: "admin"
|
|
91427
|
-
}),
|
|
91428
|
-
deleteSource: customAction(object({ id: string().min(1) }), object({ ok: literal(true) }), {
|
|
91429
|
-
kind: "mutation",
|
|
91430
|
-
auth: "admin"
|
|
91431
91104
|
})
|
|
91432
91105
|
});
|
|
91433
91106
|
//#endregion
|
|
@@ -91461,33 +91134,6 @@ var WASTE_SECRET_STATE_PATHS = SECRET_ARG_KEYS.map((key) => `sources[id].args.${
|
|
|
91461
91134
|
function isSecretArg(key) {
|
|
91462
91135
|
return SECRET_ARG_KEYS.includes(key.toLowerCase());
|
|
91463
91136
|
}
|
|
91464
|
-
/** Is a credential stored for this argument (a value, or a marker the keychain could not serve)? */
|
|
91465
|
-
function isSet(value) {
|
|
91466
|
-
return isSecretMarker(value) || typeof value === "string" && value.length > 0;
|
|
91467
|
-
}
|
|
91468
|
-
/** The arguments as a read surface may show them: a stored credential is the redaction token. */
|
|
91469
|
-
function redactArgs(args) {
|
|
91470
|
-
const out = {};
|
|
91471
|
-
for (const [key, value] of Object.entries(args)) out[key] = isSecretArg(key) && isSet(value) ? REDACTED_SECRET : value;
|
|
91472
|
-
return out;
|
|
91473
|
-
}
|
|
91474
|
-
/**
|
|
91475
|
-
* The write-back of {@link redactArgs}: a credential sent back as the redaction
|
|
91476
|
-
* token means "keep what is stored", so it takes the stored (resolved) value; one
|
|
91477
|
-
* with nothing stored is dropped, never saved as the token.
|
|
91478
|
-
*/
|
|
91479
|
-
function restoreRedactedArgs(incoming, stored) {
|
|
91480
|
-
const out = {};
|
|
91481
|
-
for (const [key, value] of Object.entries(incoming)) {
|
|
91482
|
-
if (isSecretArg(key) && value === "__camstack_redacted__") {
|
|
91483
|
-
const previous = stored[key];
|
|
91484
|
-
if (previous !== void 0) out[key] = previous;
|
|
91485
|
-
continue;
|
|
91486
|
-
}
|
|
91487
|
-
out[key] = value;
|
|
91488
|
-
}
|
|
91489
|
-
return out;
|
|
91490
|
-
}
|
|
91491
91137
|
/**
|
|
91492
91138
|
* Does this argument bag hold a credential that is NOT a usable value: a MARKER the keychain did
|
|
91493
91139
|
* not resolve, or the redaction token (a row read without its credential)? Either would reach a
|
|
@@ -91496,10 +91142,6 @@ function restoreRedactedArgs(incoming, stored) {
|
|
|
91496
91142
|
function hasUnresolvedCredential(args) {
|
|
91497
91143
|
return Object.entries(args).some(([key, value]) => isSecretArg(key) && (isSecretMarker(value) || value === "__camstack_redacted__"));
|
|
91498
91144
|
}
|
|
91499
|
-
/** Does it hold a non-empty credential (any form)? */
|
|
91500
|
-
function hasCredential(args) {
|
|
91501
|
-
return Object.entries(args).some(([key, value]) => isSecretArg(key) && isSet(value));
|
|
91502
|
-
}
|
|
91503
91145
|
//#endregion
|
|
91504
91146
|
//#region src/waste-types.ts
|
|
91505
91147
|
/**
|
|
@@ -91964,35 +91606,6 @@ function reportFailed(log, failures) {
|
|
|
91964
91606
|
};
|
|
91965
91607
|
}
|
|
91966
91608
|
//#endregion
|
|
91967
|
-
//#region src/source-id.ts
|
|
91968
|
-
/**
|
|
91969
|
-
* Stable calendar source ids derived from the operator label.
|
|
91970
|
-
* Pattern: `^[a-z0-9][a-z0-9-]{0,63}$` (max 64 chars).
|
|
91971
|
-
*/
|
|
91972
|
-
var SOURCE_ID_PATTERN = /^[a-z0-9][a-z0-9-]{0,63}$/;
|
|
91973
|
-
/** Slugify a display label into a candidate source id (may be empty). */
|
|
91974
|
-
function slugifySourceLabel(label) {
|
|
91975
|
-
const s = label.normalize("NFKD").replace(/[\u0300-\u036f]/g, "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
91976
|
-
if (s.length === 0) return "";
|
|
91977
|
-
return s.slice(0, 64);
|
|
91978
|
-
}
|
|
91979
|
-
/**
|
|
91980
|
-
* Pick an unused id from `label`. Collisions append `-2`, `-3`, …
|
|
91981
|
-
* (truncated so the result stays within the 64-char pattern).
|
|
91982
|
-
*/
|
|
91983
|
-
function allocateSourceId(label, existingIds) {
|
|
91984
|
-
const taken = existingIds instanceof Set ? existingIds : new Set(existingIds);
|
|
91985
|
-
const baseRaw = slugifySourceLabel(label);
|
|
91986
|
-
const base = baseRaw.length > 0 ? baseRaw : "source";
|
|
91987
|
-
if (!taken.has(base) && SOURCE_ID_PATTERN.test(base)) return base;
|
|
91988
|
-
for (let n = 2; n < 1e4; n++) {
|
|
91989
|
-
const suffix = `-${n}`;
|
|
91990
|
-
const candidate = `${base.slice(0, Math.max(1, 64 - suffix.length)).replace(/-+$/g, "")}${suffix}`;
|
|
91991
|
-
if (SOURCE_ID_PATTERN.test(candidate) && !taken.has(candidate)) return candidate;
|
|
91992
|
-
}
|
|
91993
|
-
throw new Error("could not allocate a unique source id");
|
|
91994
|
-
}
|
|
91995
|
-
//#endregion
|
|
91996
91609
|
//#region src/waste-calendar-source.ts
|
|
91997
91610
|
function startOfUtcDayMs(isoDate) {
|
|
91998
91611
|
const [y, m, d] = isoDate.split("-").map((p) => Number(p));
|
|
@@ -178037,6 +177650,35 @@ function mergeServiceArgs(service, formValues) {
|
|
|
178037
177650
|
return out;
|
|
178038
177651
|
}
|
|
178039
177652
|
//#endregion
|
|
177653
|
+
//#region src/source-id.ts
|
|
177654
|
+
/**
|
|
177655
|
+
* Stable calendar source ids derived from the operator label.
|
|
177656
|
+
* Pattern: `^[a-z0-9][a-z0-9-]{0,63}$` (max 64 chars).
|
|
177657
|
+
*/
|
|
177658
|
+
var SOURCE_ID_PATTERN = /^[a-z0-9][a-z0-9-]{0,63}$/;
|
|
177659
|
+
/** Slugify a display label into a candidate source id (may be empty). */
|
|
177660
|
+
function slugifySourceLabel(label) {
|
|
177661
|
+
const s = label.normalize("NFKD").replace(/[\u0300-\u036f]/g, "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
177662
|
+
if (s.length === 0) return "";
|
|
177663
|
+
return s.slice(0, 64);
|
|
177664
|
+
}
|
|
177665
|
+
/**
|
|
177666
|
+
* Pick an unused id from `label`. Collisions append `-2`, `-3`, …
|
|
177667
|
+
* (truncated so the result stays within the 64-char pattern).
|
|
177668
|
+
*/
|
|
177669
|
+
function allocateSourceId(label, existingIds) {
|
|
177670
|
+
const taken = existingIds instanceof Set ? existingIds : new Set(existingIds);
|
|
177671
|
+
const baseRaw = slugifySourceLabel(label);
|
|
177672
|
+
const base = baseRaw.length > 0 ? baseRaw : "source";
|
|
177673
|
+
if (!taken.has(base) && SOURCE_ID_PATTERN.test(base)) return base;
|
|
177674
|
+
for (let n = 2; n < 1e4; n++) {
|
|
177675
|
+
const suffix = `-${n}`;
|
|
177676
|
+
const candidate = `${base.slice(0, Math.max(1, 64 - suffix.length)).replace(/-+$/g, "")}${suffix}`;
|
|
177677
|
+
if (SOURCE_ID_PATTERN.test(candidate) && !taken.has(candidate)) return candidate;
|
|
177678
|
+
}
|
|
177679
|
+
throw new Error("could not allocate a unique source id");
|
|
177680
|
+
}
|
|
177681
|
+
//#endregion
|
|
178040
177682
|
//#region src/waste-source-store.ts
|
|
178041
177683
|
/**
|
|
178042
177684
|
* A stored body as a source. A row read while the keychain is locked still carries its markers
|
|
@@ -178540,23 +178182,13 @@ var WasteCollectionsAddon = class extends BaseAddon {
|
|
|
178540
178182
|
customActions: wasteCollectionsActions,
|
|
178541
178183
|
actionHandlers: {
|
|
178542
178184
|
fetchNow: async (input) => this.fetchNow(input),
|
|
178543
|
-
listSources: async () => this.listSources(),
|
|
178544
178185
|
listCountries: async () => listCatalogCountries(),
|
|
178545
178186
|
listServices: async (input) => listCatalogServices(input.countryId).map((s) => ({
|
|
178546
178187
|
id: s.id,
|
|
178547
178188
|
label: serviceDisplayLabel(s),
|
|
178548
178189
|
title: s.label,
|
|
178549
178190
|
module: s.module
|
|
178550
|
-
}))
|
|
178551
|
-
serviceFormSchema: async (input) => {
|
|
178552
|
-
const service = findCatalogService(input.serviceId);
|
|
178553
|
-
if (!service) throw new Error(`unknown service '${input.serviceId}'`);
|
|
178554
|
-
return serviceFormSchema(service);
|
|
178555
|
-
},
|
|
178556
|
-
createSource: async (input) => this.createSource(input),
|
|
178557
|
-
updateSource: async (input) => this.updateSource(input),
|
|
178558
|
-
deleteSource: async (input) => this.deleteSource(input),
|
|
178559
|
-
migrateSources: async (input) => this.migrateSources(input.apply)
|
|
178191
|
+
}))
|
|
178560
178192
|
}
|
|
178561
178193
|
};
|
|
178562
178194
|
}
|
|
@@ -178623,17 +178255,6 @@ var WasteCollectionsAddon = class extends BaseAddon {
|
|
|
178623
178255
|
if (!this.legacyServed) return records;
|
|
178624
178256
|
return withUnmigratedLegacyRows(records, this.parseConfigSources(this.config.sources));
|
|
178625
178257
|
}
|
|
178626
|
-
async persistSources(sources) {
|
|
178627
|
-
this.activeSources = [...sources];
|
|
178628
|
-
const store = this.sourceStore;
|
|
178629
|
-
if (store !== null) {
|
|
178630
|
-
await store.replaceAll(sources);
|
|
178631
|
-
const kept = new Set(sources.map((s) => s.id));
|
|
178632
|
-
await this.pruneLegacyRows((legacyId) => kept.has(legacyId));
|
|
178633
|
-
return;
|
|
178634
|
-
}
|
|
178635
|
-
await this.updateGlobalSettings({ sources: [...sources] });
|
|
178636
|
-
}
|
|
178637
178258
|
/**
|
|
178638
178259
|
* A source deleted at the records leaves the legacy setting too, or it would reappear beside the
|
|
178639
178260
|
* records (while the migration is pending) or be copied back by it.
|
|
@@ -178648,195 +178269,6 @@ var WasteCollectionsAddon = class extends BaseAddon {
|
|
|
178648
178269
|
if (this.activeSources.length > 0 || this.sourceStore !== null) return this.activeSources;
|
|
178649
178270
|
return this.parseConfigSources(this.config.sources);
|
|
178650
178271
|
}
|
|
178651
|
-
listSources() {
|
|
178652
|
-
return this.configuredSources().map((s) => {
|
|
178653
|
-
let args = {};
|
|
178654
|
-
try {
|
|
178655
|
-
args = sourceArgs(s);
|
|
178656
|
-
} catch {
|
|
178657
|
-
args = { ...s.args };
|
|
178658
|
-
}
|
|
178659
|
-
const matched = matchCatalogService(s.module, args);
|
|
178660
|
-
const formValues = {
|
|
178661
|
-
label: s.label,
|
|
178662
|
-
enabled: s.enabled,
|
|
178663
|
-
...redactArgs(args)
|
|
178664
|
-
};
|
|
178665
|
-
if (matched) for (const key of Object.keys(matched.defaultArgs)) delete formValues[key];
|
|
178666
|
-
return {
|
|
178667
|
-
id: s.id,
|
|
178668
|
-
label: s.label,
|
|
178669
|
-
module: s.module,
|
|
178670
|
-
enabled: s.enabled,
|
|
178671
|
-
formValues,
|
|
178672
|
-
serviceId: matched?.id,
|
|
178673
|
-
countryId: matched?.countryId
|
|
178674
|
-
};
|
|
178675
|
-
});
|
|
178676
|
-
}
|
|
178677
|
-
async createSource(input) {
|
|
178678
|
-
const existing = this.configuredSources().map((s) => s.id);
|
|
178679
|
-
let id;
|
|
178680
|
-
if (input.id !== void 0) {
|
|
178681
|
-
if (!SOURCE_ID_PATTERN.test(input.id)) throw new Error("id must be a lowercase slug (e.g. ics-home, junker)");
|
|
178682
|
-
if (existing.includes(input.id)) throw new Error(`source '${input.id}' already exists`);
|
|
178683
|
-
id = input.id;
|
|
178684
|
-
} else id = allocateSourceId(input.label, existing);
|
|
178685
|
-
const service = findCatalogService(input.serviceId);
|
|
178686
|
-
if (!service) throw new Error(`unknown service '${input.serviceId}'`);
|
|
178687
|
-
const row = WasteSourceConfigSchema.parse({
|
|
178688
|
-
id,
|
|
178689
|
-
label: input.label,
|
|
178690
|
-
module: service.module,
|
|
178691
|
-
args: this.typedArgs(mergeServiceArgs(service, restoreRedactedArgs(input.args, {}))),
|
|
178692
|
-
enabled: input.enabled ?? true
|
|
178693
|
-
});
|
|
178694
|
-
await this.persistSources([...this.configuredSources(), row]);
|
|
178695
|
-
return { id };
|
|
178696
|
-
}
|
|
178697
|
-
async updateSource(input) {
|
|
178698
|
-
const sources = this.configuredSources();
|
|
178699
|
-
const idx = sources.findIndex((s) => s.id === input.id);
|
|
178700
|
-
if (idx < 0) throw new Error(`source '${input.id}' not found`);
|
|
178701
|
-
const prev = sources[idx];
|
|
178702
|
-
let prevArgs = {};
|
|
178703
|
-
try {
|
|
178704
|
-
prevArgs = sourceArgs(prev);
|
|
178705
|
-
} catch {
|
|
178706
|
-
prevArgs = { ...prev.args };
|
|
178707
|
-
}
|
|
178708
|
-
let module = prev.module;
|
|
178709
|
-
let args = prevArgs;
|
|
178710
|
-
if (input.serviceId !== void 0) {
|
|
178711
|
-
const service = findCatalogService(input.serviceId);
|
|
178712
|
-
if (!service) throw new Error(`unknown service '${input.serviceId}'`);
|
|
178713
|
-
module = service.module;
|
|
178714
|
-
args = mergeServiceArgs(service, restoreRedactedArgs(input.args ?? {}, prevArgs));
|
|
178715
|
-
} else if (input.args !== void 0) {
|
|
178716
|
-
const sent = restoreRedactedArgs(input.args, prevArgs);
|
|
178717
|
-
const matched = matchCatalogService(prev.module, prevArgs);
|
|
178718
|
-
args = matched ? mergeServiceArgs(matched, sent) : {
|
|
178719
|
-
...prevArgs,
|
|
178720
|
-
...sent
|
|
178721
|
-
};
|
|
178722
|
-
}
|
|
178723
|
-
const next = WasteSourceConfigSchema.parse({
|
|
178724
|
-
id: prev.id,
|
|
178725
|
-
label: input.label,
|
|
178726
|
-
module,
|
|
178727
|
-
args: this.typedArgs(args),
|
|
178728
|
-
enabled: input.enabled ?? prev.enabled
|
|
178729
|
-
});
|
|
178730
|
-
await this.persistSources(sources.map((s, i) => i === idx ? next : s));
|
|
178731
|
-
return { ok: true };
|
|
178732
|
-
}
|
|
178733
|
-
/** Validate an argument bag against the typed value schema (a nested object is refused). */
|
|
178734
|
-
typedArgs(args) {
|
|
178735
|
-
const out = {};
|
|
178736
|
-
for (const [key, value] of Object.entries(args)) out[key] = WasteArgValueSchema.parse(value);
|
|
178737
|
-
return out;
|
|
178738
|
-
}
|
|
178739
|
-
/**
|
|
178740
|
-
* D880: rewrite every legacy source (free `argsJson`) as typed `args`; its
|
|
178741
|
-
* credentials go to the keychain through the normal save path. Then every
|
|
178742
|
-
* credential is read back and compared with what the legacy row held; on any
|
|
178743
|
-
* difference the legacy rows are written back, so nothing is lost. Dry run
|
|
178744
|
-
* unless `apply`. Idempotent. Counts only - never an argument, a ref or an id.
|
|
178745
|
-
*/
|
|
178746
|
-
async migrateSources(apply) {
|
|
178747
|
-
const sources = this.configuredSources();
|
|
178748
|
-
const legacy = sources.filter((s) => s.argsJson !== void 0);
|
|
178749
|
-
const rawRows = legacy.filter((s) => {
|
|
178750
|
-
try {
|
|
178751
|
-
return hasCredential(sourceArgs(s));
|
|
178752
|
-
} catch {
|
|
178753
|
-
return false;
|
|
178754
|
-
}
|
|
178755
|
-
});
|
|
178756
|
-
const markerRows = sources.filter((s) => s.argsJson === void 0 && hasCredential(s.args)).length;
|
|
178757
|
-
const report = (over) => ({
|
|
178758
|
-
apply,
|
|
178759
|
-
rows: sources.length,
|
|
178760
|
-
raw: rawRows.length,
|
|
178761
|
-
markers: markerRows,
|
|
178762
|
-
migrated: 0,
|
|
178763
|
-
failed: 0,
|
|
178764
|
-
remainingRaw: rawRows.length,
|
|
178765
|
-
unresolvedMarkers: this.unresolvedSecrets.length,
|
|
178766
|
-
redundantCopies: legacy.length,
|
|
178767
|
-
verified: rawRows.length === 0 && this.unresolvedSecrets.length === 0,
|
|
178768
|
-
...over
|
|
178769
|
-
});
|
|
178770
|
-
if (!apply || legacy.length === 0) return report({});
|
|
178771
|
-
const expected = /* @__PURE__ */ new Map();
|
|
178772
|
-
const unconverted = /* @__PURE__ */ new Set();
|
|
178773
|
-
const migrated = sources.map((s) => {
|
|
178774
|
-
if (s.argsJson === void 0) return s;
|
|
178775
|
-
try {
|
|
178776
|
-
const args = sourceArgs(s);
|
|
178777
|
-
const row = WasteSourceConfigSchema.parse({
|
|
178778
|
-
id: s.id,
|
|
178779
|
-
label: s.label,
|
|
178780
|
-
module: s.module,
|
|
178781
|
-
args: this.typedArgs(args),
|
|
178782
|
-
enabled: s.enabled
|
|
178783
|
-
});
|
|
178784
|
-
expected.set(s.id, args);
|
|
178785
|
-
return row;
|
|
178786
|
-
} catch {
|
|
178787
|
-
unconverted.add(s.id);
|
|
178788
|
-
return s;
|
|
178789
|
-
}
|
|
178790
|
-
});
|
|
178791
|
-
const failedRows = unconverted.size;
|
|
178792
|
-
if (expected.size === 0) return report({
|
|
178793
|
-
failed: failedRows,
|
|
178794
|
-
remainingRaw: legacy.length
|
|
178795
|
-
});
|
|
178796
|
-
try {
|
|
178797
|
-
await this.persistSources(migrated);
|
|
178798
|
-
} catch {
|
|
178799
|
-
return report({ failed: legacy.length });
|
|
178800
|
-
}
|
|
178801
|
-
const back = new Map(this.configuredSources().map((s) => [s.id, s]));
|
|
178802
|
-
if (![...expected].every(([id, args]) => {
|
|
178803
|
-
const row = back.get(id);
|
|
178804
|
-
return row !== void 0 && row.argsJson === void 0 && JSON.stringify(sortedEntries(row.args)) === JSON.stringify(sortedEntries(args));
|
|
178805
|
-
}) || this.unresolvedSecrets.length > 0) {
|
|
178806
|
-
await this.rollbackMigration(sources, expected);
|
|
178807
|
-
return report({ failed: legacy.length });
|
|
178808
|
-
}
|
|
178809
|
-
return report({
|
|
178810
|
-
migrated: expected.size,
|
|
178811
|
-
failed: failedRows,
|
|
178812
|
-
remainingRaw: failedRows,
|
|
178813
|
-
unresolvedMarkers: 0,
|
|
178814
|
-
redundantCopies: legacy.length,
|
|
178815
|
-
verified: failedRows === 0
|
|
178816
|
-
});
|
|
178817
|
-
}
|
|
178818
|
-
/**
|
|
178819
|
-
* Put the legacy rows back. A converted row's `args` is written as `null`, which
|
|
178820
|
-
* the save path reads as "this object is gone": it deletes the keychain refs the
|
|
178821
|
-
* migration created (a plain `{}` would keep them). Never throws - the report
|
|
178822
|
-
* says failed either way, and the legacy JSON stays authoritative.
|
|
178823
|
-
*/
|
|
178824
|
-
async rollbackMigration(sources, converted) {
|
|
178825
|
-
try {
|
|
178826
|
-
await this.updateGlobalSettingsAsOperator({ sources: sources.map((s) => converted.has(s.id) ? {
|
|
178827
|
-
...s,
|
|
178828
|
-
args: null
|
|
178829
|
-
} : s) });
|
|
178830
|
-
} catch {
|
|
178831
|
-
this.ctx.logger.error("waste-collections: the migration rollback failed - keychain refs may be orphaned (System -> Secrets)");
|
|
178832
|
-
}
|
|
178833
|
-
}
|
|
178834
|
-
async deleteSource(input) {
|
|
178835
|
-
const sources = this.configuredSources();
|
|
178836
|
-
if (!sources.some((s) => s.id === input.id)) throw new Error(`source '${input.id}' not found`);
|
|
178837
|
-
await this.persistSources(sources.filter((s) => s.id !== input.id));
|
|
178838
|
-
return { ok: true };
|
|
178839
|
-
}
|
|
178840
178272
|
async fetchNow(input) {
|
|
178841
178273
|
const targets = this.configuredSources().filter((s) => {
|
|
178842
178274
|
if (!s.enabled) return false;
|
|
@@ -178937,32 +178369,10 @@ var WasteCollectionsAddon = class extends BaseAddon {
|
|
|
178937
178369
|
this.ctx.logger.warn("waste-collections: cache persist failed", { meta: { error: err instanceof Error ? err.message : String(err) } });
|
|
178938
178370
|
}
|
|
178939
178371
|
}
|
|
178940
|
-
globalSettingsSchema() {
|
|
178941
|
-
return this.schema({ sections: [{
|
|
178942
|
-
id: "refresh",
|
|
178943
|
-
title: "Refresh",
|
|
178944
|
-
description: "Sources are managed in the table above (Add / Edit): pick a country and a service, then fill only that service’s fields. Each source becomes one calendar under System → Calendars.",
|
|
178945
|
-
columns: 2,
|
|
178946
|
-
fields: [{
|
|
178947
|
-
type: "addon-action-button",
|
|
178948
|
-
key: "_fetchNow",
|
|
178949
|
-
label: "Refresh",
|
|
178950
|
-
buttonLabel: "Fetch now",
|
|
178951
|
-
description: "Sources refresh once at boot and then every 24 hours; this refreshes every enabled source immediately.",
|
|
178952
|
-
addonId: "waste-collections",
|
|
178953
|
-
action: "fetchNow",
|
|
178954
|
-
variant: "primary",
|
|
178955
|
-
paramsStatic: {}
|
|
178956
|
-
}]
|
|
178957
|
-
}] });
|
|
178958
|
-
}
|
|
178959
178372
|
};
|
|
178960
178373
|
/** Re-parse helper for tests. */
|
|
178961
178374
|
function parseWasteConfig(raw) {
|
|
178962
178375
|
return WasteConfigSchema.parse(raw);
|
|
178963
178376
|
}
|
|
178964
|
-
function sortedEntries(args) {
|
|
178965
|
-
return Object.entries(args).toSorted(([a], [b]) => a < b ? -1 : 1);
|
|
178966
|
-
}
|
|
178967
178377
|
//#endregion
|
|
178968
178378
|
export { WasteCollectionsAddon, WasteCollectionsAddon as default, sourceArgs as a, wasteCollectionsActions as customActions, WasteConfigSchema as i, createWasteCalendarSource as n, parseWasteConfig, DEFAULT_WASTE_CONFIG as r, collectionsToEvents as t };
|