@stamprally/core 0.6.0 → 0.7.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.cjs +233 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +133 -4
- package/dist/index.d.ts +133 -4
- package/dist/index.js +228 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -110,6 +110,116 @@ type Result<T, E> = {
|
|
|
110
110
|
readonly error: E;
|
|
111
111
|
};
|
|
112
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 {
|
|
117
|
+
readonly type: string;
|
|
118
|
+
readonly id: string;
|
|
119
|
+
readonly url?: string;
|
|
120
|
+
readonly metadata?: Readonly<Record<string, unknown>>;
|
|
121
|
+
}
|
|
122
|
+
/** Server-only verification material. Never send this shape to a browser. */
|
|
123
|
+
type VerificationCondition = {
|
|
124
|
+
readonly type: "qr";
|
|
125
|
+
readonly secretToken: string;
|
|
126
|
+
readonly qrEntryUrl?: string;
|
|
127
|
+
} | {
|
|
128
|
+
readonly type: "passcode";
|
|
129
|
+
readonly code: string;
|
|
130
|
+
readonly caseSensitive?: boolean;
|
|
131
|
+
} | {
|
|
132
|
+
readonly type: "gps";
|
|
133
|
+
readonly latitude: number;
|
|
134
|
+
readonly longitude: number;
|
|
135
|
+
readonly radiusMeters: number;
|
|
136
|
+
} | {
|
|
137
|
+
readonly type: "custom";
|
|
138
|
+
readonly validatorName: string;
|
|
139
|
+
readonly secretParams?: Readonly<Record<string, unknown>>;
|
|
140
|
+
};
|
|
141
|
+
/** Safe condition metadata intended for a participant client. */
|
|
142
|
+
type PublicCheckInCondition = {
|
|
143
|
+
readonly type: "qr";
|
|
144
|
+
readonly qrEntryUrl: string;
|
|
145
|
+
} | {
|
|
146
|
+
readonly type: "passcode";
|
|
147
|
+
} | {
|
|
148
|
+
readonly type: "gps";
|
|
149
|
+
readonly latitude: number;
|
|
150
|
+
readonly longitude: number;
|
|
151
|
+
readonly radiusMeters: number;
|
|
152
|
+
} | {
|
|
153
|
+
readonly type: "custom";
|
|
154
|
+
readonly validatorName: string;
|
|
155
|
+
};
|
|
156
|
+
interface UniversalSpotItem<TLocale extends string = string, TMeta extends Record<string, unknown> = Record<string, unknown>> {
|
|
157
|
+
readonly id: string;
|
|
158
|
+
readonly orderIndex: number;
|
|
159
|
+
readonly name: UniversalLocalizedText<TLocale>;
|
|
160
|
+
readonly description?: UniversalLocalizedText<TLocale>;
|
|
161
|
+
readonly hint?: UniversalLocalizedText<TLocale>;
|
|
162
|
+
readonly imageUrl?: string;
|
|
163
|
+
readonly iconUrl?: string;
|
|
164
|
+
readonly redirectUrlAfterClaim?: string;
|
|
165
|
+
readonly externalReferences?: ReadonlyArray<ExternalReference$1>;
|
|
166
|
+
readonly metadata?: TMeta;
|
|
167
|
+
readonly conditions: ReadonlyArray<VerificationCondition>;
|
|
168
|
+
readonly prerequisites?: ReadonlyArray<string>;
|
|
169
|
+
}
|
|
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;
|
|
182
|
+
};
|
|
183
|
+
type PublicReward<TLocale extends string = string> = Omit<AdminReward<TLocale>, "staffPasscode" | "digitalContentUrl">;
|
|
184
|
+
type RewardUnlockCondition$1 = {
|
|
185
|
+
readonly type: "stamp_count";
|
|
186
|
+
readonly count: number;
|
|
187
|
+
} | {
|
|
188
|
+
readonly type: "stamps";
|
|
189
|
+
readonly stampIds: ReadonlyArray<string>;
|
|
190
|
+
} | {
|
|
191
|
+
readonly type: "all" | "any";
|
|
192
|
+
readonly conditions: ReadonlyArray<RewardUnlockCondition$1>;
|
|
193
|
+
};
|
|
194
|
+
interface AdminRallyConfig<TLocale extends string = string, TMeta extends Record<string, unknown> = Record<string, unknown>> {
|
|
195
|
+
readonly id: string;
|
|
196
|
+
readonly version: string;
|
|
197
|
+
readonly title: UniversalLocalizedText<TLocale>;
|
|
198
|
+
readonly description?: UniversalLocalizedText<TLocale>;
|
|
199
|
+
readonly theme?: SheetTheme;
|
|
200
|
+
readonly spots: ReadonlyArray<UniversalSpotItem<TLocale, TMeta>>;
|
|
201
|
+
readonly rewards: ReadonlyArray<AdminReward<TLocale>>;
|
|
202
|
+
readonly serverEndpoint?: string;
|
|
203
|
+
readonly metadata?: TMeta;
|
|
204
|
+
}
|
|
205
|
+
interface PublicRallyConfig<TLocale extends string = string, TMeta extends Record<string, unknown> = Record<string, unknown>> {
|
|
206
|
+
readonly id: string;
|
|
207
|
+
readonly version: string;
|
|
208
|
+
readonly title: UniversalLocalizedText<TLocale>;
|
|
209
|
+
readonly description?: UniversalLocalizedText<TLocale>;
|
|
210
|
+
readonly theme?: SheetTheme;
|
|
211
|
+
readonly spots: ReadonlyArray<Omit<UniversalSpotItem<TLocale, TMeta>, "conditions"> & {
|
|
212
|
+
readonly conditions: ReadonlyArray<PublicCheckInCondition>;
|
|
213
|
+
}>;
|
|
214
|
+
readonly rewards: ReadonlyArray<PublicReward<TLocale>>;
|
|
215
|
+
readonly serverEndpoint?: string;
|
|
216
|
+
readonly metadata?: TMeta;
|
|
217
|
+
}
|
|
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
|
+
|
|
113
223
|
type SupportedLocale = "ja" | "en";
|
|
114
224
|
type LocalizedString<TLocale extends string = SupportedLocale> = Record<TLocale, string>;
|
|
115
225
|
type LocalizedText$1<TLocale extends string = string> = string | Partial<Record<TLocale, string>>;
|
|
@@ -152,6 +262,10 @@ interface SpotItem<TLocale extends string = SupportedLocale, TMeta extends Recor
|
|
|
152
262
|
readonly externalUrl?: string;
|
|
153
263
|
readonly redirectUrlAfterClaim?: string;
|
|
154
264
|
readonly metadata?: TMeta;
|
|
265
|
+
/** Canonical universal-model conditions. Legacy `condition` remains for engine internals. */
|
|
266
|
+
readonly conditions?: ReadonlyArray<VerificationCondition>;
|
|
267
|
+
readonly externalReferences?: ReadonlyArray<ExternalReference$1>;
|
|
268
|
+
readonly prerequisites?: ReadonlyArray<string>;
|
|
155
269
|
readonly dependsOn?: ReadonlyArray<string>;
|
|
156
270
|
readonly requiresStampIds?: ReadonlyArray<string>;
|
|
157
271
|
}
|
|
@@ -231,13 +345,28 @@ declare function toLocalizedString<TLocale extends string>(text: LocalizedText$1
|
|
|
231
345
|
declare function migrateRallyConfig<TLocale extends string = SupportedLocale>(raw: unknown): RallyConfig<TLocale>;
|
|
232
346
|
|
|
233
347
|
type PublicRewardItem<TLocale extends string = string> = Omit<RewardItem<TLocale>, "staffPasscode">;
|
|
234
|
-
type
|
|
348
|
+
type LegacyPublicRallyConfig<TLocale extends string = string, TMeta extends Record<string, unknown> = Record<string, unknown>> = Omit<RallyConfig<TLocale, TMeta>, "rewards"> & {
|
|
235
349
|
readonly rewards?: ReadonlyArray<PublicRewardItem<TLocale>>;
|
|
236
350
|
};
|
|
237
|
-
declare function stripSensitiveConfig<TLocale extends string, TMeta extends Record<string, unknown>>(config:
|
|
351
|
+
declare function stripSensitiveConfig<TLocale extends string, TMeta extends Record<string, unknown>>(config: AdminRallyConfig<TLocale, TMeta>): PublicRallyConfig<TLocale, TMeta>;
|
|
352
|
+
declare function stripSensitiveConfig<TLocale extends string, TMeta extends Record<string, unknown>>(config: RallyConfig<TLocale, TMeta>): LegacyPublicRallyConfig<TLocale, TMeta>;
|
|
238
353
|
|
|
239
354
|
declare const THEME_PRESETS: ReadonlyArray<ThemePreset>;
|
|
240
355
|
|
|
356
|
+
interface UniversalValidationError {
|
|
357
|
+
readonly path: string;
|
|
358
|
+
readonly code: "INVALID_TYPE" | "REQUIRED" | "EMPTY_STRING" | "DUPLICATE_ID" | "INVALID_COORDINATES" | "INVALID_RADIUS" | "INVALID_VERSION" | "INVALID_REWARD" | "CYCLE_DETECTED" | "SECRET_IN_PUBLIC_CONFIG";
|
|
359
|
+
readonly message: string;
|
|
360
|
+
}
|
|
361
|
+
interface UniversalValidationResult {
|
|
362
|
+
readonly valid: boolean;
|
|
363
|
+
readonly errors: ReadonlyArray<UniversalValidationError>;
|
|
364
|
+
}
|
|
365
|
+
declare function validateAdminRallyConfig(value: unknown): UniversalValidationResult;
|
|
366
|
+
declare function validatePublicRallyConfig(value: unknown): UniversalValidationResult;
|
|
367
|
+
declare function isAdminRallyConfig(value: unknown): value is AdminRallyConfig;
|
|
368
|
+
declare function isPublicRallyConfigShape(value: unknown): value is PublicRallyConfig;
|
|
369
|
+
|
|
241
370
|
declare const CURRENT_RALLY_CONFIG_VERSION = 2;
|
|
242
371
|
interface ValidationError {
|
|
243
372
|
readonly path: string;
|
|
@@ -449,7 +578,7 @@ declare class StampRallyClient {
|
|
|
449
578
|
readonly events: true;
|
|
450
579
|
}): () => void;
|
|
451
580
|
subscribeEvents(listener: StampRallyEventListener): () => void;
|
|
452
|
-
updateConfig(newConfig:
|
|
581
|
+
updateConfig(newConfig: LegacyPublicRallyConfig): Promise<StampRallyState>;
|
|
453
582
|
notifyRewardClaimed(rewardId: string, state?: StampRallyState | null): void;
|
|
454
583
|
notifySyncCompleted(state?: StampRallyState | null): void;
|
|
455
584
|
init(): Promise<StampRallyState>;
|
|
@@ -741,4 +870,4 @@ type SnapshotTokenVerification<T extends SnapshotTokenPayload = SnapshotTokenPay
|
|
|
741
870
|
declare function createSignedSnapshotToken<T extends SnapshotTokenPayload>(payload: T, secretKey: SnapshotSecretKey): Promise<string>;
|
|
742
871
|
declare function verifySnapshotToken<T extends SnapshotTokenPayload = SnapshotTokenPayload>(token: string, secretKey: SnapshotSecretKey, now?: number): Promise<SnapshotTokenVerification<T>>;
|
|
743
872
|
|
|
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 };
|
|
873
|
+
export { type AdminRallyConfig, type AdminReward, 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$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 UniversalLocalizedText, type UniversalSpotItem, type UniversalValidationError, type UniversalValidationResult, type UserId, 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 };
|
package/dist/index.d.ts
CHANGED
|
@@ -110,6 +110,116 @@ type Result<T, E> = {
|
|
|
110
110
|
readonly error: E;
|
|
111
111
|
};
|
|
112
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 {
|
|
117
|
+
readonly type: string;
|
|
118
|
+
readonly id: string;
|
|
119
|
+
readonly url?: string;
|
|
120
|
+
readonly metadata?: Readonly<Record<string, unknown>>;
|
|
121
|
+
}
|
|
122
|
+
/** Server-only verification material. Never send this shape to a browser. */
|
|
123
|
+
type VerificationCondition = {
|
|
124
|
+
readonly type: "qr";
|
|
125
|
+
readonly secretToken: string;
|
|
126
|
+
readonly qrEntryUrl?: string;
|
|
127
|
+
} | {
|
|
128
|
+
readonly type: "passcode";
|
|
129
|
+
readonly code: string;
|
|
130
|
+
readonly caseSensitive?: boolean;
|
|
131
|
+
} | {
|
|
132
|
+
readonly type: "gps";
|
|
133
|
+
readonly latitude: number;
|
|
134
|
+
readonly longitude: number;
|
|
135
|
+
readonly radiusMeters: number;
|
|
136
|
+
} | {
|
|
137
|
+
readonly type: "custom";
|
|
138
|
+
readonly validatorName: string;
|
|
139
|
+
readonly secretParams?: Readonly<Record<string, unknown>>;
|
|
140
|
+
};
|
|
141
|
+
/** Safe condition metadata intended for a participant client. */
|
|
142
|
+
type PublicCheckInCondition = {
|
|
143
|
+
readonly type: "qr";
|
|
144
|
+
readonly qrEntryUrl: string;
|
|
145
|
+
} | {
|
|
146
|
+
readonly type: "passcode";
|
|
147
|
+
} | {
|
|
148
|
+
readonly type: "gps";
|
|
149
|
+
readonly latitude: number;
|
|
150
|
+
readonly longitude: number;
|
|
151
|
+
readonly radiusMeters: number;
|
|
152
|
+
} | {
|
|
153
|
+
readonly type: "custom";
|
|
154
|
+
readonly validatorName: string;
|
|
155
|
+
};
|
|
156
|
+
interface UniversalSpotItem<TLocale extends string = string, TMeta extends Record<string, unknown> = Record<string, unknown>> {
|
|
157
|
+
readonly id: string;
|
|
158
|
+
readonly orderIndex: number;
|
|
159
|
+
readonly name: UniversalLocalizedText<TLocale>;
|
|
160
|
+
readonly description?: UniversalLocalizedText<TLocale>;
|
|
161
|
+
readonly hint?: UniversalLocalizedText<TLocale>;
|
|
162
|
+
readonly imageUrl?: string;
|
|
163
|
+
readonly iconUrl?: string;
|
|
164
|
+
readonly redirectUrlAfterClaim?: string;
|
|
165
|
+
readonly externalReferences?: ReadonlyArray<ExternalReference$1>;
|
|
166
|
+
readonly metadata?: TMeta;
|
|
167
|
+
readonly conditions: ReadonlyArray<VerificationCondition>;
|
|
168
|
+
readonly prerequisites?: ReadonlyArray<string>;
|
|
169
|
+
}
|
|
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;
|
|
182
|
+
};
|
|
183
|
+
type PublicReward<TLocale extends string = string> = Omit<AdminReward<TLocale>, "staffPasscode" | "digitalContentUrl">;
|
|
184
|
+
type RewardUnlockCondition$1 = {
|
|
185
|
+
readonly type: "stamp_count";
|
|
186
|
+
readonly count: number;
|
|
187
|
+
} | {
|
|
188
|
+
readonly type: "stamps";
|
|
189
|
+
readonly stampIds: ReadonlyArray<string>;
|
|
190
|
+
} | {
|
|
191
|
+
readonly type: "all" | "any";
|
|
192
|
+
readonly conditions: ReadonlyArray<RewardUnlockCondition$1>;
|
|
193
|
+
};
|
|
194
|
+
interface AdminRallyConfig<TLocale extends string = string, TMeta extends Record<string, unknown> = Record<string, unknown>> {
|
|
195
|
+
readonly id: string;
|
|
196
|
+
readonly version: string;
|
|
197
|
+
readonly title: UniversalLocalizedText<TLocale>;
|
|
198
|
+
readonly description?: UniversalLocalizedText<TLocale>;
|
|
199
|
+
readonly theme?: SheetTheme;
|
|
200
|
+
readonly spots: ReadonlyArray<UniversalSpotItem<TLocale, TMeta>>;
|
|
201
|
+
readonly rewards: ReadonlyArray<AdminReward<TLocale>>;
|
|
202
|
+
readonly serverEndpoint?: string;
|
|
203
|
+
readonly metadata?: TMeta;
|
|
204
|
+
}
|
|
205
|
+
interface PublicRallyConfig<TLocale extends string = string, TMeta extends Record<string, unknown> = Record<string, unknown>> {
|
|
206
|
+
readonly id: string;
|
|
207
|
+
readonly version: string;
|
|
208
|
+
readonly title: UniversalLocalizedText<TLocale>;
|
|
209
|
+
readonly description?: UniversalLocalizedText<TLocale>;
|
|
210
|
+
readonly theme?: SheetTheme;
|
|
211
|
+
readonly spots: ReadonlyArray<Omit<UniversalSpotItem<TLocale, TMeta>, "conditions"> & {
|
|
212
|
+
readonly conditions: ReadonlyArray<PublicCheckInCondition>;
|
|
213
|
+
}>;
|
|
214
|
+
readonly rewards: ReadonlyArray<PublicReward<TLocale>>;
|
|
215
|
+
readonly serverEndpoint?: string;
|
|
216
|
+
readonly metadata?: TMeta;
|
|
217
|
+
}
|
|
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
|
+
|
|
113
223
|
type SupportedLocale = "ja" | "en";
|
|
114
224
|
type LocalizedString<TLocale extends string = SupportedLocale> = Record<TLocale, string>;
|
|
115
225
|
type LocalizedText$1<TLocale extends string = string> = string | Partial<Record<TLocale, string>>;
|
|
@@ -152,6 +262,10 @@ interface SpotItem<TLocale extends string = SupportedLocale, TMeta extends Recor
|
|
|
152
262
|
readonly externalUrl?: string;
|
|
153
263
|
readonly redirectUrlAfterClaim?: string;
|
|
154
264
|
readonly metadata?: TMeta;
|
|
265
|
+
/** Canonical universal-model conditions. Legacy `condition` remains for engine internals. */
|
|
266
|
+
readonly conditions?: ReadonlyArray<VerificationCondition>;
|
|
267
|
+
readonly externalReferences?: ReadonlyArray<ExternalReference$1>;
|
|
268
|
+
readonly prerequisites?: ReadonlyArray<string>;
|
|
155
269
|
readonly dependsOn?: ReadonlyArray<string>;
|
|
156
270
|
readonly requiresStampIds?: ReadonlyArray<string>;
|
|
157
271
|
}
|
|
@@ -231,13 +345,28 @@ declare function toLocalizedString<TLocale extends string>(text: LocalizedText$1
|
|
|
231
345
|
declare function migrateRallyConfig<TLocale extends string = SupportedLocale>(raw: unknown): RallyConfig<TLocale>;
|
|
232
346
|
|
|
233
347
|
type PublicRewardItem<TLocale extends string = string> = Omit<RewardItem<TLocale>, "staffPasscode">;
|
|
234
|
-
type
|
|
348
|
+
type LegacyPublicRallyConfig<TLocale extends string = string, TMeta extends Record<string, unknown> = Record<string, unknown>> = Omit<RallyConfig<TLocale, TMeta>, "rewards"> & {
|
|
235
349
|
readonly rewards?: ReadonlyArray<PublicRewardItem<TLocale>>;
|
|
236
350
|
};
|
|
237
|
-
declare function stripSensitiveConfig<TLocale extends string, TMeta extends Record<string, unknown>>(config:
|
|
351
|
+
declare function stripSensitiveConfig<TLocale extends string, TMeta extends Record<string, unknown>>(config: AdminRallyConfig<TLocale, TMeta>): PublicRallyConfig<TLocale, TMeta>;
|
|
352
|
+
declare function stripSensitiveConfig<TLocale extends string, TMeta extends Record<string, unknown>>(config: RallyConfig<TLocale, TMeta>): LegacyPublicRallyConfig<TLocale, TMeta>;
|
|
238
353
|
|
|
239
354
|
declare const THEME_PRESETS: ReadonlyArray<ThemePreset>;
|
|
240
355
|
|
|
356
|
+
interface UniversalValidationError {
|
|
357
|
+
readonly path: string;
|
|
358
|
+
readonly code: "INVALID_TYPE" | "REQUIRED" | "EMPTY_STRING" | "DUPLICATE_ID" | "INVALID_COORDINATES" | "INVALID_RADIUS" | "INVALID_VERSION" | "INVALID_REWARD" | "CYCLE_DETECTED" | "SECRET_IN_PUBLIC_CONFIG";
|
|
359
|
+
readonly message: string;
|
|
360
|
+
}
|
|
361
|
+
interface UniversalValidationResult {
|
|
362
|
+
readonly valid: boolean;
|
|
363
|
+
readonly errors: ReadonlyArray<UniversalValidationError>;
|
|
364
|
+
}
|
|
365
|
+
declare function validateAdminRallyConfig(value: unknown): UniversalValidationResult;
|
|
366
|
+
declare function validatePublicRallyConfig(value: unknown): UniversalValidationResult;
|
|
367
|
+
declare function isAdminRallyConfig(value: unknown): value is AdminRallyConfig;
|
|
368
|
+
declare function isPublicRallyConfigShape(value: unknown): value is PublicRallyConfig;
|
|
369
|
+
|
|
241
370
|
declare const CURRENT_RALLY_CONFIG_VERSION = 2;
|
|
242
371
|
interface ValidationError {
|
|
243
372
|
readonly path: string;
|
|
@@ -449,7 +578,7 @@ declare class StampRallyClient {
|
|
|
449
578
|
readonly events: true;
|
|
450
579
|
}): () => void;
|
|
451
580
|
subscribeEvents(listener: StampRallyEventListener): () => void;
|
|
452
|
-
updateConfig(newConfig:
|
|
581
|
+
updateConfig(newConfig: LegacyPublicRallyConfig): Promise<StampRallyState>;
|
|
453
582
|
notifyRewardClaimed(rewardId: string, state?: StampRallyState | null): void;
|
|
454
583
|
notifySyncCompleted(state?: StampRallyState | null): void;
|
|
455
584
|
init(): Promise<StampRallyState>;
|
|
@@ -741,4 +870,4 @@ type SnapshotTokenVerification<T extends SnapshotTokenPayload = SnapshotTokenPay
|
|
|
741
870
|
declare function createSignedSnapshotToken<T extends SnapshotTokenPayload>(payload: T, secretKey: SnapshotSecretKey): Promise<string>;
|
|
742
871
|
declare function verifySnapshotToken<T extends SnapshotTokenPayload = SnapshotTokenPayload>(token: string, secretKey: SnapshotSecretKey, now?: number): Promise<SnapshotTokenVerification<T>>;
|
|
743
872
|
|
|
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 };
|
|
873
|
+
export { type AdminRallyConfig, type AdminReward, 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$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 UniversalLocalizedText, type UniversalSpotItem, type UniversalValidationError, type UniversalValidationResult, type UserId, 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 };
|
package/dist/index.js
CHANGED
|
@@ -1878,8 +1878,61 @@ var DEFAULT_SHEET_THEME = {
|
|
|
1878
1878
|
fontFamily: "serif"
|
|
1879
1879
|
};
|
|
1880
1880
|
|
|
1881
|
+
// src/domain/universalModel.ts
|
|
1882
|
+
function toPublicCondition(condition2) {
|
|
1883
|
+
switch (condition2.type) {
|
|
1884
|
+
case "qr":
|
|
1885
|
+
return { type: "qr", qrEntryUrl: condition2.qrEntryUrl ?? "" };
|
|
1886
|
+
case "passcode":
|
|
1887
|
+
return { type: "passcode" };
|
|
1888
|
+
case "gps":
|
|
1889
|
+
return {
|
|
1890
|
+
type: "gps",
|
|
1891
|
+
latitude: condition2.latitude,
|
|
1892
|
+
longitude: condition2.longitude,
|
|
1893
|
+
radiusMeters: condition2.radiusMeters
|
|
1894
|
+
};
|
|
1895
|
+
case "custom":
|
|
1896
|
+
return { type: "custom", validatorName: condition2.validatorName };
|
|
1897
|
+
}
|
|
1898
|
+
}
|
|
1899
|
+
function toPublicRallyConfig(config) {
|
|
1900
|
+
return {
|
|
1901
|
+
...config,
|
|
1902
|
+
spots: config.spots.map((spot) => ({
|
|
1903
|
+
...spot,
|
|
1904
|
+
conditions: spot.conditions.map(toPublicCondition)
|
|
1905
|
+
})),
|
|
1906
|
+
rewards: config.rewards.map(
|
|
1907
|
+
({ staffPasscode: _staffPasscode, digitalContentUrl: _content, ...reward }) => reward
|
|
1908
|
+
)
|
|
1909
|
+
};
|
|
1910
|
+
}
|
|
1911
|
+
function isPublicRallyConfig(value) {
|
|
1912
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
|
|
1913
|
+
const candidate = value;
|
|
1914
|
+
if (candidate.secretKey !== void 0 || candidate.verificationSecrets !== void 0)
|
|
1915
|
+
return false;
|
|
1916
|
+
return Array.isArray(candidate.spots) && Array.isArray(candidate.rewards) && candidate.spots.every((spot) => {
|
|
1917
|
+
if (typeof spot !== "object" || spot === null || Array.isArray(spot)) return false;
|
|
1918
|
+
const conditions = spot.conditions;
|
|
1919
|
+
return Array.isArray(conditions) && conditions.every((condition2) => {
|
|
1920
|
+
if (typeof condition2 !== "object" || condition2 === null) return false;
|
|
1921
|
+
const type = condition2.type;
|
|
1922
|
+
return type === "qr" || type === "passcode" || type === "gps" || type === "custom";
|
|
1923
|
+
});
|
|
1924
|
+
}) && candidate.rewards.every((reward) => {
|
|
1925
|
+
if (typeof reward !== "object" || reward === null || Array.isArray(reward)) return false;
|
|
1926
|
+
const item = reward;
|
|
1927
|
+
return item.staffPasscode === void 0 && item.digitalContentUrl === void 0;
|
|
1928
|
+
});
|
|
1929
|
+
}
|
|
1930
|
+
|
|
1881
1931
|
// src/domain/publicConfig.ts
|
|
1882
1932
|
function stripSensitiveConfig(config) {
|
|
1933
|
+
if ("spots" in config && !("stamps" in config)) {
|
|
1934
|
+
return toPublicRallyConfig(config);
|
|
1935
|
+
}
|
|
1883
1936
|
const rewards = config.rewards?.map(({ staffPasscode: _staffPasscode, ...reward }) => reward);
|
|
1884
1937
|
return {
|
|
1885
1938
|
...config,
|
|
@@ -1986,6 +2039,180 @@ var THEME_PRESETS = [
|
|
|
1986
2039
|
}
|
|
1987
2040
|
];
|
|
1988
2041
|
|
|
2042
|
+
// src/domain/universalValidation.ts
|
|
2043
|
+
function isObject3(value) {
|
|
2044
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2045
|
+
}
|
|
2046
|
+
function add2(errors, path, code, message) {
|
|
2047
|
+
errors.push({ path, code, message });
|
|
2048
|
+
}
|
|
2049
|
+
function hasText2(value) {
|
|
2050
|
+
if (typeof value === "string") return value.trim() !== "";
|
|
2051
|
+
return isObject3(value) && Object.values(value).some((item) => typeof item === "string" && item.trim() !== "");
|
|
2052
|
+
}
|
|
2053
|
+
function validateCondition2(condition2, path, errors) {
|
|
2054
|
+
if (!isObject3(condition2) || typeof condition2.type !== "string") {
|
|
2055
|
+
add2(errors, path, "INVALID_TYPE", "Condition must have a type.");
|
|
2056
|
+
return;
|
|
2057
|
+
}
|
|
2058
|
+
switch (condition2.type) {
|
|
2059
|
+
case "qr":
|
|
2060
|
+
if (typeof condition2.secretToken !== "string" || condition2.secretToken.trim() === "")
|
|
2061
|
+
add2(errors, `${path}.secretToken`, "REQUIRED", "QR secretToken is required.");
|
|
2062
|
+
if (condition2.qrEntryUrl !== void 0 && typeof condition2.qrEntryUrl !== "string")
|
|
2063
|
+
add2(errors, `${path}.qrEntryUrl`, "INVALID_TYPE", "QR entry URL must be a string.");
|
|
2064
|
+
return;
|
|
2065
|
+
case "passcode":
|
|
2066
|
+
if (typeof condition2.code !== "string" || condition2.code.trim() === "")
|
|
2067
|
+
add2(errors, `${path}.code`, "REQUIRED", "Passcode is required.");
|
|
2068
|
+
return;
|
|
2069
|
+
case "gps":
|
|
2070
|
+
if (typeof condition2.latitude !== "number" || !Number.isFinite(condition2.latitude) || condition2.latitude < -90 || condition2.latitude > 90 || typeof condition2.longitude !== "number" || !Number.isFinite(condition2.longitude) || condition2.longitude < -180 || condition2.longitude > 180)
|
|
2071
|
+
add2(errors, path, "INVALID_COORDINATES", "GPS coordinates are invalid.");
|
|
2072
|
+
if (typeof condition2.radiusMeters !== "number" || !Number.isFinite(condition2.radiusMeters) || condition2.radiusMeters <= 0)
|
|
2073
|
+
add2(errors, `${path}.radiusMeters`, "INVALID_RADIUS", "GPS radius must be positive.");
|
|
2074
|
+
return;
|
|
2075
|
+
case "custom":
|
|
2076
|
+
if (typeof condition2.validatorName !== "string" || condition2.validatorName.trim() === "")
|
|
2077
|
+
add2(errors, `${path}.validatorName`, "REQUIRED", "Custom validatorName is required.");
|
|
2078
|
+
return;
|
|
2079
|
+
default:
|
|
2080
|
+
add2(errors, `${path}.type`, "INVALID_TYPE", "Unsupported verification condition.");
|
|
2081
|
+
}
|
|
2082
|
+
}
|
|
2083
|
+
function validateDag2(spots, errors) {
|
|
2084
|
+
const graph = /* @__PURE__ */ new Map();
|
|
2085
|
+
for (const spot of spots) {
|
|
2086
|
+
if (!isObject3(spot) || typeof spot.id !== "string") continue;
|
|
2087
|
+
const prerequisites = Array.isArray(spot.prerequisites) ? spot.prerequisites.filter((item) => typeof item === "string") : [];
|
|
2088
|
+
graph.set(spot.id, prerequisites);
|
|
2089
|
+
}
|
|
2090
|
+
const visiting = /* @__PURE__ */ new Set();
|
|
2091
|
+
const visited = /* @__PURE__ */ new Set();
|
|
2092
|
+
const visit = (id) => {
|
|
2093
|
+
if (visiting.has(id)) {
|
|
2094
|
+
add2(
|
|
2095
|
+
errors,
|
|
2096
|
+
`spots.${id}.prerequisites`,
|
|
2097
|
+
"CYCLE_DETECTED",
|
|
2098
|
+
`Dependency cycle detected at '${id}'.`
|
|
2099
|
+
);
|
|
2100
|
+
return;
|
|
2101
|
+
}
|
|
2102
|
+
if (visited.has(id)) return;
|
|
2103
|
+
visiting.add(id);
|
|
2104
|
+
for (const prerequisite of graph.get(id) ?? [])
|
|
2105
|
+
if (graph.has(prerequisite)) visit(prerequisite);
|
|
2106
|
+
visiting.delete(id);
|
|
2107
|
+
visited.add(id);
|
|
2108
|
+
};
|
|
2109
|
+
for (const id of graph.keys()) visit(id);
|
|
2110
|
+
}
|
|
2111
|
+
function validateAdminRallyConfig(value) {
|
|
2112
|
+
const errors = [];
|
|
2113
|
+
if (!isObject3(value))
|
|
2114
|
+
return {
|
|
2115
|
+
valid: false,
|
|
2116
|
+
errors: [{ path: "", code: "INVALID_TYPE", message: "Admin config must be an object." }]
|
|
2117
|
+
};
|
|
2118
|
+
if (typeof value.id !== "string" || value.id.trim() === "")
|
|
2119
|
+
add2(errors, "id", "REQUIRED", "Rally ID is required.");
|
|
2120
|
+
if (typeof value.version !== "string" || value.version.trim() === "")
|
|
2121
|
+
add2(errors, "version", "INVALID_VERSION", "Version is required.");
|
|
2122
|
+
if (!Array.isArray(value.spots)) {
|
|
2123
|
+
add2(errors, "spots", "INVALID_TYPE", "spots must be an array.");
|
|
2124
|
+
} else {
|
|
2125
|
+
const ids = [];
|
|
2126
|
+
value.spots.forEach((spot, index) => {
|
|
2127
|
+
const path = `spots[${index}]`;
|
|
2128
|
+
if (!isObject3(spot)) {
|
|
2129
|
+
add2(errors, path, "INVALID_TYPE", "Spot must be an object.");
|
|
2130
|
+
return;
|
|
2131
|
+
}
|
|
2132
|
+
if (typeof spot.id !== "string" || spot.id.trim() === "")
|
|
2133
|
+
add2(errors, `${path}.id`, "REQUIRED", "Spot ID is required.");
|
|
2134
|
+
else if (ids.includes(spot.id))
|
|
2135
|
+
add2(errors, `${path}.id`, "DUPLICATE_ID", `Duplicate spot ID '${spot.id}'.`);
|
|
2136
|
+
else ids.push(spot.id);
|
|
2137
|
+
if (!hasText2(spot.name)) add2(errors, `${path}.name`, "REQUIRED", "Spot name is required.");
|
|
2138
|
+
if (typeof spot.orderIndex !== "number" || !Number.isInteger(spot.orderIndex))
|
|
2139
|
+
add2(errors, `${path}.orderIndex`, "INVALID_TYPE", "orderIndex must be an integer.");
|
|
2140
|
+
if (!Array.isArray(spot.conditions) || spot.conditions.length === 0)
|
|
2141
|
+
add2(errors, `${path}.conditions`, "REQUIRED", "At least one condition is required.");
|
|
2142
|
+
else {
|
|
2143
|
+
spot.conditions.forEach((condition2, conditionIndex) => {
|
|
2144
|
+
validateCondition2(condition2, `${path}.conditions[${conditionIndex}]`, errors);
|
|
2145
|
+
});
|
|
2146
|
+
}
|
|
2147
|
+
});
|
|
2148
|
+
validateDag2(value.spots, errors);
|
|
2149
|
+
}
|
|
2150
|
+
if (!Array.isArray(value.rewards))
|
|
2151
|
+
add2(errors, "rewards", "INVALID_TYPE", "rewards must be an array.");
|
|
2152
|
+
else {
|
|
2153
|
+
const ids = [];
|
|
2154
|
+
value.rewards.forEach((reward, index) => {
|
|
2155
|
+
const path = `rewards[${index}]`;
|
|
2156
|
+
if (!isObject3(reward)) {
|
|
2157
|
+
add2(errors, path, "INVALID_TYPE", "Reward must be an object.");
|
|
2158
|
+
return;
|
|
2159
|
+
}
|
|
2160
|
+
if (typeof reward.id !== "string" || reward.id.trim() === "")
|
|
2161
|
+
add2(errors, `${path}.id`, "REQUIRED", "Reward ID is required.");
|
|
2162
|
+
else if (ids.includes(reward.id))
|
|
2163
|
+
add2(errors, `${path}.id`, "DUPLICATE_ID", `Duplicate reward ID '${reward.id}'.`);
|
|
2164
|
+
else ids.push(reward.id);
|
|
2165
|
+
if (!hasText2(reward.title))
|
|
2166
|
+
add2(errors, `${path}.title`, "REQUIRED", "Reward title is required.");
|
|
2167
|
+
if (typeof reward.requiredStampCount !== "number" || !Number.isInteger(reward.requiredStampCount) || reward.requiredStampCount < 0)
|
|
2168
|
+
add2(
|
|
2169
|
+
errors,
|
|
2170
|
+
`${path}.requiredStampCount`,
|
|
2171
|
+
"INVALID_REWARD",
|
|
2172
|
+
"requiredStampCount must be a non-negative integer."
|
|
2173
|
+
);
|
|
2174
|
+
});
|
|
2175
|
+
}
|
|
2176
|
+
return { valid: errors.length === 0, errors };
|
|
2177
|
+
}
|
|
2178
|
+
function validatePublicRallyConfig(value) {
|
|
2179
|
+
const errors = [];
|
|
2180
|
+
if (!isObject3(value))
|
|
2181
|
+
return {
|
|
2182
|
+
valid: false,
|
|
2183
|
+
errors: [{ path: "", code: "INVALID_TYPE", message: "Public config must be an object." }]
|
|
2184
|
+
};
|
|
2185
|
+
if ("secretKey" in value || "verificationSecrets" in value)
|
|
2186
|
+
add2(
|
|
2187
|
+
errors,
|
|
2188
|
+
"",
|
|
2189
|
+
"SECRET_IN_PUBLIC_CONFIG",
|
|
2190
|
+
"Public config must not contain server verification secrets."
|
|
2191
|
+
);
|
|
2192
|
+
if (!Array.isArray(value.spots)) add2(errors, "spots", "INVALID_TYPE", "spots must be an array.");
|
|
2193
|
+
else
|
|
2194
|
+
value.spots.forEach((spot, index) => {
|
|
2195
|
+
if (!isObject3(spot) || !Array.isArray(spot.conditions)) return;
|
|
2196
|
+
spot.conditions.forEach((condition2, conditionIndex) => {
|
|
2197
|
+
if (!isObject3(condition2)) return;
|
|
2198
|
+
if ("secretToken" in condition2 || "code" in condition2 || "secretParams" in condition2)
|
|
2199
|
+
add2(
|
|
2200
|
+
errors,
|
|
2201
|
+
`spots[${index}].conditions[${conditionIndex}]`,
|
|
2202
|
+
"SECRET_IN_PUBLIC_CONFIG",
|
|
2203
|
+
"Public condition contains verification secret material."
|
|
2204
|
+
);
|
|
2205
|
+
});
|
|
2206
|
+
});
|
|
2207
|
+
return { valid: errors.length === 0, errors };
|
|
2208
|
+
}
|
|
2209
|
+
function isAdminRallyConfig(value) {
|
|
2210
|
+
return validateAdminRallyConfig(value).valid;
|
|
2211
|
+
}
|
|
2212
|
+
function isPublicRallyConfigShape(value) {
|
|
2213
|
+
return validatePublicRallyConfig(value).valid;
|
|
2214
|
+
}
|
|
2215
|
+
|
|
1989
2216
|
// src/security/snapshotToken.ts
|
|
1990
2217
|
var encoder2 = new TextEncoder();
|
|
1991
2218
|
function cryptoApi2() {
|
|
@@ -2105,6 +2332,6 @@ async function verifySnapshotToken(token, secretKey, now = Date.now()) {
|
|
|
2105
2332
|
}
|
|
2106
2333
|
}
|
|
2107
2334
|
|
|
2108
|
-
export { CURRENT_RALLY_CONFIG_VERSION, DEFAULT_SHEET_THEME, InMemoryStorage, IndexedDBAdapter, LocalStorageAdapter, StampRallyClient, StorageAdapterError, THEME_PRESETS, 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 };
|
|
2335
|
+
export { CURRENT_RALLY_CONFIG_VERSION, DEFAULT_SHEET_THEME, InMemoryStorage, IndexedDBAdapter, LocalStorageAdapter, StampRallyClient, StorageAdapterError, THEME_PRESETS, 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 };
|
|
2109
2336
|
//# sourceMappingURL=index.js.map
|
|
2110
2337
|
//# sourceMappingURL=index.js.map
|