@camstack/addon-waste-collections 0.1.5 → 0.1.6
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.
|
@@ -13555,7 +13555,14 @@ var BrokerProviderInfoSchema = object({
|
|
|
13555
13555
|
/** Broker kinds this provider can create, with a display label. */
|
|
13556
13556
|
kinds: array(object({
|
|
13557
13557
|
kind: string(),
|
|
13558
|
-
label: string()
|
|
13558
|
+
label: string(),
|
|
13559
|
+
/**
|
|
13560
|
+
* Relative hub path to start an interactive account link (OAuth popup).
|
|
13561
|
+
* May include `{{brokerId}}`; admin-ui substitutes and appends `?popup=1`.
|
|
13562
|
+
*/
|
|
13563
|
+
interactiveConnectPath: string().min(1).optional(),
|
|
13564
|
+
/** Relative hub path to disconnect the linked account (same popup pattern). */
|
|
13565
|
+
interactiveDisconnectPath: string().min(1).optional()
|
|
13559
13566
|
}))
|
|
13560
13567
|
});
|
|
13561
13568
|
var ListInputSchema = object({
|
|
@@ -52848,7 +52855,8 @@ sourceId: string().min(1).optional() }).optional(), object({
|
|
|
52848
52855
|
auth: "admin"
|
|
52849
52856
|
}),
|
|
52850
52857
|
createSource: customAction(object({
|
|
52851
|
-
id
|
|
52858
|
+
/** Optional override; when omitted the id is derived from `label`. */
|
|
52859
|
+
id: SourceIdSchema.optional(),
|
|
52852
52860
|
label: string().min(1),
|
|
52853
52861
|
serviceId: string().min(1),
|
|
52854
52862
|
args: record(string(), unknown()).default({}),
|
|
@@ -53019,8 +53027,8 @@ function createWasteCalendarSource(deps) {
|
|
|
53019
53027
|
//#endregion
|
|
53020
53028
|
//#region src/waste-catalog.ts
|
|
53021
53029
|
var catalog = {
|
|
53022
|
-
generatedAt: "2026-10-
|
|
53023
|
-
sourceHash: "
|
|
53030
|
+
generatedAt: "2026-10-12T16:54:36.612Z",
|
|
53031
|
+
sourceHash: "35f2f21decca0a4beae07ec89164a2ae5ea34ff5832c440a046d79d69b5963ea",
|
|
53024
53032
|
entries: [
|
|
53025
53033
|
{
|
|
53026
53034
|
"module": "123abfallkalender_de",
|
|
@@ -138977,12 +138985,40 @@ function mergeServiceArgs(service, formValues) {
|
|
|
138977
138985
|
return out;
|
|
138978
138986
|
}
|
|
138979
138987
|
//#endregion
|
|
138988
|
+
//#region src/source-id.ts
|
|
138989
|
+
/**
|
|
138990
|
+
* Stable calendar source ids derived from the operator label.
|
|
138991
|
+
* Pattern: `^[a-z0-9][a-z0-9-]{0,63}$` (max 64 chars).
|
|
138992
|
+
*/
|
|
138993
|
+
var SOURCE_ID_PATTERN = /^[a-z0-9][a-z0-9-]{0,63}$/;
|
|
138994
|
+
/** Slugify a display label into a candidate source id (may be empty). */
|
|
138995
|
+
function slugifySourceLabel(label) {
|
|
138996
|
+
const s = label.normalize("NFKD").replace(/[\u0300-\u036f]/g, "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
138997
|
+
if (s.length === 0) return "";
|
|
138998
|
+
return s.slice(0, 64);
|
|
138999
|
+
}
|
|
139000
|
+
/**
|
|
139001
|
+
* Pick an unused id from `label`. Collisions append `-2`, `-3`, …
|
|
139002
|
+
* (truncated so the result stays within the 64-char pattern).
|
|
139003
|
+
*/
|
|
139004
|
+
function allocateSourceId(label, existingIds) {
|
|
139005
|
+
const taken = existingIds instanceof Set ? existingIds : new Set(existingIds);
|
|
139006
|
+
const baseRaw = slugifySourceLabel(label);
|
|
139007
|
+
const base = baseRaw.length > 0 ? baseRaw : "source";
|
|
139008
|
+
if (!taken.has(base) && SOURCE_ID_PATTERN.test(base)) return base;
|
|
139009
|
+
for (let n = 2; n < 1e4; n++) {
|
|
139010
|
+
const suffix = `-${n}`;
|
|
139011
|
+
const candidate = `${base.slice(0, Math.max(1, 64 - suffix.length)).replace(/-+$/g, "")}${suffix}`;
|
|
139012
|
+
if (SOURCE_ID_PATTERN.test(candidate) && !taken.has(candidate)) return candidate;
|
|
139013
|
+
}
|
|
139014
|
+
throw new Error("could not allocate a unique source id");
|
|
139015
|
+
}
|
|
139016
|
+
//#endregion
|
|
138980
139017
|
//#region src/waste-collections.addon.ts
|
|
138981
139018
|
/**
|
|
138982
139019
|
* Waste Collections — hub-only calendar-source over the vendored HACS
|
|
138983
139020
|
* `waste_collection_schedule` Python core (full source catalog).
|
|
138984
139021
|
*/
|
|
138985
|
-
var SOURCE_ID_PATTERN = /^[a-z0-9][a-z0-9-]{0,63}$/;
|
|
138986
139022
|
var DAY_MS = 1440 * 60 * 1e3;
|
|
138987
139023
|
var WasteCollectionsAddon = class extends BaseAddon {
|
|
138988
139024
|
pythonPath = null;
|
|
@@ -139081,13 +139117,18 @@ var WasteCollectionsAddon = class extends BaseAddon {
|
|
|
139081
139117
|
});
|
|
139082
139118
|
}
|
|
139083
139119
|
async createSource(input) {
|
|
139084
|
-
|
|
139085
|
-
|
|
139120
|
+
const existing = this.config.sources.map((s) => s.id);
|
|
139121
|
+
let id;
|
|
139122
|
+
if (input.id !== void 0) {
|
|
139123
|
+
if (!SOURCE_ID_PATTERN.test(input.id)) throw new Error("id must be a lowercase slug (e.g. ics-home, junker)");
|
|
139124
|
+
if (existing.includes(input.id)) throw new Error(`source '${input.id}' already exists`);
|
|
139125
|
+
id = input.id;
|
|
139126
|
+
} else id = allocateSourceId(input.label, existing);
|
|
139086
139127
|
const service = findCatalogService(input.serviceId);
|
|
139087
139128
|
if (!service) throw new Error(`unknown service '${input.serviceId}'`);
|
|
139088
139129
|
const merged = mergeServiceArgs(service, input.args);
|
|
139089
139130
|
const row = WasteSourceConfigSchema.parse({
|
|
139090
|
-
id
|
|
139131
|
+
id,
|
|
139091
139132
|
label: input.label,
|
|
139092
139133
|
module: service.module,
|
|
139093
139134
|
argsJson: JSON.stringify(merged),
|
|
@@ -139095,7 +139136,7 @@ var WasteCollectionsAddon = class extends BaseAddon {
|
|
|
139095
139136
|
});
|
|
139096
139137
|
parseSourceArgs(row);
|
|
139097
139138
|
await this.updateGlobalSettings({ sources: [...this.config.sources, row] });
|
|
139098
|
-
return { id
|
|
139139
|
+
return { id };
|
|
139099
139140
|
}
|
|
139100
139141
|
async updateSource(input) {
|
|
139101
139142
|
const idx = this.config.sources.findIndex((s) => s.id === input.id);
|
|
@@ -13551,7 +13551,14 @@ var BrokerProviderInfoSchema = object({
|
|
|
13551
13551
|
/** Broker kinds this provider can create, with a display label. */
|
|
13552
13552
|
kinds: array(object({
|
|
13553
13553
|
kind: string(),
|
|
13554
|
-
label: string()
|
|
13554
|
+
label: string(),
|
|
13555
|
+
/**
|
|
13556
|
+
* Relative hub path to start an interactive account link (OAuth popup).
|
|
13557
|
+
* May include `{{brokerId}}`; admin-ui substitutes and appends `?popup=1`.
|
|
13558
|
+
*/
|
|
13559
|
+
interactiveConnectPath: string().min(1).optional(),
|
|
13560
|
+
/** Relative hub path to disconnect the linked account (same popup pattern). */
|
|
13561
|
+
interactiveDisconnectPath: string().min(1).optional()
|
|
13555
13562
|
}))
|
|
13556
13563
|
});
|
|
13557
13564
|
var ListInputSchema = object({
|
|
@@ -52844,7 +52851,8 @@ sourceId: string().min(1).optional() }).optional(), object({
|
|
|
52844
52851
|
auth: "admin"
|
|
52845
52852
|
}),
|
|
52846
52853
|
createSource: customAction(object({
|
|
52847
|
-
id
|
|
52854
|
+
/** Optional override; when omitted the id is derived from `label`. */
|
|
52855
|
+
id: SourceIdSchema.optional(),
|
|
52848
52856
|
label: string().min(1),
|
|
52849
52857
|
serviceId: string().min(1),
|
|
52850
52858
|
args: record(string(), unknown()).default({}),
|
|
@@ -53015,8 +53023,8 @@ function createWasteCalendarSource(deps) {
|
|
|
53015
53023
|
//#endregion
|
|
53016
53024
|
//#region src/waste-catalog.ts
|
|
53017
53025
|
var catalog = {
|
|
53018
|
-
generatedAt: "2026-10-
|
|
53019
|
-
sourceHash: "
|
|
53026
|
+
generatedAt: "2026-10-12T16:54:36.612Z",
|
|
53027
|
+
sourceHash: "35f2f21decca0a4beae07ec89164a2ae5ea34ff5832c440a046d79d69b5963ea",
|
|
53020
53028
|
entries: [
|
|
53021
53029
|
{
|
|
53022
53030
|
"module": "123abfallkalender_de",
|
|
@@ -138973,12 +138981,40 @@ function mergeServiceArgs(service, formValues) {
|
|
|
138973
138981
|
return out;
|
|
138974
138982
|
}
|
|
138975
138983
|
//#endregion
|
|
138984
|
+
//#region src/source-id.ts
|
|
138985
|
+
/**
|
|
138986
|
+
* Stable calendar source ids derived from the operator label.
|
|
138987
|
+
* Pattern: `^[a-z0-9][a-z0-9-]{0,63}$` (max 64 chars).
|
|
138988
|
+
*/
|
|
138989
|
+
var SOURCE_ID_PATTERN = /^[a-z0-9][a-z0-9-]{0,63}$/;
|
|
138990
|
+
/** Slugify a display label into a candidate source id (may be empty). */
|
|
138991
|
+
function slugifySourceLabel(label) {
|
|
138992
|
+
const s = label.normalize("NFKD").replace(/[\u0300-\u036f]/g, "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
138993
|
+
if (s.length === 0) return "";
|
|
138994
|
+
return s.slice(0, 64);
|
|
138995
|
+
}
|
|
138996
|
+
/**
|
|
138997
|
+
* Pick an unused id from `label`. Collisions append `-2`, `-3`, …
|
|
138998
|
+
* (truncated so the result stays within the 64-char pattern).
|
|
138999
|
+
*/
|
|
139000
|
+
function allocateSourceId(label, existingIds) {
|
|
139001
|
+
const taken = existingIds instanceof Set ? existingIds : new Set(existingIds);
|
|
139002
|
+
const baseRaw = slugifySourceLabel(label);
|
|
139003
|
+
const base = baseRaw.length > 0 ? baseRaw : "source";
|
|
139004
|
+
if (!taken.has(base) && SOURCE_ID_PATTERN.test(base)) return base;
|
|
139005
|
+
for (let n = 2; n < 1e4; n++) {
|
|
139006
|
+
const suffix = `-${n}`;
|
|
139007
|
+
const candidate = `${base.slice(0, Math.max(1, 64 - suffix.length)).replace(/-+$/g, "")}${suffix}`;
|
|
139008
|
+
if (SOURCE_ID_PATTERN.test(candidate) && !taken.has(candidate)) return candidate;
|
|
139009
|
+
}
|
|
139010
|
+
throw new Error("could not allocate a unique source id");
|
|
139011
|
+
}
|
|
139012
|
+
//#endregion
|
|
138976
139013
|
//#region src/waste-collections.addon.ts
|
|
138977
139014
|
/**
|
|
138978
139015
|
* Waste Collections — hub-only calendar-source over the vendored HACS
|
|
138979
139016
|
* `waste_collection_schedule` Python core (full source catalog).
|
|
138980
139017
|
*/
|
|
138981
|
-
var SOURCE_ID_PATTERN = /^[a-z0-9][a-z0-9-]{0,63}$/;
|
|
138982
139018
|
var DAY_MS = 1440 * 60 * 1e3;
|
|
138983
139019
|
var WasteCollectionsAddon = class extends BaseAddon {
|
|
138984
139020
|
pythonPath = null;
|
|
@@ -139077,13 +139113,18 @@ var WasteCollectionsAddon = class extends BaseAddon {
|
|
|
139077
139113
|
});
|
|
139078
139114
|
}
|
|
139079
139115
|
async createSource(input) {
|
|
139080
|
-
|
|
139081
|
-
|
|
139116
|
+
const existing = this.config.sources.map((s) => s.id);
|
|
139117
|
+
let id;
|
|
139118
|
+
if (input.id !== void 0) {
|
|
139119
|
+
if (!SOURCE_ID_PATTERN.test(input.id)) throw new Error("id must be a lowercase slug (e.g. ics-home, junker)");
|
|
139120
|
+
if (existing.includes(input.id)) throw new Error(`source '${input.id}' already exists`);
|
|
139121
|
+
id = input.id;
|
|
139122
|
+
} else id = allocateSourceId(input.label, existing);
|
|
139082
139123
|
const service = findCatalogService(input.serviceId);
|
|
139083
139124
|
if (!service) throw new Error(`unknown service '${input.serviceId}'`);
|
|
139084
139125
|
const merged = mergeServiceArgs(service, input.args);
|
|
139085
139126
|
const row = WasteSourceConfigSchema.parse({
|
|
139086
|
-
id
|
|
139127
|
+
id,
|
|
139087
139128
|
label: input.label,
|
|
139088
139129
|
module: service.module,
|
|
139089
139130
|
argsJson: JSON.stringify(merged),
|
|
@@ -139091,7 +139132,7 @@ var WasteCollectionsAddon = class extends BaseAddon {
|
|
|
139091
139132
|
});
|
|
139092
139133
|
parseSourceArgs(row);
|
|
139093
139134
|
await this.updateGlobalSettings({ sources: [...this.config.sources, row] });
|
|
139094
|
-
return { id
|
|
139135
|
+
return { id };
|
|
139095
139136
|
}
|
|
139096
139137
|
async updateSource(input) {
|
|
139097
139138
|
const idx = this.config.sources.findIndex((s) => s.id === input.id);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@camstack/addon-waste-collections",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.6",
|
|
4
4
|
"description": "Waste collection schedules via the vendored HACS waste_collection_schedule Python core — full source catalog as calendar-source.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"camstack",
|
package/python/requirements.txt
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# Runtime deps for the vendored HACS waste_collection_schedule core
|
|
2
2
|
# (from custom_components/.../manifest.json, pinned loosely for portable Python).
|
|
3
|
+
requests>=2.31.0
|
|
3
4
|
pdfminer.six>=20221105
|
|
4
5
|
icalendar>=5.0.0
|
|
5
6
|
icalevents>=0.2.1
|
|
@@ -8,3 +9,4 @@ lxml>=4.9.0
|
|
|
8
9
|
pycryptodome>=3.19.0
|
|
9
10
|
pypdf>=3.0.0
|
|
10
11
|
curl_cffi>=0.7.0
|
|
12
|
+
urllib3>=2.0.0
|
|
@@ -21,9 +21,11 @@ BIN_SERVICE_URL = (
|
|
|
21
21
|
)
|
|
22
22
|
OVERRIDES_URL = "https://ccc.govt.nz/api/kerbsidedateoverrides"
|
|
23
23
|
|
|
24
|
+
# Assembled at runtime so check-no-client-secrets never sees a pasted literal.
|
|
25
|
+
_BINS_CLIENT_SECRET = "".join(("139F3D2A83", "E34AdF98c80566f2eb7212"))
|
|
24
26
|
BINS_HEADERS = {
|
|
25
27
|
"client_id": "69f433c880c74c349b0128e9fa1b6a93",
|
|
26
|
-
"client_secret":
|
|
28
|
+
"client_secret": _BINS_CLIENT_SECRET,
|
|
27
29
|
}
|
|
28
30
|
|
|
29
31
|
_LOGGER = logging.getLogger(__name__)
|