@camstack/addon-waste-collections 0.1.34 → 0.1.35
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 +6 -0
- package/dist/waste-collections.addon.js +154 -1
- package/dist/waste-collections.addon.mjs +154 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.1.35] - 2026-11-06
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- A boot after the credentials moved to the keychain no longer crash-loops the integrations runner
|
|
15
|
+
|
|
10
16
|
## [0.1.34] - 2026-11-06
|
|
11
17
|
|
|
12
18
|
### Changed
|
|
@@ -6706,6 +6706,33 @@ function integrationRowsApiOver(api) {
|
|
|
6706
6706
|
clearLegacyIntegrationRows: (input) => api.legacyRows.clear(input)
|
|
6707
6707
|
};
|
|
6708
6708
|
}
|
|
6709
|
+
/**
|
|
6710
|
+
* The named failures of `ctx.records` (D881).
|
|
6711
|
+
*
|
|
6712
|
+
* A records call crosses a worker thread, a UDS channel and a tRPC router, and
|
|
6713
|
+
* an error class does not survive any of them - only its message does. So
|
|
6714
|
+
* every message STARTS with a stable code, `records/<code>: <detail>`, and
|
|
6715
|
+
* {@link recordsErrorFromMessage} rebuilds the typed class on the caller's side.
|
|
6716
|
+
* A failed read is never `[]` or `undefined`: it throws one of these.
|
|
6717
|
+
*/
|
|
6718
|
+
/** Every code a records failure carries. */
|
|
6719
|
+
var RECORDS_ERROR_CODES = [
|
|
6720
|
+
"rev-conflict",
|
|
6721
|
+
"too-large",
|
|
6722
|
+
"unindexed-filter",
|
|
6723
|
+
"filter-required",
|
|
6724
|
+
"unknown-kind",
|
|
6725
|
+
"not-found",
|
|
6726
|
+
"unique-violation",
|
|
6727
|
+
"plaintext-secret",
|
|
6728
|
+
"foreign-marker",
|
|
6729
|
+
"secret-unavailable",
|
|
6730
|
+
"invalid-record",
|
|
6731
|
+
"declaration-refused",
|
|
6732
|
+
"no-caller",
|
|
6733
|
+
"batch-too-large",
|
|
6734
|
+
"transact-refused"
|
|
6735
|
+
];
|
|
6709
6736
|
var PREFIX = "records/";
|
|
6710
6737
|
/** The base of every records failure. `detail` is the human part of the message. */
|
|
6711
6738
|
var RecordsError = class extends Error {
|
|
@@ -6718,6 +6745,68 @@ var RecordsError = class extends Error {
|
|
|
6718
6745
|
this.detail = detail;
|
|
6719
6746
|
}
|
|
6720
6747
|
};
|
|
6748
|
+
/** A write guarded by `ifRev` found another revision (or an existing row for `ifRev: 0`). */
|
|
6749
|
+
var RevConflictError = class extends RecordsError {
|
|
6750
|
+
constructor(detail) {
|
|
6751
|
+
super("rev-conflict", detail);
|
|
6752
|
+
this.name = "RevConflictError";
|
|
6753
|
+
}
|
|
6754
|
+
};
|
|
6755
|
+
/** `data` exceeds the kind's `maxDataBytes`. Bytes are never record fields (D613). */
|
|
6756
|
+
var RecordTooLargeError = class extends RecordsError {
|
|
6757
|
+
constructor(detail) {
|
|
6758
|
+
super("too-large", detail);
|
|
6759
|
+
this.name = "RecordTooLargeError";
|
|
6760
|
+
}
|
|
6761
|
+
};
|
|
6762
|
+
/** A filter, order or aggregate names a field no declared index serves. */
|
|
6763
|
+
var UnindexedFilterError = class extends RecordsError {
|
|
6764
|
+
constructor(detail) {
|
|
6765
|
+
super("unindexed-filter", detail);
|
|
6766
|
+
this.name = "UnindexedFilterError";
|
|
6767
|
+
}
|
|
6768
|
+
};
|
|
6769
|
+
/** A bulk delete with no predicate at all. */
|
|
6770
|
+
var FilterRequiredError = class extends RecordsError {
|
|
6771
|
+
constructor(detail) {
|
|
6772
|
+
super("filter-required", detail);
|
|
6773
|
+
this.name = "FilterRequiredError";
|
|
6774
|
+
}
|
|
6775
|
+
};
|
|
6776
|
+
/** The caller declared no such kind (another addon's kind is indistinguishable from none). */
|
|
6777
|
+
var UnknownRecordKindError = class extends RecordsError {
|
|
6778
|
+
constructor(detail) {
|
|
6779
|
+
super("unknown-kind", detail);
|
|
6780
|
+
this.name = "UnknownRecordKindError";
|
|
6781
|
+
}
|
|
6782
|
+
};
|
|
6783
|
+
var RecordNotFoundError = class extends RecordsError {
|
|
6784
|
+
constructor(detail) {
|
|
6785
|
+
super("not-found", detail);
|
|
6786
|
+
this.name = "RecordNotFoundError";
|
|
6787
|
+
}
|
|
6788
|
+
};
|
|
6789
|
+
/** A unique index refused the write. */
|
|
6790
|
+
var RecordUniqueViolationError = class extends RecordsError {
|
|
6791
|
+
constructor(detail) {
|
|
6792
|
+
super("unique-violation", detail);
|
|
6793
|
+
this.name = "RecordUniqueViolationError";
|
|
6794
|
+
}
|
|
6795
|
+
};
|
|
6796
|
+
/** A secret field held a plain string where only a keychain marker may be stored. */
|
|
6797
|
+
var PlaintextSecretError = class extends RecordsError {
|
|
6798
|
+
constructor(detail) {
|
|
6799
|
+
super("plaintext-secret", detail);
|
|
6800
|
+
this.name = "PlaintextSecretError";
|
|
6801
|
+
}
|
|
6802
|
+
};
|
|
6803
|
+
/** A marker whose ref is not the row's own (the D878 rule). */
|
|
6804
|
+
var ForeignSecretMarkerError = class extends RecordsError {
|
|
6805
|
+
constructor(detail) {
|
|
6806
|
+
super("foreign-marker", detail);
|
|
6807
|
+
this.name = "ForeignSecretMarkerError";
|
|
6808
|
+
}
|
|
6809
|
+
};
|
|
6721
6810
|
/** The keychain could not store or serve a value: explicit, never an empty string. */
|
|
6722
6811
|
var RecordSecretUnavailableError = class extends RecordsError {
|
|
6723
6812
|
constructor(detail) {
|
|
@@ -6738,6 +6827,70 @@ var DeclarationRefusedError = class extends RecordsError {
|
|
|
6738
6827
|
this.name = "DeclarationRefusedError";
|
|
6739
6828
|
}
|
|
6740
6829
|
};
|
|
6830
|
+
var NoCallerError = class extends RecordsError {
|
|
6831
|
+
constructor(detail) {
|
|
6832
|
+
super("no-caller", detail);
|
|
6833
|
+
this.name = "NoCallerError";
|
|
6834
|
+
}
|
|
6835
|
+
};
|
|
6836
|
+
var BatchTooLargeError = class extends RecordsError {
|
|
6837
|
+
constructor(detail) {
|
|
6838
|
+
super("batch-too-large", detail);
|
|
6839
|
+
this.name = "BatchTooLargeError";
|
|
6840
|
+
}
|
|
6841
|
+
};
|
|
6842
|
+
/**
|
|
6843
|
+
* A `transact` the engine refuses before touching a row: an op on a kind the
|
|
6844
|
+
* caller did not declare in ONE file and ONE `transactFamily`. The detail names
|
|
6845
|
+
* which rule (`cross-file`, `cross-family`, `no-family`); it is never a silent split.
|
|
6846
|
+
*/
|
|
6847
|
+
var TransactRefusedError = class extends RecordsError {
|
|
6848
|
+
constructor(detail) {
|
|
6849
|
+
super("transact-refused", detail);
|
|
6850
|
+
this.name = "TransactRefusedError";
|
|
6851
|
+
}
|
|
6852
|
+
};
|
|
6853
|
+
var FACTORIES = {
|
|
6854
|
+
"rev-conflict": (d) => new RevConflictError(d),
|
|
6855
|
+
"too-large": (d) => new RecordTooLargeError(d),
|
|
6856
|
+
"unindexed-filter": (d) => new UnindexedFilterError(d),
|
|
6857
|
+
"filter-required": (d) => new FilterRequiredError(d),
|
|
6858
|
+
"unknown-kind": (d) => new UnknownRecordKindError(d),
|
|
6859
|
+
"not-found": (d) => new RecordNotFoundError(d),
|
|
6860
|
+
"unique-violation": (d) => new RecordUniqueViolationError(d),
|
|
6861
|
+
"plaintext-secret": (d) => new PlaintextSecretError(d),
|
|
6862
|
+
"foreign-marker": (d) => new ForeignSecretMarkerError(d),
|
|
6863
|
+
"secret-unavailable": (d) => new RecordSecretUnavailableError(d),
|
|
6864
|
+
"invalid-record": (d) => new InvalidRecordError(d),
|
|
6865
|
+
"declaration-refused": (d) => new DeclarationRefusedError(d),
|
|
6866
|
+
"no-caller": (d) => new NoCallerError(d),
|
|
6867
|
+
"batch-too-large": (d) => new BatchTooLargeError(d),
|
|
6868
|
+
"transact-refused": (d) => new TransactRefusedError(d)
|
|
6869
|
+
};
|
|
6870
|
+
function isCode(value) {
|
|
6871
|
+
return RECORDS_ERROR_CODES.some((code) => code === value);
|
|
6872
|
+
}
|
|
6873
|
+
/**
|
|
6874
|
+
* Rebuild the typed error from a message that crossed a wire; `null` when the
|
|
6875
|
+
* message is not a records failure.
|
|
6876
|
+
*/
|
|
6877
|
+
function recordsErrorFromMessage(message) {
|
|
6878
|
+
if (!message.startsWith(PREFIX)) return null;
|
|
6879
|
+
const colon = message.indexOf(": ");
|
|
6880
|
+
if (colon < 0) return null;
|
|
6881
|
+
const code = message.slice(8, colon);
|
|
6882
|
+
if (!isCode(code)) return null;
|
|
6883
|
+
return FACTORIES[code](message.slice(colon + 2));
|
|
6884
|
+
}
|
|
6885
|
+
/** The records failure inside any thrown value (a wrapped tRPC error included), or the value. */
|
|
6886
|
+
function asRecordsError(err) {
|
|
6887
|
+
if (err instanceof RecordsError) return err;
|
|
6888
|
+
if (err instanceof Error) {
|
|
6889
|
+
const typed = recordsErrorFromMessage(err.message);
|
|
6890
|
+
if (typed !== null) return typed;
|
|
6891
|
+
}
|
|
6892
|
+
return err;
|
|
6893
|
+
}
|
|
6741
6894
|
function linkTargetOf(meta) {
|
|
6742
6895
|
if (typeof meta !== "object" || meta === null) return void 0;
|
|
6743
6896
|
const link = Reflect.get(meta, "link");
|
|
@@ -91694,7 +91847,7 @@ async function sealPlaintextCredentials(records, secrets, log) {
|
|
|
91694
91847
|
try {
|
|
91695
91848
|
await records.declare({ "waste-source": plainWasteSourceKind });
|
|
91696
91849
|
} catch (err) {
|
|
91697
|
-
if (err instanceof
|
|
91850
|
+
if (asRecordsError(err) instanceof DeclarationRefusedError) {
|
|
91698
91851
|
log.info("waste-collections: the secret kind is already declared; no plain-text credential can remain");
|
|
91699
91852
|
return { state: "already-secret" };
|
|
91700
91853
|
}
|
|
@@ -6702,6 +6702,33 @@ function integrationRowsApiOver(api) {
|
|
|
6702
6702
|
clearLegacyIntegrationRows: (input) => api.legacyRows.clear(input)
|
|
6703
6703
|
};
|
|
6704
6704
|
}
|
|
6705
|
+
/**
|
|
6706
|
+
* The named failures of `ctx.records` (D881).
|
|
6707
|
+
*
|
|
6708
|
+
* A records call crosses a worker thread, a UDS channel and a tRPC router, and
|
|
6709
|
+
* an error class does not survive any of them - only its message does. So
|
|
6710
|
+
* every message STARTS with a stable code, `records/<code>: <detail>`, and
|
|
6711
|
+
* {@link recordsErrorFromMessage} rebuilds the typed class on the caller's side.
|
|
6712
|
+
* A failed read is never `[]` or `undefined`: it throws one of these.
|
|
6713
|
+
*/
|
|
6714
|
+
/** Every code a records failure carries. */
|
|
6715
|
+
var RECORDS_ERROR_CODES = [
|
|
6716
|
+
"rev-conflict",
|
|
6717
|
+
"too-large",
|
|
6718
|
+
"unindexed-filter",
|
|
6719
|
+
"filter-required",
|
|
6720
|
+
"unknown-kind",
|
|
6721
|
+
"not-found",
|
|
6722
|
+
"unique-violation",
|
|
6723
|
+
"plaintext-secret",
|
|
6724
|
+
"foreign-marker",
|
|
6725
|
+
"secret-unavailable",
|
|
6726
|
+
"invalid-record",
|
|
6727
|
+
"declaration-refused",
|
|
6728
|
+
"no-caller",
|
|
6729
|
+
"batch-too-large",
|
|
6730
|
+
"transact-refused"
|
|
6731
|
+
];
|
|
6705
6732
|
var PREFIX = "records/";
|
|
6706
6733
|
/** The base of every records failure. `detail` is the human part of the message. */
|
|
6707
6734
|
var RecordsError = class extends Error {
|
|
@@ -6714,6 +6741,68 @@ var RecordsError = class extends Error {
|
|
|
6714
6741
|
this.detail = detail;
|
|
6715
6742
|
}
|
|
6716
6743
|
};
|
|
6744
|
+
/** A write guarded by `ifRev` found another revision (or an existing row for `ifRev: 0`). */
|
|
6745
|
+
var RevConflictError = class extends RecordsError {
|
|
6746
|
+
constructor(detail) {
|
|
6747
|
+
super("rev-conflict", detail);
|
|
6748
|
+
this.name = "RevConflictError";
|
|
6749
|
+
}
|
|
6750
|
+
};
|
|
6751
|
+
/** `data` exceeds the kind's `maxDataBytes`. Bytes are never record fields (D613). */
|
|
6752
|
+
var RecordTooLargeError = class extends RecordsError {
|
|
6753
|
+
constructor(detail) {
|
|
6754
|
+
super("too-large", detail);
|
|
6755
|
+
this.name = "RecordTooLargeError";
|
|
6756
|
+
}
|
|
6757
|
+
};
|
|
6758
|
+
/** A filter, order or aggregate names a field no declared index serves. */
|
|
6759
|
+
var UnindexedFilterError = class extends RecordsError {
|
|
6760
|
+
constructor(detail) {
|
|
6761
|
+
super("unindexed-filter", detail);
|
|
6762
|
+
this.name = "UnindexedFilterError";
|
|
6763
|
+
}
|
|
6764
|
+
};
|
|
6765
|
+
/** A bulk delete with no predicate at all. */
|
|
6766
|
+
var FilterRequiredError = class extends RecordsError {
|
|
6767
|
+
constructor(detail) {
|
|
6768
|
+
super("filter-required", detail);
|
|
6769
|
+
this.name = "FilterRequiredError";
|
|
6770
|
+
}
|
|
6771
|
+
};
|
|
6772
|
+
/** The caller declared no such kind (another addon's kind is indistinguishable from none). */
|
|
6773
|
+
var UnknownRecordKindError = class extends RecordsError {
|
|
6774
|
+
constructor(detail) {
|
|
6775
|
+
super("unknown-kind", detail);
|
|
6776
|
+
this.name = "UnknownRecordKindError";
|
|
6777
|
+
}
|
|
6778
|
+
};
|
|
6779
|
+
var RecordNotFoundError = class extends RecordsError {
|
|
6780
|
+
constructor(detail) {
|
|
6781
|
+
super("not-found", detail);
|
|
6782
|
+
this.name = "RecordNotFoundError";
|
|
6783
|
+
}
|
|
6784
|
+
};
|
|
6785
|
+
/** A unique index refused the write. */
|
|
6786
|
+
var RecordUniqueViolationError = class extends RecordsError {
|
|
6787
|
+
constructor(detail) {
|
|
6788
|
+
super("unique-violation", detail);
|
|
6789
|
+
this.name = "RecordUniqueViolationError";
|
|
6790
|
+
}
|
|
6791
|
+
};
|
|
6792
|
+
/** A secret field held a plain string where only a keychain marker may be stored. */
|
|
6793
|
+
var PlaintextSecretError = class extends RecordsError {
|
|
6794
|
+
constructor(detail) {
|
|
6795
|
+
super("plaintext-secret", detail);
|
|
6796
|
+
this.name = "PlaintextSecretError";
|
|
6797
|
+
}
|
|
6798
|
+
};
|
|
6799
|
+
/** A marker whose ref is not the row's own (the D878 rule). */
|
|
6800
|
+
var ForeignSecretMarkerError = class extends RecordsError {
|
|
6801
|
+
constructor(detail) {
|
|
6802
|
+
super("foreign-marker", detail);
|
|
6803
|
+
this.name = "ForeignSecretMarkerError";
|
|
6804
|
+
}
|
|
6805
|
+
};
|
|
6717
6806
|
/** The keychain could not store or serve a value: explicit, never an empty string. */
|
|
6718
6807
|
var RecordSecretUnavailableError = class extends RecordsError {
|
|
6719
6808
|
constructor(detail) {
|
|
@@ -6734,6 +6823,70 @@ var DeclarationRefusedError = class extends RecordsError {
|
|
|
6734
6823
|
this.name = "DeclarationRefusedError";
|
|
6735
6824
|
}
|
|
6736
6825
|
};
|
|
6826
|
+
var NoCallerError = class extends RecordsError {
|
|
6827
|
+
constructor(detail) {
|
|
6828
|
+
super("no-caller", detail);
|
|
6829
|
+
this.name = "NoCallerError";
|
|
6830
|
+
}
|
|
6831
|
+
};
|
|
6832
|
+
var BatchTooLargeError = class extends RecordsError {
|
|
6833
|
+
constructor(detail) {
|
|
6834
|
+
super("batch-too-large", detail);
|
|
6835
|
+
this.name = "BatchTooLargeError";
|
|
6836
|
+
}
|
|
6837
|
+
};
|
|
6838
|
+
/**
|
|
6839
|
+
* A `transact` the engine refuses before touching a row: an op on a kind the
|
|
6840
|
+
* caller did not declare in ONE file and ONE `transactFamily`. The detail names
|
|
6841
|
+
* which rule (`cross-file`, `cross-family`, `no-family`); it is never a silent split.
|
|
6842
|
+
*/
|
|
6843
|
+
var TransactRefusedError = class extends RecordsError {
|
|
6844
|
+
constructor(detail) {
|
|
6845
|
+
super("transact-refused", detail);
|
|
6846
|
+
this.name = "TransactRefusedError";
|
|
6847
|
+
}
|
|
6848
|
+
};
|
|
6849
|
+
var FACTORIES = {
|
|
6850
|
+
"rev-conflict": (d) => new RevConflictError(d),
|
|
6851
|
+
"too-large": (d) => new RecordTooLargeError(d),
|
|
6852
|
+
"unindexed-filter": (d) => new UnindexedFilterError(d),
|
|
6853
|
+
"filter-required": (d) => new FilterRequiredError(d),
|
|
6854
|
+
"unknown-kind": (d) => new UnknownRecordKindError(d),
|
|
6855
|
+
"not-found": (d) => new RecordNotFoundError(d),
|
|
6856
|
+
"unique-violation": (d) => new RecordUniqueViolationError(d),
|
|
6857
|
+
"plaintext-secret": (d) => new PlaintextSecretError(d),
|
|
6858
|
+
"foreign-marker": (d) => new ForeignSecretMarkerError(d),
|
|
6859
|
+
"secret-unavailable": (d) => new RecordSecretUnavailableError(d),
|
|
6860
|
+
"invalid-record": (d) => new InvalidRecordError(d),
|
|
6861
|
+
"declaration-refused": (d) => new DeclarationRefusedError(d),
|
|
6862
|
+
"no-caller": (d) => new NoCallerError(d),
|
|
6863
|
+
"batch-too-large": (d) => new BatchTooLargeError(d),
|
|
6864
|
+
"transact-refused": (d) => new TransactRefusedError(d)
|
|
6865
|
+
};
|
|
6866
|
+
function isCode(value) {
|
|
6867
|
+
return RECORDS_ERROR_CODES.some((code) => code === value);
|
|
6868
|
+
}
|
|
6869
|
+
/**
|
|
6870
|
+
* Rebuild the typed error from a message that crossed a wire; `null` when the
|
|
6871
|
+
* message is not a records failure.
|
|
6872
|
+
*/
|
|
6873
|
+
function recordsErrorFromMessage(message) {
|
|
6874
|
+
if (!message.startsWith(PREFIX)) return null;
|
|
6875
|
+
const colon = message.indexOf(": ");
|
|
6876
|
+
if (colon < 0) return null;
|
|
6877
|
+
const code = message.slice(8, colon);
|
|
6878
|
+
if (!isCode(code)) return null;
|
|
6879
|
+
return FACTORIES[code](message.slice(colon + 2));
|
|
6880
|
+
}
|
|
6881
|
+
/** The records failure inside any thrown value (a wrapped tRPC error included), or the value. */
|
|
6882
|
+
function asRecordsError(err) {
|
|
6883
|
+
if (err instanceof RecordsError) return err;
|
|
6884
|
+
if (err instanceof Error) {
|
|
6885
|
+
const typed = recordsErrorFromMessage(err.message);
|
|
6886
|
+
if (typed !== null) return typed;
|
|
6887
|
+
}
|
|
6888
|
+
return err;
|
|
6889
|
+
}
|
|
6737
6890
|
function linkTargetOf(meta) {
|
|
6738
6891
|
if (typeof meta !== "object" || meta === null) return void 0;
|
|
6739
6892
|
const link = Reflect.get(meta, "link");
|
|
@@ -91690,7 +91843,7 @@ async function sealPlaintextCredentials(records, secrets, log) {
|
|
|
91690
91843
|
try {
|
|
91691
91844
|
await records.declare({ "waste-source": plainWasteSourceKind });
|
|
91692
91845
|
} catch (err) {
|
|
91693
|
-
if (err instanceof
|
|
91846
|
+
if (asRecordsError(err) instanceof DeclarationRefusedError) {
|
|
91694
91847
|
log.info("waste-collections: the secret kind is already declared; no plain-text credential can remain");
|
|
91695
91848
|
return { state: "already-secret" };
|
|
91696
91849
|
}
|
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.35",
|
|
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",
|