@usergist/sdk-core 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -0
- package/LICENSE +21 -0
- package/README.md +29 -0
- package/dist/index.cjs +1154 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +250 -0
- package/dist/index.d.ts +250 -0
- package/dist/index.js +1092 -0
- package/dist/index.js.map +1 -0
- package/dist/mobile-H9slSAy8.d.cts +2991 -0
- package/dist/mobile-H9slSAy8.d.ts +2991 -0
- package/dist/mobile.cjs +763 -0
- package/dist/mobile.cjs.map +1 -0
- package/dist/mobile.d.cts +1 -0
- package/dist/mobile.d.ts +1 -0
- package/dist/mobile.js +710 -0
- package/dist/mobile.js.map +1 -0
- package/mobile.js +4 -0
- package/package.json +64 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/types/segment-dsl.ts","../src/types/api.ts","../src/types/survey.ts","../src/types/inapp-message.ts","../src/types/request.ts","../src/types/targeting.ts","../src/types/themes.ts","../src/types/brand.ts","../src/types/integration.ts","../src/constants/push-events.ts","../src/types/push-runtime.ts","../src/evaluate/segment.ts","../src/evaluate/branch.ts","../src/evaluate/periodic.ts"],"names":["cutoff"],"mappings":"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","file":"mobile.js","sourcesContent":["// ==========================================================\n// Segment DSL (shared between server and SDK). The DSL is a\n// JSON structure — not raw SQL — so that:\n// 1. The dashboard UI can safely build/edit rules.\n// 2. The SDK can evaluate a lightweight subset client-side\n// for instant trigger firing (the server re-verifies).\n// 3. The server can compile the full DSL to ClickHouse SQL.\n// ==========================================================\n\nexport type ScalarValue = string | number | boolean\nexport type ScalarList = ReadonlyArray<string | number>\n\nexport type ComparisonOp =\n | 'eq'\n | 'neq'\n | 'in'\n | 'nin'\n | 'gt'\n | 'gte'\n | 'lt'\n | 'lte'\n | 'contains'\n | 'starts_with'\n | 'exists'\n | 'not_exists'\n\nexport interface UserPropertyPredicate {\n readonly kind: 'user_property'\n readonly key: string\n readonly op: ComparisonOp\n readonly value?: ScalarValue | ScalarList\n}\n\nexport type CountOp = 'gte' | 'lte' | 'eq' | 'gt' | 'lt'\n\nexport interface EventCountPredicate {\n readonly kind: 'event_count'\n readonly eventName: string\n readonly op: CountOp\n readonly count: number\n readonly windowDays: number\n readonly propertyFilters?: ReadonlyArray<UserPropertyPredicate>\n}\n\nexport interface EventOccurredPredicate {\n readonly kind: 'event_occurred'\n readonly eventName: string\n readonly ever: boolean // true => \"has ever done X\", false => \"has never done X\"\n readonly windowDays?: number\n}\n\nexport type Predicate =\n | UserPropertyPredicate\n | EventCountPredicate\n | EventOccurredPredicate\n\nexport type Combinator = 'AND' | 'OR'\n\nexport interface PredicateGroup {\n readonly combinator: Combinator\n readonly predicates: ReadonlyArray<Predicate | PredicateGroup>\n}\n\nexport interface SegmentDsl {\n readonly version: 1\n readonly root: PredicateGroup\n}\n\nexport function emptySegmentDsl(): SegmentDsl {\n return { version: 1, root: { combinator: 'AND', predicates: [] } }\n}\n","export interface ApiError {\n readonly code: string\n readonly message: string\n readonly details?: unknown\n}\n\nexport interface ApiMeta {\n readonly total?: number\n readonly page?: number\n readonly limit?: number\n}\n\nexport interface ApiResponse<T> {\n readonly success: boolean\n readonly data?: T\n readonly error?: ApiError\n readonly meta?: ApiMeta\n}\n\nexport function ok<T>(data: T, meta?: ApiMeta): ApiResponse<T> {\n return meta ? { success: true, data, meta } : { success: true, data }\n}\n\nexport function err(\n code: string,\n message: string,\n details?: unknown,\n): ApiResponse<never> {\n return {\n success: false,\n error: details === undefined ? { code, message } : { code, message, details },\n }\n}\n","// ============================================================\n// Survey types — shared between API, dashboard, and SDKs.\n// A survey is a Campaign with type='survey'. The multi-step\n// question graph + branching lives here.\n// ============================================================\n\nimport type { PromptTheme, FrequencyCaps, SerializedSegmentRules } from './prompt.js'\nimport type { PushFrequencyCap, PushSchedule } from './campaign.js'\nimport type { AudienceSpec, TriggerSpec } from './targeting.js'\nimport type { ThemeMode } from './brand.js'\n\nexport type SurveyQuestionType =\n | 'single_choice'\n | 'multi_choice'\n | 'nps'\n | 'rating'\n | 'likert'\n | 'short_text'\n | 'long_text'\n | 'ranking'\n | 'single_date'\n | 'info_screen'\n\nexport type SurveyProgressStyle = 'bar' | 'dots' | 'none'\n\nexport interface SurveyChoiceOption {\n readonly id: string\n readonly label: string\n}\n\nexport interface SurveyTextValidation {\n readonly kind?: 'email' | 'url' | 'number' | 'regex'\n readonly pattern?: string\n readonly minLength?: number\n readonly maxLength?: number\n}\n\nexport interface BaseSurveyQuestion {\n readonly id: string\n readonly title: string\n readonly subtitle?: string\n readonly required?: boolean\n // Optional image rendered above the question title. Uploaded\n // through the dashboard composer; URL points at the public R2\n // bucket.\n readonly imageUrl?: string\n readonly mergeTagContext?: Readonly<Record<string, unknown>>\n}\n\nexport interface SingleChoiceQuestion extends BaseSurveyQuestion {\n readonly type: 'single_choice'\n readonly options: ReadonlyArray<SurveyChoiceOption>\n readonly allowOther?: boolean\n}\n\nexport interface MultiChoiceQuestion extends BaseSurveyQuestion {\n readonly type: 'multi_choice'\n readonly options: ReadonlyArray<SurveyChoiceOption>\n readonly minSelections?: number\n readonly maxSelections?: number\n readonly allowOther?: boolean\n}\n\nexport interface SurveyNpsQuestion extends BaseSurveyQuestion {\n readonly type: 'nps'\n readonly lowLabel?: string\n readonly highLabel?: string\n}\n\nexport interface SurveyRatingQuestion extends BaseSurveyQuestion {\n readonly type: 'rating'\n readonly scale: 5 | 10\n readonly style?: 'star' | 'numeric'\n readonly lowLabel?: string\n readonly highLabel?: string\n}\n\nexport interface LikertQuestion extends BaseSurveyQuestion {\n readonly type: 'likert'\n // 5-point: strongly disagree → strongly agree. Labels overridable.\n readonly labels?: readonly [string, string, string, string, string]\n}\n\nexport interface SurveyShortTextQuestion extends BaseSurveyQuestion {\n readonly type: 'short_text'\n readonly placeholder?: string\n readonly validation?: SurveyTextValidation\n}\n\nexport interface LongTextQuestion extends BaseSurveyQuestion {\n readonly type: 'long_text'\n readonly placeholder?: string\n readonly maxLength?: number\n}\n\nexport interface RankingQuestion extends BaseSurveyQuestion {\n readonly type: 'ranking'\n readonly items: ReadonlyArray<SurveyChoiceOption>\n}\n\nexport interface SingleDateQuestion extends BaseSurveyQuestion {\n readonly type: 'single_date'\n readonly minDate?: string\n readonly maxDate?: string\n}\n\nexport interface InfoScreenQuestion extends BaseSurveyQuestion {\n readonly type: 'info_screen'\n readonly body?: string\n}\n\nexport type SurveyQuestion =\n | SingleChoiceQuestion\n | MultiChoiceQuestion\n | SurveyNpsQuestion\n | SurveyRatingQuestion\n | LikertQuestion\n | SurveyShortTextQuestion\n | LongTextQuestion\n | RankingQuestion\n | SingleDateQuestion\n | InfoScreenQuestion\n\n// ---------- Branching DSL ----------\n\nexport type SurveyBranchOp =\n | 'eq'\n | 'neq'\n | 'lt'\n | 'lte'\n | 'gt'\n | 'gte'\n | 'includes'\n | 'not_includes'\n | 'answered'\n | 'unanswered'\n\nexport type SurveyBranchValue = string | number | boolean | ReadonlyArray<string | number>\n\nexport interface SurveyBranchCondition {\n readonly op: SurveyBranchOp\n readonly value?: SurveyBranchValue\n}\n\nexport interface SurveyBranch {\n readonly fromQuestionId: string\n readonly condition: SurveyBranchCondition\n readonly toQuestionId: string // or '__end__' to jump straight to end screen\n}\n\nexport const SURVEY_END_SENTINEL = '__end__'\n\n// ---------- End screen ----------\n\nexport type SurveyEndCtaKind = 'url' | 'deep_link' | 'close'\n\nexport interface SurveyEndCta {\n readonly kind: SurveyEndCtaKind\n readonly label: string\n readonly target?: string\n}\n\nexport interface SurveyFollowUp {\n readonly headline: string\n readonly body?: string\n readonly cta?: SurveyEndCta\n}\n\nexport interface SurveyEndScreen {\n readonly headline: string\n readonly body?: string\n readonly cta?: SurveyEndCta\n readonly followUp?: SurveyFollowUp\n}\n\n// ---------- Localization ----------\n\nexport interface SurveyLocalization {\n readonly defaultLanguage?: string\n readonly languages?: Readonly<Record<string, {\n readonly questions?: ReadonlyArray<SurveyQuestion>\n readonly endScreen?: SurveyEndScreen\n }>>\n}\n\n// ---------- Flow ----------\n\nexport interface SurveyFlow {\n readonly startQuestionId: string\n readonly questions: ReadonlyArray<SurveyQuestion>\n readonly branches: ReadonlyArray<SurveyBranch>\n readonly progressStyle: SurveyProgressStyle\n readonly backNavigation: boolean\n readonly localization?: SurveyLocalization\n readonly endScreen?: SurveyEndScreen\n}\n\n// ---------- Campaign surface ----------\n\nexport type SurveyDeliveryMode =\n | 'triggered'\n | 'scheduled'\n | 'on_demand'\n | 'link_only'\n\nexport type SurveyAttemptSource =\n | 'triggered'\n | 'scheduled'\n | 'link'\n | 'on_demand'\n | 'test'\n\nexport interface SurveyCampaign {\n readonly id: string\n readonly appId: string\n readonly name: string\n readonly type: 'survey'\n readonly mode: SurveyDeliveryMode\n readonly status: 'draft' | 'scheduled' | 'active' | 'paused' | 'completed' | 'archived'\n readonly audienceSegmentId: string | null\n readonly triggerEventName: string | null\n // Inline AudienceSpec + TriggerSpec mirroring prompts.audience/trigger.\n // Null until the dashboard / API write them; legacy\n // audienceSegmentId / triggerEventName remain authoritative until\n // both sides have migrated.\n readonly audience: AudienceSpec | null\n readonly trigger: TriggerSpec | null\n readonly schedule: PushSchedule | null\n readonly frequencyCap: PushFrequencyCap\n readonly cooldownSeconds: number | null\n readonly openAccess: boolean\n readonly saveResumeWindowSeconds: number\n readonly endScreen: SurveyEndScreen | null\n readonly themeMode: ThemeMode\n readonly theme: PromptTheme | null\n readonly startAt: string | null\n readonly endAt: string | null\n readonly startedAt: string | null\n readonly endedAt: string | null\n readonly createdAt: string\n readonly updatedAt: string\n}\n\nexport interface SurveyCampaignWithFlow extends SurveyCampaign {\n readonly flow: SurveyFlow\n}\n\n// ---------- Attempts / responses ----------\n\nexport interface SurveyAnswerRecord {\n readonly [questionId: string]: SurveyAnswerValue\n}\n\nexport type SurveyAnswerValue =\n | string\n | number\n | boolean\n | null\n | ReadonlyArray<string>\n | ReadonlyArray<number>\n\nexport interface SurveyAttempt {\n readonly id: string\n readonly campaignId: string\n readonly anonymousId: string\n readonly externalId: string | null\n readonly startedAt: string\n readonly completedAt: string | null\n readonly abandonedAt: string | null\n readonly currentQuestionId: string | null\n readonly progressSnapshot: SurveyAnswerRecord\n readonly source: SurveyAttemptSource\n readonly language: string | null\n}\n\nexport interface SurveyResponseRecord {\n readonly id: string\n readonly attemptId: string\n readonly campaignId: string\n readonly questionId: string\n readonly answerValue: SurveyAnswerValue\n readonly answeredAt: string\n}\n\n// ---------- SDK-facing payloads ----------\n\nexport interface SurveySummary {\n readonly id: string\n readonly name: string\n readonly mode: SurveyDeliveryMode\n readonly source: SurveyAttemptSource\n readonly offeredAt?: string\n readonly resumableAttemptId?: string | null\n}\n\nexport interface SurveyOfferInstruction {\n readonly type: 'survey.offer'\n readonly surveyId: string\n readonly name: string\n readonly mode: SurveyDeliveryMode\n readonly source: SurveyAttemptSource\n readonly emittedAt: string\n}\n\nexport interface CreateSurveyAttemptRequest {\n readonly anonymousId: string\n readonly externalId?: string | null\n readonly source: SurveyAttemptSource\n readonly language?: string\n readonly resume?: boolean\n readonly sdkVersion?: string\n readonly appVersion?: string\n readonly platform?: string\n}\n\nexport interface CreateSurveyAttemptResponse {\n readonly attemptId: string\n readonly startQuestionId: string\n readonly progressSnapshot: SurveyAnswerRecord\n readonly currentQuestionId: string | null\n readonly resumed: boolean\n}\n\nexport interface SubmitSurveyAnswersRequest {\n readonly answers: ReadonlyArray<{\n readonly questionId: string\n readonly value: SurveyAnswerValue\n }>\n readonly currentQuestionId?: string | null\n}\n\nexport interface UpdateSurveyAttemptProgressRequest {\n readonly currentQuestionId: string | null\n readonly progressSnapshot: SurveyAnswerRecord\n}\n\nexport interface CompleteSurveyAttemptRequest {\n readonly finalAnswers?: ReadonlyArray<{\n readonly questionId: string\n readonly value: SurveyAnswerValue\n }>\n readonly latencyMs?: number\n}\n\nexport interface ResolveSurveyLinkRequest {\n readonly token: string\n readonly anonymousId: string\n readonly externalId?: string | null\n}\n\nexport interface ResolveSurveyLinkResponse {\n readonly surveyId: string\n readonly name: string\n readonly consentRequired: boolean\n readonly openAccess: boolean\n}\n\nexport interface SurveyShareLinkResponse {\n readonly url: string\n readonly token: string\n readonly expiresAt: string | null\n}\n\n// ---------- Templates ----------\n\nexport interface SurveyTemplate {\n readonly id: string\n readonly slug: string\n readonly name: string\n readonly description: string | null\n readonly flow: SurveyFlow\n readonly recommendedTriggerEvent: string | null\n readonly recommendedMode: SurveyDeliveryMode | null\n readonly createdAt: string\n}\n\n// ---------- Create / update requests ----------\n\nexport interface CreateSurveyRequest {\n readonly name: string\n readonly mode: SurveyDeliveryMode\n readonly flow: SurveyFlow\n readonly audienceSegmentId?: string | null\n readonly triggerEventName?: string | null\n readonly schedule?: PushSchedule | null\n readonly frequencyCap?: PushFrequencyCap\n readonly frequency?: FrequencyCaps\n readonly cooldownSeconds?: number | null\n readonly openAccess?: boolean\n readonly saveResumeWindowSeconds?: number\n readonly endScreen?: SurveyEndScreen\n readonly themeMode?: ThemeMode\n readonly theme?: PromptTheme\n readonly startAt?: string | null\n readonly endAt?: string | null\n readonly status?: SurveyCampaign['status']\n}\n\nexport interface UpdateSurveyRequest extends Partial<CreateSurveyRequest> {\n readonly status?: SurveyCampaign['status']\n}\n\nexport interface CloneSurveyFromTemplateRequest {\n readonly name?: string\n readonly audienceSegmentId?: string | null\n readonly triggerEventName?: string | null\n}\n\n// ---------- Analytics ----------\n\nexport interface SurveyFunnelStep {\n readonly questionId: string\n readonly shown: number\n readonly answered: number\n readonly skipped: number\n}\n\nexport interface SurveyQuestionDistribution {\n readonly questionId: string\n readonly type: SurveyQuestionType\n readonly distribution: Readonly<Record<string, number>>\n readonly average?: number\n readonly npsScore?: number\n readonly sampleSize: number\n}\n\nexport interface SurveyAnalytics {\n readonly surveyId: string\n readonly totals: {\n readonly started: number\n readonly completed: number\n readonly abandoned: number\n readonly completionRate: number\n }\n readonly funnel: ReadonlyArray<SurveyFunnelStep>\n readonly perQuestion: ReadonlyArray<SurveyQuestionDistribution>\n readonly npsOverTime?: ReadonlyArray<{ day: string; score: number; samples: number }>\n readonly perLanguage?: Readonly<Record<string, number>>\n}\n\n// ---------- SDK-side armed surveys ----------\n//\n// Mirrors `ArmedTrigger` (feedback). Returned by\n// `GET /v1/sdk/armed-surveys` for every triggered + active survey\n// the SDK should evaluate locally on each `track()`. The full\n// `survey` payload is included so the SDK can render immediately\n// on a match without a follow-up content fetch.\n\nexport interface ArmedSurvey {\n readonly campaignId: string\n readonly eventName: string\n readonly segmentRules?: SerializedSegmentRules | null\n /** True only when the SDK can make the same targeting decision locally. */\n readonly clientSideEligible?: boolean\n readonly cooldownSeconds: number | null\n readonly frequencyCap: PushFrequencyCap\n readonly survey: SurveyCampaignWithFlow\n}\n","import type { AudienceSpec, TriggerSpec } from './targeting.js'\nimport type { ThemeMode } from './brand.js'\n\nexport const INAPP_SHOWN_EVENT_NAME = '$inapp_shown'\nexport const INAPP_DISMISSED_EVENT_NAME = '$inapp_dismissed'\nexport const INAPP_AUTO_DISMISSED_EVENT_NAME = '$inapp_auto_dismissed'\nexport const INAPP_CTA_CLICKED_EVENT_NAME = '$inapp_cta_clicked'\n\nexport type InAppMessageFormat = 'modal' | 'modal_full' | 'slideup'\n\nexport type InAppMessageStatus =\n | 'draft'\n | 'scheduled'\n | 'active'\n | 'paused'\n | 'completed'\n | 'archived'\n\nexport type InAppMessageMode = 'triggered' | 'scheduled'\n\nexport type JsonAction = Readonly<Record<string, unknown>>\n\nexport type InAppCtaAction =\n | 'open_url'\n | 'deep_link'\n | 'dismiss'\n | 'custom_event'\n | 'json'\n\nexport interface InAppCta {\n readonly label: string\n readonly action: InAppCtaAction\n readonly target?: string\n /** Host-defined action data dispatched to the app when this CTA is tapped. */\n readonly actionJson?: JsonAction\n}\n\n// Three-state cooldowns + cross-pillar caps. Each key is optional —\n// omitting means \"no cap on this dimension\".\nexport interface InAppFrequency {\n readonly cooldownAfterShownDays?: number\n readonly cooldownAfterDismissedDays?: number\n readonly cooldownAfterCtaClickedDays?: number\n readonly maxImpressionsPerUser?: number\n readonly perPillarDays?: number\n readonly perGlobalDays?: number\n}\n\nexport interface InAppMessage {\n readonly id: string\n readonly appId: string\n readonly name: string\n readonly status: InAppMessageStatus\n readonly mode: InAppMessageMode\n\n readonly audienceSegmentId: string | null\n readonly audience: AudienceSpec | null\n readonly trigger: TriggerSpec | null\n readonly triggerEventName: string | null\n readonly schedule: unknown | null\n\n readonly screenAllowlist: ReadonlyArray<string>\n readonly screenDenylist: ReadonlyArray<string>\n\n readonly frequency: InAppFrequency\n\n readonly conversionGoalEvent: string | null\n readonly conversionWindowHours: number\n\n readonly priority: number\n readonly forceShow: boolean\n readonly autoDismissSeconds: number | null\n\n readonly format: InAppMessageFormat\n readonly title: string\n readonly body: string | null\n readonly imageUrl: string | null\n readonly themeMode: ThemeMode\n readonly backgroundColor: string | null\n readonly accentColor: string | null\n readonly backdropEnabled: boolean\n readonly ctas: ReadonlyArray<InAppCta>\n\n readonly startAt: string | null\n readonly endAt: string | null\n readonly createdAt: string\n readonly updatedAt: string\n}\n\nexport interface CreateInAppMessageRequest {\n readonly name: string\n readonly audienceSegmentId?: string | null\n readonly audience?: AudienceSpec\n readonly trigger?: TriggerSpec\n readonly triggerEventName?: string | null\n readonly screenAllowlist?: ReadonlyArray<string>\n readonly screenDenylist?: ReadonlyArray<string>\n readonly frequency?: InAppFrequency\n readonly conversionGoalEvent?: string | null\n readonly conversionWindowHours?: number\n readonly priority?: number\n readonly forceShow?: boolean\n readonly autoDismissSeconds?: number | null\n readonly format: InAppMessageFormat\n readonly title: string\n readonly body?: string | null\n readonly imageUrl?: string | null\n readonly themeMode?: ThemeMode\n readonly backgroundColor?: string | null\n readonly accentColor?: string | null\n readonly backdropEnabled?: boolean\n readonly ctas?: ReadonlyArray<InAppCta>\n readonly startAt?: string | null\n readonly endAt?: string | null\n readonly status?: InAppMessageStatus\n}\n\nexport interface UpdateInAppMessageRequest extends Partial<CreateInAppMessageRequest> {\n readonly status?: InAppMessageStatus\n}\n\nexport interface InAppMessageAnalytics {\n readonly totals: {\n readonly impressions: number\n readonly dismissed: number\n readonly autoDismissed: number\n readonly ctaClicked: number\n }\n readonly timeline: ReadonlyArray<{\n readonly day: string\n readonly impressions: number\n readonly dismissed: number\n readonly ctaClicked: number\n }>\n}\n\n// Subset of the message the SDK needs at render time. Mirrors\n// `ArmedTrigger.prompt` for feedback prompts — strips fields the device\n// doesn't need (audit columns, segment id) and leaves what the renderer\n// uses.\nexport interface ArmedInAppMessage {\n readonly messageId: string\n readonly eventName: string\n /** True only when the SDK can make the same targeting decision locally. */\n readonly clientSideEligible?: boolean\n readonly format: InAppMessageFormat\n readonly title: string\n readonly body: string | null\n readonly imageUrl: string | null\n readonly themeMode?: ThemeMode\n readonly backgroundColor: string | null\n readonly accentColor: string | null\n /** Defaults to true when omitted by an older API/cache payload. */\n readonly backdropEnabled?: boolean\n readonly ctas: ReadonlyArray<InAppCta>\n readonly autoDismissSeconds: number | null\n readonly screenAllowlist: ReadonlyArray<string>\n readonly screenDenylist: ReadonlyArray<string>\n readonly forceShow: boolean\n}\n","// ============================================================\n// Feature requests (5th pillar) — public types\n// ============================================================\n// Shared between API, dashboard, web-roadmap, and SDKs.\n// All shapes are `readonly`. Identity uses anonymousId + externalId\n// as on every other SDK payload — no new identity types here.\n\nimport type { ThemeMode } from './brand.js'\n\nexport type RequestStatus =\n | 'under_review'\n | 'planned'\n | 'in_progress'\n | 'shipped'\n | 'declined'\n\nexport type RequestFollowSource = 'upvote_auto' | 'manual'\n\nexport type RequestSort = 'top' | 'newest' | 'recently_updated'\n\nexport type RequestPersonalFilter = 'submitted' | 'upvoted' | 'following'\n\n// Event-name constants for the 7 events emitted by the request engine.\n// All flow through services/ingest.ts and become segmentable like every\n// other event (no segment-engine code changes needed).\nexport const REQUEST_SUBMITTED_EVENT_NAME = '$request_submitted' as const\nexport const REQUEST_UPVOTED_EVENT_NAME = '$request_upvoted' as const\nexport const REQUEST_UNUPVOTED_EVENT_NAME = '$request_unupvoted' as const\nexport const REQUEST_FOLLOWED_EVENT_NAME = '$request_followed' as const\nexport const REQUEST_UNFOLLOWED_EVENT_NAME = '$request_unfollowed' as const\nexport const REQUEST_STATUS_CHANGED_EVENT_NAME = '$request_status_changed' as const\nexport const REQUEST_RESPONDED_EVENT_NAME = '$request_responded' as const\nexport const REQUEST_COMMENTED_EVENT_NAME = '$request_commented' as const\nexport const REQUEST_COMMENT_EDITED_EVENT_NAME = '$request_comment_edited' as const\nexport const REQUEST_COMMENT_DELETED_EVENT_NAME = '$request_comment_deleted' as const\n\n// ---------- core domain shapes ----------\n\n/**\n * A feature request with viewer-relative state attached. Returned from\n * detail and list endpoints; `viewer*` fields are computed server-side\n * from the caller's identity.\n */\nexport interface Request {\n readonly id: string\n readonly appId: string\n readonly title: string\n readonly description: string\n readonly status: RequestStatus\n readonly devResponse: string | null\n readonly upvoteCount: number\n readonly followerCount: number\n readonly createdAt: string\n readonly updatedAt: string\n readonly statusChangedAt: string\n readonly lastRespondedAt: string | null\n readonly viewerHasUpvoted: boolean\n readonly viewerIsFollowing: boolean\n readonly viewerIsSubmitter: boolean\n}\n\n/** Compact summary used in list views and search typeahead. */\nexport interface RequestSummary {\n readonly id: string\n readonly title: string\n readonly description: string\n readonly status: RequestStatus\n readonly upvoteCount: number\n readonly followerCount: number\n readonly createdAt: string\n readonly statusChangedAt: string\n readonly viewerHasUpvoted: boolean\n readonly viewerIsFollowing: boolean\n}\n\n/** Search-as-you-type result; the SDK shows up to 5. */\nexport interface RequestSearchResult {\n readonly id: string\n readonly title: string\n readonly status: RequestStatus\n readonly upvoteCount: number\n}\n\n// ---------- toggle return shapes ----------\n\n/** Returned from POST/DELETE /v1/sdk/requests/:id/votes. */\nexport interface RequestVote {\n readonly requestId: string\n readonly upvoted: boolean\n readonly followed: boolean\n readonly upvoteCount: number\n readonly followerCount: number\n}\n\n/** Returned from POST/DELETE /v1/sdk/requests/:id/follows. */\nexport interface RequestFollow {\n readonly requestId: string\n readonly following: boolean\n readonly followerCount: number\n readonly source: RequestFollowSource\n}\n\n// ---------- request payloads ----------\n\nexport interface GetRequestsOptions {\n readonly sort?: RequestSort\n readonly statuses?: ReadonlyArray<RequestStatus>\n readonly mine?: RequestPersonalFilter\n readonly q?: string\n readonly cursor?: string | null\n readonly limit?: number\n}\n\nexport interface GetRequestsResult {\n readonly items: ReadonlyArray<RequestSummary>\n readonly nextCursor: string | null\n}\n\nexport interface SubmitRequestPayload {\n readonly anonymousId: string\n readonly externalId?: string | null\n readonly title: string\n readonly description: string\n}\n\nexport interface RequestVotePayload {\n readonly anonymousId: string\n readonly externalId?: string | null\n}\n\nexport interface RequestFollowPayload {\n readonly anonymousId: string\n readonly externalId?: string | null\n}\n\n// ---------- dashboard shapes ----------\n\nexport interface RequestDetail extends Request {\n readonly submitterAnonymousId: string\n readonly submitterExternalId: string | null\n readonly hidden: boolean\n}\n\nexport interface RequestUpvoterSegmentBreakdown {\n readonly requestId: string\n readonly totalUpvoters: number\n readonly segments: ReadonlyArray<{\n readonly segmentId: string\n readonly segmentName: string\n readonly count: number\n readonly percentage: number\n }>\n}\n\nexport type RequestTimelineEntryKind =\n | 'submitted'\n | 'upvote_burst'\n | 'follow_burst'\n | 'status_changed'\n | 'responded'\n\nexport interface RequestTimelineEntry {\n readonly kind: RequestTimelineEntryKind\n readonly at: string\n readonly count?: number\n readonly fromStatus?: RequestStatus\n readonly toStatus?: RequestStatus\n readonly responseExcerpt?: string\n}\n\nexport interface RequestAnalytics {\n readonly submissions: ReadonlyArray<{ readonly date: string; readonly count: number }>\n readonly upvotes: ReadonlyArray<{ readonly date: string; readonly count: number }>\n readonly follows: ReadonlyArray<{ readonly date: string; readonly count: number }>\n readonly statusDistribution: Record<RequestStatus, number>\n readonly devResponseRate: number\n readonly medianResponseHours: number | null\n readonly leaderboard: ReadonlyArray<{\n readonly anonymousId: string\n readonly externalId: string | null\n readonly submissions: number\n readonly upvotes: number\n }>\n}\n\nexport interface UpdateRequestStatusRequest {\n readonly status: RequestStatus\n readonly responseAppend?: string\n}\n\nexport interface UpdateRequestResponseRequest {\n readonly body: string\n}\n\nexport interface UpdateRequestModerationRequest {\n readonly hidden: boolean\n}\n\nexport interface MergeRequestsRequest {\n readonly canonicalId: string\n readonly duplicateIds: ReadonlyArray<string>\n}\n\nexport interface BulkUpdateStatusRequest {\n readonly ids: ReadonlyArray<string>\n readonly status: RequestStatus\n}\n\nexport interface ListRequestsQuery {\n readonly sort?: RequestSort\n readonly status?: RequestStatus | ReadonlyArray<RequestStatus>\n readonly filter?: RequestPersonalFilter\n readonly anonymousId?: string\n readonly q?: string\n readonly hidden?: boolean\n readonly page?: number\n readonly limit?: number\n}\n\n// ---------- settings ----------\n\nexport interface RequestBranding {\n readonly logoUrl?: string | null\n readonly accentColor?: string | null\n readonly coverImageUrl?: string | null\n readonly introCopy?: string | null\n}\n\nexport interface RequestNotificationRules {\n readonly transitions?: Record<string, boolean>\n readonly responseFirst?: boolean\n readonly responseEdit?: boolean\n readonly templateOverrides?: {\n readonly statusChange?: string\n readonly response?: string\n }\n}\n\nexport interface RequestSettings {\n readonly appId: string\n readonly enabled: boolean\n readonly entryLabel: string\n readonly viewSegmentId: string | null\n readonly submitSegmentId: string | null\n readonly publicRoadmapEnabled: boolean\n readonly publicSlug: string | null\n readonly themeMode: ThemeMode\n readonly branding: RequestBranding\n readonly notificationRules: RequestNotificationRules\n}\n\nexport interface UpdateRequestSettingsRequest {\n readonly enabled?: boolean\n readonly entryLabel?: string\n readonly viewSegmentId?: string | null\n readonly submitSegmentId?: string | null\n readonly publicRoadmapEnabled?: boolean\n readonly publicSlug?: string | null\n readonly themeMode?: ThemeMode\n readonly branding?: RequestBranding\n readonly notificationRules?: RequestNotificationRules\n}\n\n// ---------- public web roadmap shapes ----------\n\n/** Public-safe request summary (no submitter identity). */\nexport interface RequestPublicSummary {\n readonly id: string\n readonly title: string\n readonly description: string\n readonly status: RequestStatus\n readonly upvoteCount: number\n readonly followerCount: number\n readonly createdAt: string\n readonly statusChangedAt: string\n}\n\nexport interface RequestPublicDetail extends RequestPublicSummary {\n readonly devResponse: string | null\n readonly lastRespondedAt: string | null\n}\n\nexport interface RequestPublicBranding {\n readonly entryLabel: string\n readonly appName: string\n readonly branding: RequestBranding\n readonly fallbackInstallUrl: string | null\n}\n\n// ---------- SDK push payload ----------\n\n/** Carried inside push/in-app message payloads when status changes. */\nexport interface RequestStatusChangedNotice {\n readonly requestId: string\n readonly title: string\n readonly oldStatus: RequestStatus\n readonly newStatus: RequestStatus\n readonly devResponseExcerpt?: string\n readonly receivedVia: 'push' | 'inapp'\n}\n\n// ---------- comments ----------\n\nexport interface RequestComment {\n readonly id: string\n readonly requestId: string\n readonly body: string\n readonly authorAnonymousId: string\n readonly authorExternalId: string | null\n readonly viewerIsAuthor: boolean\n readonly createdAt: string\n readonly updatedAt: string\n}\n\nexport interface PostCommentPayload {\n readonly anonymousId: string\n readonly externalId?: string | null\n readonly body: string\n}\n\nexport interface EditCommentPayload {\n readonly anonymousId: string\n readonly body: string\n}\n\n/** Host-app callbacks registered via `setRequestsHandlers`. */\nexport interface RequestsHandlers {\n readonly onSubmit?: (request: Request) => void\n readonly onVote?: (vote: RequestVote) => void\n readonly onFollow?: (follow: RequestFollow) => void\n readonly onStatusChanged?: (notice: RequestStatusChangedNotice) => void\n}\n","// ==========================================================\n// Inline targeting spec — used by feedback prompts, surveys,\n// and push campaigns. Wraps each pillar record with an\n// `AudienceSpec` (who) + `TriggerSpec` (when).\n//\n// One condition kind in `AudienceCondition` is `segment`,\n// which references saved Segments by id (so the dashboard\n// suggests existing segments in that one branch). All other\n// kinds are evaluated inline against user properties or\n// recent event aggregates.\n//\n// `TriggerSpec` is a discriminated union with a shared base\n// (`app_open`, `event`, `audience_join`). Pillar packages\n// add extra kinds locally (e.g. push adds `manual` /\n// `scheduled`) — engines `switch` on `kind` and treat\n// unknowns as no-op.\n// ==========================================================\n\nimport type { ComparisonOp } from './segment-dsl.js'\n\nexport type Platform = 'ios' | 'android' | 'web'\n\nexport type AudienceCombinator = 'all' | 'any'\n\nexport type AudienceMode = 'everyone' | 'match'\n\n// -------------------- Audience conditions ----------------\n\nexport interface SegmentCondition {\n readonly kind: 'segment'\n readonly op: 'is' | 'is_not'\n readonly segmentIds: ReadonlyArray<string>\n}\n\nexport interface CountryCondition {\n readonly kind: 'country'\n readonly op: 'is_any_of' | 'is_none_of'\n readonly values: ReadonlyArray<string> // ISO 3166-1 alpha-2\n}\n\nexport interface LastActiveCondition {\n readonly kind: 'last_active'\n readonly op: 'within_days' | 'before_days' | 'never'\n readonly days?: number\n}\n\nexport interface InstallDateCondition {\n readonly kind: 'install_date'\n // `*_days` operators are relative to today; `*_date` and `between`\n // pin to user-picked calendar dates (ISO yyyy-mm-dd).\n readonly op:\n | 'within_days'\n | 'before_days'\n | 'after_date'\n | 'before_date'\n | 'between'\n readonly days?: number\n readonly date?: string // ISO date — used by after_date / before_date\n readonly from?: string // ISO date — used by between\n readonly to?: string // ISO date — used by between\n}\n\nexport interface PlatformCondition {\n readonly kind: 'platform'\n readonly op: 'is' | 'is_not'\n readonly values: ReadonlyArray<Platform>\n}\n\nexport interface UserPropertyCondition {\n readonly kind: 'user_property'\n readonly key: string\n readonly op: ComparisonOp\n readonly value?: string | number | boolean | ReadonlyArray<string | number>\n}\n\nexport interface EventPropertyFilter {\n readonly key: string\n readonly op: ComparisonOp\n readonly value?: string | number | boolean | ReadonlyArray<string | number>\n}\n\nexport interface EventPerformedCondition {\n readonly kind: 'event_performed'\n readonly op: 'did' | 'did_not'\n readonly eventName: string\n /** @deprecated Kept so previously saved audience definitions still load. */\n readonly property?: EventPropertyFilter\n readonly propertyFilters?: ReadonlyArray<EventPropertyFilter>\n readonly windowDays?: number\n readonly minCount?: number\n}\n\nexport interface AppVersionCondition {\n readonly kind: 'app_version'\n // String comparison for v1 — \"2.10.0\" sorts before \"2.9.0\" lexically.\n // Acceptable until we ship a semver-aware compare; the dashboard\n // input warns users.\n readonly op: 'eq' | 'neq' | 'gte' | 'lte' | 'gt' | 'lt'\n readonly version: string\n}\n\nexport type AudienceCondition =\n | SegmentCondition\n | CountryCondition\n | LastActiveCondition\n | InstallDateCondition\n | PlatformCondition\n | UserPropertyCondition\n | EventPerformedCondition\n | AppVersionCondition\n\nexport type AudienceConditionKind = AudienceCondition['kind']\n\nexport interface AudienceSpec {\n readonly version: 1\n readonly mode: AudienceMode\n readonly combinator: AudienceCombinator\n readonly conditions: ReadonlyArray<AudienceCondition>\n}\n\nexport function emptyAudienceSpec(): AudienceSpec {\n return { version: 1, mode: 'everyone', combinator: 'all', conditions: [] }\n}\n\n// -------------------- Trigger spec -----------------------\n\nexport type TriggerOccurrenceMode = 'every' | 'after_nth' | 'first_only'\n\nexport interface TriggerOccurrence {\n readonly mode: TriggerOccurrenceMode\n readonly n?: number // required when mode === 'after_nth'\n}\n\nexport interface ActiveWindow {\n readonly startAt?: string // ISO datetime\n readonly endAt?: string // ISO datetime\n}\n\nexport interface AppOpenTrigger {\n readonly kind: 'app_open'\n readonly delaySeconds?: number\n readonly onceOnly?: boolean\n readonly activeWindow?: ActiveWindow\n}\n\nexport interface EventTrigger {\n readonly kind: 'event'\n readonly eventName: string\n readonly propertyFilters?: ReadonlyArray<EventPropertyFilter>\n readonly occurrence?: TriggerOccurrence\n readonly delaySeconds?: number\n readonly onceOnly?: boolean\n readonly activeWindow?: ActiveWindow\n}\n\nexport interface AudienceJoinTrigger {\n readonly kind: 'audience_join'\n readonly delaySeconds?: number\n readonly onceOnly?: boolean\n readonly activeWindow?: ActiveWindow\n}\n\nexport interface AppVersionChangedTrigger {\n readonly kind: 'app_version_changed'\n readonly delaySeconds?: number\n readonly onceOnly?: boolean\n readonly activeWindow?: ActiveWindow\n}\n\nexport type TriggerSpec =\n | AppOpenTrigger\n | EventTrigger\n | AudienceJoinTrigger\n | AppVersionChangedTrigger\n\nexport type TriggerKind = TriggerSpec['kind']\n\n/**\n * Synthetic event name the SDK emits whenever the host app cold-starts\n * or transitions from background to foreground. The trigger engine\n * indexes `app_open`-kind prompts under this name so the same matching\n * pipeline handles both event-driven and lifecycle-driven prompts.\n */\nexport const APP_OPEN_EVENT_NAME = '$app_open'\n\n/**\n * Synthetic event the engine indexes `audience_join` campaigns under.\n * Mirrors APP_OPEN_EVENT_NAME so the same matching pipeline handles\n * both lifecycle and audience-membership triggers.\n */\nexport const AUDIENCE_JOIN_EVENT_NAME = '$audience_join'\n\nexport const AUDIENCE_JOIN_TRIGGER_KIND: AudienceJoinTrigger['kind'] = 'audience_join'\n\n/**\n * Synthetic event the SDK emits on cold-start when the persisted app\n * version differs from the running binary's version. Lets in-app\n * messages (and feedback / surveys) target users right after an update\n * — e.g. \"What's new\" modals.\n */\nexport const APP_VERSION_CHANGED_EVENT_NAME = '$app_version_changed'\n\nexport function defaultTriggerSpec(): TriggerSpec {\n return { kind: 'app_open' }\n}\n\nexport function defaultEventTrigger(eventName = ''): EventTrigger {\n return {\n kind: 'event',\n eventName,\n occurrence: { mode: 'every' },\n }\n}\n","// ==========================================================\n// Preset themes for the Feedback Design step. 12 curated\n// presets + a custom-your-own option in the UI. Each preset\n// surfaces 3 swatches in the gallery card for quick scan.\n// ==========================================================\n\nexport interface ThemeColors {\n readonly primary: string\n readonly background: string\n readonly text: string\n readonly subtext: string\n readonly border: string\n readonly accent?: string\n readonly button?: string\n}\n\nexport type CornerRadiusPreset = 'sharp' | 'soft' | 'rounded' | 'pill'\n\nexport const RADIUS_PRESETS: Record<CornerRadiusPreset, number> = {\n sharp: 4,\n soft: 12,\n rounded: 20,\n pill: 999,\n}\n\nexport interface ThemePreset {\n readonly id: string\n readonly name: string\n readonly description: string\n readonly colors: ThemeColors\n readonly radius: number\n readonly fontFamily: string\n readonly swatches: readonly [string, string, string]\n}\n\n// Default font family for every preset. Matches the SDK's\n// DEFAULT_THEME so a freshly-saved theme renders the same in the\n// dashboard preview (web font loaded via next/font + Google Fonts\n// stylesheet) and on the mobile app (host bundles the .ttf via\n// react-native.config.js). Previously the presets used 'Inter',\n// which neither side had loaded — both fell back to system sans,\n// so designers saw a font drift between the dashboard and device.\nconst JAKARTA = 'Plus Jakarta Sans'\n\nexport const THEME_PRESETS: ReadonlyArray<ThemePreset> = [\n {\n id: 'minimal',\n name: 'Minimal',\n description: 'Clean neutral palette',\n colors: {\n primary: '#111827',\n background: '#FFFFFF',\n text: '#111827',\n subtext: '#6B7280',\n border: '#E5E7EB',\n button: '#111827',\n },\n radius: 16,\n fontFamily: JAKARTA,\n swatches: ['#111827', '#FFFFFF', '#E5E7EB'],\n },\n {\n id: 'ocean',\n name: 'Ocean',\n description: 'Cool blue tones',\n colors: {\n primary: '#0EA5E9',\n background: '#F0F9FF',\n text: '#0C4A6E',\n subtext: '#0369A1',\n border: '#BAE6FD',\n button: '#0EA5E9',\n },\n radius: 16,\n fontFamily: JAKARTA,\n swatches: ['#0EA5E9', '#0C4A6E', '#BAE6FD'],\n },\n {\n id: 'sunset',\n name: 'Sunset',\n description: 'Warm orange glow',\n colors: {\n primary: '#F97316',\n background: '#FFF7ED',\n text: '#7C2D12',\n subtext: '#C2410C',\n border: '#FED7AA',\n button: '#F97316',\n },\n radius: 16,\n fontFamily: JAKARTA,\n swatches: ['#F97316', '#7C2D12', '#FED7AA'],\n },\n {\n id: 'forest',\n name: 'Forest',\n description: 'Natural green hues',\n colors: {\n primary: '#16A34A',\n background: '#F0FDF4',\n text: '#14532D',\n subtext: '#166534',\n border: '#BBF7D0',\n button: '#16A34A',\n },\n radius: 16,\n fontFamily: JAKARTA,\n swatches: ['#16A34A', '#14532D', '#BBF7D0'],\n },\n {\n id: 'midnight',\n name: 'Midnight',\n description: 'Deep dark mode',\n colors: {\n primary: '#A78BFA',\n background: '#0F172A',\n text: '#F8FAFC',\n subtext: '#94A3B8',\n border: '#1E293B',\n button: '#A78BFA',\n },\n radius: 16,\n fontFamily: JAKARTA,\n swatches: ['#A78BFA', '#0F172A', '#1E293B'],\n },\n {\n id: 'candy',\n name: 'Candy',\n description: 'Playful pink + violet',\n colors: {\n primary: '#EC4899',\n background: '#FDF2F8',\n text: '#831843',\n subtext: '#BE185D',\n border: '#FBCFE8',\n button: '#EC4899',\n },\n radius: 20,\n fontFamily: JAKARTA,\n swatches: ['#EC4899', '#831843', '#FBCFE8'],\n },\n {\n id: 'mono',\n name: 'Mono',\n description: 'High-contrast B&W',\n colors: {\n primary: '#000000',\n background: '#FFFFFF',\n text: '#000000',\n subtext: '#525252',\n border: '#000000',\n button: '#000000',\n },\n radius: 4,\n fontFamily: JAKARTA,\n swatches: ['#000000', '#FFFFFF', '#525252'],\n },\n {\n id: 'coral',\n name: 'Coral',\n description: 'Soft coral accent',\n colors: {\n primary: '#FB7185',\n background: '#FFF1F2',\n text: '#881337',\n subtext: '#9F1239',\n border: '#FECDD3',\n button: '#FB7185',\n },\n radius: 16,\n fontFamily: JAKARTA,\n swatches: ['#FB7185', '#881337', '#FECDD3'],\n },\n {\n id: 'ink',\n name: 'Ink',\n description: 'Deep navy editorial',\n colors: {\n primary: '#1E3A8A',\n background: '#F8FAFC',\n text: '#0F172A',\n subtext: '#475569',\n border: '#CBD5E1',\n button: '#1E3A8A',\n },\n radius: 12,\n fontFamily: JAKARTA,\n swatches: ['#1E3A8A', '#0F172A', '#CBD5E1'],\n },\n {\n id: 'mint',\n name: 'Mint',\n description: 'Fresh teal vibe',\n colors: {\n primary: '#14B8A6',\n background: '#F0FDFA',\n text: '#134E4A',\n subtext: '#0F766E',\n border: '#99F6E4',\n button: '#14B8A6',\n },\n radius: 16,\n fontFamily: JAKARTA,\n swatches: ['#14B8A6', '#134E4A', '#99F6E4'],\n },\n {\n id: 'slate',\n name: 'Slate',\n description: 'Quiet professional',\n colors: {\n primary: '#475569',\n background: '#F1F5F9',\n text: '#0F172A',\n subtext: '#64748B',\n border: '#CBD5E1',\n button: '#475569',\n },\n radius: 12,\n fontFamily: JAKARTA,\n swatches: ['#475569', '#0F172A', '#CBD5E1'],\n },\n {\n id: 'aurora',\n name: 'Aurora',\n description: 'Vibrant gradient pop',\n colors: {\n primary: '#8B5CF6',\n background: '#FAF5FF',\n text: '#3B0764',\n subtext: '#7E22CE',\n border: '#E9D5FF',\n accent: '#EC4899',\n button: '#8B5CF6',\n },\n radius: 20,\n fontFamily: JAKARTA,\n swatches: ['#8B5CF6', '#EC4899', '#E9D5FF'],\n },\n] as const\n\nexport function getThemePresetById(id: string): ThemePreset | undefined {\n return THEME_PRESETS.find((preset) => preset.id === id)\n}\n\nexport function defaultThemePreset(): ThemePreset {\n // The presets list is non-empty by construction; assert via index access.\n return THEME_PRESETS[0] as ThemePreset\n}\n","import type { PromptTheme } from './prompt.js'\nimport type { ThemePreset } from './themes.js'\n\nexport type BrandPillar = 'feedback' | 'survey' | 'inapp' | 'requests'\nexport type ThemeMode = 'app_default' | 'custom'\n\nexport interface BrandThemeTokens {\n readonly colors: {\n readonly primary: string\n readonly background: string\n readonly text: string\n readonly subtext: string\n readonly border: string\n }\n readonly radius: number\n readonly fontFamily: string\n}\n\nexport type BrandThemeRef = `preset:${string}` | `custom:${string}`\n\nexport interface BrandTheme {\n readonly ref: BrandThemeRef\n readonly id: string\n readonly kind: 'preset' | 'custom'\n readonly name: string\n readonly description?: string\n readonly tokens: BrandThemeTokens\n readonly swatches: readonly [string, string, string]\n readonly editable: boolean\n readonly assignedPillars: ReadonlyArray<BrandPillar>\n readonly createdAt?: string\n readonly updatedAt?: string\n}\n\nexport type BrandThemeDefaults = Readonly<Record<BrandPillar, BrandThemeRef>>\n\nexport interface AppBrandSettings {\n readonly appId: string\n readonly themes: ReadonlyArray<BrandTheme>\n readonly defaults: BrandThemeDefaults\n readonly resolvedDefaults: Readonly<Record<BrandPillar, BrandThemeTokens>>\n readonly updatedAt: string\n}\n\nexport interface CreateBrandThemeRequest {\n readonly name: string\n readonly tokens: BrandThemeTokens\n}\n\nexport interface UpdateBrandThemeRequest {\n readonly name?: string\n readonly tokens?: BrandThemeTokens\n}\n\nexport interface UpdateBrandThemeDefaultsRequest {\n readonly defaults: BrandThemeDefaults\n}\n\nexport function brandTokensFromPreset(\n preset: Pick<ThemePreset, 'colors' | 'radius' | 'fontFamily'>,\n): BrandThemeTokens {\n return {\n colors: {\n primary: preset.colors.primary,\n background: preset.colors.background,\n text: preset.colors.text,\n subtext: preset.colors.subtext,\n border: preset.colors.border,\n },\n radius: preset.radius,\n fontFamily: preset.fontFamily,\n }\n}\n\nexport function promptThemeFromBrandTokens(tokens: BrandThemeTokens): PromptTheme {\n return {\n colors: { ...tokens.colors },\n radius: tokens.radius,\n fontFamily: tokens.fontFamily,\n }\n}\n\nexport function inAppColorsFromBrandTokens(tokens: BrandThemeTokens): {\n readonly backgroundColor: string\n readonly accentColor: string\n} {\n return {\n backgroundColor: tokens.colors.background,\n accentColor: tokens.colors.primary,\n }\n}\n\nexport function requestAccentFromBrandTokens(tokens: BrandThemeTokens): string {\n return tokens.colors.primary\n}\n","import type { EventPropertyValue } from './event.js'\n\nexport const INTEGRATION_PROVIDERS = ['amplitude', 'mixpanel'] as const\nexport type IntegrationProvider = (typeof INTEGRATION_PROVIDERS)[number]\n\nexport const INTEGRATION_CATEGORIES = [\n 'feedback', 'surveys', 'inapp', 'push', 'requests', 'lifecycle',\n] as const\nexport type IntegrationCategory = (typeof INTEGRATION_CATEGORIES)[number]\n\nexport type IntegrationStatus = 'connected' | 'paused' | 'needs_attention' | 'disconnected'\nexport type AmplitudeIntegrationRegion = 'us' | 'eu'\nexport type MixpanelIntegrationRegion = 'us' | 'eu' | 'in'\nexport type IntegrationRegion = 'us' | 'eu' | 'in'\nexport type IntegrationDeliveryStatus =\n | 'pending' | 'leased' | 'retrying' | 'delivered' | 'dead_lettered' | 'skipped'\nexport type CoreEventSubjectRole = 'actor' | 'affected_user'\n\nexport interface CoreIntegrationEventDefinition {\n readonly key: string\n readonly name: string\n readonly category: IntegrationCategory | 'identity'\n readonly subjectRole: CoreEventSubjectRole\n readonly required?: boolean\n /** Stable output property key -> accepted source property aliases. */\n readonly properties: Readonly<Record<string, ReadonlyArray<string>>>\n}\n\nexport const USER_IDENTIFIED_EVENT_NAME = '$user_identified' as const\n\nfunction camelize(value: string): string {\n return value.replace(/_([a-z])/g, (_match, letter: string) => letter.toUpperCase())\n}\n\nconst ids = (...keys: string[]): Readonly<Record<string, ReadonlyArray<string>>> =>\n Object.fromEntries(keys.map((key) => [key, [key, camelize(key)]]))\n\nconst pushEvents: ReadonlyArray<readonly [string, string]> = [\n ['$push_sent', 'UserGist Push Sent'],\n ['$push_delivered', 'UserGist Push Delivered'],\n ['$push_received', 'UserGist Push Received'],\n ['$push_displayed', 'UserGist Push Displayed'],\n ['$push_opened', 'UserGist Push Opened'],\n ['$push_dismissed', 'UserGist Push Dismissed'],\n ['$push_clicked', 'UserGist Push Clicked'],\n ['$push_action_clicked', 'UserGist Push Action Clicked'],\n ['$push_bounced', 'UserGist Push Bounced'],\n]\n\nconst requestEvents: ReadonlyArray<readonly [string, string, CoreEventSubjectRole]> = [\n ['$request_submitted', 'UserGist Request Submitted', 'actor'],\n ['$request_upvoted', 'UserGist Request Upvoted', 'actor'],\n ['$request_unupvoted', 'UserGist Request Unupvoted', 'actor'],\n ['$request_followed', 'UserGist Request Followed', 'actor'],\n ['$request_unfollowed', 'UserGist Request Unfollowed', 'actor'],\n ['$request_status_changed', 'UserGist Request Status Changed', 'affected_user'],\n ['$request_responded', 'UserGist Request Responded', 'affected_user'],\n ['$request_commented', 'UserGist Request Commented', 'actor'],\n ['$request_comment_edited', 'UserGist Request Comment Edited', 'actor'],\n ['$request_comment_deleted', 'UserGist Request Comment Deleted', 'affected_user'],\n]\n\nconst answerProperties: Readonly<Record<string, ReadonlyArray<string>>> = {\n ...ids(\n 'question_id',\n 'question_type',\n 'question_title',\n 'answer_format',\n 'answer_present',\n 'answer_numeric_value',\n 'answer_selection_count',\n 'answer_text_length',\n ),\n // These aliases are generated only by the trusted server response paths.\n // The API delivery boundary removes them from public SDK events before this\n // normalizer runs. The complete answer_value stays in UserGist; destinations\n // receive a value only for server-verified structured data.\n answer_value: ['__usergist_destination_answer_value'],\n answer_display_value: ['__usergist_destination_answer_display_value'],\n}\n\nexport const CORE_INTEGRATION_EVENTS: ReadonlyArray<CoreIntegrationEventDefinition> = [\n { key: '$app_open', name: 'UserGist App Opened', category: 'lifecycle', subjectRole: 'actor', properties: {} },\n { key: '$app_version_changed', name: 'UserGist App Version Changed', category: 'lifecycle', subjectRole: 'actor', properties: { ...ids('old_version', 'new_version') } },\n { key: USER_IDENTIFIED_EVENT_NAME, name: 'UserGist User Identified', category: 'identity', subjectRole: 'actor', required: true, properties: {} },\n { key: '$feedback_prompt_shown', name: 'UserGist Feedback Prompt Shown', category: 'feedback', subjectRole: 'actor', properties: { ...ids('prompt_id') } },\n { key: '$feedback_response', name: 'UserGist Feedback Response Submitted', category: 'feedback', subjectRole: 'actor', properties: { ...ids('response_id', 'prompt_id', 'prompt_name', 'dismissed', 'latency_ms', 'answer_count', 'feedback_types') } },\n { key: '$feedback_answer_submitted', name: 'UserGist Feedback Answer Submitted', category: 'feedback', subjectRole: 'actor', properties: { ...ids('response_id', 'prompt_id', 'prompt_name'), ...answerProperties } },\n { key: '$survey_started', name: 'UserGist Survey Started', category: 'surveys', subjectRole: 'actor', properties: { ...ids('campaign_id', 'survey_name', 'attempt_id', 'language', 'source') } },\n { key: '$survey_answer_submitted', name: 'UserGist Survey Answer Submitted', category: 'surveys', subjectRole: 'actor', properties: { ...ids('response_id', 'campaign_id', 'survey_name', 'attempt_id', 'language'), ...answerProperties } },\n { key: '$survey_completed', name: 'UserGist Survey Completed', category: 'surveys', subjectRole: 'actor', properties: { ...ids('campaign_id', 'survey_name', 'attempt_id', 'language', 'source', 'duration_ms') } },\n { key: '$survey_abandoned', name: 'UserGist Survey Abandoned', category: 'surveys', subjectRole: 'actor', properties: { ...ids('campaign_id', 'survey_name', 'attempt_id', 'language', 'source', 'duration_ms') } },\n { key: '$inapp_shown', name: 'UserGist In-App Message Shown', category: 'inapp', subjectRole: 'actor', properties: { ...ids('message_id') } },\n { key: '$inapp_dismissed', name: 'UserGist In-App Message Dismissed', category: 'inapp', subjectRole: 'actor', properties: { ...ids('message_id', 'dismiss_reason') } },\n { key: '$inapp_auto_dismissed', name: 'UserGist In-App Message Auto-Dismissed', category: 'inapp', subjectRole: 'actor', properties: { ...ids('message_id', 'dismiss_reason') } },\n { key: '$inapp_cta_clicked', name: 'UserGist In-App Message CTA Clicked', category: 'inapp', subjectRole: 'actor', properties: { ...ids('message_id', 'cta_id', 'cta_index'), action: ['action', 'cta_action'] } },\n ...pushEvents.map(([key, name]) => ({\n key,\n name,\n category: 'push' as const,\n subjectRole: 'actor' as const,\n properties: {\n ...ids('delivery_id', 'campaign_id', 'delivery_state', 'failure_code'),\n action_id: ['action_id', 'actionId', 'action_button', 'actionButton'],\n },\n })),\n ...requestEvents.map(([key, name, subjectRole]) => ({ key, name, category: 'requests' as const, subjectRole, properties: { ...ids('request_id', 'comment_id', 'source', 'old_status', 'new_status', 'deleted_by'), usergist_actor_type: ['usergist_actor_type', 'actor_type'] } })),\n]\n\nconst CORE_EVENT_BY_KEY = new Map(CORE_INTEGRATION_EVENTS.map((event) => [event.key, event]))\n\nexport function getCoreIntegrationEvent(key: string): CoreIntegrationEventDefinition | null {\n return CORE_EVENT_BY_KEY.get(key) ?? null\n}\n\nexport function sanitizeCoreIntegrationProperties(\n definition: CoreIntegrationEventDefinition,\n input: Readonly<Record<string, unknown>> | null | undefined,\n): Readonly<Record<string, EventPropertyValue>> {\n if (!input) return {}\n const output: Record<string, EventPropertyValue> = {}\n for (const [outputKey, aliases] of Object.entries(definition.properties)) {\n const alias = aliases.find((candidate) => Object.prototype.hasOwnProperty.call(input, candidate))\n if (!alias) continue\n const value = input[alias]\n if (typeof value === 'string') output[outputKey] = value.slice(0, 1024)\n else if (typeof value === 'number' && Number.isFinite(value)) output[outputKey] = value\n else if (typeof value === 'boolean' || value === null) output[outputKey] = value\n }\n return output\n}\n\nexport interface IntegrationSummary {\n readonly id: string\n readonly provider: IntegrationProvider\n readonly status: IntegrationStatus\n readonly region: IntegrationRegion\n readonly categories: ReadonlyArray<IntegrationCategory>\n readonly credentialHint: string | null\n readonly connectedAt: string | null\n readonly pausedAt: string | null\n readonly lastVerifiedAt: string | null\n readonly lastSuccessAt: string | null\n readonly lastFailureAt: string | null\n readonly lastErrorCode: string | null\n readonly lastErrorMessage: string | null\n}\n\nexport type ConnectIntegrationRequest =\n | { readonly provider: 'amplitude'; readonly apiKey: string; readonly region: 'us' | 'eu'; readonly categories: ReadonlyArray<IntegrationCategory> }\n | { readonly provider: 'mixpanel'; readonly projectToken: string; readonly region: 'us' | 'eu' | 'in'; readonly categories: ReadonlyArray<IntegrationCategory>; readonly identityMode: 'simplified' }\n\nexport interface UpdateIntegrationRequest {\n readonly categories: ReadonlyArray<IntegrationCategory>\n}\n\nexport interface IntegrationTestResult {\n readonly accepted: true\n readonly eventName: 'UserGist Integration Connected'\n readonly deviceId: string\n readonly acceptedAt: string\n}\n\nexport interface IntegrationDeliverySummary {\n readonly id: string\n readonly eventKey: string\n readonly eventName: string\n readonly status: IntegrationDeliveryStatus\n readonly identity: { readonly anonymousId: string; readonly externalId: string | null }\n readonly occurredAt: string\n readonly attempts: number\n readonly providerStatusCode: number | null\n readonly lastErrorMessage: string | null\n}\n\nexport interface IntegrationDeliveriesResponse {\n readonly items: ReadonlyArray<IntegrationDeliverySummary>\n readonly nextCursor: string | null\n}\n","/**\n * Canonical event names emitted by the push pillar. These land in the\n * events pipeline so segments can query them like any other event.\n */\nexport const PUSH_EVENTS = {\n SENT: '$push_sent',\n DELIVERED: '$push_delivered',\n DISPLAYED: '$push_displayed',\n RECEIVED: '$push_received',\n OPENED: '$push_opened',\n DISMISSED: '$push_dismissed',\n CLICKED: '$push_clicked',\n ACTION_CLICKED: '$push_action_clicked',\n BOUNCED: '$push_bounced',\n SILENT_ACK: '$push_silent_ack',\n} as const\n\nexport type PushEventName = (typeof PUSH_EVENTS)[keyof typeof PUSH_EVENTS]\n","/**\n * Runtime types shared by the React Native, iOS, and Android SDKs for\n * the \"under the hood\" push primitives:\n * • Silent reachability ping payloads\n * • Delivery beacon contract (delivered / displayed / dismissed)\n * • Channel registry (Android NotificationChannel + iOS category)\n * • App-open beacon\n */\n\nexport interface SilentPushPayload {\n readonly usergist_silent: '1'\n readonly usergist_ping_id: string\n}\n\nexport type AndroidImportance = 0 | 1 | 2 | 3 | 4\n\nexport type ChannelCategory =\n | 'transactional'\n | 'marketing'\n | 'silent'\n | 'digest'\n | 'alert'\n\nexport interface PushChannelDef {\n readonly app_id: string\n readonly channel_id: string\n readonly display_name: string\n readonly description: string | null\n readonly importance: AndroidImportance\n readonly default_sound: string | null\n readonly default_vibrate: boolean\n readonly default_badge: boolean\n readonly category: ChannelCategory\n}\n\nexport interface DeliveryBeacon {\n readonly deliveryId: string\n readonly occurredAt?: string\n readonly attemptId?: string\n readonly actionButton?: string\n}\n\nexport type DeliveryBeaconKind =\n | 'delivered'\n | 'displayed'\n | 'dismissed'\n\nexport interface SilentAck {\n readonly pingId: string\n readonly anonymousId: string\n readonly receivedAt?: string\n}\n\nexport interface RebindRequest {\n readonly anonymousId: string\n readonly externalId: string\n readonly token: string\n}\n\nexport interface AppOpenBeacon {\n readonly anonymousId: string\n readonly occurredAt?: string\n}\n\n/**\n * SDK-side recognized payload after parsing a server-sent push. Both\n * APNs (via NSE) and FCM (via FirebaseMessagingService) decode into\n * this shape so the cross-platform UI/behaviour layer can stay\n * platform-agnostic.\n */\nexport interface ParsedPushPayload {\n readonly campaignId: string\n readonly variantId: string\n readonly deliveryId: string\n readonly title: string\n readonly body: string\n readonly imageUrl: string | null\n readonly deepLink: string | null\n readonly language: string | null\n readonly actionButtons: ReadonlyArray<{\n readonly label: string\n readonly action: 'open_app' | 'deep_link' | 'url' | 'dismiss'\n readonly target?: string\n }>\n readonly androidChannelId: string | null\n readonly silent: boolean\n readonly silentPingId: string | null\n}\n\n/**\n * Helper used by the data-only Android branch and the iOS NSE to\n * detect a silent reachability ping.\n */\nexport function isSilentPushPayload(\n raw: Record<string, unknown> | null | undefined,\n): boolean {\n if (!raw) return false\n return raw.usergist_silent === '1' && typeof raw.usergist_ping_id === 'string'\n}\n","import type {\n Predicate,\n PredicateGroup,\n SegmentDsl,\n UserPropertyPredicate,\n EventCountPredicate,\n EventOccurredPredicate,\n} from '../types/segment-dsl.js'\nimport type {\n SerializedSegmentRules,\n UserPropertyRule,\n} from '../types/prompt.js'\n\nexport interface UserState {\n readonly properties: Readonly<Record<string, string | number | boolean | null | undefined>>\n // eventCounts: eventName -> map of windowDays -> count\n readonly eventCounts: Readonly<Record<string, Readonly<Record<number, number>>>>\n // lastEventAt: eventName -> ISO timestamp (most recent)\n readonly lastEventAt: Readonly<Record<string, string | undefined>>\n}\n\n/**\n * Evaluate a segment DSL against a user snapshot.\n *\n * @param now - Reference timestamp (ms since epoch) used for time-window\n * predicates. MUST be supplied explicitly so evaluation is deterministic\n * across processes (server trigger engine + client SDK), independent of\n * wall-clock skew. Defaults to `Date.now()` for backwards compatibility,\n * but callers that care about parity should pass the same `now` they pass\n * to the matching server-side call.\n */\nexport function evaluateSegment(\n dsl: SegmentDsl,\n user: UserState,\n now: number = Date.now(),\n): boolean {\n return evaluateGroup(dsl.root, user, now)\n}\n\nfunction evaluateGroup(group: PredicateGroup, user: UserState, now: number): boolean {\n if (group.predicates.length === 0) return true\n if (group.combinator === 'AND') {\n return group.predicates.every((p) => evaluateNode(p, user, now))\n }\n return group.predicates.some((p) => evaluateNode(p, user, now))\n}\n\nfunction evaluateNode(node: Predicate | PredicateGroup, user: UserState, now: number): boolean {\n if ('combinator' in node) return evaluateGroup(node, user, now)\n switch (node.kind) {\n case 'user_property':\n return evaluateUserProperty(node, user)\n case 'event_count':\n return evaluateEventCount(node, user)\n case 'event_occurred':\n return evaluateEventOccurred(node, user, now)\n }\n}\n\nfunction evaluateUserProperty(p: UserPropertyPredicate, user: UserState): boolean {\n const actual = user.properties[p.key]\n switch (p.op) {\n case 'exists':\n return actual !== undefined && actual !== null\n case 'not_exists':\n return actual === undefined || actual === null\n case 'eq':\n return actual === p.value\n case 'neq':\n return actual !== p.value\n case 'in':\n return Array.isArray(p.value) && actual != null && (p.value as ReadonlyArray<unknown>).includes(actual)\n case 'nin':\n return Array.isArray(p.value) && actual != null && !(p.value as ReadonlyArray<unknown>).includes(actual)\n case 'gt':\n return typeof actual === 'number' && typeof p.value === 'number' && actual > p.value\n case 'gte':\n return typeof actual === 'number' && typeof p.value === 'number' && actual >= p.value\n case 'lt':\n return typeof actual === 'number' && typeof p.value === 'number' && actual < p.value\n case 'lte':\n return typeof actual === 'number' && typeof p.value === 'number' && actual <= p.value\n case 'contains':\n return typeof actual === 'string' && typeof p.value === 'string' && actual.includes(p.value)\n case 'starts_with':\n return typeof actual === 'string' && typeof p.value === 'string' && actual.startsWith(p.value)\n }\n}\n\nfunction evaluateEventCount(p: EventCountPredicate, user: UserState): boolean {\n const eventBucket = user.eventCounts[p.eventName]\n const count = eventBucket?.[p.windowDays] ?? 0\n switch (p.op) {\n case 'eq': return count === p.count\n case 'gte': return count >= p.count\n case 'lte': return count <= p.count\n case 'gt': return count > p.count\n case 'lt': return count < p.count\n }\n}\n\nfunction evaluateEventOccurred(p: EventOccurredPredicate, user: UserState, now: number): boolean {\n const last = user.lastEventAt[p.eventName]\n if (p.ever) {\n if (!last) return false\n if (p.windowDays == null) return true\n const cutoff = now - p.windowDays * 86400_000\n return Date.parse(last) >= cutoff\n }\n if (!last) return true\n if (p.windowDays == null) return false\n const cutoff = now - p.windowDays * 86400_000\n return Date.parse(last) < cutoff\n}\n\n// ============================================================\n// SerializedSegmentRules → SegmentDsl bridge.\n//\n// The SDK ships armed triggers with a flattened rule set\n// (`SerializedSegmentRules`) for transport efficiency. We deliberately keep\n// only ONE evaluator (`evaluateSegment`) so that server and SDK paths cannot\n// diverge. The bridge converts the serialized form into an AND-combined\n// PredicateGroup and delegates to the same engine.\n// ============================================================\n\nexport function evaluateSerializedSegmentRules(\n rules: SerializedSegmentRules | null | undefined,\n user: UserState,\n now: number = Date.now(),\n): boolean {\n if (!rules) return true\n const dsl = serializedRulesToDsl(rules)\n return evaluateSegment(dsl, user, now)\n}\n\nexport function serializedRulesToDsl(rules: SerializedSegmentRules): SegmentDsl {\n const predicates: Predicate[] = []\n\n for (const rule of rules.userProperties ?? []) {\n predicates.push(userPropertyRuleToPredicate(rule))\n }\n for (const rule of rules.eventCounts ?? []) {\n predicates.push({\n kind: 'event_count',\n eventName: rule.eventName,\n op: rule.op,\n count: rule.count,\n windowDays: rule.windowDays,\n })\n }\n\n return {\n version: 1,\n root: { combinator: 'AND', predicates },\n }\n}\n\nfunction userPropertyRuleToPredicate(rule: UserPropertyRule): UserPropertyPredicate {\n // SerializedSegmentRules constrains operators to a subset; cast safely.\n return {\n kind: 'user_property',\n key: rule.key,\n op: rule.op,\n value: rule.value as UserPropertyPredicate['value'],\n }\n}\n","// ============================================================\n// Branch DSL evaluator — shared by SDKs and dashboard preview.\n// Given a flow, a current question, and the answer just recorded,\n// returns the next question id (or SURVEY_END_SENTINEL).\n// ============================================================\n\nimport {\n SURVEY_END_SENTINEL,\n type SurveyAnswerRecord,\n type SurveyAnswerValue,\n type SurveyBranch,\n type SurveyBranchCondition,\n type SurveyFlow,\n type SurveyQuestion,\n} from '../types/survey.js'\n\nexport function evaluateBranchCondition(\n cond: SurveyBranchCondition,\n answer: SurveyAnswerValue | undefined,\n): boolean {\n if (cond.op === 'answered') return answer !== undefined && answer !== null && answer !== ''\n if (cond.op === 'unanswered') return answer === undefined || answer === null || answer === ''\n if (answer === undefined || answer === null) return false\n\n switch (cond.op) {\n case 'eq':\n return answer === cond.value\n case 'neq':\n return answer !== cond.value\n case 'lt':\n return typeof answer === 'number' && typeof cond.value === 'number' && answer < cond.value\n case 'lte':\n return typeof answer === 'number' && typeof cond.value === 'number' && answer <= cond.value\n case 'gt':\n return typeof answer === 'number' && typeof cond.value === 'number' && answer > cond.value\n case 'gte':\n return typeof answer === 'number' && typeof cond.value === 'number' && answer >= cond.value\n case 'includes':\n return Array.isArray(answer) && (answer as ReadonlyArray<unknown>).includes(cond.value as never)\n case 'not_includes':\n return Array.isArray(answer) && !(answer as ReadonlyArray<unknown>).includes(cond.value as never)\n default:\n return false\n }\n}\n\nexport function nextQuestionId(\n flow: SurveyFlow,\n currentQuestionId: string,\n answers: SurveyAnswerRecord,\n): string | null {\n const branches = flow.branches.filter((b) => b.fromQuestionId === currentQuestionId)\n const answer = answers[currentQuestionId]\n for (const branch of branches) {\n if (evaluateBranchCondition(branch.condition, answer)) {\n if (branch.toQuestionId === SURVEY_END_SENTINEL) return null\n return branch.toQuestionId\n }\n }\n return defaultNext(flow, currentQuestionId)\n}\n\nfunction defaultNext(flow: SurveyFlow, currentQuestionId: string): string | null {\n const idx = flow.questions.findIndex((q) => q.id === currentQuestionId)\n if (idx < 0 || idx >= flow.questions.length - 1) return null\n const next = flow.questions[idx + 1]\n return next ? next.id : null\n}\n\nexport function findQuestion(\n flow: SurveyFlow,\n questionId: string,\n): SurveyQuestion | undefined {\n return flow.questions.find((q) => q.id === questionId)\n}\n\nexport function findQuestionIndex(flow: SurveyFlow, questionId: string): number {\n return flow.questions.findIndex((q) => q.id === questionId)\n}\n\n// Conservative progress estimate: count the current index + 1 over total. Branching\n// makes an exact number impossible, so we expose the worst-case fraction.\nexport function estimateProgress(flow: SurveyFlow, currentQuestionId: string | null): number {\n if (!currentQuestionId) return 1\n const idx = findQuestionIndex(flow, currentQuestionId)\n if (idx < 0) return 0\n return (idx + 1) / Math.max(1, flow.questions.length)\n}\n\n// Given a branch filter list, compute the *reachable* set of questions from a starting\n// point. Used by the composer to render \"dead question\" warnings.\nexport function reachableQuestions(\n flow: SurveyFlow,\n startId?: string,\n): ReadonlySet<string> {\n const start = startId ?? flow.startQuestionId\n const visited = new Set<string>()\n const stack: string[] = [start]\n while (stack.length > 0) {\n const id = stack.pop()\n if (id === undefined) continue\n if (visited.has(id)) continue\n visited.add(id)\n const outgoing = flow.branches.filter((b) => b.fromQuestionId === id)\n for (const b of outgoing) {\n if (b.toQuestionId !== SURVEY_END_SENTINEL) stack.push(b.toQuestionId)\n }\n const idx = flow.questions.findIndex((q) => q.id === id)\n if (idx >= 0 && idx < flow.questions.length - 1) {\n const next = flow.questions[idx + 1]\n if (next) stack.push(next.id)\n }\n }\n return visited\n}\n","import type { PeriodicFrequency } from '../types/campaign.js'\n\nexport interface PeriodicSchedule {\n readonly frequency: PeriodicFrequency\n readonly hourLocal: number\n readonly minuteLocal: number\n /** 0..6 (Sun=0). Required for `weekly`. */\n readonly weekday?: number\n /** 1..31. Required for `monthly`. */\n readonly dayOfMonth?: number\n /** IANA timezone the hour/minute are expressed in. Defaults to UTC. */\n readonly tz?: string\n}\n\n/**\n * Returns the next firing instant (as a Date in UTC) for a structured\n * periodic schedule, strictly after `now`.\n *\n * Pure / dependency-free. Used both server-side (push-scheduler `isDue`\n * check) and client-side (dashboard \"Next occurrence\" preview). Keep\n * deterministic for a given (schedule, now) tuple — no randomness.\n *\n * The walk is bounded — daily 2 iters, weekly 8, monthly 13 — so DST\n * gaps and short-month overflows can't loop forever.\n */\nexport function nextPeriodicFire(\n schedule: PeriodicSchedule,\n now: Date = new Date(),\n): Date {\n const tz = schedule.tz || 'UTC'\n const start = startCandidate(schedule, now, tz)\n return walkForward(start, schedule, now, tz)\n}\n\n/**\n * Minutes east of UTC for `tz` at instant `at`. Falls back to 0 (UTC)\n * for invalid input. Exported so server-side callers can share the\n * same offset math the periodic walker uses (avoids a separate\n * implementation in push-scheduler.ts).\n */\nexport function tzOffsetMinutes(at: Date, tz: string): number {\n if (tz === 'UTC') return 0\n try {\n const fmt = getFormatter(tz)\n const parts = fmt.formatToParts(at).reduce<Record<string, string>>((acc, p) => {\n if (p.type !== 'literal') acc[p.type] = p.value\n return acc\n }, {})\n const utc = Date.UTC(\n Number(parts.year),\n Number(parts.month) - 1,\n Number(parts.day),\n Number(parts.hour) === 24 ? 0 : Number(parts.hour),\n Number(parts.minute),\n Number(parts.second),\n )\n return Math.round((utc - at.getTime()) / 60_000)\n } catch {\n return 0\n }\n}\n\nfunction startCandidate(\n schedule: PeriodicSchedule,\n now: Date,\n tz: string,\n): Date {\n const localNow = wallClock(now, tz)\n const target = new Date(localNow)\n target.setHours(schedule.hourLocal, schedule.minuteLocal, 0, 0)\n return localToUtc(target, tz)\n}\n\nfunction walkForward(\n candidate: Date,\n schedule: PeriodicSchedule,\n now: Date,\n tz: string,\n): Date {\n let cursor = candidate\n const max = schedule.frequency === 'daily' ? 2 : schedule.frequency === 'weekly' ? 8 : 13\n for (let i = 0; i < max; i++) {\n const local = wallClock(cursor, tz)\n if (matchesFrequency(local, schedule) && cursor.getTime() > now.getTime()) {\n return cursor\n }\n cursor = step(cursor, local, schedule, tz)\n }\n return cursor\n}\n\nfunction matchesFrequency(local: Date, schedule: PeriodicSchedule): boolean {\n if (schedule.frequency === 'daily') return true\n if (schedule.frequency === 'weekly') {\n return schedule.weekday === undefined || local.getDay() === schedule.weekday\n }\n return schedule.dayOfMonth === undefined || local.getDate() === schedule.dayOfMonth\n}\n\nfunction step(\n cursor: Date,\n cursorLocal: Date,\n schedule: PeriodicSchedule,\n tz: string,\n): Date {\n if (schedule.frequency === 'daily' || schedule.frequency === 'weekly') {\n return addDays(cursor, 1)\n }\n // Monthly: jump to the next month at the same dayOfMonth (or last day if shorter).\n const next = new Date(cursorLocal)\n next.setMonth(next.getMonth() + 1)\n if (schedule.dayOfMonth !== undefined) {\n const lastDay = lastDayOfMonth(next.getFullYear(), next.getMonth())\n next.setDate(Math.min(schedule.dayOfMonth, lastDay))\n }\n next.setHours(schedule.hourLocal, schedule.minuteLocal, 0, 0)\n return localToUtc(next, tz)\n}\n\nfunction addDays(d: Date, days: number): Date {\n const next = new Date(d.getTime())\n next.setDate(next.getDate() + days)\n return next\n}\n\nfunction lastDayOfMonth(year: number, monthIndex: number): number {\n return new Date(year, monthIndex + 1, 0).getDate()\n}\n\n/** Returns the Date adjusted so its `getX()` methods read in `tz`'s wall clock. */\nfunction wallClock(d: Date, tz: string): Date {\n const offsetMin = tzOffsetMinutes(d, tz)\n return new Date(d.getTime() + offsetMin * 60_000)\n}\n\n/** Inverse of `wallClock` — given a Date whose getX reads in `tz`, return UTC. */\nfunction localToUtc(localView: Date, tz: string): Date {\n const offsetMin = tzOffsetMinutes(localView, tz)\n return new Date(localView.getTime() - offsetMin * 60_000)\n}\n\n// `Intl.DateTimeFormat` construction dominates this module's cost (~100 µs\n// per ctor). The scheduler can call `nextPeriodicFire` thousands of times\n// per tick across many users, so we cache one formatter per tz at module\n// scope. Map is keyed by IANA name and lookups are O(1). Safe to share —\n// formatter instances are stateless across calls.\nconst FORMATTER_CACHE = /* @__PURE__ */ new Map<string, Intl.DateTimeFormat>()\n\nfunction getFormatter(tz: string): Intl.DateTimeFormat {\n const cached = FORMATTER_CACHE.get(tz)\n if (cached) return cached\n const fmt = new Intl.DateTimeFormat('en-US', {\n timeZone: tz,\n hour12: false,\n year: 'numeric',\n month: '2-digit',\n day: '2-digit',\n hour: '2-digit',\n minute: '2-digit',\n second: '2-digit',\n })\n FORMATTER_CACHE.set(tz, fmt)\n return fmt\n}\n"]}
|
package/mobile.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@usergist/sdk-core",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Shared types and utilities across the userGist feedback platform",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"homepage": "https://usergist.com/docs/sdks/core",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/Future-Picnic/usergist-js.git",
|
|
10
|
+
"directory": "packages/sdk-core"
|
|
11
|
+
},
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/Future-Picnic/usergist-js/issues"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"usergist",
|
|
17
|
+
"mobile-sdk",
|
|
18
|
+
"targeting",
|
|
19
|
+
"surveys"
|
|
20
|
+
],
|
|
21
|
+
"type": "module",
|
|
22
|
+
"main": "./dist/index.cjs",
|
|
23
|
+
"module": "./dist/index.js",
|
|
24
|
+
"types": "./dist/index.d.ts",
|
|
25
|
+
"exports": {
|
|
26
|
+
".": {
|
|
27
|
+
"types": "./dist/index.d.ts",
|
|
28
|
+
"import": "./dist/index.js",
|
|
29
|
+
"require": "./dist/index.cjs"
|
|
30
|
+
},
|
|
31
|
+
"./mobile": {
|
|
32
|
+
"types": "./dist/mobile.d.ts",
|
|
33
|
+
"import": "./dist/mobile.js",
|
|
34
|
+
"require": "./dist/mobile.cjs"
|
|
35
|
+
},
|
|
36
|
+
"./package.json": "./package.json"
|
|
37
|
+
},
|
|
38
|
+
"sideEffects": false,
|
|
39
|
+
"files": [
|
|
40
|
+
"dist",
|
|
41
|
+
"mobile.js",
|
|
42
|
+
"README.md",
|
|
43
|
+
"CHANGELOG.md",
|
|
44
|
+
"LICENSE"
|
|
45
|
+
],
|
|
46
|
+
"dependencies": {
|
|
47
|
+
"zod": "^3.23.8"
|
|
48
|
+
},
|
|
49
|
+
"publishConfig": {
|
|
50
|
+
"access": "public"
|
|
51
|
+
},
|
|
52
|
+
"devDependencies": {
|
|
53
|
+
"tsup": "^8.3.0",
|
|
54
|
+
"typescript": "^5.5.4",
|
|
55
|
+
"vitest": "^2.1.0"
|
|
56
|
+
},
|
|
57
|
+
"scripts": {
|
|
58
|
+
"build": "tsup",
|
|
59
|
+
"dev": "tsup --watch",
|
|
60
|
+
"typecheck": "tsc --noEmit",
|
|
61
|
+
"test": "vitest run",
|
|
62
|
+
"test:watch": "vitest"
|
|
63
|
+
}
|
|
64
|
+
}
|