@camstack/types 1.2.327 → 1.2.329

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.
Files changed (72) hide show
  1. package/dist/addon/base-addon.d.ts +58 -0
  2. package/dist/addon/secret-aware-context.d.ts +27 -0
  3. package/dist/addon/secret-paths.d.ts +48 -0
  4. package/dist/addon/secret-settings-view.d.ts +80 -0
  5. package/dist/addon.d.ts +1 -0
  6. package/dist/addon.js +52 -4
  7. package/dist/addon.mjs +27 -5
  8. package/dist/capabilities/addons.cap.d.ts +4 -4
  9. package/dist/capabilities/alarm-panel.cap.d.ts +8 -8
  10. package/dist/capabilities/alerts.cap.d.ts +5 -5
  11. package/dist/capabilities/control.cap.d.ts +11 -11
  12. package/dist/capabilities/day-night.cap.d.ts +16 -16
  13. package/dist/capabilities/device-manager.cap.d.ts +2 -0
  14. package/dist/capabilities/enum-sensor.cap.d.ts +4 -4
  15. package/dist/capabilities/index.d.ts +6 -2
  16. package/dist/capabilities/integrations.cap.d.ts +6 -3
  17. package/dist/capabilities/keychain-admin.cap.d.ts +312 -0
  18. package/dist/capabilities/keychain.cap.d.ts +180 -0
  19. package/dist/capabilities/lawn-mower-control.cap.d.ts +4 -4
  20. package/dist/capabilities/log-channels.cap.d.ts +1 -1
  21. package/dist/capabilities/log-destination.cap.d.ts +5 -5
  22. package/dist/capabilities/notification-rules.cap.d.ts +118 -118
  23. package/dist/capabilities/osd-manager.cap.d.ts +11 -11
  24. package/dist/capabilities/osd.cap.d.ts +5 -5
  25. package/dist/capabilities/pipeline-analytics.cap.d.ts +1291 -118
  26. package/dist/capabilities/pipeline-orchestrator.cap.d.ts +384 -0
  27. package/dist/capabilities/pipeline-runner.cap.d.ts +145 -2
  28. package/dist/capabilities/storage.cap.d.ts +1 -1
  29. package/dist/capabilities/system.cap.d.ts +16 -16
  30. package/dist/capabilities/webrtc-session.cap.d.ts +3 -3
  31. package/dist/client.js +37 -1
  32. package/dist/client.mjs +37 -1
  33. package/dist/device/device-context.d.ts +11 -1
  34. package/dist/device/index.d.ts +1 -1
  35. package/dist/enums/event-category.d.ts +7 -0
  36. package/dist/enums.js +1 -1
  37. package/dist/enums.mjs +1 -1
  38. package/dist/{event-category-CtBAl88K.js → event-category-CHduMGvg.js} +7 -0
  39. package/dist/{event-category-B_0XEcLF.mjs → event-category-DaIZi00R.mjs} +7 -0
  40. package/dist/generated/addon-api.d.ts +289 -0
  41. package/dist/generated/cap-input-defaults.d.ts +1 -1
  42. package/dist/generated/capability-router-map.d.ts +8 -2
  43. package/dist/generated/method-access-map.d.ts +1 -1
  44. package/dist/generated/method-device-selectors.d.ts +1 -1
  45. package/dist/generated/system-proxy.d.ts +4 -2
  46. package/dist/health/wiring-health.d.ts +8 -8
  47. package/dist/index.d.ts +6 -2
  48. package/dist/index.js +1881 -101
  49. package/dist/index.mjs +1766 -98
  50. package/dist/interfaces/addon.d.ts +25 -0
  51. package/dist/interfaces/config-ui-secrets.d.ts +12 -0
  52. package/dist/interfaces/config-ui.d.ts +29 -1
  53. package/dist/interfaces/event-bus.d.ts +11 -0
  54. package/dist/interfaces/pipeline-runner-capability.d.ts +18 -0
  55. package/dist/keychain/index.d.ts +5 -0
  56. package/dist/keychain/known-secrets.d.ts +31 -0
  57. package/dist/keychain/resolve-secret-views.d.ts +2 -0
  58. package/dist/keychain/secret-marker.d.ts +52 -0
  59. package/dist/keychain/secret-ref.d.ts +62 -0
  60. package/dist/keychain/secrets-access.d.ts +77 -0
  61. package/dist/logging/log-channel.d.ts +2 -2
  62. package/dist/pipeline/auto-tune/plan-schemas.d.ts +123 -0
  63. package/dist/pipeline/auto-tune/recommend.d.ts +26 -1
  64. package/dist/pipeline/load-balancing/schemas.d.ts +8 -7
  65. package/dist/pipeline/node-benchmark/benchmark-mode.d.ts +57 -0
  66. package/dist/pipeline/node-benchmark/index.d.ts +9 -0
  67. package/dist/pipeline/node-benchmark/results.d.ts +52 -0
  68. package/dist/pipeline/node-benchmark/schemas.d.ts +848 -0
  69. package/dist/pipeline/node-benchmark/step-tree.d.ts +23 -0
  70. package/dist/{sleep-az1qiFzK.js → sleep-ClNXPpWR.js} +1580 -121
  71. package/dist/{sleep-B0JG7-_F.mjs → sleep-DujUvOcb.mjs} +1340 -121
  72. package/package.json +1 -1
@@ -4,6 +4,7 @@ import type { CustomActionCaller, CustomActionsSpec } from '../capabilities/cust
4
4
  import type { PipelineSlot } from '../types/pipeline.js';
5
5
  import type { AddonDataPlane } from './addon-data-plane.js';
6
6
  import type { AddonPeerBytes } from './addon-peer-bytes.js';
7
+ import type { SecretsAccess } from '../keychain/secrets-access.js';
7
8
  import type { CapabilityDeclaration } from './capability.js';
8
9
  import type { ConfigUISchemaWithValues, FieldProbeResult } from './config-ui.js';
9
10
  import type { IEventBus, ReadinessScope } from './event-bus.js';
@@ -202,6 +203,14 @@ export interface IKernelServices {
202
203
  * dispatch from remote dispatch without a direct Moleculer dependency.
203
204
  */
204
205
  readonly localNodeId?: string;
206
+ /**
207
+ * The runner id hosting an addon — its `execution.group`, else itself
208
+ * (`resolveRunnerId`). Hub in-process contexts only: the keychain uses it to
209
+ * accept a grouped runner's transport stamp (the group id) for the refs of
210
+ * the addons that runner hosts. Absent elsewhere; callers fall back to
211
+ * identity.
212
+ */
213
+ readonly runnerIdForAddon?: (addonId: string) => string;
205
214
  /**
206
215
  * Local storage provider — direct filesystem access with zero serialization.
207
216
  * Use for file I/O (write/read with Buffer data) that can't go through tRPC.
@@ -695,6 +704,17 @@ export interface AddonContext<TConfig = Record<string, unknown>> {
695
704
  * (tests, tooling), which is why the field is optional.
696
705
  */
697
706
  readonly peerBytes?: AddonPeerBytes;
707
+ /**
708
+ * This addon's keychain values (D787). The owner is the addon's own id,
709
+ * closed over by the kernel; nothing passed to it can change that.
710
+ * `BaseAddon` uses it for every secret field of its schema (a marker in the
711
+ * blob, the value here) — reach for it directly only for values that are
712
+ * not settings (a business collection's credentials, a minted token).
713
+ *
714
+ * Absent when the addon is loaded in isolation (tests, tooling) or on a
715
+ * kernel that predates the keychain.
716
+ */
717
+ readonly secrets?: SecretsAccess;
698
718
  /**
699
719
  * Runtime accessor for the capability registry — exposed to addons that
700
720
  * need to enumerate peers of a collection cap (e.g. `turn-provider`) or
@@ -829,6 +849,11 @@ export interface ICamstackAddon {
829
849
  * persisted store. */
830
850
  getGlobalSettings?(overlay?: Record<string, unknown>, cap?: string, nodeId?: string): Promise<ConfigUISchemaWithValues | null>;
831
851
  updateGlobalSettings?(patch: Record<string, unknown>, nodeId?: string): Promise<void>;
852
+ /**
853
+ * The same write, made by the OPERATOR (D787): the kernel's settings
854
+ * dispatch prefers it when the addon has it.
855
+ */
856
+ updateGlobalSettingsAsOperator?(patch: Record<string, unknown>, nodeId?: string): Promise<void>;
832
857
  /**
833
858
  * Integration-level settings — the subset of the global schema the addon
834
859
  * declared as its INTEGRATION's configuration (`BaseAddon.
@@ -35,11 +35,23 @@ import type { ConfigField } from './config-ui.js';
35
35
  export declare const REDACTED_SECRET = "__camstack_redacted__";
36
36
  /** Is this field's stored value a credential? */
37
37
  export declare function isSecretConfigField(field: ConfigField): boolean;
38
+ /**
39
+ * Is this field's value stored in the KEYCHAIN (D787)? Every secret field is,
40
+ * by its TYPE, unless it opts out with `storage: 'inline'` — never by its name.
41
+ */
42
+ export declare function isKeychainStoredField(field: ConfigField): boolean;
38
43
  /**
39
44
  * Every config key in `schema` whose value is a secret, including keys nested
40
45
  * inside `group` / `sub-tabs` containers.
41
46
  */
42
47
  export declare function collectSecretConfigKeys(schema: unknown): ReadonlySet<string>;
48
+ /**
49
+ * Every top-level config key whose value the KEYCHAIN stores (D787) —
50
+ * {@link collectSecretConfigKeys} minus `storage: 'inline'` and minus JSON
51
+ * blobs (see {@link isKeychainStoredField}). What a form sends as
52
+ * `secretKeys` so the owner's door knows which values to keep out of the blob.
53
+ */
54
+ export declare function collectKeychainStoredKeys(schema: unknown): ReadonlySet<string>;
43
55
  /**
44
56
  * True when the value is a readable schema declaring at least one field of any
45
57
  * kind. Lets a caller tell "this provider has no secrets" from "this provider's
@@ -148,6 +148,15 @@ export interface ConfigFieldBase {
148
148
  * non-admin session. It costs nothing when the field is already a password.
149
149
  */
150
150
  readonly secret?: boolean;
151
+ /**
152
+ * Where a SECRET field's value is stored (D787). Default for every field
153
+ * {@link isSecretConfigField} selects (`type: 'password'` or `secret: true`):
154
+ * `'keychain'` — the settings blob holds a `{"$secret": ref}` marker and the
155
+ * value lives in the encrypted keychain; the form sees "set / not set",
156
+ * never the value. `'inline'` opts out, for a NON-secret value that is merely
157
+ * drawn masked. Decided by the field's TYPE and this flag — never its name.
158
+ */
159
+ readonly storage?: 'keychain' | 'inline';
151
160
  /** Per-model knob applicability — see {@link ConfigFieldModelApplicability}. */
152
161
  readonly modelApplicability?: ConfigFieldModelApplicability;
153
162
  /**
@@ -745,6 +754,14 @@ export interface ConfigEditableArrayField extends ConfigFieldBase {
745
754
  * collapse to an em-dash. Falls back to `Row N` when not provided.
746
755
  */
747
756
  readonly rowTitleTemplate?: string;
757
+ /**
758
+ * The row field that IDENTIFIES a row (default `'id'`). A secret inside a row
759
+ * is stored under a ref addressed by this id — never by index — so a reorder
760
+ * keeps every ref, a removed row's refs are deleted, and a duplicated row's
761
+ * secret is "not set" rather than copied (D787). A row saved without one has
762
+ * an id minted for it.
763
+ */
764
+ readonly itemIdKey?: string;
748
765
  }
749
766
  export interface ConfigModelSelectorField extends ConfigFieldBase {
750
767
  type: 'model-selector';
@@ -1096,4 +1113,15 @@ export declare function resolveHydratedFieldValue(schema: unknown, key: string):
1096
1113
  * the schema default or `null`. This mirrors the old backend behaviour where
1097
1114
  * `FormBuilder` rendered `values[key] ?? field.default`.
1098
1115
  */
1099
- export declare function hydrateSchema(schema: ConfigUISchema, values: Record<string, unknown>): ConfigUISchemaWithValues;
1116
+ /** How `hydrateSchema` treats keychain-stored secret fields (D789). */
1117
+ export interface HydrateSchemaOptions {
1118
+ /**
1119
+ * `true` — the form is the addon's OWN settings form, saved through the
1120
+ * keychain-aware `BaseAddon` path: a pre-keychain inline value is shown as
1121
+ * "set" too, never as text. Omitted — only a keychain MARKER becomes a view;
1122
+ * an inline value hydrates as before, because forms saved through other
1123
+ * paths (a camera driver's settings) need the value they were given.
1124
+ */
1125
+ readonly inlineSecretsAsViews?: boolean;
1126
+ }
1127
+ export declare function hydrateSchema(schema: ConfigUISchema, values: Record<string, unknown>, options?: HydrateSchemaOptions): ConfigUISchemaWithValues;
@@ -743,6 +743,16 @@ export interface TopologyNode {
743
743
  */
744
744
  export type StreamHealthReason = 'stale-timeout' | 'recovered' | 'first-packet' | 'suspended' | 'resumed' | 'broker-destroyed';
745
745
  /** All known event categories with their typed payloads */
746
+ /**
747
+ * `keychain.changed` — a value was put or deleted. Never carries the value.
748
+ */
749
+ export type KeychainChangedPayload = {
750
+ readonly ref: string;
751
+ readonly owner: string;
752
+ /** The version now stored; `null` after a delete. */
753
+ readonly version: number | null;
754
+ readonly change: 'put' | 'delete';
755
+ };
746
756
  export interface EventCatalog {
747
757
  'system.boot': {
748
758
  mode: string;
@@ -753,6 +763,7 @@ export interface EventCatalog {
753
763
  'system.restarting': PendingRestartMarkerPayload;
754
764
  'system.restart-completed': PendingRestartMarkerPayload;
755
765
  'system.tls-cert-changed': TlsCertChangedPayload;
766
+ 'keychain.changed': KeychainChangedPayload;
756
767
  'update.available': {
757
768
  /**
758
769
  * `addon` and `server` are npm packages a node can install for itself.
@@ -305,4 +305,22 @@ export interface IPipelineRunnerProvider {
305
305
  }): Promise<{
306
306
  released: number;
307
307
  }>;
308
+ /**
309
+ * Node benchmark measurement on THIS node (D791). See
310
+ * `pipelineRunnerCapability.startNodeBench` for the contract.
311
+ */
312
+ startNodeBench(input: import('../pipeline/node-benchmark/schemas.js').NodeBenchRunnerInputRaw): Promise<{
313
+ accepted: true;
314
+ runId: string;
315
+ }>;
316
+ /** The run's status; `null` when this runner does not know `runId`. */
317
+ getNodeBenchStatus(input: {
318
+ readonly runId: string;
319
+ }): Promise<import('../pipeline/node-benchmark/schemas.js').NodeBenchRunnerStatus | null>;
320
+ /** Stop the run; what it finished is kept. */
321
+ abortNodeBench(input: {
322
+ readonly runId: string;
323
+ }): Promise<{
324
+ aborted: boolean;
325
+ }>;
308
326
  }
@@ -0,0 +1,5 @@
1
+ export { clearKnownSecrets, forgetKnownSecret, knownSecretCount, MIN_SCRUBBED_LENGTH, registerKnownSecret, scrubKnownSecrets, shortSecretRefHash, } from './known-secrets.js';
2
+ export { classifySecretWrite, isSecretClear, isSecretFieldView, isSecretMarker, isSecretMarkerLike, makeSecretMarker, SECRET_CLEAR, type SecretClearInstruction, type SecretFieldView, type SecretMarker, type SecretWriteIntent, toSecretFieldView, } from './secret-marker.js';
3
+ export { arrayItemFieldPath, buildSecretRef, formatSecretScope, globalSecretScope, isSecretRef, normalizeSecretOwner, parseSecretRef, SECRET_REF_SCHEME, type SecretRefParts, type SecretScope, } from './secret-ref.js';
4
+ export { createSecretsAccess, type KeychainTransport, REVALIDATE_AFTER_MS, type SecretsAccess, type SecretsAccessOptions, } from './secrets-access.js';
5
+ export { resolveSecretViewsIn } from './resolve-secret-views.js';
@@ -0,0 +1,31 @@
1
+ /**
2
+ * The per-process set of secret VALUES this process has resolved, so the log
3
+ * pipeline can scrub them wherever they turn up — a library's error message,
4
+ * an argv a spawn logged, a URL someone interpolated.
5
+ *
6
+ * Key-name redaction cannot catch `Command failed: cloudflared --token eyJ…`:
7
+ * the value is in a message, not under a named key. The only thing that can is
8
+ * knowing the value. `ctx.secrets` registers every value it resolves (and every
9
+ * value it stores), and `scrubKnownSecrets` replaces each occurrence with
10
+ * `‹secret:<hash of its ref>›` — enough to say WHICH secret leaked, nothing of
11
+ * what it is.
12
+ *
13
+ * Process-global on purpose: a forked runner scrubs its own logs before they
14
+ * leave over UDS, and hub-main scrubs what it resolved. Values shorter than
15
+ * {@link MIN_SCRUBBED_LENGTH} are not registered — a 4-digit PIN would turn
16
+ * every timestamp containing it into a redaction.
17
+ */
18
+ /** Below this length a value is too likely to collide with ordinary text. */
19
+ export declare const MIN_SCRUBBED_LENGTH = 8;
20
+ /** FNV-1a, 32-bit, as 8 hex chars — a label, not a security property. */
21
+ export declare function shortSecretRefHash(ref: string): string;
22
+ /** Remember a value this process holds. A no-op for short or empty values. */
23
+ export declare function registerKnownSecret(value: string, ref: string): void;
24
+ /** Forget a value (it was replaced or deleted). */
25
+ export declare function forgetKnownSecret(value: string): void;
26
+ /** How many values are registered — for tests and the status page. */
27
+ export declare function knownSecretCount(): number;
28
+ /** Test seam: drop every registered value. */
29
+ export declare function clearKnownSecrets(): void;
30
+ /** Replace every registered value inside `text` with its label. */
31
+ export declare function scrubKnownSecrets(text: string): string;
@@ -0,0 +1,2 @@
1
+ import type { SecretsAccess } from './secrets-access.js';
2
+ export declare function resolveSecretViewsIn(args: unknown, secrets: SecretsAccess | undefined): Promise<unknown>;
@@ -0,0 +1,52 @@
1
+ /** The marker a settings blob stores in place of a secret value. */
2
+ export interface SecretMarker {
3
+ readonly $secret: string;
4
+ readonly v: 1;
5
+ }
6
+ /**
7
+ * What a read surface hands the UI for a secret field that holds something.
8
+ * `$secret` is `null` when the stored value predates the keychain (it is still
9
+ * plaintext in the blob until the operator's one-off migration moves it): the
10
+ * UI draws "set" either way and the value never leaves the hub.
11
+ */
12
+ export interface SecretFieldView {
13
+ readonly $secret: string | null;
14
+ readonly v: 1;
15
+ readonly set: true;
16
+ /** The stored value is still inline plaintext (pre-keychain). */
17
+ readonly inline?: true;
18
+ }
19
+ /** The explicit "remove this secret" instruction a form sends. */
20
+ export interface SecretClearInstruction {
21
+ readonly $secretClear: true;
22
+ }
23
+ export declare const SECRET_CLEAR: SecretClearInstruction;
24
+ export declare function makeSecretMarker(ref: string): SecretMarker;
25
+ /** A stored marker: an object whose `$secret` is a non-empty string. */
26
+ export declare function isSecretMarker(value: unknown): value is SecretMarker;
27
+ /** Anything carrying a `$secret` key — a stored marker or a UI view of one. */
28
+ export declare function isSecretMarkerLike(value: unknown): boolean;
29
+ export declare function isSecretClear(value: unknown): value is SecretClearInstruction;
30
+ export declare function isSecretFieldView(value: unknown): value is SecretFieldView;
31
+ /**
32
+ * The UI view of a stored secret field value: a marker becomes "set", inline
33
+ * plaintext becomes "set (inline)", nothing becomes `null`. A value never
34
+ * survives this function.
35
+ */
36
+ export declare function toSecretFieldView(stored: unknown): SecretFieldView | null;
37
+ /** How an incoming value for a secret path is to be treated. */
38
+ export type SecretWriteIntent = {
39
+ readonly kind: 'keep';
40
+ } | {
41
+ readonly kind: 'clear';
42
+ } | {
43
+ readonly kind: 'set';
44
+ readonly value: string;
45
+ };
46
+ /**
47
+ * Classify an incoming value for a secret path. Only a non-empty string that is
48
+ * not a redaction token sets a value; only {@link SECRET_CLEAR} clears.
49
+ * Everything else — a marker (ours or anyone's), a UI view, `''`, `null`,
50
+ * `undefined`, a redaction token, a non-string — keeps what is stored.
51
+ */
52
+ export declare function classifySecretWrite(incoming: unknown): SecretWriteIntent;
@@ -0,0 +1,62 @@
1
+ /**
2
+ * The address of one keychain value: `secret://<owner>/<scope>/<fieldPath>`.
3
+ *
4
+ * A ref is DETERMINISTIC from where the value lives — the owner addon, the
5
+ * scope (global, one node, one device, one integration, one row of a business
6
+ * collection) and the field path inside that scope — so saving the same field
7
+ * twice updates the same ref, and the ref itself says which settings blob
8
+ * points at it. It is also the AAD of the value's ciphertext: a ciphertext
9
+ * copied onto another ref does not decrypt.
10
+ *
11
+ * Array items are addressed by ITEM ID, never by index
12
+ * (`providers[authentik].clientSecret`), so reordering a list keeps every ref.
13
+ *
14
+ * Pure and browser-safe: no node builtins, no I/O.
15
+ */
16
+ /** The URI scheme of every keychain ref. */
17
+ export declare const SECRET_REF_SCHEME = "secret://";
18
+ /** Where, inside its owner, a secret lives. */
19
+ export type SecretScope = {
20
+ readonly kind: 'global';
21
+ } | {
22
+ readonly kind: 'node';
23
+ readonly nodeId: string;
24
+ } | {
25
+ readonly kind: 'device';
26
+ readonly deviceId: number;
27
+ } | {
28
+ readonly kind: 'integration';
29
+ readonly integrationId: string;
30
+ } | {
31
+ readonly kind: 'row';
32
+ readonly collection: string;
33
+ readonly rowId: string;
34
+ };
35
+ /** A ref, taken apart. */
36
+ export interface SecretRefParts {
37
+ readonly owner: string;
38
+ readonly scope: SecretScope;
39
+ readonly fieldPath: string;
40
+ }
41
+ /** The scope every addon-wide (not per-node, not per-device) setting lives in. */
42
+ export declare function globalSecretScope(): SecretScope;
43
+ /**
44
+ * An addon id as a ref owner. A hub in-process builtin's context id is
45
+ * `addon:<id>`; the owner of its secrets is `<id>`, exactly as for the same
46
+ * addon running forked.
47
+ */
48
+ export declare function normalizeSecretOwner(addonId: string): string;
49
+ /** The scope as it appears inside a ref (`global`, `node/<id>`, …). */
50
+ export declare function formatSecretScope(scope: SecretScope): string;
51
+ /**
52
+ * The field path of a value inside an array item, addressed by the item's id:
53
+ * `arrayItemFieldPath('providers', 'authentik', 'clientSecret')` →
54
+ * `providers[authentik].clientSecret`.
55
+ */
56
+ export declare function arrayItemFieldPath(arrayKey: string, itemId: string, fieldKey: string): string;
57
+ /** Build a ref. Throws on an empty owner or field path — both are bugs. */
58
+ export declare function buildSecretRef(parts: SecretRefParts): string;
59
+ /** True when `value` is shaped like a keychain ref (not that it exists). */
60
+ export declare function isSecretRef(value: unknown): value is string;
61
+ /** Take a ref apart; `null` when it is not a well-formed ref. */
62
+ export declare function parseSecretRef(ref: string): SecretRefParts | null;
@@ -0,0 +1,77 @@
1
+ /**
2
+ * `ctx.secrets` — an addon's handle on its OWN keychain values.
3
+ *
4
+ * The owner is closed over at construction (the addon's id); nothing a caller
5
+ * passes can change it. How the call travels is the transport's business:
6
+ *
7
+ * - hub in-process builtin: the provider is in the same process, so the
8
+ * transport states the owner explicitly (`callerAddonId`) — the one place a
9
+ * claim is trusted, because no wire is involved;
10
+ * - forked runner / agent addon: the transport sends the bare input and the
11
+ * parent (or the agent, through `$hub-cap-fwd`) stamps who is calling.
12
+ *
13
+ * The cache holds `ref → {value, version}` with no expiry while the version is
14
+ * current. `keychain.changed` drops an entry; an entry older than
15
+ * {@link REVALIDATE_AFTER_MS} is re-fetched on its next use (the safety net
16
+ * for a dropped event, D8). A failed fetch answers the last good value when
17
+ * there is one — a locked keychain never turns a working credential into an
18
+ * empty one — and `unavailable` otherwise, never `missing`.
19
+ */
20
+ import type { KeychainResolveResult, KeychainState } from '../capabilities/keychain.cap.js';
21
+ import type { IEventBus } from '../interfaces/event-bus.js';
22
+ import { type SecretScope } from './secret-ref.js';
23
+ /** Re-fetch a cached value after this long, even with no change event. */
24
+ export declare const REVALIDATE_AFTER_MS: number;
25
+ /** The four calls a {@link SecretsAccess} makes. `callerAddonId` is set only in-process. */
26
+ export interface KeychainTransport {
27
+ put(input: {
28
+ readonly ref: string;
29
+ readonly value: string;
30
+ }): Promise<{
31
+ readonly ref: string;
32
+ readonly version: number;
33
+ }>;
34
+ resolve(input: {
35
+ readonly refs: readonly string[];
36
+ }): Promise<KeychainResolveResult>;
37
+ delete(input: {
38
+ readonly refs: readonly string[];
39
+ }): Promise<{
40
+ readonly deleted: number;
41
+ }>;
42
+ getState(): Promise<KeychainState>;
43
+ }
44
+ export interface SecretsAccess {
45
+ /** The owner every ref of this handle belongs to. */
46
+ readonly owner: string;
47
+ /** Build this owner's ref for a field. */
48
+ ref(scope: SecretScope, fieldPath: string): string;
49
+ /** Resolve refs in one call; cached values are served without one. */
50
+ resolve(refs: readonly string[]): Promise<KeychainResolveResult>;
51
+ /** Store a value. Throws while the keychain is locked. */
52
+ put(ref: string, value: string): Promise<number>;
53
+ /** Remove refs. Unknown refs are ignored. */
54
+ delete(refs: readonly string[]): Promise<number>;
55
+ /** Whether values can be stored right now. */
56
+ state(): Promise<KeychainState>;
57
+ /**
58
+ * Subscribe to changes of refs this handle has served. The handler runs
59
+ * after the cache dropped the ref. Returns the unsubscribe.
60
+ */
61
+ onChange(handler: (ref: string) => void): () => void;
62
+ /**
63
+ * In-process SYSTEM builtins only (device-manager, storage-orchestrator):
64
+ * act as a door for another owner's values. `null` everywhere else — a
65
+ * forked addon has no way to state an identity the transport would accept.
66
+ */
67
+ readonly forOwner: ((owner: string) => SecretsAccess) | null;
68
+ }
69
+ export interface SecretsAccessOptions {
70
+ readonly owner: string;
71
+ readonly transport: KeychainTransport;
72
+ /** Builds the transport for another owner — in-process system builtins only. */
73
+ readonly transportForOwner?: (owner: string) => KeychainTransport;
74
+ readonly eventBus?: Pick<IEventBus, 'subscribe'>;
75
+ readonly now?: () => number;
76
+ }
77
+ export declare function createSecretsAccess(opts: SecretsAccessOptions): SecretsAccess;
@@ -56,8 +56,8 @@ import type { IScopedLogger, LogExtras } from '../interfaces/logging.js';
56
56
  * to read it later.
57
57
  */
58
58
  export declare const LogChannelLevelSchema: z.ZodEnum<{
59
- error: "error";
60
59
  info: "info";
60
+ error: "error";
61
61
  warn: "warn";
62
62
  }>;
63
63
  /**
@@ -68,8 +68,8 @@ export declare const LogChannelDescriptorSchema: z.ZodObject<{
68
68
  name: z.ZodString;
69
69
  description: z.ZodString;
70
70
  defaultLevel: z.ZodEnum<{
71
- error: "error";
72
71
  info: "info";
72
+ error: "error";
73
73
  warn: "warn";
74
74
  }>;
75
75
  perDevice: z.ZodBoolean;