@stamprally/core 0.8.0 → 0.9.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/dist/index.d.cts CHANGED
@@ -1,126 +1,36 @@
1
- type StampCondition = {
2
- readonly type: "instant";
3
- } | {
4
- readonly type: "token";
5
- readonly token: string;
6
- } | {
7
- readonly type: "geo";
8
- readonly latitude: number;
9
- readonly longitude: number;
10
- readonly radiusMeters: number;
11
- } | {
12
- readonly type: "composite";
13
- readonly operator: "AND" | "OR";
14
- readonly conditions: ReadonlyArray<StampCondition>;
15
- } | {
16
- readonly type: "time_window";
17
- readonly startsAt: string;
18
- readonly endsAt: string;
19
- readonly condition: StampCondition;
20
- };
21
- type VerificationContext = {
22
- readonly type: "instant";
23
- } | {
24
- readonly type: "token";
25
- readonly token: string;
26
- } | {
27
- readonly type: "geo";
28
- readonly currentLatitude: number;
29
- readonly currentLongitude: number;
30
- } | {
31
- readonly type: "composite";
32
- readonly contexts: ReadonlyArray<VerificationContext>;
33
- };
34
-
35
- interface ConditionMatch {
36
- readonly conditionType: StampCondition["type"];
37
- readonly distanceMeters?: number;
1
+ type SupportedLocale = "ja" | "en";
2
+ type LocalizedText<TLocale extends string = string> = string | Partial<Record<TLocale, string>>;
3
+ type LocalizedString<TLocale extends string = SupportedLocale> = Record<TLocale, string>;
4
+ type LocaleDictionary<TLocale extends string = string> = Readonly<Record<TLocale, Readonly<Record<string, string>>>>;
5
+ type SlotShape = "circle" | "square" | "rounded";
6
+ type FontFamily = "system-ui" | "serif" | "rounded-sans" | "monospace" | "handwritten";
7
+ interface SheetTheme {
8
+ readonly primaryColor: string;
9
+ readonly backgroundColor?: string;
10
+ readonly backgroundImageUrl?: string;
11
+ readonly cardBackgroundColor: string;
12
+ readonly textColor: string;
13
+ readonly slotShape: SlotShape;
14
+ readonly gridColumns: number;
15
+ readonly unclaimedOpacity?: number;
16
+ readonly completedStampColor?: string;
17
+ readonly fontFamily?: FontFamily;
38
18
  }
39
- interface CompositeConditionFailure {
40
- readonly index: number;
41
- readonly error: ConditionMismatch;
19
+ type ThemePresetId = "default" | "modern_dark" | "pop_candy" | "retro_craft" | "cyber";
20
+ interface ThemePreset<TLocale extends string = SupportedLocale> {
21
+ readonly id: ThemePresetId;
22
+ readonly name: LocalizedString<TLocale>;
23
+ readonly description: LocalizedString<TLocale>;
24
+ readonly theme: SheetTheme;
42
25
  }
43
- type ConditionMismatch = {
44
- readonly code: "CONDITION_MISMATCH";
45
- readonly conditionType: Exclude<StampCondition["type"], "time_window">;
46
- readonly reason: "CONTEXT_TYPE_MISMATCH";
47
- readonly expectedContextType: VerificationContext["type"];
48
- readonly actualContextType: VerificationContext["type"];
49
- } | {
50
- readonly code: "CONDITION_MISMATCH";
51
- readonly conditionType: "token";
52
- readonly reason: "TOKEN_MISMATCH";
53
- } | {
54
- readonly code: "CONDITION_MISMATCH";
55
- readonly conditionType: "geo";
56
- readonly reason: "INVALID_GEO_INPUT";
57
- } | {
58
- readonly code: "CONDITION_MISMATCH";
59
- readonly conditionType: "geo";
60
- readonly reason: "OUTSIDE_RADIUS";
61
- readonly distanceMeters: number;
62
- readonly radiusMeters: number;
63
- readonly differenceMeters: number;
64
- } | {
65
- readonly code: "CONDITION_MISMATCH";
66
- readonly conditionType: "composite";
67
- readonly reason: "CONTEXT_LENGTH_MISMATCH";
68
- readonly expectedCount: number;
69
- readonly actualCount: number;
70
- } | {
71
- readonly code: "CONDITION_MISMATCH";
72
- readonly conditionType: "composite";
73
- readonly reason: "AND_CHILD_FAILED" | "OR_ALL_FAILED";
74
- readonly failures: ReadonlyArray<CompositeConditionFailure>;
75
- } | {
76
- readonly code: "CONDITION_MISMATCH";
77
- readonly conditionType: "time_window";
78
- readonly reason: "INVALID_NOW" | "INVALID_TIME_WINDOW" | "BEFORE_START" | "AFTER_END";
79
- readonly now: string;
80
- readonly startsAt: string;
81
- readonly endsAt: string;
82
- };
83
- type StampError = {
84
- readonly code: "STAMP_NOT_FOUND";
85
- readonly stampId: string;
86
- } | {
87
- readonly code: "STAMP_ALREADY_ACQUIRED";
88
- readonly stampId: string;
89
- } | {
90
- readonly code: "INVALID_ORDER";
91
- readonly stampId: string;
92
- readonly expectedStampId: string;
93
- } | {
94
- readonly code: "CONDITION_MISMATCH";
95
- readonly stampId: string;
96
- readonly mismatch: ConditionMismatch;
97
- } | {
98
- readonly code: "OFFLINE_QUEUED";
99
- readonly stampId: string;
100
- readonly idempotencyKey: string;
101
- } | {
102
- readonly code: "INVALID_PROOF";
103
- readonly stampId: string;
104
- };
105
- type Result<T, E> = {
106
- readonly ok: true;
107
- readonly value: T;
108
- } | {
109
- readonly ok: false;
110
- readonly error: E;
111
- };
112
-
113
- /** A human-readable value that may be supplied in one or more locales. */
114
- type UniversalLocalizedText<TLocale extends string = string> = string | Partial<Record<TLocale, string>>;
115
- /** A link to an entity owned by the host application or another system. */
116
- interface ExternalReference$1 {
26
+ declare const DEFAULT_SHEET_THEME: SheetTheme;
27
+ interface ExternalReference {
117
28
  readonly type: string;
118
29
  readonly id: string;
119
30
  readonly url?: string;
120
31
  readonly metadata?: Readonly<Record<string, unknown>>;
121
32
  }
122
- /** Server-only verification material. Never send this shape to a browser. */
123
- type VerificationCondition = {
33
+ type CheckInCondition = {
124
34
  readonly type: "qr";
125
35
  readonly secretToken: string;
126
36
  readonly qrEntryUrl?: string;
@@ -133,15 +43,17 @@ type VerificationCondition = {
133
43
  readonly latitude: number;
134
44
  readonly longitude: number;
135
45
  readonly radiusMeters: number;
46
+ } | {
47
+ readonly type: "nfc";
48
+ readonly tagId: string;
136
49
  } | {
137
50
  readonly type: "custom";
138
51
  readonly validatorName: string;
139
52
  readonly secretParams?: Readonly<Record<string, unknown>>;
140
53
  };
141
- /** Safe condition metadata intended for a participant client. */
142
54
  type PublicCheckInCondition = {
143
55
  readonly type: "qr";
144
- readonly qrEntryUrl: string;
56
+ readonly qrEntryUrl?: string;
145
57
  } | {
146
58
  readonly type: "passcode";
147
59
  } | {
@@ -149,39 +61,30 @@ type PublicCheckInCondition = {
149
61
  readonly latitude: number;
150
62
  readonly longitude: number;
151
63
  readonly radiusMeters: number;
64
+ } | {
65
+ readonly type: "nfc";
152
66
  } | {
153
67
  readonly type: "custom";
154
68
  readonly validatorName: string;
155
69
  };
156
- interface UniversalSpotItem<TLocale extends string = string, TMeta extends Record<string, unknown> = Record<string, unknown>> {
70
+ interface SpotItem<TLocale extends string = string, TMeta extends Record<string, unknown> = Record<string, unknown>> {
157
71
  readonly id: string;
158
72
  readonly orderIndex: number;
159
- readonly name: UniversalLocalizedText<TLocale>;
160
- readonly description?: UniversalLocalizedText<TLocale>;
161
- readonly hint?: UniversalLocalizedText<TLocale>;
73
+ readonly name: LocalizedText<TLocale>;
74
+ readonly description?: LocalizedText<TLocale>;
75
+ readonly hint?: LocalizedText<TLocale>;
162
76
  readonly imageUrl?: string;
163
77
  readonly iconUrl?: string;
164
78
  readonly redirectUrlAfterClaim?: string;
165
- readonly externalReferences?: ReadonlyArray<ExternalReference$1>;
79
+ readonly externalReferences?: ReadonlyArray<ExternalReference>;
166
80
  readonly metadata?: TMeta;
167
- readonly conditions: ReadonlyArray<VerificationCondition>;
81
+ readonly conditions: ReadonlyArray<CheckInCondition>;
168
82
  readonly prerequisites?: ReadonlyArray<string>;
169
83
  }
170
- type AdminReward<TLocale extends string = string> = {
171
- readonly id: string;
172
- readonly title: UniversalLocalizedText<TLocale>;
173
- readonly description?: UniversalLocalizedText<TLocale>;
174
- readonly type: "digital" | "in_person";
175
- readonly redemptionMethod: "manual_slide" | "staff_passcode" | "view_only" | "server_claim";
176
- readonly requiredStampCount: number;
177
- readonly conditions?: ReadonlyArray<RewardUnlockCondition$1>;
178
- readonly stockLimit?: number;
179
- readonly userClaimLimit?: number;
180
- readonly staffPasscode?: string;
181
- readonly digitalContentUrl?: string;
84
+ type PublicSpotItem<TLocale extends string = string, TMeta extends Record<string, unknown> = Record<string, unknown>> = Omit<SpotItem<TLocale, TMeta>, "conditions"> & {
85
+ readonly conditions: ReadonlyArray<PublicCheckInCondition>;
182
86
  };
183
- type PublicReward<TLocale extends string = string> = Omit<AdminReward<TLocale>, "staffPasscode" | "digitalContentUrl">;
184
- type RewardUnlockCondition$1 = {
87
+ type RewardUnlockCondition = {
185
88
  readonly type: "stamp_count";
186
89
  readonly count: number;
187
90
  } | {
@@ -189,127 +92,60 @@ type RewardUnlockCondition$1 = {
189
92
  readonly stampIds: ReadonlyArray<string>;
190
93
  } | {
191
94
  readonly type: "all" | "any";
192
- readonly conditions: ReadonlyArray<RewardUnlockCondition$1>;
95
+ readonly conditions: ReadonlyArray<RewardUnlockCondition>;
193
96
  };
97
+ type RewardType = "digital" | "in_person";
98
+ type RedemptionMethod = "manual_slide" | "staff_passcode" | "view_only" | "server_claim";
99
+ interface Reward<TLocale extends string = string> {
100
+ readonly id: string;
101
+ readonly title: LocalizedText<TLocale>;
102
+ readonly description?: LocalizedText<TLocale>;
103
+ readonly type: RewardType;
104
+ readonly redemptionMethod: RedemptionMethod;
105
+ readonly requiredStampCount: number;
106
+ readonly conditions?: ReadonlyArray<RewardUnlockCondition>;
107
+ readonly digitalContentUrl?: string;
108
+ readonly staffPasscode?: string;
109
+ readonly validUntil?: string;
110
+ readonly stockLimit?: number;
111
+ readonly userClaimLimit?: number;
112
+ }
113
+ type PublicReward<TLocale extends string = string> = Omit<Reward<TLocale>, "digitalContentUrl" | "staffPasscode">;
194
114
  interface AdminRallyConfig<TLocale extends string = string, TMeta extends Record<string, unknown> = Record<string, unknown>> {
195
115
  readonly id: string;
196
116
  readonly version: string;
197
- readonly title: UniversalLocalizedText<TLocale>;
198
- readonly description?: UniversalLocalizedText<TLocale>;
117
+ readonly title: LocalizedText<TLocale>;
118
+ readonly description?: LocalizedText<TLocale>;
199
119
  readonly theme?: SheetTheme;
200
- readonly spots: ReadonlyArray<UniversalSpotItem<TLocale, TMeta>>;
201
- readonly rewards: ReadonlyArray<AdminReward<TLocale>>;
202
- readonly serverEndpoint?: string;
120
+ readonly spots: ReadonlyArray<SpotItem<TLocale, TMeta>>;
121
+ readonly rewards: ReadonlyArray<Reward<TLocale>>;
122
+ readonly staffPasscode?: string;
123
+ readonly inventory?: Readonly<Record<string, number>>;
124
+ readonly serverMetadata?: Readonly<Record<string, unknown>>;
203
125
  readonly metadata?: TMeta;
126
+ readonly serverEndpoint?: string;
204
127
  }
205
128
  interface PublicRallyConfig<TLocale extends string = string, TMeta extends Record<string, unknown> = Record<string, unknown>> {
206
129
  readonly id: string;
207
130
  readonly version: string;
208
- readonly title: UniversalLocalizedText<TLocale>;
209
- readonly description?: UniversalLocalizedText<TLocale>;
131
+ readonly title: LocalizedText<TLocale>;
132
+ readonly description?: LocalizedText<TLocale>;
210
133
  readonly theme?: SheetTheme;
211
- readonly spots: ReadonlyArray<Omit<UniversalSpotItem<TLocale, TMeta>, "conditions"> & {
212
- readonly conditions: ReadonlyArray<PublicCheckInCondition>;
213
- }>;
134
+ readonly spots: ReadonlyArray<PublicSpotItem<TLocale, TMeta>>;
214
135
  readonly rewards: ReadonlyArray<PublicReward<TLocale>>;
215
- readonly serverEndpoint?: string;
216
136
  readonly metadata?: TMeta;
137
+ readonly serverEndpoint?: string;
217
138
  }
218
- /** Produce the browser-safe projection without mutating the admin config. */
219
- declare function toPublicRallyConfig<TLocale extends string, TMeta extends Record<string, unknown>>(config: AdminRallyConfig<TLocale, TMeta>): PublicRallyConfig<TLocale, TMeta>;
220
- /** Runtime guard for values crossing the public configuration boundary. */
221
- declare function isPublicRallyConfig(value: unknown): value is PublicRallyConfig;
222
-
223
- type SupportedLocale = "ja" | "en";
224
- type LocalizedString<TLocale extends string = SupportedLocale> = Record<TLocale, string>;
225
- type LocalizedText$1<TLocale extends string = string> = string | Partial<Record<TLocale, string>>;
226
- type LocaleDictionary<TLocale extends string = string> = Readonly<Record<TLocale, Readonly<Record<string, string>>>>;
227
- type SlotShape = "circle" | "square" | "rounded";
228
- type FontFamily = "system-ui" | "serif" | "rounded-sans" | "monospace" | "handwritten";
229
- interface SheetTheme {
230
- readonly primaryColor: string;
231
- readonly backgroundColor?: string;
232
- readonly backgroundImageUrl?: string;
233
- readonly cardBackgroundColor: string;
234
- readonly textColor: string;
235
- readonly slotShape: SlotShape;
236
- readonly gridColumns: number;
237
- readonly unclaimedOpacity?: number;
238
- readonly completedStampColor?: string;
239
- readonly fontFamily?: FontFamily;
240
- }
241
- type ThemePresetId = "default" | "modern_dark" | "pop_candy" | "retro_craft" | "cyber";
242
- interface ThemePreset<TLocale extends string = SupportedLocale> {
243
- readonly id: ThemePresetId;
244
- readonly name: LocalizedString<TLocale>;
245
- readonly description: LocalizedString<TLocale>;
246
- readonly theme: SheetTheme;
247
- }
248
- declare const DEFAULT_SHEET_THEME: SheetTheme;
249
- /** @deprecated Use UniversalSpotItem from the universal model. */
250
- interface SpotItem<TLocale extends string = SupportedLocale, TMeta extends Record<string, unknown> = Record<string, unknown>> {
251
- readonly id: string;
252
- readonly name: LocalizedText$1<TLocale>;
253
- readonly description?: LocalizedText$1<TLocale>;
254
- readonly hint?: LocalizedText$1<TLocale>;
255
- readonly condition: StampCondition;
256
- readonly orderIndex?: number;
257
- readonly order?: number;
258
- readonly deckId?: string;
259
- readonly groupId?: string;
260
- readonly guideId?: string;
261
- readonly iconUrl?: string;
262
- readonly imageUrl?: string;
263
- readonly externalUrl?: string;
264
- readonly redirectUrlAfterClaim?: string;
265
- readonly metadata?: TMeta;
266
- /** Canonical universal-model conditions. Legacy `condition` remains for engine internals. */
267
- readonly conditions?: ReadonlyArray<VerificationCondition>;
268
- readonly externalReferences?: ReadonlyArray<ExternalReference$1>;
269
- readonly prerequisites?: ReadonlyArray<string>;
270
- readonly dependsOn?: ReadonlyArray<string>;
271
- readonly requiresStampIds?: ReadonlyArray<string>;
272
- }
273
- /** @deprecated Use SpotItem instead. */
274
- type StampDefinition<TLocale extends string = SupportedLocale, TMeta extends Record<string, unknown> = Record<string, unknown>> = SpotItem<TLocale, TMeta>;
275
- interface StampRecord$1 {
139
+ type RallyConfig<TLocale extends string = string, TMeta extends Record<string, unknown> = Record<string, unknown>> = PublicRallyConfig<TLocale, TMeta>;
140
+ declare function toPublicConfig<TLocale extends string, TMeta extends Record<string, unknown>>(config: AdminRallyConfig<TLocale, TMeta>): PublicRallyConfig<TLocale, TMeta>;
141
+ declare function assertPublicConfig(config: unknown): asserts config is PublicRallyConfig;
142
+ declare function isPublicConfig(value: unknown): value is PublicRallyConfig;
143
+ interface StampRecord {
276
144
  readonly stampId: string;
277
145
  readonly acquiredAt: string;
278
146
  readonly metadata?: Readonly<Record<string, unknown>>;
279
147
  }
280
- type RewardType = "digital" | "in_person";
281
- type RedemptionMethod = "manual_slide" | "staff_passcode" | "view_only" | "server_claim";
282
- type RewardUnlockCondition = {
283
- readonly type: "stamp_count";
284
- readonly count: number;
285
- } | {
286
- readonly type: "stamps";
287
- readonly stampIds: ReadonlyArray<string>;
288
- } | {
289
- readonly type: "group_complete";
290
- readonly groupId: string;
291
- } | {
292
- readonly type: "all" | "any";
293
- readonly conditions: ReadonlyArray<RewardUnlockCondition>;
294
- };
295
148
  type RewardStatus = "LOCKED" | "AVAILABLE" | "CONSUMED" | "EXPIRED";
296
- interface RewardItem<TLocale extends string = SupportedLocale> {
297
- readonly id: string;
298
- readonly title: LocalizedText$1<TLocale>;
299
- readonly description: LocalizedText$1<TLocale>;
300
- readonly type: RewardType;
301
- readonly redemptionMethod: RedemptionMethod;
302
- readonly requiredStampCount: number;
303
- readonly conditions?: ReadonlyArray<RewardUnlockCondition>;
304
- readonly digitalContentUrl?: string;
305
- readonly staffPasscode?: string;
306
- readonly validUntil?: string;
307
- readonly stockLimit?: number;
308
- readonly userClaimLimit?: number;
309
- readonly maxStock?: number;
310
- readonly limitPerUser?: number;
311
- readonly claimTicketNumber?: string;
312
- }
313
149
  interface RewardState {
314
150
  readonly rewardId: string;
315
151
  readonly status: RewardStatus;
@@ -322,104 +158,111 @@ interface RewardState {
322
158
  }
323
159
  interface StampRallyState {
324
160
  readonly rallyId: string;
325
- readonly records: ReadonlyArray<StampRecord$1>;
326
- readonly rewards?: ReadonlyArray<RewardState>;
161
+ readonly userId: string | null;
162
+ readonly records: ReadonlyArray<StampRecord>;
163
+ readonly rewards: ReadonlyArray<RewardState>;
327
164
  readonly updatedAt: string;
328
165
  }
329
- /** @deprecated Use AdminRallyConfig or PublicRallyConfig from the universal model. */
330
- interface RallyConfig<TLocale extends string = SupportedLocale, TMeta extends Record<string, unknown> = Record<string, unknown>> {
331
- readonly id: string;
332
- readonly title?: LocalizedText$1<TLocale>;
333
- readonly description?: LocalizedText$1<TLocale>;
334
- readonly stamps: ReadonlyArray<StampDefinition<TLocale, TMeta>>;
335
- readonly rewards?: ReadonlyArray<RewardItem<TLocale>>;
336
- readonly isSequential?: boolean;
337
- readonly theme?: SheetTheme;
338
- readonly version?: number;
339
- readonly startDate?: string;
340
- readonly endDate?: string;
341
- }
342
-
343
- declare function resolveLocalizedText<TLocale extends string = SupportedLocale>(text: LocalizedText$1<TLocale> | undefined, locale: string, fallbackLocale?: string): string;
344
- declare function toLocalizedString(text: LocalizedText$1 | undefined): LocalizedString;
345
- declare function toLocalizedString<TLocale extends string>(text: LocalizedText$1<TLocale> | undefined): LocalizedString<TLocale>;
346
-
347
- declare function migrateRallyConfig<TLocale extends string = SupportedLocale>(raw: unknown): RallyConfig<TLocale>;
166
+ type UserRallyState = StampRallyState;
348
167
 
349
- type PublicRewardItem<TLocale extends string = string> = Omit<RewardItem<TLocale>, "staffPasscode">;
350
- type LegacyPublicRallyConfig<TLocale extends string = string, TMeta extends Record<string, unknown> = Record<string, unknown>> = Omit<RallyConfig<TLocale, TMeta>, "rewards"> & {
351
- readonly rewards?: ReadonlyArray<PublicRewardItem<TLocale>>;
168
+ type VerificationContext = {
169
+ readonly type: "qr";
170
+ readonly token: string;
171
+ } | {
172
+ readonly type: "passcode";
173
+ readonly code: string;
174
+ } | {
175
+ readonly type: "gps";
176
+ readonly latitude: number;
177
+ readonly longitude: number;
178
+ } | {
179
+ readonly type: "nfc";
180
+ readonly tagId: string;
181
+ } | {
182
+ readonly type: "custom";
183
+ readonly value: unknown;
352
184
  };
353
- declare function stripSensitiveConfig<TLocale extends string, TMeta extends Record<string, unknown>>(config: AdminRallyConfig<TLocale, TMeta>): PublicRallyConfig<TLocale, TMeta>;
354
- declare function stripSensitiveConfig<TLocale extends string, TMeta extends Record<string, unknown>>(config: RallyConfig<TLocale, TMeta>): LegacyPublicRallyConfig<TLocale, TMeta>;
355
-
356
- declare const THEME_PRESETS: ReadonlyArray<ThemePreset>;
357
185
 
358
- interface UniversalValidationError {
359
- readonly path: string;
360
- readonly code: "INVALID_TYPE" | "REQUIRED" | "EMPTY_STRING" | "DUPLICATE_ID" | "INVALID_COORDINATES" | "INVALID_RADIUS" | "INVALID_VERSION" | "INVALID_REWARD" | "CYCLE_DETECTED" | "SECRET_IN_PUBLIC_CONFIG";
361
- readonly message: string;
186
+ interface ConditionMatch {
187
+ readonly conditionType: CheckInCondition["type"];
188
+ readonly distanceMeters?: number;
362
189
  }
363
- interface UniversalValidationResult {
364
- readonly valid: boolean;
365
- readonly errors: ReadonlyArray<UniversalValidationError>;
190
+ type ConditionMismatch = {
191
+ readonly code: "CONDITION_MISMATCH";
192
+ readonly conditionType: CheckInCondition["type"];
193
+ readonly reason: "INVALID_PROOF" | "INVALID_GEO_INPUT" | "OUTSIDE_RADIUS" | "VALIDATOR_FAILED";
194
+ readonly distanceMeters?: number;
195
+ readonly radiusMeters?: number;
196
+ };
197
+ interface CompositeConditionFailure {
198
+ readonly index: number;
199
+ readonly error: ConditionMismatch;
366
200
  }
367
- declare function validateAdminRallyConfig(value: unknown): UniversalValidationResult;
368
- declare function validatePublicRallyConfig(value: unknown): UniversalValidationResult;
369
- declare function isAdminRallyConfig(value: unknown): value is AdminRallyConfig;
370
- declare function isPublicRallyConfigShape(value: unknown): value is PublicRallyConfig;
371
-
372
- declare const CURRENT_RALLY_CONFIG_VERSION = 2;
373
- interface ValidationError {
374
- readonly path: string;
375
- readonly code: "INVALID_TYPE" | "REQUIRED" | "EMPTY_STRING" | "DUPLICATE_ID" | "INVALID_COORDINATES" | "INVALID_RADIUS" | "INVALID_DATE" | "INVALID_VERSION" | "INVALID_REWARD" | "CYCLE_DETECTED";
201
+ type StampError = {
202
+ readonly code: "SPOT_NOT_FOUND";
203
+ readonly spotId: string;
204
+ } | {
205
+ readonly code: "STAMP_ALREADY_ACQUIRED";
206
+ readonly spotId: string;
207
+ } | {
208
+ readonly code: "PREREQUISITES_NOT_MET";
209
+ readonly spotId: string;
210
+ } | {
211
+ readonly code: "INVALID_PROOF";
212
+ readonly spotId: string;
213
+ } | {
214
+ readonly code: "CUSTOM_VALIDATION_FAILED";
215
+ readonly spotId: string;
376
216
  readonly message: string;
377
- }
378
- interface RallyConfigValidationResult {
379
- readonly valid: boolean;
380
- readonly errors: ReadonlyArray<ValidationError>;
381
- }
382
- declare function validateRallyConfig(config: unknown): RallyConfigValidationResult;
383
-
384
- type CheckInErrorCode = "ORDER_VIOLATION" | "OUT_OF_RANGE" | "EXPIRED" | "INVALID_PROOF" | "INVALID_CONTEXT" | "ALREADY_CLAIMED";
385
- interface CheckInContext {
386
- readonly verificationContext: VerificationContext;
387
- readonly now?: string;
388
- readonly expectedStampId?: string;
389
- readonly proof?: string;
390
- readonly alreadyClaimed?: boolean;
391
- }
392
- type CheckInInput = VerificationContext | (VerificationContext & {
393
- readonly now?: string;
394
- readonly expectedStampId?: string;
395
- readonly alreadyClaimed?: boolean;
396
- }) | CheckInContext;
397
- type CheckInResult$1 = {
217
+ };
218
+ type Result<T, E> = {
398
219
  readonly ok: true;
399
- readonly success: true;
400
- readonly stampId: string;
401
- readonly checkedAt: string;
220
+ readonly value: T;
402
221
  } | {
403
222
  readonly ok: false;
404
- readonly success: false;
405
- readonly code: CheckInErrorCode;
406
- readonly stampId: string;
407
- readonly message: string;
223
+ readonly error: E;
408
224
  };
409
- declare function evaluateCheckIn(spot: SpotItem, input: CheckInInput): CheckInResult$1;
225
+ interface CustomValidationContext {
226
+ readonly rallyId: string;
227
+ readonly spotId: string;
228
+ readonly proofData: unknown;
229
+ readonly condition: Extract<CheckInCondition, {
230
+ readonly type: "custom";
231
+ }>;
232
+ readonly userState: UserRallyState;
233
+ }
234
+ interface CustomValidator {
235
+ validate(context: CustomValidationContext): Promise<boolean | {
236
+ readonly valid: boolean;
237
+ readonly message?: string;
238
+ }>;
239
+ }
240
+ type Validator = CustomValidator | ((context: CustomValidationContext) => Promise<boolean | {
241
+ readonly valid: boolean;
242
+ readonly message?: string;
243
+ }> | boolean | {
244
+ readonly valid: boolean;
245
+ readonly message?: string;
246
+ });
247
+
248
+ declare function resolveLocalizedText<TLocale extends string = SupportedLocale>(text: LocalizedText<TLocale> | undefined, locale: string, fallbackLocale?: string): string;
249
+ declare function toLocalizedString(text: LocalizedText | undefined): LocalizedString;
250
+ declare function toLocalizedString<TLocale extends string>(text: LocalizedText<TLocale> | undefined): LocalizedString<TLocale>;
251
+
252
+ declare const THEME_PRESETS: ReadonlyArray<ThemePreset>;
410
253
 
411
- declare function calculateDistanceMeters(latitudeA: number, longitudeA: number, latitudeB: number, longitudeB: number): number;
412
- declare function evaluateConditionDetailed(condition: StampCondition, context: VerificationContext, now: string): Result<ConditionMatch, ConditionMismatch>;
413
- declare function evaluateCondition(condition: StampCondition, context: VerificationContext, now?: string): boolean;
254
+ declare function calculateDistanceMeters(aLat: number, aLon: number, bLat: number, bLon: number): number;
255
+ declare function evaluateConditionDetailed(condition: CheckInCondition, context: VerificationContext): Result<ConditionMatch, ConditionMismatch>;
256
+ declare function evaluateCondition(condition: CheckInCondition, context: VerificationContext): boolean;
257
+
258
+ declare function getOrderedSpots<TLocale extends string, TMeta extends Record<string, unknown>>(spots: ReadonlyArray<SpotItem<TLocale, TMeta>>): ReadonlyArray<SpotItem<TLocale, TMeta>>;
414
259
 
415
260
  interface StampRallyProgress {
416
261
  readonly acquired: number;
417
262
  readonly total: number;
418
263
  readonly percentage: number;
419
264
  readonly isCompleted: boolean;
420
- /** @deprecated Use isCompleted instead. */
421
- readonly isComplete: boolean;
422
- readonly nextAvailableStamps: ReadonlyArray<StampDefinition>;
265
+ readonly nextAvailableSpots: ReadonlyArray<PublicSpotItem>;
423
266
  }
424
267
  declare function calculateProgress(state: StampRallyState, config: RallyConfig): StampRallyProgress;
425
268
 
@@ -430,29 +273,10 @@ interface ClaimTicketOptions {
430
273
  declare function createClaimTicketNumber(rewardId: string, options?: ClaimTicketOptions): string;
431
274
  /** Creates a one-time ticket for a successful reward consumption. */
432
275
  declare function createUniqueClaimTicketNumber(rewardId: string, issuedAt: string): string;
433
- declare function issueClaimTicketNumber(reward: RewardItem, currentState: RewardState, options?: ClaimTicketOptions): RewardState;
276
+ declare function issueClaimTicketNumber(reward: Reward, currentState: RewardState, options?: ClaimTicketOptions): RewardState;
434
277
 
435
- type StampRallyEvent = {
436
- readonly type: "stampAcquired";
437
- readonly record: StampRecord$1;
438
- } | {
439
- readonly type: "rallyCompleted";
440
- readonly rallyId: string;
441
- readonly completedAt: string;
442
- } | {
443
- readonly type: "rewardUnlocked";
444
- readonly rewardId: string;
445
- readonly unlockedAt: string;
446
- };
447
- interface ProcessStampValue {
448
- readonly nextState: StampRallyState;
449
- readonly events: ReadonlyArray<StampRallyEvent>;
450
- }
451
278
  type RewardConsumeError = {
452
- readonly code: "NOT_AVAILABLE";
453
- readonly rewardId: string;
454
- } | {
455
- readonly code: "ALREADY_CONSUMED";
279
+ readonly code: "NOT_AVAILABLE" | "ALREADY_CONSUMED" | "OUT_OF_STOCK" | "REWARD_NOT_FOUND";
456
280
  readonly rewardId: string;
457
281
  } | {
458
282
  readonly code: "INVALID_PASSCODE";
@@ -460,37 +284,35 @@ type RewardConsumeError = {
460
284
  readonly message: string;
461
285
  } | {
462
286
  readonly code: "EXPIRED";
463
- readonly reason: "EXPIRED";
464
- readonly rewardId: string;
465
- } | {
466
- readonly code: "OUT_OF_STOCK";
467
287
  readonly rewardId: string;
468
288
  } | {
469
289
  readonly code: "USER_LIMIT_REACHED";
470
- readonly reason: "LIMIT_EXCEEDED";
471
- readonly rewardId: string;
472
- } | {
473
- readonly code: "REWARD_NOT_FOUND";
474
290
  readonly rewardId: string;
475
291
  };
476
292
  interface ConsumeRewardParams {
477
- readonly reward: RewardItem;
293
+ readonly reward: Reward;
478
294
  readonly currentState: RewardState;
479
295
  readonly inputPasscode?: string;
480
296
  readonly staffId?: string;
481
297
  readonly now: string;
482
- readonly userId?: string;
483
298
  readonly userRedemptionCount?: number;
484
299
  }
485
300
  type ConsumeResult = Result<RewardState, RewardConsumeError>;
486
- declare function reconcileRewardStates(rewards: ReadonlyArray<RewardItem>, currentStates: ReadonlyArray<RewardState>, acquiredStampCount: number, now: string): ReadonlyArray<RewardState>;
301
+ declare function reconcileRewardStates(rewards: ReadonlyArray<Reward>, currentStates: ReadonlyArray<RewardState>, acquiredStampCount: number, now: string): ReadonlyArray<RewardState>;
487
302
  declare function consumeReward(params: ConsumeRewardParams): ConsumeResult;
488
- declare function processStamp(state: StampRallyState, config: RallyConfig, targetStampId: string, context: VerificationContext, now: string): Result<ProcessStampValue, StampError>;
303
+ interface ProcessStampValue {
304
+ readonly nextState: StampRallyState;
305
+ readonly events: ReadonlyArray<{
306
+ readonly type: "stampAcquired";
307
+ readonly record: StampRecord;
308
+ }>;
309
+ }
310
+ declare function processStamp(state: StampRallyState, config: AdminRallyConfig, spotId: string, context: VerificationContext, now: string): Result<ProcessStampValue, StampError>;
489
311
 
490
312
  interface StampStorage {
491
- load(rallyId: string): Promise<StampRallyState | null>;
313
+ load(rallyId: string, userId: string | null): Promise<StampRallyState | null>;
492
314
  save(state: StampRallyState): Promise<void>;
493
- remove(rallyId: string): Promise<void>;
315
+ remove(rallyId: string, userId: string | null): Promise<void>;
494
316
  }
495
317
  interface StorageLike {
496
318
  getItem(key: string): string | null;
@@ -513,7 +335,8 @@ declare function isStampRallyState(value: unknown): value is StampRallyState;
513
335
  interface RallySnapshot {
514
336
  readonly version: 1;
515
337
  readonly rallyId: string;
516
- readonly stamps: ReadonlyArray<StampRecord$1>;
338
+ readonly userId: string | null;
339
+ readonly records: ReadonlyArray<StampRecord>;
517
340
  readonly rewards: ReadonlyArray<RewardState>;
518
341
  readonly exportedAt: string;
519
342
  }
@@ -521,10 +344,11 @@ declare function exportProgressToken(snapshot: RallySnapshot): string;
521
344
  declare function importProgressToken(token: string, currentRallyId: string): RallySnapshot | null;
522
345
  declare class InMemoryStorage implements StampStorage {
523
346
  #private;
524
- load(rallyId: string): Promise<StampRallyState | null>;
347
+ load(rallyId: string, userId: string | null): Promise<StampRallyState | null>;
525
348
  save(state: StampRallyState): Promise<void>;
526
- remove(rallyId: string): Promise<void>;
349
+ remove(rallyId: string, userId: string | null): Promise<void>;
527
350
  }
351
+ declare function storageKey(rallyId: string, userId: string | null): string;
528
352
  interface LocalStorageAdapterOptions {
529
353
  readonly storage?: StorageLike | null;
530
354
  readonly keyPrefix?: string;
@@ -536,9 +360,9 @@ type StorageWarningHandler = (error: StorageAdapterError) => void;
536
360
  declare class LocalStorageAdapter implements StampStorage {
537
361
  #private;
538
362
  constructor(options?: LocalStorageAdapterOptions);
539
- load(rallyId: string): Promise<StampRallyState | null>;
363
+ load(rallyId: string, userId: string | null): Promise<StampRallyState | null>;
540
364
  save(state: StampRallyState): Promise<void>;
541
- remove(rallyId: string): Promise<void>;
365
+ remove(rallyId: string, userId: string | null): Promise<void>;
542
366
  }
543
367
  interface IndexedDBAdapterOptions {
544
368
  readonly indexedDB?: IDBFactory | null;
@@ -547,101 +371,25 @@ interface IndexedDBAdapterOptions {
547
371
  declare class IndexedDBAdapter implements StampStorage {
548
372
  #private;
549
373
  constructor(options?: IndexedDBAdapterOptions);
550
- load(rallyId: string): Promise<StampRallyState | null>;
374
+ load(rallyId: string, userId: string | null): Promise<StampRallyState | null>;
551
375
  save(state: StampRallyState): Promise<void>;
552
- remove(rallyId: string): Promise<void>;
376
+ remove(rallyId: string, userId: string | null): Promise<void>;
553
377
  }
554
378
 
555
- type StampRallyListener = (state: StampRallyState) => void;
556
- type StampRallyClientEvent = {
557
- readonly type: "checkIn";
558
- readonly stampId: string;
559
- readonly state: StampRallyState;
560
- } | {
561
- readonly type: "rewardClaimed";
562
- readonly rewardId: string;
563
- readonly state: StampRallyState;
564
- } | {
565
- readonly type: "syncCompleted";
566
- readonly state: StampRallyState;
567
- } | {
568
- readonly type: "error";
569
- readonly error: unknown;
570
- };
571
- type StampRallyEventListener = (event: StampRallyClientEvent) => void;
572
- type Clock = () => string;
573
- declare class StampRallyClient {
574
- #private;
575
- constructor(config: RallyConfig, storage: StampStorage, clock?: Clock);
576
- getState(): StampRallyState | null;
577
- getConfig(): RallyConfig;
578
- subscribe(listener: StampRallyListener): () => void;
579
- subscribe(listener: StampRallyEventListener, options: {
580
- readonly events: true;
581
- }): () => void;
582
- subscribeEvents(listener: StampRallyEventListener): () => void;
583
- updateConfig(newConfig: LegacyPublicRallyConfig): Promise<StampRallyState>;
584
- notifyRewardClaimed(rewardId: string, state?: StampRallyState | null): void;
585
- notifySyncCompleted(state?: StampRallyState | null): void;
586
- init(): Promise<StampRallyState>;
587
- initialize(): Promise<StampRallyState>;
588
- acquire(stampId: string, context: VerificationContext, now?: string): Promise<Result<ProcessStampValue, StampError>>;
589
- reset(now?: string): Promise<StampRallyState>;
590
- restore(state: StampRallyState): Promise<StampRallyState>;
591
- }
592
-
593
- type UserRallyState = StampRallyState;
594
- type CustomValidator = (context: {
595
- readonly spotId: string;
596
- readonly proofData: unknown;
597
- readonly config: PublicRallyConfig;
598
- readonly userState: UserRallyState;
599
- }) => Promise<{
600
- readonly success: boolean;
601
- readonly error?: string;
602
- }>;
603
- interface CheckInOptions {
379
+ type CheckInOptions = {
604
380
  readonly now?: string;
605
381
  readonly idempotencyKey?: string;
606
382
  readonly sync?: boolean;
607
- }
608
- interface ClaimOptions {
383
+ };
384
+ type ClaimOptions = {
609
385
  readonly now?: string;
610
386
  readonly idempotencyKey?: string;
611
387
  readonly staffPasscode?: string;
612
388
  readonly staffId?: string;
613
389
  readonly sync?: boolean;
614
- }
615
- interface UniversalClientRequest {
616
- readonly rallyId: string;
617
- readonly spotId: string;
618
- readonly proofData: unknown;
619
- readonly idempotencyKey: string;
620
- readonly now: string;
621
- readonly state: UserRallyState;
622
- }
623
- interface UniversalClaimRequest {
624
- readonly rallyId: string;
625
- readonly rewardId: string;
626
- readonly idempotencyKey: string;
627
- readonly now: string;
628
- readonly options: ClaimOptions;
629
- readonly state: UserRallyState;
630
- }
631
- type UniversalClientError = {
632
- readonly code: "SPOT_NOT_FOUND";
633
- readonly spotId: string;
634
- readonly message: string;
635
- } | {
636
- readonly code: "STAMP_ALREADY_ACQUIRED";
637
- readonly spotId: string;
638
- readonly message: string;
639
- } | {
640
- readonly code: "PREREQUISITES_NOT_MET";
641
- readonly spotId: string;
642
- readonly message: string;
643
- } | {
644
- readonly code: "INVALID_PROOF";
390
+ };
391
+ type ClientError = {
392
+ readonly code: "SPOT_NOT_FOUND" | "STAMP_ALREADY_ACQUIRED" | "PREREQUISITES_NOT_MET" | "INVALID_PROOF";
645
393
  readonly spotId: string;
646
394
  readonly message: string;
647
395
  } | {
@@ -655,70 +403,86 @@ type UniversalClientError = {
655
403
  } | {
656
404
  readonly code: "SYNC_FAILED";
657
405
  readonly message: string;
658
- } | {
659
- readonly code: "REMOTE_ERROR";
660
- readonly message: string;
661
406
  } | RewardConsumeError;
662
407
  interface CheckInSuccess {
663
408
  readonly state: UserRallyState;
664
- readonly record: StampRecord$1;
409
+ readonly record: StampRecord;
665
410
  }
666
- type UniversalCheckInResult = Result<CheckInSuccess, UniversalClientError>;
667
- type ClientCheckInResult = UniversalCheckInResult;
411
+ type CheckInResult = Result<CheckInSuccess, ClientError>;
668
412
  interface ClaimSuccess {
669
413
  readonly state: UserRallyState;
670
414
  readonly reward: RewardState;
671
415
  }
672
- type UniversalClaimResult = Result<ClaimSuccess, UniversalClientError>;
673
- type ClaimResult = UniversalClaimResult;
674
- type ClientClaimResult = UniversalClaimResult;
675
- type UniversalClientEvent = {
416
+ type ClaimResult = Result<ClaimSuccess, ClientError>;
417
+ type ClientEvent = {
676
418
  readonly type: "checkIn";
677
- readonly result: UniversalCheckInResult;
419
+ readonly result: CheckInResult;
678
420
  } | {
679
421
  readonly type: "rewardClaimed";
680
- readonly result: UniversalClaimResult;
422
+ readonly result: ClaimResult;
681
423
  } | {
682
424
  readonly type: "sync";
683
425
  readonly state: UserRallyState;
684
426
  } | {
685
427
  readonly type: "error";
686
- readonly error: UniversalClientError;
428
+ readonly error: ClientError;
687
429
  };
688
- type UniversalClientListener = (state: UserRallyState) => void;
689
- type UniversalClientEventListener = (event: UniversalClientEvent) => void;
690
- interface UniversalClientSyncAdapter {
691
- readonly checkIn?: (request: UniversalClientRequest) => Promise<UniversalCheckInResult>;
692
- readonly claimReward?: (request: UniversalClaimRequest) => Promise<UniversalClaimResult>;
430
+ type ClientListener = (state: UserRallyState) => void;
431
+ type ClientEventListener = (event: ClientEvent) => void;
432
+ interface CheckInRequest {
433
+ readonly rallyId: string;
434
+ readonly userId: string | null;
435
+ readonly spotId: string;
436
+ readonly proofData: unknown;
437
+ readonly idempotencyKey: string;
438
+ readonly now: string;
439
+ readonly state: UserRallyState;
440
+ }
441
+ interface ClaimRequest {
442
+ readonly rallyId: string;
443
+ readonly userId: string | null;
444
+ readonly rewardId: string;
445
+ readonly idempotencyKey: string;
446
+ readonly now: string;
447
+ readonly options: ClaimOptions;
448
+ readonly state: UserRallyState;
449
+ }
450
+ interface SyncAdapter {
451
+ readonly checkIn?: (request: CheckInRequest) => Promise<CheckInResult>;
452
+ readonly claimReward?: (request: ClaimRequest) => Promise<ClaimResult>;
693
453
  readonly sync?: (request: {
694
454
  readonly rallyId: string;
455
+ readonly userId: string | null;
695
456
  readonly state: UserRallyState;
696
457
  }) => Promise<UserRallyState>;
697
458
  }
698
- interface UniversalStampRallyClientOptions {
459
+ interface ClientOptions {
699
460
  readonly storage?: StampStorage;
700
- readonly syncAdapter?: UniversalClientSyncAdapter;
701
- readonly customValidator?: CustomValidator;
702
- readonly customValidators?: Readonly<Record<string, CustomValidator>>;
461
+ readonly syncAdapter?: SyncAdapter;
462
+ readonly customValidator?: Validator;
463
+ readonly customValidators?: Readonly<Record<string, Validator>>;
703
464
  readonly clock?: () => string;
465
+ readonly userId?: string | null;
704
466
  }
705
- type UniversalClientOptionsOrStorage = UniversalStampRallyClientOptions | StampStorage;
706
- /**
707
- * Storage- and framework-independent client state machine for a public rally.
708
- * All operations create new state snapshots and notify subscribers after persistence.
709
- */
710
- declare class UniversalStampRallyClient {
467
+ type StorageOrOptions = StampStorage | ClientOptions;
468
+ declare class StampRallyClient {
711
469
  #private;
712
- constructor(config: PublicRallyConfig, storageOrOptions?: UniversalClientOptionsOrStorage, clock?: () => string);
713
- getConfig(): PublicRallyConfig;
470
+ constructor(config: PublicRallyConfig, storageOrOptions?: StorageOrOptions);
471
+ getConfig(): RallyConfig;
714
472
  getState(): UserRallyState | null;
715
- subscribe(listener: UniversalClientListener): () => void;
716
- subscribeEvents(listener: UniversalClientEventListener): () => void;
473
+ getUserId(): string | null;
474
+ subscribe(listener: ClientListener): () => void;
475
+ subscribeEvents(listener: ClientEventListener): () => void;
717
476
  init(): Promise<UserRallyState>;
718
477
  initialize(): Promise<UserRallyState>;
719
- checkIn(spotId: string, proofData: unknown, options?: CheckInOptions): Promise<UniversalCheckInResult>;
720
- claimReward(rewardId: string, options?: ClaimOptions): Promise<UniversalClaimResult>;
721
- sync(adapter?: UniversalClientSyncAdapter): Promise<void>;
478
+ switchUser(newUserId: string | null): Promise<UserRallyState>;
479
+ getUserState(rallyId: string, userId: string): Promise<UserRallyState | null>;
480
+ clearUserState(userId?: string | null): Promise<void>;
481
+ checkIn(spotId: string, proofData: unknown, options?: CheckInOptions): Promise<CheckInResult>;
482
+ claimReward(rewardId: string, options?: ClaimOptions): Promise<ClaimResult>;
483
+ sync(adapter?: SyncAdapter | undefined): Promise<void>;
484
+ reset(): Promise<UserRallyState>;
485
+ restore(state: UserRallyState): Promise<UserRallyState>;
722
486
  }
723
487
 
724
488
  type SecureTokenSecretKey = string | Uint8Array;
@@ -756,23 +520,19 @@ interface DetectorError {
756
520
  readonly cause?: unknown;
757
521
  }
758
522
  type GeoVerificationContext = Extract<VerificationContext, {
759
- readonly type: "geo";
523
+ readonly type: "gps";
760
524
  }>;
761
- type TokenVerificationContext = Extract<VerificationContext, {
762
- readonly type: "token";
525
+ type QrVerificationContext = Extract<VerificationContext, {
526
+ readonly type: "qr";
527
+ }>;
528
+ type NfcVerificationContext = Extract<VerificationContext, {
529
+ readonly type: "nfc";
763
530
  }>;
764
531
  type DetectorResult<T extends VerificationContext> = Result<T, DetectorError>;
765
- interface PasscodeCondition {
766
- readonly passcode: string;
532
+ interface PasscodeCondition$1 {
533
+ readonly code: string;
767
534
  readonly caseSensitive?: boolean;
768
535
  }
769
- type CheckInResult = {
770
- readonly success: true;
771
- } | {
772
- readonly success: false;
773
- readonly reason: "INVALID_PASSCODE";
774
- readonly message: string;
775
- };
776
536
 
777
537
  interface GeoDetectorOptions {
778
538
  readonly enableHighAccuracy?: boolean;
@@ -786,10 +546,18 @@ interface NfcDetectorOptions {
786
546
  readonly signal?: AbortSignal;
787
547
  }
788
548
  declare function isNfcSupported(): boolean;
789
- declare function readNfcContext(options?: NfcDetectorOptions): Promise<DetectorResult<TokenVerificationContext>>;
549
+ declare function readNfcContext(options?: NfcDetectorOptions): Promise<DetectorResult<NfcVerificationContext>>;
790
550
 
551
+ interface PasscodeCondition {
552
+ readonly code: string;
553
+ readonly caseSensitive?: boolean;
554
+ }
555
+ interface PasscodeCheckResult {
556
+ readonly success: boolean;
557
+ readonly message?: string;
558
+ }
791
559
  declare function normalizePasscode(input: string, caseSensitive?: boolean): string;
792
- declare function verifyPasscode(inputCode: string, condition: PasscodeCondition): CheckInResult;
560
+ declare function verifyPasscode(inputCode: string, condition: PasscodeCondition): PasscodeCheckResult;
793
561
 
794
562
  interface QrDetectorOptions {
795
563
  readonly timeout?: number;
@@ -797,188 +565,7 @@ interface QrDetectorOptions {
797
565
  readonly facingMode?: "user" | "environment";
798
566
  }
799
567
  declare function isQrSupported(): boolean;
800
- declare function readQrContext(videoElement: HTMLVideoElement, options?: QrDetectorOptions): Promise<DetectorResult<TokenVerificationContext>>;
801
-
802
- /**
803
- * Branded identifiers keep values from different parts of the domain from
804
- * being exchanged accidentally while remaining plain strings at runtime.
805
- */
806
- type RallyId = string & {
807
- readonly __brand: "RallyId";
808
- };
809
- type SpotId = string & {
810
- readonly __brand: "SpotId";
811
- };
812
- type UserId = string & {
813
- readonly __brand: "UserId";
814
- };
815
- type Metadata = Readonly<Record<string, unknown>>;
816
- /** A locale-independent fallback plus zero or more locale-specific values. */
817
- interface LocalizedText<TLocale extends string = string> {
818
- readonly default: string;
819
- readonly translations: Readonly<Partial<Record<TLocale, string>>>;
820
- }
821
- /** A reference to an entity owned by an external system. */
822
- interface ExternalReference {
823
- readonly systemId: string;
824
- readonly entityType: string;
825
- readonly entityId: string;
826
- readonly attributes?: Metadata;
827
- }
828
- /** Public, non-secret configuration for one check-in location. */
829
- interface SpotDefinition<TLocale extends string = string> {
830
- readonly id: SpotId;
831
- readonly name: LocalizedText<TLocale>;
832
- readonly description?: LocalizedText<TLocale>;
833
- readonly hint?: LocalizedText<TLocale>;
834
- readonly order?: number;
835
- readonly iconUrl?: string;
836
- readonly imageUrl?: string;
837
- readonly externalReference?: ExternalReference;
838
- readonly metadata?: Metadata;
839
- readonly verification: VerificationRequirement;
840
- readonly dependsOn?: ReadonlyArray<SpotId>;
841
- }
842
- /** Public description of a verifier selected at runtime through DI. */
843
- interface VerificationRequirement {
844
- readonly pluginId: string;
845
- /** Public parameters only; secrets belong to SpotVerificationSecret. */
846
- readonly parameters?: Metadata;
847
- }
848
- /** Public configuration safe to distribute to a browser client. */
849
- interface RallyDefinition<TLocale extends string = string> {
850
- readonly id: RallyId;
851
- readonly title: LocalizedText<TLocale>;
852
- readonly description?: LocalizedText<TLocale>;
853
- readonly spots: ReadonlyArray<SpotDefinition<TLocale>>;
854
- readonly startsAt?: string;
855
- readonly endsAt?: string;
856
- readonly externalReference?: ExternalReference;
857
- readonly metadata?: Metadata;
858
- }
859
- interface VerificationCoordinates {
860
- readonly latitude: number;
861
- readonly longitude: number;
862
- readonly radiusMeters: number;
863
- }
864
- /** Server-only material used by a verifier. Never include this in a public definition. */
865
- interface SpotVerificationSecret {
866
- readonly spotId: SpotId;
867
- readonly pluginId: string;
868
- readonly secret?: string | Readonly<Uint8Array>;
869
- readonly expectedValue?: string;
870
- readonly coordinates?: VerificationCoordinates;
871
- readonly metadata?: Metadata;
872
- }
873
- /** Server-only configuration composed from a public definition and secrets. */
874
- interface ServerRallyConfig<TLocale extends string = string> {
875
- readonly definition: RallyDefinition<TLocale>;
876
- readonly verificationSecrets: ReadonlyArray<SpotVerificationSecret>;
877
- readonly schemaVersion: SchemaVersion;
878
- readonly metadata?: Metadata;
879
- }
880
- type SchemaVersion = number;
881
- interface StampRecord {
882
- readonly stampId: SpotId;
883
- readonly acquiredAt: string;
884
- readonly verificationPluginId?: string;
885
- readonly metadata?: Metadata;
886
- }
887
- interface RallyProgress {
888
- readonly rallyId: RallyId;
889
- readonly userId: UserId;
890
- readonly stamps: ReadonlyArray<StampRecord>;
891
- /** Monotonically increasing revision used for optimistic locking. */
892
- readonly stateSequence: number;
893
- readonly schemaVersion: SchemaVersion;
894
- readonly updatedAt: string;
895
- readonly completedAt?: string;
896
- readonly metadata?: Metadata;
897
- }
898
- interface StorageSaveRequest {
899
- readonly progress: RallyProgress;
900
- readonly expectedStateSequence: number;
901
- readonly idempotencyKey: string;
902
- }
903
- type StorageSaveOutcome = {
904
- readonly status: "saved";
905
- readonly progress: RallyProgress;
906
- readonly idempotent: boolean;
907
- } | {
908
- readonly status: "conflict";
909
- readonly current: RallyProgress | null;
910
- };
911
- /** Persistence boundary. Implementations own transactions and concurrency control. */
912
- interface StorageAdapter {
913
- load(rallyId: RallyId, userId: UserId): Promise<RallyProgress | null>;
914
- save(request: StorageSaveRequest): Promise<StorageSaveOutcome>;
915
- }
916
- interface AuthContextAdapter<TRequest = unknown> {
917
- getUserId(request: TRequest): Promise<UserId | null> | UserId | null;
918
- }
919
- interface ValidationInput<TProof = unknown> {
920
- readonly rallyId: RallyId;
921
- readonly spotId: SpotId;
922
- readonly userId: UserId;
923
- readonly proof: TProof;
924
- readonly requestedAt: string;
925
- readonly publicParameters?: Metadata;
926
- }
927
- type ValidationOutcome = {
928
- readonly valid: true;
929
- readonly reason?: string;
930
- readonly metadata?: Metadata;
931
- } | {
932
- readonly valid: false;
933
- readonly code: string;
934
- readonly reason?: string;
935
- readonly metadata?: Metadata;
936
- };
937
- /** Pluggable verifier for GPS, TOTP/HMAC, signatures, or application rules. */
938
- interface ConditionVerifierPlugin<TProof = unknown> {
939
- readonly id: string;
940
- verify(input: ValidationInput<TProof>, secret: SpotVerificationSecret): Promise<ValidationOutcome> | ValidationOutcome;
941
- }
942
- interface CheckInAttemptAuditEntry {
943
- readonly rallyId: RallyId;
944
- readonly spotId: SpotId;
945
- readonly userId: UserId;
946
- readonly attemptedAt: string;
947
- readonly outcome: ValidationOutcome;
948
- readonly idempotencyKey?: string;
949
- /** Use a digest or other redacted representation; never require raw proof data. */
950
- readonly proofDigest?: string;
951
- readonly metadata?: Metadata;
952
- }
953
- interface AuditLoggerAdapter {
954
- logCheckInAttempt(entry: CheckInAttemptAuditEntry): Promise<void>;
955
- }
956
- interface StampAcquiredEvent {
957
- readonly type: "stampAcquired";
958
- readonly rallyId: RallyId;
959
- readonly spotId: SpotId;
960
- readonly userId: UserId;
961
- readonly record: StampRecord;
962
- }
963
- interface RallyCompletedEvent {
964
- readonly type: "rallyCompleted";
965
- readonly rallyId: RallyId;
966
- readonly userId: UserId;
967
- readonly completedAt: string;
968
- }
969
- type RallyEvent = StampAcquiredEvent | RallyCompletedEvent;
970
- interface EventPublisherAdapter {
971
- publish(event: RallyEvent): Promise<void>;
972
- }
973
- interface SystemClockAdapter {
974
- now(): string;
975
- }
976
- interface IdGeneratorAdapter {
977
- generate(): string;
978
- }
979
- interface StateMigrator {
980
- migrate(state: unknown, fromVersion: SchemaVersion, toVersion: SchemaVersion): RallyProgress;
981
- }
568
+ declare function readQrContext(videoElement: HTMLVideoElement, options?: QrDetectorOptions): Promise<DetectorResult<QrVerificationContext>>;
982
569
 
983
570
  type SnapshotSecretKey = string | Uint8Array;
984
571
  interface SnapshotTokenPayload {
@@ -1003,4 +590,4 @@ type SnapshotTokenVerification<T extends SnapshotTokenPayload = SnapshotTokenPay
1003
590
  declare function createSignedSnapshotToken<T extends SnapshotTokenPayload>(payload: T, secretKey: SnapshotSecretKey): Promise<string>;
1004
591
  declare function verifySnapshotToken<T extends SnapshotTokenPayload = SnapshotTokenPayload>(token: string, secretKey: SnapshotSecretKey, now?: number): Promise<SnapshotTokenVerification<T>>;
1005
592
 
1006
- export { type AdminRallyConfig, type AdminReward, type AuditLoggerAdapter, type AuthContextAdapter, CURRENT_RALLY_CONFIG_VERSION, type CheckInAttemptAuditEntry, type CheckInContext, type CheckInErrorCode, type CheckInInput, type CheckInOptions, type CheckInResult$1 as CheckInResult, type CheckInSuccess, type ClaimOptions, type ClaimResult, type ClaimSuccess, type ClaimTicketOptions, type ClientCheckInResult, type ClientClaimResult, type Clock, type CompositeConditionFailure, type ConditionMatch, type ConditionMismatch, type ConditionVerifierPlugin, type ConsumeResult, type ConsumeRewardParams, type CustomValidator, DEFAULT_SHEET_THEME, type DetectorError, type DetectorErrorCode, type DetectorKind, type DetectorResult, type EventPublisherAdapter, type ExternalReference$1 as ExternalReference, type FontFamily, type GeoDetectorOptions, type GeoVerificationContext, type LocalizedText as HeadlessLocalizedText, type IdGeneratorAdapter, InMemoryStorage, IndexedDBAdapter, type IndexedDBAdapterOptions, type LegacyPublicRallyConfig, LocalStorageAdapter, type LocalStorageAdapterOptions, type LocalStorageFailureMode, type LocaleDictionary, type LocalizedString, type LocalizedText$1 as LocalizedText, type Metadata, type NfcDetectorOptions, type PasscodeCondition, type ProcessStampValue, type PublicCheckInCondition, type PublicRallyConfig, type PublicReward, type PublicRewardItem, type QrDetectorOptions, type RallyCompletedEvent, type RallyConfig, type RallyConfigValidationResult, type RallyDefinition, type RallyEvent, type RallyId, type RallyProgress, type RallySnapshot, type RedemptionMethod, type Result, type RewardConsumeError, type RewardItem, type RewardState, type RewardStatus, type RewardType, type RewardUnlockCondition, type SchemaVersion, type SecureTokenError, type SecureTokenErrorCode, type SecureTokenOptions, type SecureTokenPayload, type SecureTokenSecretKey, type SecureTokenVerification, type ServerRallyConfig, type SheetTheme, type SlotShape, type SnapshotSecretKey, type SnapshotTokenError, type SnapshotTokenErrorCode, type SnapshotTokenPayload, type SnapshotTokenVerification, type SpotDefinition, type SpotId, type SpotItem, type SpotVerificationSecret, type StampAcquiredEvent, type StampCondition, type StampDefinition, type StampError, StampRallyClient, type StampRallyClientEvent, type StampRallyEvent, type StampRallyEventListener, type StampRallyListener, type StampRallyProgress, type StampRallyState, type StampRecord$1 as StampRecord, type StampStorage, type StateMigrator, type StorageAdapter, StorageAdapterError, type StorageAdapterErrorCode, type StorageLike, type StorageOperation, type StorageSaveOutcome, type StorageSaveRequest, type StorageWarningHandler, type SupportedLocale, type SystemClockAdapter, THEME_PRESETS, type ThemePreset, type ThemePresetId, type TokenVerificationContext, type UniversalCheckInResult, type UniversalClaimRequest, type UniversalClaimResult, type UniversalClientError, type UniversalClientEvent, type UniversalClientEventListener, type UniversalClientListener, type UniversalClientRequest, type UniversalClientSyncAdapter, type UniversalLocalizedText, type UniversalSpotItem, UniversalStampRallyClient, type UniversalStampRallyClientOptions, type UniversalValidationError, type UniversalValidationResult, type UserId, type UserRallyState, type ValidationError, type ValidationInput, type ValidationOutcome, type VerificationCondition, type VerificationContext, type VerificationCoordinates, type VerificationRequirement, calculateDistanceMeters, calculateProgress, consumeReward, createClaimTicketNumber, createSecureToken, createSignedSnapshotToken, createUniqueClaimTicketNumber, evaluateCheckIn, evaluateCondition, evaluateConditionDetailed, exportProgressToken, getCurrentGeoContext, importProgressToken, isAdminRallyConfig, isGeolocationSupported, isNfcSupported, isPublicRallyConfig, isPublicRallyConfigShape, isQrSupported, isRewardState, isStampRallyState, issueClaimTicketNumber, migrateRallyConfig, normalizePasscode, processStamp, readNfcContext, readQrContext, reconcileRewardStates, resolveLocalizedText, stripSensitiveConfig, toLocalizedString, toPublicRallyConfig, validateAdminRallyConfig, validatePublicRallyConfig, validateRallyConfig, verifyPasscode, verifySecureToken, verifySnapshotToken };
593
+ export { type AdminRallyConfig, type CheckInCondition, type CheckInOptions, type CheckInRequest, type CheckInResult, type CheckInSuccess, type ClaimOptions, type ClaimRequest, type ClaimResult, type ClaimSuccess, type ClaimTicketOptions, type ClientError, type ClientEvent, type ClientEventListener, type ClientListener, type ClientOptions, type CompositeConditionFailure, type ConditionMatch, type ConditionMismatch, type ConsumeResult, type ConsumeRewardParams, type CustomValidationContext, type CustomValidator, DEFAULT_SHEET_THEME, type DetectorError, type DetectorErrorCode, type DetectorKind, type DetectorResult, type ExternalReference, type FontFamily, type GeoDetectorOptions, type GeoVerificationContext, InMemoryStorage, IndexedDBAdapter, type IndexedDBAdapterOptions, LocalStorageAdapter, type LocalStorageAdapterOptions, type LocalStorageFailureMode, type LocaleDictionary, type LocalizedString, type LocalizedText, type NfcDetectorOptions, type NfcVerificationContext, type PasscodeCondition$1 as PasscodeCondition, type ProcessStampValue, type PublicCheckInCondition, type PublicRallyConfig, type PublicReward, type PublicSpotItem, type QrDetectorOptions, type QrVerificationContext, type RallyConfig, type RallySnapshot, type RedemptionMethod, type Result, type Reward, type RewardConsumeError, type RewardState, type RewardStatus, type RewardType, type RewardUnlockCondition, type SecureTokenError, type SecureTokenErrorCode, type SecureTokenOptions, type SecureTokenPayload, type SecureTokenSecretKey, type SecureTokenVerification, type SheetTheme, type SlotShape, type SnapshotSecretKey, type SnapshotTokenError, type SnapshotTokenErrorCode, type SnapshotTokenPayload, type SnapshotTokenVerification, type SpotItem, type StampError, StampRallyClient, type StampRallyProgress, type StampRallyState, type StampRecord, type StampStorage, StorageAdapterError, type StorageAdapterErrorCode, type StorageLike, type StorageOperation, type StorageWarningHandler, type SupportedLocale, type SyncAdapter, THEME_PRESETS, type ThemePreset, type ThemePresetId, type UserRallyState, type Validator, type VerificationContext, assertPublicConfig, calculateDistanceMeters, calculateProgress, consumeReward, createClaimTicketNumber, createSecureToken, createSignedSnapshotToken, createUniqueClaimTicketNumber, evaluateCondition, evaluateConditionDetailed, exportProgressToken, getCurrentGeoContext, getOrderedSpots, importProgressToken, isGeolocationSupported, isNfcSupported, isPublicConfig, isQrSupported, isRewardState, isStampRallyState, issueClaimTicketNumber, normalizePasscode, processStamp, readNfcContext, readQrContext, reconcileRewardStates, resolveLocalizedText, storageKey, toLocalizedString, toPublicConfig, verifyPasscode, verifySecureToken, verifySnapshotToken };