@stamprally/core 0.5.1 → 0.6.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
@@ -112,7 +112,7 @@ type Result<T, E> = {
112
112
 
113
113
  type SupportedLocale = "ja" | "en";
114
114
  type LocalizedString<TLocale extends string = SupportedLocale> = Record<TLocale, string>;
115
- type LocalizedText<TLocale extends string = string> = string | Partial<Record<TLocale, string>>;
115
+ type LocalizedText$1<TLocale extends string = string> = string | Partial<Record<TLocale, string>>;
116
116
  type LocaleDictionary<TLocale extends string = string> = Readonly<Record<TLocale, Readonly<Record<string, string>>>>;
117
117
  type SlotShape = "circle" | "square" | "rounded";
118
118
  type FontFamily = "system-ui" | "serif" | "rounded-sans" | "monospace" | "handwritten";
@@ -138,9 +138,9 @@ interface ThemePreset<TLocale extends string = SupportedLocale> {
138
138
  declare const DEFAULT_SHEET_THEME: SheetTheme;
139
139
  interface SpotItem<TLocale extends string = SupportedLocale, TMeta extends Record<string, unknown> = Record<string, unknown>> {
140
140
  readonly id: string;
141
- readonly name: LocalizedText<TLocale>;
142
- readonly description?: LocalizedText<TLocale>;
143
- readonly hint?: LocalizedText<TLocale>;
141
+ readonly name: LocalizedText$1<TLocale>;
142
+ readonly description?: LocalizedText$1<TLocale>;
143
+ readonly hint?: LocalizedText$1<TLocale>;
144
144
  readonly condition: StampCondition;
145
145
  readonly orderIndex?: number;
146
146
  readonly order?: number;
@@ -157,7 +157,7 @@ interface SpotItem<TLocale extends string = SupportedLocale, TMeta extends Recor
157
157
  }
158
158
  /** @deprecated Use SpotItem instead. */
159
159
  type StampDefinition<TLocale extends string = SupportedLocale, TMeta extends Record<string, unknown> = Record<string, unknown>> = SpotItem<TLocale, TMeta>;
160
- interface StampRecord {
160
+ interface StampRecord$1 {
161
161
  readonly stampId: string;
162
162
  readonly acquiredAt: string;
163
163
  readonly metadata?: Readonly<Record<string, unknown>>;
@@ -180,8 +180,8 @@ type RewardUnlockCondition = {
180
180
  type RewardStatus = "LOCKED" | "AVAILABLE" | "CONSUMED" | "EXPIRED";
181
181
  interface RewardItem<TLocale extends string = SupportedLocale> {
182
182
  readonly id: string;
183
- readonly title: LocalizedText<TLocale>;
184
- readonly description: LocalizedText<TLocale>;
183
+ readonly title: LocalizedText$1<TLocale>;
184
+ readonly description: LocalizedText$1<TLocale>;
185
185
  readonly type: RewardType;
186
186
  readonly redemptionMethod: RedemptionMethod;
187
187
  readonly requiredStampCount: number;
@@ -207,14 +207,14 @@ interface RewardState {
207
207
  }
208
208
  interface StampRallyState {
209
209
  readonly rallyId: string;
210
- readonly records: ReadonlyArray<StampRecord>;
210
+ readonly records: ReadonlyArray<StampRecord$1>;
211
211
  readonly rewards?: ReadonlyArray<RewardState>;
212
212
  readonly updatedAt: string;
213
213
  }
214
214
  interface RallyConfig<TLocale extends string = SupportedLocale, TMeta extends Record<string, unknown> = Record<string, unknown>> {
215
215
  readonly id: string;
216
- readonly title?: LocalizedText<TLocale>;
217
- readonly description?: LocalizedText<TLocale>;
216
+ readonly title?: LocalizedText$1<TLocale>;
217
+ readonly description?: LocalizedText$1<TLocale>;
218
218
  readonly stamps: ReadonlyArray<StampDefinition<TLocale, TMeta>>;
219
219
  readonly rewards?: ReadonlyArray<RewardItem<TLocale>>;
220
220
  readonly isSequential?: boolean;
@@ -224,9 +224,9 @@ interface RallyConfig<TLocale extends string = SupportedLocale, TMeta extends Re
224
224
  readonly endDate?: string;
225
225
  }
226
226
 
227
- declare function resolveLocalizedText<TLocale extends string = SupportedLocale>(text: LocalizedText<TLocale> | undefined, locale: string, fallbackLocale?: string): string;
228
- declare function toLocalizedString(text: LocalizedText | undefined): LocalizedString;
229
- declare function toLocalizedString<TLocale extends string>(text: LocalizedText<TLocale> | undefined): LocalizedString<TLocale>;
227
+ declare function resolveLocalizedText<TLocale extends string = SupportedLocale>(text: LocalizedText$1<TLocale> | undefined, locale: string, fallbackLocale?: string): string;
228
+ declare function toLocalizedString(text: LocalizedText$1 | undefined): LocalizedString;
229
+ declare function toLocalizedString<TLocale extends string>(text: LocalizedText$1<TLocale> | undefined): LocalizedString<TLocale>;
230
230
 
231
231
  declare function migrateRallyConfig<TLocale extends string = SupportedLocale>(raw: unknown): RallyConfig<TLocale>;
232
232
 
@@ -303,7 +303,7 @@ declare function issueClaimTicketNumber(reward: RewardItem, currentState: Reward
303
303
 
304
304
  type StampRallyEvent = {
305
305
  readonly type: "stampAcquired";
306
- readonly record: StampRecord;
306
+ readonly record: StampRecord$1;
307
307
  } | {
308
308
  readonly type: "rallyCompleted";
309
309
  readonly rallyId: string;
@@ -382,7 +382,7 @@ declare function isStampRallyState(value: unknown): value is StampRallyState;
382
382
  interface RallySnapshot {
383
383
  readonly version: 1;
384
384
  readonly rallyId: string;
385
- readonly stamps: ReadonlyArray<StampRecord>;
385
+ readonly stamps: ReadonlyArray<StampRecord$1>;
386
386
  readonly rewards: ReadonlyArray<RewardState>;
387
387
  readonly exportedAt: string;
388
388
  }
@@ -537,6 +537,187 @@ interface QrDetectorOptions {
537
537
  declare function isQrSupported(): boolean;
538
538
  declare function readQrContext(videoElement: HTMLVideoElement, options?: QrDetectorOptions): Promise<DetectorResult<TokenVerificationContext>>;
539
539
 
540
+ /**
541
+ * Branded identifiers keep values from different parts of the domain from
542
+ * being exchanged accidentally while remaining plain strings at runtime.
543
+ */
544
+ type RallyId = string & {
545
+ readonly __brand: "RallyId";
546
+ };
547
+ type SpotId = string & {
548
+ readonly __brand: "SpotId";
549
+ };
550
+ type UserId = string & {
551
+ readonly __brand: "UserId";
552
+ };
553
+ type Metadata = Readonly<Record<string, unknown>>;
554
+ /** A locale-independent fallback plus zero or more locale-specific values. */
555
+ interface LocalizedText<TLocale extends string = string> {
556
+ readonly default: string;
557
+ readonly translations: Readonly<Partial<Record<TLocale, string>>>;
558
+ }
559
+ /** A reference to an entity owned by an external system. */
560
+ interface ExternalReference {
561
+ readonly systemId: string;
562
+ readonly entityType: string;
563
+ readonly entityId: string;
564
+ readonly attributes?: Metadata;
565
+ }
566
+ /** Public, non-secret configuration for one check-in location. */
567
+ interface SpotDefinition<TLocale extends string = string> {
568
+ readonly id: SpotId;
569
+ readonly name: LocalizedText<TLocale>;
570
+ readonly description?: LocalizedText<TLocale>;
571
+ readonly hint?: LocalizedText<TLocale>;
572
+ readonly order?: number;
573
+ readonly iconUrl?: string;
574
+ readonly imageUrl?: string;
575
+ readonly externalReference?: ExternalReference;
576
+ readonly metadata?: Metadata;
577
+ readonly verification: VerificationRequirement;
578
+ readonly dependsOn?: ReadonlyArray<SpotId>;
579
+ }
580
+ /** Public description of a verifier selected at runtime through DI. */
581
+ interface VerificationRequirement {
582
+ readonly pluginId: string;
583
+ /** Public parameters only; secrets belong to SpotVerificationSecret. */
584
+ readonly parameters?: Metadata;
585
+ }
586
+ /** Public configuration safe to distribute to a browser client. */
587
+ interface RallyDefinition<TLocale extends string = string> {
588
+ readonly id: RallyId;
589
+ readonly title: LocalizedText<TLocale>;
590
+ readonly description?: LocalizedText<TLocale>;
591
+ readonly spots: ReadonlyArray<SpotDefinition<TLocale>>;
592
+ readonly startsAt?: string;
593
+ readonly endsAt?: string;
594
+ readonly externalReference?: ExternalReference;
595
+ readonly metadata?: Metadata;
596
+ }
597
+ interface VerificationCoordinates {
598
+ readonly latitude: number;
599
+ readonly longitude: number;
600
+ readonly radiusMeters: number;
601
+ }
602
+ /** Server-only material used by a verifier. Never include this in a public definition. */
603
+ interface SpotVerificationSecret {
604
+ readonly spotId: SpotId;
605
+ readonly pluginId: string;
606
+ readonly secret?: string | Readonly<Uint8Array>;
607
+ readonly expectedValue?: string;
608
+ readonly coordinates?: VerificationCoordinates;
609
+ readonly metadata?: Metadata;
610
+ }
611
+ /** Server-only configuration composed from a public definition and secrets. */
612
+ interface ServerRallyConfig<TLocale extends string = string> {
613
+ readonly definition: RallyDefinition<TLocale>;
614
+ readonly verificationSecrets: ReadonlyArray<SpotVerificationSecret>;
615
+ readonly schemaVersion: SchemaVersion;
616
+ readonly metadata?: Metadata;
617
+ }
618
+ type SchemaVersion = number;
619
+ interface StampRecord {
620
+ readonly stampId: SpotId;
621
+ readonly acquiredAt: string;
622
+ readonly verificationPluginId?: string;
623
+ readonly metadata?: Metadata;
624
+ }
625
+ interface RallyProgress {
626
+ readonly rallyId: RallyId;
627
+ readonly userId: UserId;
628
+ readonly stamps: ReadonlyArray<StampRecord>;
629
+ /** Monotonically increasing revision used for optimistic locking. */
630
+ readonly stateSequence: number;
631
+ readonly schemaVersion: SchemaVersion;
632
+ readonly updatedAt: string;
633
+ readonly completedAt?: string;
634
+ readonly metadata?: Metadata;
635
+ }
636
+ interface StorageSaveRequest {
637
+ readonly progress: RallyProgress;
638
+ readonly expectedStateSequence: number;
639
+ readonly idempotencyKey: string;
640
+ }
641
+ type StorageSaveOutcome = {
642
+ readonly status: "saved";
643
+ readonly progress: RallyProgress;
644
+ readonly idempotent: boolean;
645
+ } | {
646
+ readonly status: "conflict";
647
+ readonly current: RallyProgress | null;
648
+ };
649
+ /** Persistence boundary. Implementations own transactions and concurrency control. */
650
+ interface StorageAdapter {
651
+ load(rallyId: RallyId, userId: UserId): Promise<RallyProgress | null>;
652
+ save(request: StorageSaveRequest): Promise<StorageSaveOutcome>;
653
+ }
654
+ interface AuthContextAdapter<TRequest = unknown> {
655
+ getUserId(request: TRequest): Promise<UserId | null> | UserId | null;
656
+ }
657
+ interface ValidationInput<TProof = unknown> {
658
+ readonly rallyId: RallyId;
659
+ readonly spotId: SpotId;
660
+ readonly userId: UserId;
661
+ readonly proof: TProof;
662
+ readonly requestedAt: string;
663
+ readonly publicParameters?: Metadata;
664
+ }
665
+ type ValidationOutcome = {
666
+ readonly valid: true;
667
+ readonly reason?: string;
668
+ readonly metadata?: Metadata;
669
+ } | {
670
+ readonly valid: false;
671
+ readonly code: string;
672
+ readonly reason?: string;
673
+ readonly metadata?: Metadata;
674
+ };
675
+ /** Pluggable verifier for GPS, TOTP/HMAC, signatures, or application rules. */
676
+ interface ConditionVerifierPlugin<TProof = unknown> {
677
+ readonly id: string;
678
+ verify(input: ValidationInput<TProof>, secret: SpotVerificationSecret): Promise<ValidationOutcome> | ValidationOutcome;
679
+ }
680
+ interface CheckInAttemptAuditEntry {
681
+ readonly rallyId: RallyId;
682
+ readonly spotId: SpotId;
683
+ readonly userId: UserId;
684
+ readonly attemptedAt: string;
685
+ readonly outcome: ValidationOutcome;
686
+ readonly idempotencyKey?: string;
687
+ /** Use a digest or other redacted representation; never require raw proof data. */
688
+ readonly proofDigest?: string;
689
+ readonly metadata?: Metadata;
690
+ }
691
+ interface AuditLoggerAdapter {
692
+ logCheckInAttempt(entry: CheckInAttemptAuditEntry): Promise<void>;
693
+ }
694
+ interface StampAcquiredEvent {
695
+ readonly type: "stampAcquired";
696
+ readonly rallyId: RallyId;
697
+ readonly spotId: SpotId;
698
+ readonly userId: UserId;
699
+ readonly record: StampRecord;
700
+ }
701
+ interface RallyCompletedEvent {
702
+ readonly type: "rallyCompleted";
703
+ readonly rallyId: RallyId;
704
+ readonly userId: UserId;
705
+ readonly completedAt: string;
706
+ }
707
+ type RallyEvent = StampAcquiredEvent | RallyCompletedEvent;
708
+ interface EventPublisherAdapter {
709
+ publish(event: RallyEvent): Promise<void>;
710
+ }
711
+ interface SystemClockAdapter {
712
+ now(): string;
713
+ }
714
+ interface IdGeneratorAdapter {
715
+ generate(): string;
716
+ }
717
+ interface StateMigrator {
718
+ migrate(state: unknown, fromVersion: SchemaVersion, toVersion: SchemaVersion): RallyProgress;
719
+ }
720
+
540
721
  type SnapshotSecretKey = string | Uint8Array;
541
722
  interface SnapshotTokenPayload {
542
723
  readonly [key: string]: unknown;
@@ -560,4 +741,4 @@ type SnapshotTokenVerification<T extends SnapshotTokenPayload = SnapshotTokenPay
560
741
  declare function createSignedSnapshotToken<T extends SnapshotTokenPayload>(payload: T, secretKey: SnapshotSecretKey): Promise<string>;
561
742
  declare function verifySnapshotToken<T extends SnapshotTokenPayload = SnapshotTokenPayload>(token: string, secretKey: SnapshotSecretKey, now?: number): Promise<SnapshotTokenVerification<T>>;
562
743
 
563
- export { CURRENT_RALLY_CONFIG_VERSION, type CheckInContext, type CheckInErrorCode, type CheckInInput, type CheckInResult$1 as CheckInResult, type ClaimTicketOptions, type Clock, type CompositeConditionFailure, type ConditionMatch, type ConditionMismatch, type ConsumeResult, type ConsumeRewardParams, DEFAULT_SHEET_THEME, type DetectorError, type DetectorErrorCode, type DetectorKind, type DetectorResult, type FontFamily, type GeoDetectorOptions, type GeoVerificationContext, InMemoryStorage, IndexedDBAdapter, type IndexedDBAdapterOptions, LocalStorageAdapter, type LocalStorageAdapterOptions, type LocalStorageFailureMode, type LocaleDictionary, type LocalizedString, type LocalizedText, type NfcDetectorOptions, type PasscodeCondition, type ProcessStampValue, type PublicRallyConfig, type PublicRewardItem, type QrDetectorOptions, type RallyConfig, type RallyConfigValidationResult, type RallySnapshot, type RedemptionMethod, type Result, type RewardConsumeError, type RewardItem, 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 StampCondition, type StampDefinition, type StampError, StampRallyClient, type StampRallyClientEvent, type StampRallyEvent, type StampRallyEventListener, type StampRallyListener, type StampRallyProgress, type StampRallyState, type StampRecord, type StampStorage, StorageAdapterError, type StorageAdapterErrorCode, type StorageLike, type StorageOperation, type StorageWarningHandler, type SupportedLocale, THEME_PRESETS, type ThemePreset, type ThemePresetId, type TokenVerificationContext, type ValidationError, type VerificationContext, calculateDistanceMeters, calculateProgress, consumeReward, createClaimTicketNumber, createSecureToken, createSignedSnapshotToken, createUniqueClaimTicketNumber, evaluateCheckIn, evaluateCondition, evaluateConditionDetailed, exportProgressToken, getCurrentGeoContext, importProgressToken, isGeolocationSupported, isNfcSupported, isQrSupported, isRewardState, isStampRallyState, issueClaimTicketNumber, migrateRallyConfig, normalizePasscode, processStamp, readNfcContext, readQrContext, reconcileRewardStates, resolveLocalizedText, stripSensitiveConfig, toLocalizedString, validateRallyConfig, verifyPasscode, verifySecureToken, verifySnapshotToken };
744
+ export { type AuditLoggerAdapter, type AuthContextAdapter, CURRENT_RALLY_CONFIG_VERSION, type CheckInAttemptAuditEntry, type CheckInContext, type CheckInErrorCode, type CheckInInput, type CheckInResult$1 as CheckInResult, type ClaimTicketOptions, type Clock, type CompositeConditionFailure, type ConditionMatch, type ConditionMismatch, type ConditionVerifierPlugin, type ConsumeResult, type ConsumeRewardParams, DEFAULT_SHEET_THEME, type DetectorError, type DetectorErrorCode, type DetectorKind, type DetectorResult, type EventPublisherAdapter, type ExternalReference, type FontFamily, type GeoDetectorOptions, type GeoVerificationContext, type LocalizedText as HeadlessLocalizedText, type IdGeneratorAdapter, InMemoryStorage, IndexedDBAdapter, type IndexedDBAdapterOptions, LocalStorageAdapter, type LocalStorageAdapterOptions, type LocalStorageFailureMode, type LocaleDictionary, type LocalizedString, type LocalizedText$1 as LocalizedText, type Metadata, type NfcDetectorOptions, type PasscodeCondition, type ProcessStampValue, type PublicRallyConfig, 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 UserId, type ValidationError, type ValidationInput, type ValidationOutcome, type VerificationContext, type VerificationCoordinates, type VerificationRequirement, calculateDistanceMeters, calculateProgress, consumeReward, createClaimTicketNumber, createSecureToken, createSignedSnapshotToken, createUniqueClaimTicketNumber, evaluateCheckIn, evaluateCondition, evaluateConditionDetailed, exportProgressToken, getCurrentGeoContext, importProgressToken, isGeolocationSupported, isNfcSupported, isQrSupported, isRewardState, isStampRallyState, issueClaimTicketNumber, migrateRallyConfig, normalizePasscode, processStamp, readNfcContext, readQrContext, reconcileRewardStates, resolveLocalizedText, stripSensitiveConfig, toLocalizedString, validateRallyConfig, verifyPasscode, verifySecureToken, verifySnapshotToken };
package/dist/index.d.ts CHANGED
@@ -112,7 +112,7 @@ type Result<T, E> = {
112
112
 
113
113
  type SupportedLocale = "ja" | "en";
114
114
  type LocalizedString<TLocale extends string = SupportedLocale> = Record<TLocale, string>;
115
- type LocalizedText<TLocale extends string = string> = string | Partial<Record<TLocale, string>>;
115
+ type LocalizedText$1<TLocale extends string = string> = string | Partial<Record<TLocale, string>>;
116
116
  type LocaleDictionary<TLocale extends string = string> = Readonly<Record<TLocale, Readonly<Record<string, string>>>>;
117
117
  type SlotShape = "circle" | "square" | "rounded";
118
118
  type FontFamily = "system-ui" | "serif" | "rounded-sans" | "monospace" | "handwritten";
@@ -138,9 +138,9 @@ interface ThemePreset<TLocale extends string = SupportedLocale> {
138
138
  declare const DEFAULT_SHEET_THEME: SheetTheme;
139
139
  interface SpotItem<TLocale extends string = SupportedLocale, TMeta extends Record<string, unknown> = Record<string, unknown>> {
140
140
  readonly id: string;
141
- readonly name: LocalizedText<TLocale>;
142
- readonly description?: LocalizedText<TLocale>;
143
- readonly hint?: LocalizedText<TLocale>;
141
+ readonly name: LocalizedText$1<TLocale>;
142
+ readonly description?: LocalizedText$1<TLocale>;
143
+ readonly hint?: LocalizedText$1<TLocale>;
144
144
  readonly condition: StampCondition;
145
145
  readonly orderIndex?: number;
146
146
  readonly order?: number;
@@ -157,7 +157,7 @@ interface SpotItem<TLocale extends string = SupportedLocale, TMeta extends Recor
157
157
  }
158
158
  /** @deprecated Use SpotItem instead. */
159
159
  type StampDefinition<TLocale extends string = SupportedLocale, TMeta extends Record<string, unknown> = Record<string, unknown>> = SpotItem<TLocale, TMeta>;
160
- interface StampRecord {
160
+ interface StampRecord$1 {
161
161
  readonly stampId: string;
162
162
  readonly acquiredAt: string;
163
163
  readonly metadata?: Readonly<Record<string, unknown>>;
@@ -180,8 +180,8 @@ type RewardUnlockCondition = {
180
180
  type RewardStatus = "LOCKED" | "AVAILABLE" | "CONSUMED" | "EXPIRED";
181
181
  interface RewardItem<TLocale extends string = SupportedLocale> {
182
182
  readonly id: string;
183
- readonly title: LocalizedText<TLocale>;
184
- readonly description: LocalizedText<TLocale>;
183
+ readonly title: LocalizedText$1<TLocale>;
184
+ readonly description: LocalizedText$1<TLocale>;
185
185
  readonly type: RewardType;
186
186
  readonly redemptionMethod: RedemptionMethod;
187
187
  readonly requiredStampCount: number;
@@ -207,14 +207,14 @@ interface RewardState {
207
207
  }
208
208
  interface StampRallyState {
209
209
  readonly rallyId: string;
210
- readonly records: ReadonlyArray<StampRecord>;
210
+ readonly records: ReadonlyArray<StampRecord$1>;
211
211
  readonly rewards?: ReadonlyArray<RewardState>;
212
212
  readonly updatedAt: string;
213
213
  }
214
214
  interface RallyConfig<TLocale extends string = SupportedLocale, TMeta extends Record<string, unknown> = Record<string, unknown>> {
215
215
  readonly id: string;
216
- readonly title?: LocalizedText<TLocale>;
217
- readonly description?: LocalizedText<TLocale>;
216
+ readonly title?: LocalizedText$1<TLocale>;
217
+ readonly description?: LocalizedText$1<TLocale>;
218
218
  readonly stamps: ReadonlyArray<StampDefinition<TLocale, TMeta>>;
219
219
  readonly rewards?: ReadonlyArray<RewardItem<TLocale>>;
220
220
  readonly isSequential?: boolean;
@@ -224,9 +224,9 @@ interface RallyConfig<TLocale extends string = SupportedLocale, TMeta extends Re
224
224
  readonly endDate?: string;
225
225
  }
226
226
 
227
- declare function resolveLocalizedText<TLocale extends string = SupportedLocale>(text: LocalizedText<TLocale> | undefined, locale: string, fallbackLocale?: string): string;
228
- declare function toLocalizedString(text: LocalizedText | undefined): LocalizedString;
229
- declare function toLocalizedString<TLocale extends string>(text: LocalizedText<TLocale> | undefined): LocalizedString<TLocale>;
227
+ declare function resolveLocalizedText<TLocale extends string = SupportedLocale>(text: LocalizedText$1<TLocale> | undefined, locale: string, fallbackLocale?: string): string;
228
+ declare function toLocalizedString(text: LocalizedText$1 | undefined): LocalizedString;
229
+ declare function toLocalizedString<TLocale extends string>(text: LocalizedText$1<TLocale> | undefined): LocalizedString<TLocale>;
230
230
 
231
231
  declare function migrateRallyConfig<TLocale extends string = SupportedLocale>(raw: unknown): RallyConfig<TLocale>;
232
232
 
@@ -303,7 +303,7 @@ declare function issueClaimTicketNumber(reward: RewardItem, currentState: Reward
303
303
 
304
304
  type StampRallyEvent = {
305
305
  readonly type: "stampAcquired";
306
- readonly record: StampRecord;
306
+ readonly record: StampRecord$1;
307
307
  } | {
308
308
  readonly type: "rallyCompleted";
309
309
  readonly rallyId: string;
@@ -382,7 +382,7 @@ declare function isStampRallyState(value: unknown): value is StampRallyState;
382
382
  interface RallySnapshot {
383
383
  readonly version: 1;
384
384
  readonly rallyId: string;
385
- readonly stamps: ReadonlyArray<StampRecord>;
385
+ readonly stamps: ReadonlyArray<StampRecord$1>;
386
386
  readonly rewards: ReadonlyArray<RewardState>;
387
387
  readonly exportedAt: string;
388
388
  }
@@ -537,6 +537,187 @@ interface QrDetectorOptions {
537
537
  declare function isQrSupported(): boolean;
538
538
  declare function readQrContext(videoElement: HTMLVideoElement, options?: QrDetectorOptions): Promise<DetectorResult<TokenVerificationContext>>;
539
539
 
540
+ /**
541
+ * Branded identifiers keep values from different parts of the domain from
542
+ * being exchanged accidentally while remaining plain strings at runtime.
543
+ */
544
+ type RallyId = string & {
545
+ readonly __brand: "RallyId";
546
+ };
547
+ type SpotId = string & {
548
+ readonly __brand: "SpotId";
549
+ };
550
+ type UserId = string & {
551
+ readonly __brand: "UserId";
552
+ };
553
+ type Metadata = Readonly<Record<string, unknown>>;
554
+ /** A locale-independent fallback plus zero or more locale-specific values. */
555
+ interface LocalizedText<TLocale extends string = string> {
556
+ readonly default: string;
557
+ readonly translations: Readonly<Partial<Record<TLocale, string>>>;
558
+ }
559
+ /** A reference to an entity owned by an external system. */
560
+ interface ExternalReference {
561
+ readonly systemId: string;
562
+ readonly entityType: string;
563
+ readonly entityId: string;
564
+ readonly attributes?: Metadata;
565
+ }
566
+ /** Public, non-secret configuration for one check-in location. */
567
+ interface SpotDefinition<TLocale extends string = string> {
568
+ readonly id: SpotId;
569
+ readonly name: LocalizedText<TLocale>;
570
+ readonly description?: LocalizedText<TLocale>;
571
+ readonly hint?: LocalizedText<TLocale>;
572
+ readonly order?: number;
573
+ readonly iconUrl?: string;
574
+ readonly imageUrl?: string;
575
+ readonly externalReference?: ExternalReference;
576
+ readonly metadata?: Metadata;
577
+ readonly verification: VerificationRequirement;
578
+ readonly dependsOn?: ReadonlyArray<SpotId>;
579
+ }
580
+ /** Public description of a verifier selected at runtime through DI. */
581
+ interface VerificationRequirement {
582
+ readonly pluginId: string;
583
+ /** Public parameters only; secrets belong to SpotVerificationSecret. */
584
+ readonly parameters?: Metadata;
585
+ }
586
+ /** Public configuration safe to distribute to a browser client. */
587
+ interface RallyDefinition<TLocale extends string = string> {
588
+ readonly id: RallyId;
589
+ readonly title: LocalizedText<TLocale>;
590
+ readonly description?: LocalizedText<TLocale>;
591
+ readonly spots: ReadonlyArray<SpotDefinition<TLocale>>;
592
+ readonly startsAt?: string;
593
+ readonly endsAt?: string;
594
+ readonly externalReference?: ExternalReference;
595
+ readonly metadata?: Metadata;
596
+ }
597
+ interface VerificationCoordinates {
598
+ readonly latitude: number;
599
+ readonly longitude: number;
600
+ readonly radiusMeters: number;
601
+ }
602
+ /** Server-only material used by a verifier. Never include this in a public definition. */
603
+ interface SpotVerificationSecret {
604
+ readonly spotId: SpotId;
605
+ readonly pluginId: string;
606
+ readonly secret?: string | Readonly<Uint8Array>;
607
+ readonly expectedValue?: string;
608
+ readonly coordinates?: VerificationCoordinates;
609
+ readonly metadata?: Metadata;
610
+ }
611
+ /** Server-only configuration composed from a public definition and secrets. */
612
+ interface ServerRallyConfig<TLocale extends string = string> {
613
+ readonly definition: RallyDefinition<TLocale>;
614
+ readonly verificationSecrets: ReadonlyArray<SpotVerificationSecret>;
615
+ readonly schemaVersion: SchemaVersion;
616
+ readonly metadata?: Metadata;
617
+ }
618
+ type SchemaVersion = number;
619
+ interface StampRecord {
620
+ readonly stampId: SpotId;
621
+ readonly acquiredAt: string;
622
+ readonly verificationPluginId?: string;
623
+ readonly metadata?: Metadata;
624
+ }
625
+ interface RallyProgress {
626
+ readonly rallyId: RallyId;
627
+ readonly userId: UserId;
628
+ readonly stamps: ReadonlyArray<StampRecord>;
629
+ /** Monotonically increasing revision used for optimistic locking. */
630
+ readonly stateSequence: number;
631
+ readonly schemaVersion: SchemaVersion;
632
+ readonly updatedAt: string;
633
+ readonly completedAt?: string;
634
+ readonly metadata?: Metadata;
635
+ }
636
+ interface StorageSaveRequest {
637
+ readonly progress: RallyProgress;
638
+ readonly expectedStateSequence: number;
639
+ readonly idempotencyKey: string;
640
+ }
641
+ type StorageSaveOutcome = {
642
+ readonly status: "saved";
643
+ readonly progress: RallyProgress;
644
+ readonly idempotent: boolean;
645
+ } | {
646
+ readonly status: "conflict";
647
+ readonly current: RallyProgress | null;
648
+ };
649
+ /** Persistence boundary. Implementations own transactions and concurrency control. */
650
+ interface StorageAdapter {
651
+ load(rallyId: RallyId, userId: UserId): Promise<RallyProgress | null>;
652
+ save(request: StorageSaveRequest): Promise<StorageSaveOutcome>;
653
+ }
654
+ interface AuthContextAdapter<TRequest = unknown> {
655
+ getUserId(request: TRequest): Promise<UserId | null> | UserId | null;
656
+ }
657
+ interface ValidationInput<TProof = unknown> {
658
+ readonly rallyId: RallyId;
659
+ readonly spotId: SpotId;
660
+ readonly userId: UserId;
661
+ readonly proof: TProof;
662
+ readonly requestedAt: string;
663
+ readonly publicParameters?: Metadata;
664
+ }
665
+ type ValidationOutcome = {
666
+ readonly valid: true;
667
+ readonly reason?: string;
668
+ readonly metadata?: Metadata;
669
+ } | {
670
+ readonly valid: false;
671
+ readonly code: string;
672
+ readonly reason?: string;
673
+ readonly metadata?: Metadata;
674
+ };
675
+ /** Pluggable verifier for GPS, TOTP/HMAC, signatures, or application rules. */
676
+ interface ConditionVerifierPlugin<TProof = unknown> {
677
+ readonly id: string;
678
+ verify(input: ValidationInput<TProof>, secret: SpotVerificationSecret): Promise<ValidationOutcome> | ValidationOutcome;
679
+ }
680
+ interface CheckInAttemptAuditEntry {
681
+ readonly rallyId: RallyId;
682
+ readonly spotId: SpotId;
683
+ readonly userId: UserId;
684
+ readonly attemptedAt: string;
685
+ readonly outcome: ValidationOutcome;
686
+ readonly idempotencyKey?: string;
687
+ /** Use a digest or other redacted representation; never require raw proof data. */
688
+ readonly proofDigest?: string;
689
+ readonly metadata?: Metadata;
690
+ }
691
+ interface AuditLoggerAdapter {
692
+ logCheckInAttempt(entry: CheckInAttemptAuditEntry): Promise<void>;
693
+ }
694
+ interface StampAcquiredEvent {
695
+ readonly type: "stampAcquired";
696
+ readonly rallyId: RallyId;
697
+ readonly spotId: SpotId;
698
+ readonly userId: UserId;
699
+ readonly record: StampRecord;
700
+ }
701
+ interface RallyCompletedEvent {
702
+ readonly type: "rallyCompleted";
703
+ readonly rallyId: RallyId;
704
+ readonly userId: UserId;
705
+ readonly completedAt: string;
706
+ }
707
+ type RallyEvent = StampAcquiredEvent | RallyCompletedEvent;
708
+ interface EventPublisherAdapter {
709
+ publish(event: RallyEvent): Promise<void>;
710
+ }
711
+ interface SystemClockAdapter {
712
+ now(): string;
713
+ }
714
+ interface IdGeneratorAdapter {
715
+ generate(): string;
716
+ }
717
+ interface StateMigrator {
718
+ migrate(state: unknown, fromVersion: SchemaVersion, toVersion: SchemaVersion): RallyProgress;
719
+ }
720
+
540
721
  type SnapshotSecretKey = string | Uint8Array;
541
722
  interface SnapshotTokenPayload {
542
723
  readonly [key: string]: unknown;
@@ -560,4 +741,4 @@ type SnapshotTokenVerification<T extends SnapshotTokenPayload = SnapshotTokenPay
560
741
  declare function createSignedSnapshotToken<T extends SnapshotTokenPayload>(payload: T, secretKey: SnapshotSecretKey): Promise<string>;
561
742
  declare function verifySnapshotToken<T extends SnapshotTokenPayload = SnapshotTokenPayload>(token: string, secretKey: SnapshotSecretKey, now?: number): Promise<SnapshotTokenVerification<T>>;
562
743
 
563
- export { CURRENT_RALLY_CONFIG_VERSION, type CheckInContext, type CheckInErrorCode, type CheckInInput, type CheckInResult$1 as CheckInResult, type ClaimTicketOptions, type Clock, type CompositeConditionFailure, type ConditionMatch, type ConditionMismatch, type ConsumeResult, type ConsumeRewardParams, DEFAULT_SHEET_THEME, type DetectorError, type DetectorErrorCode, type DetectorKind, type DetectorResult, type FontFamily, type GeoDetectorOptions, type GeoVerificationContext, InMemoryStorage, IndexedDBAdapter, type IndexedDBAdapterOptions, LocalStorageAdapter, type LocalStorageAdapterOptions, type LocalStorageFailureMode, type LocaleDictionary, type LocalizedString, type LocalizedText, type NfcDetectorOptions, type PasscodeCondition, type ProcessStampValue, type PublicRallyConfig, type PublicRewardItem, type QrDetectorOptions, type RallyConfig, type RallyConfigValidationResult, type RallySnapshot, type RedemptionMethod, type Result, type RewardConsumeError, type RewardItem, 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 StampCondition, type StampDefinition, type StampError, StampRallyClient, type StampRallyClientEvent, type StampRallyEvent, type StampRallyEventListener, type StampRallyListener, type StampRallyProgress, type StampRallyState, type StampRecord, type StampStorage, StorageAdapterError, type StorageAdapterErrorCode, type StorageLike, type StorageOperation, type StorageWarningHandler, type SupportedLocale, THEME_PRESETS, type ThemePreset, type ThemePresetId, type TokenVerificationContext, type ValidationError, type VerificationContext, calculateDistanceMeters, calculateProgress, consumeReward, createClaimTicketNumber, createSecureToken, createSignedSnapshotToken, createUniqueClaimTicketNumber, evaluateCheckIn, evaluateCondition, evaluateConditionDetailed, exportProgressToken, getCurrentGeoContext, importProgressToken, isGeolocationSupported, isNfcSupported, isQrSupported, isRewardState, isStampRallyState, issueClaimTicketNumber, migrateRallyConfig, normalizePasscode, processStamp, readNfcContext, readQrContext, reconcileRewardStates, resolveLocalizedText, stripSensitiveConfig, toLocalizedString, validateRallyConfig, verifyPasscode, verifySecureToken, verifySnapshotToken };
744
+ export { type AuditLoggerAdapter, type AuthContextAdapter, CURRENT_RALLY_CONFIG_VERSION, type CheckInAttemptAuditEntry, type CheckInContext, type CheckInErrorCode, type CheckInInput, type CheckInResult$1 as CheckInResult, type ClaimTicketOptions, type Clock, type CompositeConditionFailure, type ConditionMatch, type ConditionMismatch, type ConditionVerifierPlugin, type ConsumeResult, type ConsumeRewardParams, DEFAULT_SHEET_THEME, type DetectorError, type DetectorErrorCode, type DetectorKind, type DetectorResult, type EventPublisherAdapter, type ExternalReference, type FontFamily, type GeoDetectorOptions, type GeoVerificationContext, type LocalizedText as HeadlessLocalizedText, type IdGeneratorAdapter, InMemoryStorage, IndexedDBAdapter, type IndexedDBAdapterOptions, LocalStorageAdapter, type LocalStorageAdapterOptions, type LocalStorageFailureMode, type LocaleDictionary, type LocalizedString, type LocalizedText$1 as LocalizedText, type Metadata, type NfcDetectorOptions, type PasscodeCondition, type ProcessStampValue, type PublicRallyConfig, 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 UserId, type ValidationError, type ValidationInput, type ValidationOutcome, type VerificationContext, type VerificationCoordinates, type VerificationRequirement, calculateDistanceMeters, calculateProgress, consumeReward, createClaimTicketNumber, createSecureToken, createSignedSnapshotToken, createUniqueClaimTicketNumber, evaluateCheckIn, evaluateCondition, evaluateConditionDetailed, exportProgressToken, getCurrentGeoContext, importProgressToken, isGeolocationSupported, isNfcSupported, isQrSupported, isRewardState, isStampRallyState, issueClaimTicketNumber, migrateRallyConfig, normalizePasscode, processStamp, readNfcContext, readQrContext, reconcileRewardStates, resolveLocalizedText, stripSensitiveConfig, toLocalizedString, validateRallyConfig, verifyPasscode, verifySecureToken, verifySnapshotToken };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stamprally/core",
3
- "version": "0.5.1",
3
+ "version": "0.6.0",
4
4
  "description": "A dependency-free stamp rally domain engine and storage-agnostic client.",
5
5
  "license": "MIT",
6
6
  "repository": {