@chipmobilesdk/rn-notification 0.4.0 → 0.5.0
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 +257 -166
- package/README.md +420 -410
- package/package.json +61 -75
- package/skills/sdk-rn-notification/SKILL.md +172 -173
- package/src/channel/migrate.ts +285 -289
- package/src/channel/tone-map.ts +130 -130
- package/src/channel/validate-tone.ts +61 -61
- package/src/contract/channel.ts +192 -188
- package/src/contract/diagnostics.ts +102 -102
- package/src/contract/errors.ts +142 -134
- package/src/contract/index.ts +10 -10
- package/src/contract/interaction.ts +62 -62
- package/src/contract/notification.ts +118 -118
- package/src/contract/permission.ts +55 -60
- package/src/contract/reconcile.ts +88 -88
- package/src/contract/recurrence.ts +129 -129
- package/src/diagnostics/burst.ts +101 -101
- package/src/diagnostics/events.ts +81 -72
- package/src/diagnostics/redact.ts +55 -72
- package/src/diagnostics/snapshot.ts +100 -64
- package/src/engine/adapter.ts +172 -172
- package/src/engine/codec.ts +89 -89
- package/src/engine/notify-kit-engine.ts +715 -707
- package/src/index.ts +208 -208
- package/src/initialize.ts +247 -236
- package/src/interaction/index.ts +146 -146
- package/src/maintenance/cycle.ts +150 -154
- package/src/maintenance/permission-refresh.ts +39 -41
- package/src/maintenance/reanchor.ts +101 -101
- package/src/maintenance/toggle.ts +66 -64
- package/src/maintenance/verify.ts +83 -83
- package/src/maintenance/window-refresh.ts +64 -64
- package/src/permission/index.ts +183 -183
- package/src/permission/state.ts +77 -77
- package/src/push/envelope.ts +165 -165
- package/src/push/fcm-provider.ts +150 -146
- package/src/push/gate.ts +190 -190
- package/src/push/index.ts +33 -29
- package/src/push/instructions.ts +114 -109
- package/src/push/provider-adapter.ts +54 -54
- package/src/push/signout.ts +65 -65
- package/src/reconcile/chunk.ts +53 -53
- package/src/reconcile/diff.ts +142 -145
- package/src/reconcile/duplicates.ts +73 -73
- package/src/reconcile/index.ts +180 -180
- package/src/reconcile/truncate.ts +56 -56
- package/src/recurrence/clock-guard.ts +73 -71
- package/src/recurrence/expand.ts +326 -319
- package/src/recurrence/index.ts +270 -259
- package/src/repeat/expiry.ts +53 -55
- package/src/repeat/index.ts +54 -54
- package/src/repeat/marker.ts +72 -72
- package/src/repeat/place.ts +73 -73
- package/src/schedule/anchor.ts +294 -267
- package/src/schedule/index.ts +174 -181
- package/src/schedule/partition.ts +88 -85
- package/src/schedule/resolve-moment.ts +80 -80
- package/src/schedule/validate-content.ts +111 -111
- package/src/schedule/validate-identifier.ts +126 -126
- package/src/schedule/writer.ts +55 -55
- package/src/state/caps.ts +71 -71
- package/src/state/dedup-ledger.ts +35 -35
- package/src/state/interaction-buffer.ts +101 -73
- package/src/state/mmkv-store.ts +92 -75
- package/src/state/permission-history.ts +41 -41
- package/src/state/record.ts +270 -263
- package/src/state/reset.ts +41 -41
- package/src/state/series-ledger.ts +91 -91
- package/src/state/store.ts +43 -40
- package/src/testing/conformance/index.ts +258 -248
- package/src/testing/fake-engine.ts +462 -468
- package/src/testing/fake-provider.ts +126 -129
- package/src/testing/faults.ts +72 -72
- package/src/testing/index.ts +23 -28
- package/src/testing/measure.ts +337 -337
package/src/contract/errors.ts
CHANGED
|
@@ -1,134 +1,142 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Typed error taxonomy and stable diagnostic identifiers.
|
|
3
|
-
*
|
|
4
|
-
* Every failure condition carries its own identifier. None collapses into a
|
|
5
|
-
* generic failure — an error that says only "scheduling failed" reproduces the
|
|
6
|
-
* problem this package exists to solve.
|
|
7
|
-
*
|
|
8
|
-
* Identifiers are stable across releases and safe to switch on. Adding new ones
|
|
9
|
-
* is an additive minor change.
|
|
10
|
-
*
|
|
11
|
-
* See `specs/009-rn-notification-package/contracts/errors.md`.
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
export
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
DIAGNOSTIC_CODES.
|
|
125
|
-
DIAGNOSTIC_CODES.
|
|
126
|
-
DIAGNOSTIC_CODES.
|
|
127
|
-
DIAGNOSTIC_CODES.
|
|
128
|
-
DIAGNOSTIC_CODES.
|
|
129
|
-
DIAGNOSTIC_CODES.
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Typed error taxonomy and stable diagnostic identifiers.
|
|
3
|
+
*
|
|
4
|
+
* Every failure condition carries its own identifier. None collapses into a
|
|
5
|
+
* generic failure — an error that says only "scheduling failed" reproduces the
|
|
6
|
+
* problem this package exists to solve.
|
|
7
|
+
*
|
|
8
|
+
* Identifiers are stable across releases and safe to switch on. Adding new ones
|
|
9
|
+
* is an additive minor change.
|
|
10
|
+
*
|
|
11
|
+
* See `specs/009-rn-notification-package/contracts/errors.md`.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { SdkError } from '@chipmobilesdk/rn-core';
|
|
15
|
+
|
|
16
|
+
import { redactContext } from '../diagnostics/redact';
|
|
17
|
+
|
|
18
|
+
export const DIAGNOSTIC_CODES = {
|
|
19
|
+
// --- Validation: raised before any platform call -------------------------
|
|
20
|
+
INVALID_ID_EMPTY: 'INVALID_ID_EMPTY',
|
|
21
|
+
INVALID_ID_LENGTH: 'INVALID_ID_LENGTH',
|
|
22
|
+
INVALID_ID_CHARSET: 'INVALID_ID_CHARSET',
|
|
23
|
+
INVALID_OWNER_TAG: 'INVALID_OWNER_TAG',
|
|
24
|
+
INVALID_GROUP_TAG: 'INVALID_GROUP_TAG',
|
|
25
|
+
MOMENT_IN_PAST: 'MOMENT_IN_PAST',
|
|
26
|
+
UNDECLARED_TONE: 'UNDECLARED_TONE',
|
|
27
|
+
ROUTING_PAYLOAD_TOO_LARGE: 'ROUTING_PAYLOAD_TOO_LARGE',
|
|
28
|
+
CONTENT_TOO_LARGE: 'CONTENT_TOO_LARGE',
|
|
29
|
+
TOO_MANY_ACTIONS: 'TOO_MANY_ACTIONS',
|
|
30
|
+
INVALID_RECURRENCE: 'INVALID_RECURRENCE',
|
|
31
|
+
INVALID_TONE_REPEAT: 'INVALID_TONE_REPEAT',
|
|
32
|
+
|
|
33
|
+
// --- Reconciliation ------------------------------------------------------
|
|
34
|
+
DUPLICATE_IDENTIFIER: 'DUPLICATE_IDENTIFIER',
|
|
35
|
+
TRUNCATED_OVER_CEILING: 'TRUNCATED_OVER_CEILING',
|
|
36
|
+
RECONCILE_INTERRUPTED: 'RECONCILE_INTERRUPTED',
|
|
37
|
+
PENDING_SET_DISCREPANCY: 'PENDING_SET_DISCREPANCY',
|
|
38
|
+
|
|
39
|
+
// --- Permissions ---------------------------------------------------------
|
|
40
|
+
DISPLAY_PERMISSION_DENIED: 'DISPLAY_PERMISSION_DENIED',
|
|
41
|
+
DISPLAY_PERMISSION_PERMANENT: 'DISPLAY_PERMISSION_PERMANENT',
|
|
42
|
+
EXACT_ALARM_UNAVAILABLE: 'EXACT_ALARM_UNAVAILABLE',
|
|
43
|
+
SETTINGS_UNAVAILABLE: 'SETTINGS_UNAVAILABLE',
|
|
44
|
+
BACKGROUND_RESTRICTED: 'BACKGROUND_RESTRICTED',
|
|
45
|
+
BACKGROUND_RESTRICTION_UNKNOWN: 'BACKGROUND_RESTRICTION_UNKNOWN',
|
|
46
|
+
|
|
47
|
+
// --- Channels ------------------------------------------------------------
|
|
48
|
+
CHANNEL_MIGRATION_REQUIRED: 'CHANNEL_MIGRATION_REQUIRED',
|
|
49
|
+
CHANNEL_MIGRATION_FAILED: 'CHANNEL_MIGRATION_FAILED',
|
|
50
|
+
CHANNEL_ORPHANS_FOUND: 'CHANNEL_ORPHANS_FOUND',
|
|
51
|
+
DND_BYPASS_UNAVAILABLE: 'DND_BYPASS_UNAVAILABLE',
|
|
52
|
+
TONE_LABELS_REFRESHED: 'TONE_LABELS_REFRESHED',
|
|
53
|
+
REPEAT_ALERT_UNAVAILABLE: 'REPEAT_ALERT_UNAVAILABLE',
|
|
54
|
+
REPEAT_STOP_HANDLER_MISSING: 'REPEAT_STOP_HANDLER_MISSING',
|
|
55
|
+
|
|
56
|
+
// --- Interaction ---------------------------------------------------------
|
|
57
|
+
TARGET_MISSING: 'TARGET_MISSING',
|
|
58
|
+
INTERACTION_BUFFER_EVICTED: 'INTERACTION_BUFFER_EVICTED',
|
|
59
|
+
BACKGROUND_WINDOW_EXCEEDED: 'BACKGROUND_WINDOW_EXCEEDED',
|
|
60
|
+
|
|
61
|
+
// --- Push ----------------------------------------------------------------
|
|
62
|
+
PUSH_UNAVAILABLE: 'PUSH_UNAVAILABLE',
|
|
63
|
+
TOKEN_UNAVAILABLE: 'TOKEN_UNAVAILABLE',
|
|
64
|
+
TOKEN_INVALIDATION_FAILED: 'TOKEN_INVALIDATION_FAILED',
|
|
65
|
+
PAYLOAD_MALFORMED: 'PAYLOAD_MALFORMED',
|
|
66
|
+
PAYLOAD_VERSION_SKEW: 'PAYLOAD_VERSION_SKEW',
|
|
67
|
+
PAYLOAD_DUPLICATE: 'PAYLOAD_DUPLICATE',
|
|
68
|
+
PUSH_UNDELIVERABLE: 'PUSH_UNDELIVERABLE',
|
|
69
|
+
|
|
70
|
+
// --- Persisted state -----------------------------------------------------
|
|
71
|
+
STATE_CORRUPT_REBUILT: 'STATE_CORRUPT_REBUILT',
|
|
72
|
+
STATE_WRITE_FAILED: 'STATE_WRITE_FAILED',
|
|
73
|
+
/** The durable store could not open; state lasts for this session only. */
|
|
74
|
+
STATE_STORE_DEGRADED: 'STATE_STORE_DEGRADED',
|
|
75
|
+
STATE_CAP_EVICTED: 'STATE_CAP_EVICTED',
|
|
76
|
+
|
|
77
|
+
// --- Volume --------------------------------------------------------------
|
|
78
|
+
BURST_THRESHOLD_EXCEEDED: 'BURST_THRESHOLD_EXCEEDED',
|
|
79
|
+
|
|
80
|
+
// --- Maintenance (0.4.0) -------------------------------------------------
|
|
81
|
+
/** An automatic maintenance cycle threw. Reported here because no caller awaits it. */
|
|
82
|
+
MAINTENANCE_FAILED: 'MAINTENANCE_FAILED',
|
|
83
|
+
} as const;
|
|
84
|
+
|
|
85
|
+
export type DiagnosticCode = (typeof DIAGNOSTIC_CODES)[keyof typeof DIAGNOSTIC_CODES];
|
|
86
|
+
|
|
87
|
+
/** Every identifier, for exhaustiveness tests and the documentation table. */
|
|
88
|
+
export const ALL_DIAGNOSTIC_CODES: readonly DiagnosticCode[] = Object.freeze(
|
|
89
|
+
Object.values(DIAGNOSTIC_CODES),
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* A typed package failure.
|
|
94
|
+
*
|
|
95
|
+
* Carries enough context to choose a recovery, and never carries notification
|
|
96
|
+
* body text, routing payload values, or token material. Where a value violated
|
|
97
|
+
* a rule, the *shape* of the violation is reported — a length, a character
|
|
98
|
+
* position — rather than the value itself.
|
|
99
|
+
*/
|
|
100
|
+
export class NotificationError extends SdkError<DiagnosticCode> {
|
|
101
|
+
readonly context?: Readonly<Record<string, unknown>>;
|
|
102
|
+
|
|
103
|
+
constructor(code: DiagnosticCode, message: string, context?: Readonly<Record<string, unknown>>) {
|
|
104
|
+
super('rn-notification', code, { message });
|
|
105
|
+
this.name = 'NotificationError';
|
|
106
|
+
// Redacted on the way in: an error object reaches crash reporters, which
|
|
107
|
+
// never run with verbose diagnostics.
|
|
108
|
+
const redacted = redactContext(context, false);
|
|
109
|
+
if (redacted !== undefined) {
|
|
110
|
+
this.context = redacted;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export function isNotificationError(value: unknown): value is NotificationError {
|
|
116
|
+
return value instanceof NotificationError;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Conditions that are reported outcomes rather than failures: the operation
|
|
121
|
+
* succeeded, and something the caller needs to know happened alongside it.
|
|
122
|
+
*/
|
|
123
|
+
export const NON_FAILURE_CODES: readonly DiagnosticCode[] = Object.freeze([
|
|
124
|
+
DIAGNOSTIC_CODES.TRUNCATED_OVER_CEILING,
|
|
125
|
+
DIAGNOSTIC_CODES.PENDING_SET_DISCREPANCY,
|
|
126
|
+
DIAGNOSTIC_CODES.EXACT_ALARM_UNAVAILABLE,
|
|
127
|
+
DIAGNOSTIC_CODES.TARGET_MISSING,
|
|
128
|
+
DIAGNOSTIC_CODES.BURST_THRESHOLD_EXCEEDED,
|
|
129
|
+
DIAGNOSTIC_CODES.PAYLOAD_VERSION_SKEW,
|
|
130
|
+
DIAGNOSTIC_CODES.PAYLOAD_DUPLICATE,
|
|
131
|
+
DIAGNOSTIC_CODES.STATE_CAP_EVICTED,
|
|
132
|
+
DIAGNOSTIC_CODES.STATE_CORRUPT_REBUILT,
|
|
133
|
+
DIAGNOSTIC_CODES.BACKGROUND_RESTRICTION_UNKNOWN,
|
|
134
|
+
DIAGNOSTIC_CODES.DND_BYPASS_UNAVAILABLE,
|
|
135
|
+
DIAGNOSTIC_CODES.TONE_LABELS_REFRESHED,
|
|
136
|
+
DIAGNOSTIC_CODES.REPEAT_ALERT_UNAVAILABLE,
|
|
137
|
+
DIAGNOSTIC_CODES.REPEAT_STOP_HANDLER_MISSING,
|
|
138
|
+
]);
|
|
139
|
+
|
|
140
|
+
export function isNonFailure(code: DiagnosticCode): boolean {
|
|
141
|
+
return NON_FAILURE_CODES.includes(code);
|
|
142
|
+
}
|
package/src/contract/index.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
/** Public contract types. Types only — no logic lives in this layer. */
|
|
2
|
-
|
|
3
|
-
export * from './notification';
|
|
4
|
-
export * from './recurrence';
|
|
5
|
-
export * from './reconcile';
|
|
6
|
-
export * from './permission';
|
|
7
|
-
export * from './channel';
|
|
8
|
-
export * from './interaction';
|
|
9
|
-
export * from './diagnostics';
|
|
10
|
-
export * from './errors';
|
|
1
|
+
/** Public contract types. Types only — no logic lives in this layer. */
|
|
2
|
+
|
|
3
|
+
export * from './notification';
|
|
4
|
+
export * from './recurrence';
|
|
5
|
+
export * from './reconcile';
|
|
6
|
+
export * from './permission';
|
|
7
|
+
export * from './channel';
|
|
8
|
+
export * from './interaction';
|
|
9
|
+
export * from './diagnostics';
|
|
10
|
+
export * from './errors';
|
|
@@ -1,62 +1,62 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Interaction types.
|
|
3
|
-
*
|
|
4
|
-
* One event shape covers foreground, background, and cold start, so a consumer
|
|
5
|
-
* writes one handler. Events that occur before a handler registers are buffered
|
|
6
|
-
* durably and delivered on registration — the cold-start case is the one most
|
|
7
|
-
* integrations quietly get wrong.
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import type { RoutingPayload } from './notification';
|
|
11
|
-
|
|
12
|
-
export type InteractionKind = 'tap' | 'action' | 'dismiss';
|
|
13
|
-
|
|
14
|
-
/** Which app state the interaction arrived in. Informational; the shape never varies. */
|
|
15
|
-
export type AppStateAtInteraction = 'foreground' | 'background' | 'coldStart';
|
|
16
|
-
|
|
17
|
-
export interface InteractionEvent {
|
|
18
|
-
readonly kind: InteractionKind;
|
|
19
|
-
readonly notificationId: string;
|
|
20
|
-
/** Present when `kind` is `action`. */
|
|
21
|
-
readonly actionId?: string;
|
|
22
|
-
/** Present when the action accepted typed input. */
|
|
23
|
-
readonly inputText?: string;
|
|
24
|
-
/** Round-trips unchanged from schedule time. */
|
|
25
|
-
readonly routing?: RoutingPayload;
|
|
26
|
-
readonly ownerTag?: string;
|
|
27
|
-
readonly occurredAt: number;
|
|
28
|
-
readonly appState: AppStateAtInteraction;
|
|
29
|
-
/**
|
|
30
|
-
* True when the event was held in the durable buffer before a handler
|
|
31
|
-
* existed to receive it — including across a process death.
|
|
32
|
-
*/
|
|
33
|
-
readonly wasBuffered: boolean;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Signals the routing target no longer exists.
|
|
38
|
-
*
|
|
39
|
-
* The consumer chooses its own fallback screen. A platform error is never
|
|
40
|
-
* shown to the user for this — a notification pointing at deleted data is an
|
|
41
|
-
* ordinary condition, not a crash.
|
|
42
|
-
*/
|
|
43
|
-
export interface TargetMissingSignal {
|
|
44
|
-
readonly notificationId: string;
|
|
45
|
-
readonly routing?: RoutingPayload;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export type InteractionHandler = (event: InteractionEvent) => void | Promise<void>;
|
|
49
|
-
|
|
50
|
-
export type Unsubscribe = () => void;
|
|
51
|
-
|
|
52
|
-
/** Limits on the durable interaction buffer, so it can never grow without bound. */
|
|
53
|
-
export const INTERACTION_BUFFER_LIMITS = {
|
|
54
|
-
maxEntries: 50,
|
|
55
|
-
retentionMs: 7 * 24 * 60 * 60 * 1000,
|
|
56
|
-
} as const;
|
|
57
|
-
|
|
58
|
-
/** Maximum size of a routing payload, validated at schedule time rather than discovered at tap time. */
|
|
59
|
-
export const MAX_ROUTING_PAYLOAD_BYTES = 4 * 1024;
|
|
60
|
-
|
|
61
|
-
/** Maximum action buttons on one notification. */
|
|
62
|
-
export const MAX_ACTIONS_PER_NOTIFICATION = 10;
|
|
1
|
+
/**
|
|
2
|
+
* Interaction types.
|
|
3
|
+
*
|
|
4
|
+
* One event shape covers foreground, background, and cold start, so a consumer
|
|
5
|
+
* writes one handler. Events that occur before a handler registers are buffered
|
|
6
|
+
* durably and delivered on registration — the cold-start case is the one most
|
|
7
|
+
* integrations quietly get wrong.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { RoutingPayload } from './notification';
|
|
11
|
+
|
|
12
|
+
export type InteractionKind = 'tap' | 'action' | 'dismiss';
|
|
13
|
+
|
|
14
|
+
/** Which app state the interaction arrived in. Informational; the shape never varies. */
|
|
15
|
+
export type AppStateAtInteraction = 'foreground' | 'background' | 'coldStart';
|
|
16
|
+
|
|
17
|
+
export interface InteractionEvent {
|
|
18
|
+
readonly kind: InteractionKind;
|
|
19
|
+
readonly notificationId: string;
|
|
20
|
+
/** Present when `kind` is `action`. */
|
|
21
|
+
readonly actionId?: string;
|
|
22
|
+
/** Present when the action accepted typed input. */
|
|
23
|
+
readonly inputText?: string;
|
|
24
|
+
/** Round-trips unchanged from schedule time. */
|
|
25
|
+
readonly routing?: RoutingPayload;
|
|
26
|
+
readonly ownerTag?: string;
|
|
27
|
+
readonly occurredAt: number;
|
|
28
|
+
readonly appState: AppStateAtInteraction;
|
|
29
|
+
/**
|
|
30
|
+
* True when the event was held in the durable buffer before a handler
|
|
31
|
+
* existed to receive it — including across a process death.
|
|
32
|
+
*/
|
|
33
|
+
readonly wasBuffered: boolean;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Signals the routing target no longer exists.
|
|
38
|
+
*
|
|
39
|
+
* The consumer chooses its own fallback screen. A platform error is never
|
|
40
|
+
* shown to the user for this — a notification pointing at deleted data is an
|
|
41
|
+
* ordinary condition, not a crash.
|
|
42
|
+
*/
|
|
43
|
+
export interface TargetMissingSignal {
|
|
44
|
+
readonly notificationId: string;
|
|
45
|
+
readonly routing?: RoutingPayload;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export type InteractionHandler = (event: InteractionEvent) => void | Promise<void>;
|
|
49
|
+
|
|
50
|
+
export type Unsubscribe = () => void;
|
|
51
|
+
|
|
52
|
+
/** Limits on the durable interaction buffer, so it can never grow without bound. */
|
|
53
|
+
export const INTERACTION_BUFFER_LIMITS = {
|
|
54
|
+
maxEntries: 50,
|
|
55
|
+
retentionMs: 7 * 24 * 60 * 60 * 1000,
|
|
56
|
+
} as const;
|
|
57
|
+
|
|
58
|
+
/** Maximum size of a routing payload, validated at schedule time rather than discovered at tap time. */
|
|
59
|
+
export const MAX_ROUTING_PAYLOAD_BYTES = 4 * 1024;
|
|
60
|
+
|
|
61
|
+
/** Maximum action buttons on one notification. */
|
|
62
|
+
export const MAX_ACTIONS_PER_NOTIFICATION = 10;
|