@paceful/sdk 1.0.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.mjs ADDED
@@ -0,0 +1,1938 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
6
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
7
+ }) : x)(function(x) {
8
+ if (typeof require !== "undefined") return require.apply(this, arguments);
9
+ throw Error('Dynamic require of "' + x + '" is not supported');
10
+ });
11
+ var __esm = (fn, res) => function __init() {
12
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
13
+ };
14
+ var __export = (target, all) => {
15
+ for (var name in all)
16
+ __defProp(target, name, { get: all[name], enumerable: true });
17
+ };
18
+ var __copyProps = (to, from, except, desc) => {
19
+ if (from && typeof from === "object" || typeof from === "function") {
20
+ for (let key of __getOwnPropNames(from))
21
+ if (!__hasOwnProp.call(to, key) && key !== except)
22
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
23
+ }
24
+ return to;
25
+ };
26
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
27
+
28
+ // src/widgets/PacefulProvider.tsx
29
+ var PacefulProvider_exports = {};
30
+ __export(PacefulProvider_exports, {
31
+ PacefulProvider: () => PacefulProvider,
32
+ usePaceful: () => usePaceful
33
+ });
34
+ import React, { createContext, useContext, useMemo } from "react";
35
+ function usePaceful() {
36
+ const ctx = useContext(PacefulContext);
37
+ if (!ctx) throw new Error("Wrap your component tree with <PacefulProvider>");
38
+ return ctx;
39
+ }
40
+ function PacefulProvider({ apiKey, userId, baseUrl, children }) {
41
+ const value = useMemo(() => ({
42
+ apiKey,
43
+ userId,
44
+ baseUrl: baseUrl || "https://paceful-app.vercel.app/api/v1/partner"
45
+ }), [apiKey, userId, baseUrl]);
46
+ return React.createElement(PacefulContext.Provider, { value }, children);
47
+ }
48
+ var PacefulContext;
49
+ var init_PacefulProvider = __esm({
50
+ "src/widgets/PacefulProvider.tsx"() {
51
+ "use strict";
52
+ PacefulContext = createContext(null);
53
+ }
54
+ });
55
+
56
+ // src/utils/errors.ts
57
+ var PacefulError = class _PacefulError extends Error {
58
+ constructor(message, code, statusCode, details) {
59
+ super(message);
60
+ this.name = "PacefulError";
61
+ this.code = code;
62
+ this.statusCode = statusCode;
63
+ this.details = details;
64
+ if (Error.captureStackTrace) {
65
+ Error.captureStackTrace(this, _PacefulError);
66
+ }
67
+ }
68
+ };
69
+ var PacefulAuthError = class extends PacefulError {
70
+ constructor(message = "Invalid or expired API key") {
71
+ super(message, "UNAUTHORIZED", 401);
72
+ this.name = "PacefulAuthError";
73
+ }
74
+ };
75
+ var PacefulRateLimitError = class extends PacefulError {
76
+ constructor(retryAfter = 3600) {
77
+ super("Rate limit exceeded", "RATE_LIMITED", 429);
78
+ this.name = "PacefulRateLimitError";
79
+ this.retryAfter = retryAfter;
80
+ }
81
+ };
82
+ var PacefulNotFoundError = class extends PacefulError {
83
+ constructor(resource = "Resource") {
84
+ super(`${resource} not found`, "NOT_FOUND", 404);
85
+ this.name = "PacefulNotFoundError";
86
+ }
87
+ };
88
+ var PacefulValidationError = class extends PacefulError {
89
+ constructor(message, details) {
90
+ super(message, "BAD_REQUEST", 400, details);
91
+ this.name = "PacefulValidationError";
92
+ }
93
+ };
94
+ var PacefulNetworkError = class extends PacefulError {
95
+ constructor(message = "Network request failed") {
96
+ super(message, "NETWORK_ERROR");
97
+ this.name = "PacefulNetworkError";
98
+ }
99
+ };
100
+ function parseApiError(statusCode, body, headers) {
101
+ const message = body.error?.message || body.message || "Unknown error";
102
+ const code = body.error?.code || "UNKNOWN_ERROR";
103
+ switch (statusCode) {
104
+ case 401:
105
+ return new PacefulAuthError(message);
106
+ case 404:
107
+ return new PacefulNotFoundError(message);
108
+ case 429: {
109
+ const retryAfter = headers?.get("Retry-After");
110
+ return new PacefulRateLimitError(
111
+ retryAfter ? parseInt(retryAfter, 10) : 3600
112
+ );
113
+ }
114
+ case 400:
115
+ return new PacefulValidationError(message);
116
+ default:
117
+ return new PacefulError(message, code, statusCode);
118
+ }
119
+ }
120
+
121
+ // src/utils/http.ts
122
+ var DEFAULT_BASE_URL = "https://api.paceful.app";
123
+ var DEFAULT_TIMEOUT = 3e4;
124
+ var DEFAULT_RETRIES = 3;
125
+ var HttpClient = class {
126
+ constructor(config) {
127
+ if (!config.apiKey) {
128
+ throw new PacefulError("API key is required", "CONFIGURATION_ERROR");
129
+ }
130
+ this.apiKey = config.apiKey;
131
+ this.baseUrl = (config.baseUrl || DEFAULT_BASE_URL).replace(/\/$/, "");
132
+ this.timeout = config.timeout || DEFAULT_TIMEOUT;
133
+ this.maxRetries = config.retries ?? DEFAULT_RETRIES;
134
+ }
135
+ async request(options) {
136
+ const { method, path, body, query } = options;
137
+ let url = `${this.baseUrl}${path}`;
138
+ if (query) {
139
+ const params = new URLSearchParams();
140
+ for (const [key, value] of Object.entries(query)) {
141
+ if (value !== void 0) {
142
+ params.append(key, String(value));
143
+ }
144
+ }
145
+ const queryString = params.toString();
146
+ if (queryString) {
147
+ url += `?${queryString}`;
148
+ }
149
+ }
150
+ const headers = {
151
+ "Content-Type": "application/json",
152
+ "X-API-Key": this.apiKey,
153
+ "User-Agent": "@paceful/sdk/1.0.0"
154
+ };
155
+ const fetchOptions = {
156
+ method,
157
+ headers
158
+ };
159
+ if (body && method !== "GET") {
160
+ fetchOptions.body = JSON.stringify(body);
161
+ }
162
+ let lastError = null;
163
+ for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
164
+ try {
165
+ const controller = new AbortController();
166
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
167
+ fetchOptions.signal = controller.signal;
168
+ const response = await fetch(url, fetchOptions);
169
+ clearTimeout(timeoutId);
170
+ const responseBody = await response.json();
171
+ if (!response.ok) {
172
+ const error = parseApiError(
173
+ response.status,
174
+ responseBody,
175
+ response.headers
176
+ );
177
+ if (response.status < 500 && response.status !== 429) {
178
+ throw error;
179
+ }
180
+ lastError = error;
181
+ if (attempt < this.maxRetries) {
182
+ const backoffMs = Math.min(1e3 * Math.pow(2, attempt), 1e4);
183
+ await this.sleep(backoffMs);
184
+ continue;
185
+ }
186
+ throw error;
187
+ }
188
+ if (!responseBody.success) {
189
+ throw new PacefulError(
190
+ responseBody.error?.message || "Request failed",
191
+ responseBody.error?.code || "UNKNOWN_ERROR"
192
+ );
193
+ }
194
+ return responseBody.data;
195
+ } catch (error) {
196
+ if (error instanceof PacefulError) {
197
+ throw error;
198
+ }
199
+ if (error instanceof Error) {
200
+ if (error.name === "AbortError") {
201
+ lastError = new PacefulNetworkError("Request timed out");
202
+ } else {
203
+ lastError = new PacefulNetworkError(error.message);
204
+ }
205
+ }
206
+ if (attempt < this.maxRetries) {
207
+ const backoffMs = Math.min(1e3 * Math.pow(2, attempt), 1e4);
208
+ await this.sleep(backoffMs);
209
+ continue;
210
+ }
211
+ throw lastError || new PacefulNetworkError();
212
+ }
213
+ }
214
+ throw lastError || new PacefulNetworkError();
215
+ }
216
+ sleep(ms) {
217
+ return new Promise((resolve) => setTimeout(resolve, ms));
218
+ }
219
+ // Convenience methods
220
+ async get(path, query) {
221
+ return this.request({ method: "GET", path, query });
222
+ }
223
+ async post(path, body) {
224
+ return this.request({ method: "POST", path, body });
225
+ }
226
+ async put(path, body) {
227
+ return this.request({ method: "PUT", path, body });
228
+ }
229
+ async patch(path, body) {
230
+ return this.request({ method: "PATCH", path, body });
231
+ }
232
+ async delete(path) {
233
+ return this.request({ method: "DELETE", path });
234
+ }
235
+ };
236
+
237
+ // src/modules/users.ts
238
+ var Users = class {
239
+ constructor(http) {
240
+ this.http = http;
241
+ }
242
+ /**
243
+ * Register a new user or update existing user metadata
244
+ *
245
+ * @param params - User registration parameters
246
+ * @returns The registered or updated user
247
+ *
248
+ * @example
249
+ * ```typescript
250
+ * const user = await paceful.users.register({
251
+ * externalId: 'user_123',
252
+ * email: 'user@example.com',
253
+ * metadata: { plan: 'premium' }
254
+ * });
255
+ * ```
256
+ */
257
+ async register(params) {
258
+ return this.http.post("/api/v1/partner/users", {
259
+ externalId: params.externalId,
260
+ email: params.email,
261
+ metadata: params.metadata
262
+ });
263
+ }
264
+ /**
265
+ * Get a user by their external ID
266
+ *
267
+ * @param externalId - Your system's user identifier
268
+ * @returns The user if found
269
+ *
270
+ * @example
271
+ * ```typescript
272
+ * const user = await paceful.users.get('user_123');
273
+ * ```
274
+ */
275
+ async get(externalId) {
276
+ return this.http.get(`/api/v1/partner/users/${externalId}`);
277
+ }
278
+ /**
279
+ * Update a user's metadata
280
+ *
281
+ * @param externalId - Your system's user identifier
282
+ * @param metadata - New metadata to merge with existing
283
+ * @returns The updated user
284
+ *
285
+ * @example
286
+ * ```typescript
287
+ * const user = await paceful.users.update('user_123', {
288
+ * metadata: { plan: 'enterprise' }
289
+ * });
290
+ * ```
291
+ */
292
+ async update(externalId, params) {
293
+ return this.http.patch(`/api/v1/partner/users/${externalId}`, params);
294
+ }
295
+ /**
296
+ * List all users for this partner
297
+ *
298
+ * @param params - Pagination parameters
299
+ * @returns Paginated list of users
300
+ *
301
+ * @example
302
+ * ```typescript
303
+ * const { items, total, hasMore } = await paceful.users.list({ limit: 50 });
304
+ * ```
305
+ */
306
+ async list(params) {
307
+ return this.http.get("/api/v1/partner/users", {
308
+ limit: params?.limit,
309
+ cursor: params?.cursor
310
+ });
311
+ }
312
+ /**
313
+ * Delete a user and all their data
314
+ *
315
+ * @param externalId - Your system's user identifier
316
+ *
317
+ * @example
318
+ * ```typescript
319
+ * await paceful.users.delete('user_123');
320
+ * ```
321
+ */
322
+ async delete(externalId) {
323
+ await this.http.delete(`/api/v1/partner/users/${externalId}`);
324
+ }
325
+ };
326
+
327
+ // src/modules/mood.ts
328
+ var Mood = class {
329
+ constructor(http) {
330
+ this.http = http;
331
+ }
332
+ /**
333
+ * Log a mood entry for a user
334
+ *
335
+ * @param params - Mood log parameters
336
+ * @returns The created mood entry
337
+ *
338
+ * @example
339
+ * ```typescript
340
+ * const entry = await paceful.mood.log({
341
+ * externalId: 'user_123',
342
+ * mood: 4,
343
+ * note: 'Feeling productive today',
344
+ * factors: ['work', 'exercise']
345
+ * });
346
+ * ```
347
+ */
348
+ async log(params) {
349
+ return this.http.post("/api/v1/partner/mood", {
350
+ externalId: params.externalId,
351
+ mood: params.mood,
352
+ note: params.note,
353
+ factors: params.factors,
354
+ timestamp: params.timestamp
355
+ });
356
+ }
357
+ /**
358
+ * Get mood history for a user
359
+ *
360
+ * @param params - History query parameters
361
+ * @returns List of mood entries
362
+ *
363
+ * @example
364
+ * ```typescript
365
+ * const history = await paceful.mood.history({
366
+ * externalId: 'user_123',
367
+ * startDate: '2024-01-01',
368
+ * limit: 30
369
+ * });
370
+ * ```
371
+ */
372
+ async history(params) {
373
+ return this.http.get(`/api/v1/partner/mood/${params.externalId}/history`, {
374
+ startDate: params.startDate,
375
+ endDate: params.endDate,
376
+ limit: params.limit
377
+ });
378
+ }
379
+ /**
380
+ * Get the latest mood entry for a user
381
+ *
382
+ * @param externalId - Your system's user identifier
383
+ * @returns The most recent mood entry or null
384
+ *
385
+ * @example
386
+ * ```typescript
387
+ * const latest = await paceful.mood.latest('user_123');
388
+ * if (latest) {
389
+ * console.log(`Last mood: ${latest.mood}`);
390
+ * }
391
+ * ```
392
+ */
393
+ async latest(externalId) {
394
+ return this.http.get(`/api/v1/partner/mood/${externalId}/latest`);
395
+ }
396
+ /**
397
+ * Get mood statistics for a user over a time period
398
+ *
399
+ * @param externalId - Your system's user identifier
400
+ * @param period - Time period ('7d', '30d', '90d', 'all')
401
+ * @returns Mood statistics
402
+ *
403
+ * @example
404
+ * ```typescript
405
+ * const stats = await paceful.mood.stats('user_123', '30d');
406
+ * console.log(`Average mood: ${stats.average}`);
407
+ * ```
408
+ */
409
+ async stats(externalId, period = "30d") {
410
+ return this.http.get(`/api/v1/partner/mood/${externalId}/stats`, { period });
411
+ }
412
+ };
413
+
414
+ // src/modules/journal.ts
415
+ var Journal = class {
416
+ constructor(http) {
417
+ this.http = http;
418
+ }
419
+ /**
420
+ * Create a journal entry for a user
421
+ *
422
+ * @param params - Journal entry parameters
423
+ * @returns The created journal entry with AI analysis
424
+ *
425
+ * @example
426
+ * ```typescript
427
+ * const entry = await paceful.journal.create({
428
+ * externalId: 'user_123',
429
+ * content: 'Today I reflected on my progress...',
430
+ * mood: 4
431
+ * });
432
+ *
433
+ * console.log('Themes:', entry.themes);
434
+ * console.log('Sentiment:', entry.sentimentScore);
435
+ * ```
436
+ */
437
+ async create(params) {
438
+ return this.http.post("/api/v1/partner/journal", {
439
+ externalId: params.externalId,
440
+ content: params.content,
441
+ promptId: params.promptId,
442
+ mood: params.mood
443
+ });
444
+ }
445
+ /**
446
+ * Get journal history for a user
447
+ *
448
+ * @param params - History query parameters
449
+ * @returns List of journal entries
450
+ *
451
+ * @example
452
+ * ```typescript
453
+ * const entries = await paceful.journal.history({
454
+ * externalId: 'user_123',
455
+ * limit: 10
456
+ * });
457
+ * ```
458
+ */
459
+ async history(params) {
460
+ return this.http.get(`/api/v1/partner/journal/${params.externalId}/history`, {
461
+ startDate: params.startDate,
462
+ endDate: params.endDate,
463
+ limit: params.limit
464
+ });
465
+ }
466
+ /**
467
+ * Get a specific journal entry
468
+ *
469
+ * @param externalId - Your system's user identifier
470
+ * @param entryId - The journal entry ID
471
+ * @returns The journal entry
472
+ *
473
+ * @example
474
+ * ```typescript
475
+ * const entry = await paceful.journal.get('user_123', 'entry_abc');
476
+ * ```
477
+ */
478
+ async get(externalId, entryId) {
479
+ return this.http.get(`/api/v1/partner/journal/${externalId}/${entryId}`);
480
+ }
481
+ /**
482
+ * Get available journal prompts
483
+ *
484
+ * @returns List of prompts categorized by theme
485
+ *
486
+ * @example
487
+ * ```typescript
488
+ * const prompts = await paceful.journal.prompts();
489
+ * const gratitudePrompts = prompts.gratitude;
490
+ * ```
491
+ */
492
+ async prompts() {
493
+ return this.http.get("/api/v1/partner/journal/prompts");
494
+ }
495
+ /**
496
+ * Get journal statistics for a user
497
+ *
498
+ * @param externalId - Your system's user identifier
499
+ * @param period - Time period ('7d', '30d', '90d', 'all')
500
+ * @returns Journal statistics
501
+ *
502
+ * @example
503
+ * ```typescript
504
+ * const stats = await paceful.journal.stats('user_123', '30d');
505
+ * console.log(`Entries this month: ${stats.count}`);
506
+ * ```
507
+ */
508
+ async stats(externalId, period = "30d") {
509
+ return this.http.get(`/api/v1/partner/journal/${externalId}/stats`, { period });
510
+ }
511
+ };
512
+
513
+ // src/modules/ers.ts
514
+ var ERS = class {
515
+ constructor(http) {
516
+ this.http = http;
517
+ }
518
+ /**
519
+ * Get the current ERS score for a user
520
+ * Returns cached score if recent (< 24 hours), otherwise calculates fresh
521
+ *
522
+ * @param externalId - Your system's user identifier
523
+ * @returns The user's ERS score with trend data
524
+ *
525
+ * @example
526
+ * ```typescript
527
+ * const ers = await paceful.ers.get('user_123');
528
+ *
529
+ * console.log(`ERS Score: ${ers.ersScore}`);
530
+ * console.log(`Stage: ${ers.stage}`);
531
+ * console.log(`Trend: ${ers.trend?.direction}`);
532
+ * ```
533
+ */
534
+ async get(externalId) {
535
+ return this.http.get(`/api/v1/partner/ers/${externalId}`);
536
+ }
537
+ /**
538
+ * Force a fresh ERS calculation for a user
539
+ * Useful after significant user activity
540
+ *
541
+ * @param externalId - Your system's user identifier
542
+ * @returns Fresh calculation results with change data
543
+ *
544
+ * @example
545
+ * ```typescript
546
+ * const result = await paceful.ers.calculate('user_123');
547
+ *
548
+ * if (result.change !== null) {
549
+ * console.log(`Score changed by ${result.change} points`);
550
+ * }
551
+ * ```
552
+ */
553
+ async calculate(externalId) {
554
+ return this.http.post("/api/v1/partner/ers/calculate", {
555
+ externalId
556
+ });
557
+ }
558
+ /**
559
+ * Get ERS scores for multiple users in a single request
560
+ * Maximum 50 users per request
561
+ *
562
+ * @param externalIds - Array of your system's user identifiers
563
+ * @returns Batch results with scores for each user
564
+ *
565
+ * @example
566
+ * ```typescript
567
+ * const batch = await paceful.ers.batch(['user_1', 'user_2', 'user_3']);
568
+ *
569
+ * for (const result of batch.results) {
570
+ * console.log(`${result.externalId}: ${result.ersScore}`);
571
+ * }
572
+ * ```
573
+ */
574
+ async batch(externalIds) {
575
+ return this.http.post("/api/v1/partner/ers/batch", {
576
+ externalIds
577
+ });
578
+ }
579
+ /**
580
+ * Get ERS score history for a user
581
+ *
582
+ * @param externalId - Your system's user identifier
583
+ * @param params - Query parameters
584
+ * @returns Historical ERS scores
585
+ *
586
+ * @example
587
+ * ```typescript
588
+ * const history = await paceful.ers.history('user_123', {
589
+ * period: '30d',
590
+ * granularity: 'daily'
591
+ * });
592
+ * ```
593
+ */
594
+ async history(externalId, params) {
595
+ return this.http.get(`/api/v1/partner/ers/${externalId}/history`, {
596
+ period: params?.period,
597
+ granularity: params?.granularity
598
+ });
599
+ }
600
+ /**
601
+ * Set up alerts for ERS threshold crossings
602
+ *
603
+ * @param params - Alert configuration
604
+ * @returns The created alert configuration
605
+ *
606
+ * @example
607
+ * ```typescript
608
+ * await paceful.ers.setThresholdAlert({
609
+ * externalId: 'user_123',
610
+ * threshold: 40,
611
+ * direction: 'below',
612
+ * webhookUrl: 'https://yourapp.com/alerts'
613
+ * });
614
+ * ```
615
+ */
616
+ async setThresholdAlert(params) {
617
+ return this.http.post("/api/v1/partner/ers/alerts", params);
618
+ }
619
+ };
620
+
621
+ // src/modules/analytics.ts
622
+ var Analytics = class {
623
+ constructor(http) {
624
+ this.http = http;
625
+ }
626
+ /**
627
+ * Get aggregate analytics summary for all your users
628
+ *
629
+ * @param period - Time period for analytics ('7d', '30d', '90d', 'all')
630
+ * @returns Aggregate analytics summary
631
+ *
632
+ * @example
633
+ * ```typescript
634
+ * const summary = await paceful.analytics.summary('30d');
635
+ *
636
+ * console.log(`Total users: ${summary.totalUsers}`);
637
+ * console.log(`Average ERS: ${summary.averageErs}`);
638
+ * console.log(`Healing stage: ${summary.stageDistribution.healing * 100}%`);
639
+ * ```
640
+ */
641
+ async summary(period = "30d") {
642
+ return this.http.get("/api/v1/partner/analytics/summary", {
643
+ period
644
+ });
645
+ }
646
+ /**
647
+ * Get engagement metrics over time
648
+ *
649
+ * @param params - Query parameters
650
+ * @returns Time series engagement data
651
+ *
652
+ * @example
653
+ * ```typescript
654
+ * const engagement = await paceful.analytics.engagement({
655
+ * period: '30d',
656
+ * granularity: 'daily'
657
+ * });
658
+ *
659
+ * for (const point of engagement.dataPoints) {
660
+ * console.log(`${point.date}: ${point.activeUsers} active users`);
661
+ * }
662
+ * ```
663
+ */
664
+ async engagement(params) {
665
+ return this.http.get("/api/v1/partner/analytics/engagement", {
666
+ period: params?.period,
667
+ granularity: params?.granularity
668
+ });
669
+ }
670
+ /**
671
+ * Get ERS distribution across all users
672
+ *
673
+ * @param period - Time period for analytics
674
+ * @returns ERS distribution data
675
+ *
676
+ * @example
677
+ * ```typescript
678
+ * const distribution = await paceful.analytics.ersDistribution('30d');
679
+ *
680
+ * console.log('Score ranges:');
681
+ * for (const bucket of distribution.buckets) {
682
+ * console.log(`${bucket.range}: ${bucket.count} users`);
683
+ * }
684
+ * ```
685
+ */
686
+ async ersDistribution(period = "30d") {
687
+ return this.http.get("/api/v1/partner/analytics/ers-distribution", {
688
+ period
689
+ });
690
+ }
691
+ /**
692
+ * Get retention metrics
693
+ *
694
+ * @param period - Time period for analytics
695
+ * @returns Retention and churn data
696
+ *
697
+ * @example
698
+ * ```typescript
699
+ * const retention = await paceful.analytics.retention('30d');
700
+ *
701
+ * console.log(`Day 7 retention: ${retention.day7}%`);
702
+ * console.log(`Day 30 retention: ${retention.day30}%`);
703
+ * ```
704
+ */
705
+ async retention(period = "30d") {
706
+ return this.http.get("/api/v1/partner/analytics/retention", { period });
707
+ }
708
+ /**
709
+ * Export analytics data as CSV
710
+ *
711
+ * @param params - Export parameters
712
+ * @returns Download URL for the CSV
713
+ *
714
+ * @example
715
+ * ```typescript
716
+ * const { downloadUrl } = await paceful.analytics.export({
717
+ * type: 'user_summary',
718
+ * period: '30d'
719
+ * });
720
+ * ```
721
+ */
722
+ async export(params) {
723
+ return this.http.post("/api/v1/partner/analytics/export", params);
724
+ }
725
+ };
726
+
727
+ // src/modules/webhooks.ts
728
+ var Webhooks = class {
729
+ constructor(http) {
730
+ this.http = http;
731
+ }
732
+ /**
733
+ * Register a webhook endpoint for receiving events
734
+ * Updates existing webhook if same URL already registered
735
+ *
736
+ * @param params - Webhook configuration
737
+ * @returns Webhook registration details including secret
738
+ *
739
+ * @example
740
+ * ```typescript
741
+ * const webhook = await paceful.webhooks.register({
742
+ * url: 'https://yourapp.com/webhooks/paceful',
743
+ * events: ['ers.stage_changed', 'mood.critical']
744
+ * });
745
+ *
746
+ * // Store the secret securely for signature verification
747
+ * console.log('Webhook secret:', webhook.secret);
748
+ * ```
749
+ */
750
+ async register(params) {
751
+ return this.http.post("/api/v1/partner/webhooks/register", {
752
+ url: params.url,
753
+ events: params.events
754
+ });
755
+ }
756
+ /**
757
+ * List all registered webhooks
758
+ *
759
+ * @returns Array of webhook configurations
760
+ *
761
+ * @example
762
+ * ```typescript
763
+ * const webhooks = await paceful.webhooks.list();
764
+ *
765
+ * for (const webhook of webhooks) {
766
+ * console.log(`${webhook.url}: ${webhook.events.join(', ')}`);
767
+ * }
768
+ * ```
769
+ */
770
+ async list() {
771
+ return this.http.get("/api/v1/partner/webhooks");
772
+ }
773
+ /**
774
+ * Get a specific webhook by ID
775
+ *
776
+ * @param webhookId - The webhook ID
777
+ * @returns Webhook configuration
778
+ *
779
+ * @example
780
+ * ```typescript
781
+ * const webhook = await paceful.webhooks.get('webhook_abc123');
782
+ * ```
783
+ */
784
+ async get(webhookId) {
785
+ return this.http.get(`/api/v1/partner/webhooks/${webhookId}`);
786
+ }
787
+ /**
788
+ * Update a webhook's configuration
789
+ *
790
+ * @param webhookId - The webhook ID
791
+ * @param params - Updated configuration
792
+ * @returns Updated webhook
793
+ *
794
+ * @example
795
+ * ```typescript
796
+ * await paceful.webhooks.update('webhook_abc123', {
797
+ * events: ['ers.stage_changed', 'mood.critical', 'journal.created']
798
+ * });
799
+ * ```
800
+ */
801
+ async update(webhookId, params) {
802
+ return this.http.patch(`/api/v1/partner/webhooks/${webhookId}`, params);
803
+ }
804
+ /**
805
+ * Delete a webhook
806
+ *
807
+ * @param webhookId - The webhook ID
808
+ *
809
+ * @example
810
+ * ```typescript
811
+ * await paceful.webhooks.delete('webhook_abc123');
812
+ * ```
813
+ */
814
+ async delete(webhookId) {
815
+ await this.http.delete(`/api/v1/partner/webhooks/${webhookId}`);
816
+ }
817
+ /**
818
+ * Test a webhook by sending a test event
819
+ *
820
+ * @param webhookId - The webhook ID
821
+ * @returns Test result
822
+ *
823
+ * @example
824
+ * ```typescript
825
+ * const result = await paceful.webhooks.test('webhook_abc123');
826
+ *
827
+ * if (result.success) {
828
+ * console.log('Webhook is working!');
829
+ * } else {
830
+ * console.error('Test failed:', result.error);
831
+ * }
832
+ * ```
833
+ */
834
+ async test(webhookId) {
835
+ return this.http.post(`/api/v1/partner/webhooks/${webhookId}/test`);
836
+ }
837
+ /**
838
+ * Get delivery history for a webhook
839
+ *
840
+ * @param webhookId - The webhook ID
841
+ * @param params - Query parameters
842
+ * @returns Delivery history
843
+ *
844
+ * @example
845
+ * ```typescript
846
+ * const history = await paceful.webhooks.deliveryHistory('webhook_abc123', {
847
+ * limit: 20
848
+ * });
849
+ *
850
+ * for (const delivery of history) {
851
+ * console.log(`${delivery.event}: ${delivery.status}`);
852
+ * }
853
+ * ```
854
+ */
855
+ async deliveryHistory(webhookId, params) {
856
+ return this.http.get(`/api/v1/partner/webhooks/${webhookId}/deliveries`, {
857
+ limit: params?.limit,
858
+ status: params?.status
859
+ });
860
+ }
861
+ /**
862
+ * Rotate the webhook secret
863
+ *
864
+ * @param webhookId - The webhook ID
865
+ * @returns New webhook secret
866
+ *
867
+ * @example
868
+ * ```typescript
869
+ * const { secret } = await paceful.webhooks.rotateSecret('webhook_abc123');
870
+ *
871
+ * // Update your server with the new secret
872
+ * console.log('New secret:', secret);
873
+ * ```
874
+ */
875
+ async rotateSecret(webhookId) {
876
+ return this.http.post(`/api/v1/partner/webhooks/${webhookId}/rotate-secret`);
877
+ }
878
+ /**
879
+ * Verify a webhook signature
880
+ * Call this method to validate incoming webhook requests
881
+ *
882
+ * @param payload - Raw request body as string
883
+ * @param signature - Value of X-Paceful-Signature header
884
+ * @param secret - Your webhook secret
885
+ * @returns Whether the signature is valid
886
+ *
887
+ * @example
888
+ * ```typescript
889
+ * // In your webhook handler:
890
+ * const isValid = Webhooks.verifySignature(
891
+ * rawBody,
892
+ * request.headers['x-paceful-signature'],
893
+ * process.env.PACEFUL_WEBHOOK_SECRET
894
+ * );
895
+ *
896
+ * if (!isValid) {
897
+ * return res.status(401).send('Invalid signature');
898
+ * }
899
+ * ```
900
+ */
901
+ static verifySignature(payload, signature, secret) {
902
+ try {
903
+ const crypto = __require("crypto");
904
+ const expectedSignature = crypto.createHmac("sha256", secret).update(payload).digest("hex");
905
+ const sigBuffer = Buffer.from(signature);
906
+ const expectedBuffer = Buffer.from(expectedSignature);
907
+ if (sigBuffer.length !== expectedBuffer.length) {
908
+ return false;
909
+ }
910
+ return crypto.timingSafeEqual(sigBuffer, expectedBuffer);
911
+ } catch {
912
+ console.warn("Webhook signature verification requires Node.js crypto module");
913
+ return false;
914
+ }
915
+ }
916
+ };
917
+
918
+ // src/client.ts
919
+ var PacefulClient = class {
920
+ /**
921
+ * Create a new Paceful client
922
+ *
923
+ * @param config - Configuration options
924
+ *
925
+ * @example
926
+ * ```typescript
927
+ * import { PacefulClient } from '@paceful/sdk';
928
+ *
929
+ * const paceful = new PacefulClient({
930
+ * apiKey: process.env.PACEFUL_API_KEY,
931
+ * });
932
+ *
933
+ * // Register a user
934
+ * const user = await paceful.users.register({
935
+ * externalId: 'user_123',
936
+ * email: 'user@example.com'
937
+ * });
938
+ *
939
+ * // Log a mood entry
940
+ * await paceful.mood.log({
941
+ * externalId: 'user_123',
942
+ * mood: 4,
943
+ * note: 'Feeling good today'
944
+ * });
945
+ *
946
+ * // Get ERS score
947
+ * const ers = await paceful.ers.get('user_123');
948
+ * console.log(`ERS: ${ers.ersScore}, Stage: ${ers.stage}`);
949
+ * ```
950
+ */
951
+ constructor(config) {
952
+ this.http = new HttpClient(config);
953
+ this.users = new Users(this.http);
954
+ this.mood = new Mood(this.http);
955
+ this.journal = new Journal(this.http);
956
+ this.ers = new ERS(this.http);
957
+ this.analytics = new Analytics(this.http);
958
+ this.webhooks = new Webhooks(this.http);
959
+ }
960
+ /**
961
+ * Check API connectivity and authentication
962
+ *
963
+ * @returns Health check result
964
+ *
965
+ * @example
966
+ * ```typescript
967
+ * const health = await paceful.healthCheck();
968
+ * if (health.ok) {
969
+ * console.log('API is reachable');
970
+ * }
971
+ * ```
972
+ */
973
+ async healthCheck() {
974
+ return this.http.get("/api/v1/partner/health");
975
+ }
976
+ };
977
+
978
+ // src/widgets/index.ts
979
+ init_PacefulProvider();
980
+
981
+ // src/widgets/MoodWidget.tsx
982
+ import { useState, useEffect } from "react";
983
+ import { jsx, jsxs } from "react/jsx-runtime";
984
+ var MOOD_OPTIONS = [
985
+ { value: 1, label: "Struggling", color: "#7E71B5", subtitle: "Having a hard time" },
986
+ { value: 2, label: "Low", color: "#5B7FB5", subtitle: "Feeling down" },
987
+ { value: 3, label: "Okay", color: "#C4973B", subtitle: "Getting by" },
988
+ { value: 4, label: "Good", color: "#5B8A72", subtitle: "Feeling positive" },
989
+ { value: 5, label: "Great", color: "#3D6B54", subtitle: "Thriving today" }
990
+ ];
991
+ var EMOTION_TAGS = [
992
+ "anxious",
993
+ "sad",
994
+ "lonely",
995
+ "angry",
996
+ "numb",
997
+ "hopeful",
998
+ "grateful",
999
+ "calm",
1000
+ "motivated",
1001
+ "confused"
1002
+ ];
1003
+ function MoodWidget({
1004
+ apiKey: propApiKey,
1005
+ userId: propUserId,
1006
+ baseUrl: propBaseUrl,
1007
+ theme = "light",
1008
+ brandColor = "#5B8A72",
1009
+ compact = false,
1010
+ showStreak = false,
1011
+ onComplete,
1012
+ onError,
1013
+ className
1014
+ }) {
1015
+ let contextValue = null;
1016
+ try {
1017
+ const { usePaceful: usePaceful2 } = (init_PacefulProvider(), __toCommonJS(PacefulProvider_exports));
1018
+ contextValue = usePaceful2();
1019
+ } catch {
1020
+ }
1021
+ const apiKey = propApiKey || contextValue?.apiKey;
1022
+ const userId = propUserId || contextValue?.userId;
1023
+ const baseUrl = propBaseUrl || contextValue?.baseUrl || "https://paceful-app.vercel.app/api/v1/partner";
1024
+ const [state, setState] = useState("INITIAL");
1025
+ const [selectedMood, setSelectedMood] = useState(null);
1026
+ const [selectedEmotions, setSelectedEmotions] = useState([]);
1027
+ const [streak, setStreak] = useState(0);
1028
+ const isDark = theme === "dark";
1029
+ useEffect(() => {
1030
+ if (showStreak && apiKey && userId && typeof window !== "undefined") {
1031
+ fetch(`${baseUrl}/mood/${userId}/streak`, {
1032
+ headers: { "X-API-Key": apiKey }
1033
+ }).then((res) => res.json()).then((data) => {
1034
+ if (data.success && data.data?.streak) {
1035
+ setStreak(data.data.streak);
1036
+ }
1037
+ }).catch(() => {
1038
+ });
1039
+ }
1040
+ }, [showStreak, apiKey, userId, baseUrl]);
1041
+ const handleMoodSelect = (mood) => {
1042
+ setSelectedMood(mood);
1043
+ if (compact) {
1044
+ handleSubmit(mood, []);
1045
+ } else {
1046
+ setState("EMOTIONS");
1047
+ }
1048
+ };
1049
+ const toggleEmotion = (emotion) => {
1050
+ setSelectedEmotions(
1051
+ (prev) => prev.includes(emotion) ? prev.filter((e) => e !== emotion) : [...prev, emotion]
1052
+ );
1053
+ };
1054
+ const handleSubmit = async (mood, emotions) => {
1055
+ const moodToSubmit = mood ?? selectedMood;
1056
+ const emotionsToSubmit = emotions ?? selectedEmotions;
1057
+ if (!moodToSubmit || !apiKey || !userId) {
1058
+ onError?.(new Error("Missing required data"));
1059
+ return;
1060
+ }
1061
+ setState("SUBMITTING");
1062
+ try {
1063
+ const moodOption = MOOD_OPTIONS.find((m) => m.value === moodToSubmit);
1064
+ const response = await fetch(`${baseUrl}/mood/log`, {
1065
+ method: "POST",
1066
+ headers: {
1067
+ "Content-Type": "application/json",
1068
+ "X-API-Key": apiKey
1069
+ },
1070
+ body: JSON.stringify({
1071
+ externalId: userId,
1072
+ score: moodToSubmit,
1073
+ label: moodOption?.label,
1074
+ emotions: emotionsToSubmit
1075
+ })
1076
+ });
1077
+ const data = await response.json();
1078
+ if (!response.ok) {
1079
+ throw new Error(data.error?.message || "Failed to log mood");
1080
+ }
1081
+ setState("COMPLETE");
1082
+ onComplete?.({
1083
+ logged: true,
1084
+ moodId: data.data?.id || "",
1085
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1086
+ });
1087
+ setTimeout(() => {
1088
+ setState("INITIAL");
1089
+ setSelectedMood(null);
1090
+ setSelectedEmotions([]);
1091
+ if (showStreak) setStreak((s) => s + 1);
1092
+ }, 2e3);
1093
+ } catch (error) {
1094
+ setState("INITIAL");
1095
+ onError?.(error instanceof Error ? error : new Error("Unknown error"));
1096
+ }
1097
+ };
1098
+ const styles = {
1099
+ container: {
1100
+ backgroundColor: isDark ? "#1F1D1A" : "#FFFFFF",
1101
+ borderRadius: 12,
1102
+ padding: 20,
1103
+ fontFamily: 'system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
1104
+ color: isDark ? "#FFFFFF" : "#1F1D1A"
1105
+ },
1106
+ title: {
1107
+ fontSize: 18,
1108
+ fontWeight: 600,
1109
+ marginBottom: 16,
1110
+ textAlign: "center"
1111
+ },
1112
+ moodList: {
1113
+ display: "flex",
1114
+ flexDirection: "column",
1115
+ gap: 8
1116
+ },
1117
+ moodCard: (isSelected) => ({
1118
+ display: "flex",
1119
+ alignItems: "center",
1120
+ gap: 12,
1121
+ border: `1px solid ${isSelected ? brandColor : isDark ? "#3D3D3A" : "#E5E0D9"}`,
1122
+ borderRadius: 8,
1123
+ padding: 12,
1124
+ cursor: "pointer",
1125
+ backgroundColor: isSelected ? isDark ? "#2D2D2A" : "#F9F6F2" : "transparent",
1126
+ transition: "all 0.15s ease"
1127
+ }),
1128
+ moodDot: (color) => ({
1129
+ width: 12,
1130
+ height: 12,
1131
+ borderRadius: "50%",
1132
+ backgroundColor: color,
1133
+ flexShrink: 0
1134
+ }),
1135
+ moodLabel: {
1136
+ fontWeight: 500,
1137
+ fontSize: 15
1138
+ },
1139
+ moodSubtitle: {
1140
+ fontSize: 13,
1141
+ color: isDark ? "#9A938A" : "#6B6560",
1142
+ marginLeft: "auto"
1143
+ },
1144
+ emotionsSection: {
1145
+ marginTop: 20
1146
+ },
1147
+ emotionsTitle: {
1148
+ fontSize: 14,
1149
+ color: isDark ? "#9A938A" : "#6B6560",
1150
+ marginBottom: 12
1151
+ },
1152
+ emotionTags: {
1153
+ display: "flex",
1154
+ flexWrap: "wrap",
1155
+ gap: 8
1156
+ },
1157
+ emotionTag: (isSelected) => ({
1158
+ border: `1px solid ${isSelected ? brandColor : isDark ? "#3D3D3A" : "#E5E0D9"}`,
1159
+ borderRadius: 20,
1160
+ padding: "6px 12px",
1161
+ fontSize: 13,
1162
+ cursor: "pointer",
1163
+ backgroundColor: isSelected ? brandColor : "transparent",
1164
+ color: isSelected ? "#FFFFFF" : isDark ? "#FFFFFF" : "#1F1D1A",
1165
+ transition: "all 0.15s ease"
1166
+ }),
1167
+ submitButton: {
1168
+ marginTop: 20,
1169
+ width: "100%",
1170
+ backgroundColor: brandColor,
1171
+ color: "#FFFFFF",
1172
+ border: "none",
1173
+ borderRadius: 8,
1174
+ padding: 12,
1175
+ fontSize: 15,
1176
+ fontWeight: 500,
1177
+ cursor: "pointer"
1178
+ },
1179
+ footer: {
1180
+ marginTop: 16,
1181
+ textAlign: "center",
1182
+ fontSize: 11,
1183
+ color: "#9A938A"
1184
+ },
1185
+ spinner: {
1186
+ display: "flex",
1187
+ justifyContent: "center",
1188
+ alignItems: "center",
1189
+ padding: 40
1190
+ },
1191
+ checkmark: {
1192
+ display: "flex",
1193
+ flexDirection: "column",
1194
+ alignItems: "center",
1195
+ padding: 40,
1196
+ gap: 12
1197
+ },
1198
+ streakBadge: {
1199
+ display: "inline-flex",
1200
+ alignItems: "center",
1201
+ gap: 4,
1202
+ backgroundColor: isDark ? "#2D2D2A" : "#F9F6F2",
1203
+ borderRadius: 12,
1204
+ padding: "4px 10px",
1205
+ fontSize: 12,
1206
+ color: brandColor,
1207
+ marginBottom: 16
1208
+ }
1209
+ };
1210
+ if (state === "SUBMITTING") {
1211
+ return /* @__PURE__ */ jsxs("div", { style: styles.container, className, children: [
1212
+ /* @__PURE__ */ jsx("div", { style: styles.spinner, children: /* @__PURE__ */ jsx("svg", { width: "32", height: "32", viewBox: "0 0 32 32", children: /* @__PURE__ */ jsx(
1213
+ "circle",
1214
+ {
1215
+ cx: "16",
1216
+ cy: "16",
1217
+ r: "12",
1218
+ stroke: brandColor,
1219
+ strokeWidth: "3",
1220
+ fill: "none",
1221
+ strokeDasharray: "60",
1222
+ strokeLinecap: "round",
1223
+ children: /* @__PURE__ */ jsx(
1224
+ "animateTransform",
1225
+ {
1226
+ attributeName: "transform",
1227
+ type: "rotate",
1228
+ from: "0 16 16",
1229
+ to: "360 16 16",
1230
+ dur: "1s",
1231
+ repeatCount: "indefinite"
1232
+ }
1233
+ )
1234
+ }
1235
+ ) }) }),
1236
+ /* @__PURE__ */ jsx("div", { style: styles.footer, children: "Powered by Paceful" })
1237
+ ] });
1238
+ }
1239
+ if (state === "COMPLETE") {
1240
+ return /* @__PURE__ */ jsxs("div", { style: styles.container, className, children: [
1241
+ /* @__PURE__ */ jsxs("div", { style: styles.checkmark, children: [
1242
+ /* @__PURE__ */ jsxs("svg", { width: "48", height: "48", viewBox: "0 0 48 48", children: [
1243
+ /* @__PURE__ */ jsx("circle", { cx: "24", cy: "24", r: "22", fill: brandColor }),
1244
+ /* @__PURE__ */ jsx(
1245
+ "path",
1246
+ {
1247
+ d: "M14 24 L21 31 L34 18",
1248
+ stroke: "#FFFFFF",
1249
+ strokeWidth: "3",
1250
+ fill: "none",
1251
+ strokeLinecap: "round",
1252
+ strokeLinejoin: "round"
1253
+ }
1254
+ )
1255
+ ] }),
1256
+ /* @__PURE__ */ jsx("span", { style: { fontSize: 18, fontWeight: 500 }, children: "Logged!" })
1257
+ ] }),
1258
+ /* @__PURE__ */ jsx("div", { style: styles.footer, children: "Powered by Paceful" })
1259
+ ] });
1260
+ }
1261
+ if (state === "EMOTIONS") {
1262
+ const selectedMoodOption = MOOD_OPTIONS.find((m) => m.value === selectedMood);
1263
+ return /* @__PURE__ */ jsxs("div", { style: styles.container, className, children: [
1264
+ /* @__PURE__ */ jsxs("div", { style: styles.title, children: [
1265
+ /* @__PURE__ */ jsx("span", { style: { color: selectedMoodOption?.color }, children: selectedMoodOption?.label }),
1266
+ " ",
1267
+ "\u2014 What emotions are present?"
1268
+ ] }),
1269
+ /* @__PURE__ */ jsx("div", { style: styles.emotionTags, children: EMOTION_TAGS.map((emotion) => /* @__PURE__ */ jsx(
1270
+ "button",
1271
+ {
1272
+ onClick: () => toggleEmotion(emotion),
1273
+ style: styles.emotionTag(selectedEmotions.includes(emotion)),
1274
+ children: emotion
1275
+ },
1276
+ emotion
1277
+ )) }),
1278
+ /* @__PURE__ */ jsx(
1279
+ "button",
1280
+ {
1281
+ onClick: () => handleSubmit(),
1282
+ style: styles.submitButton,
1283
+ children: "Log Mood"
1284
+ }
1285
+ ),
1286
+ /* @__PURE__ */ jsx("div", { style: styles.footer, children: "Powered by Paceful" })
1287
+ ] });
1288
+ }
1289
+ return /* @__PURE__ */ jsxs("div", { style: styles.container, className, children: [
1290
+ showStreak && streak > 0 && /* @__PURE__ */ jsx("div", { style: { textAlign: "center" }, children: /* @__PURE__ */ jsxs("span", { style: styles.streakBadge, children: [
1291
+ "\u{1F525} ",
1292
+ streak,
1293
+ " day streak"
1294
+ ] }) }),
1295
+ /* @__PURE__ */ jsx("div", { style: styles.title, children: "How are you feeling?" }),
1296
+ /* @__PURE__ */ jsx("div", { style: styles.moodList, children: MOOD_OPTIONS.map((mood) => /* @__PURE__ */ jsxs(
1297
+ "div",
1298
+ {
1299
+ onClick: () => handleMoodSelect(mood.value),
1300
+ style: styles.moodCard(selectedMood === mood.value),
1301
+ children: [
1302
+ /* @__PURE__ */ jsx("div", { style: styles.moodDot(mood.color) }),
1303
+ /* @__PURE__ */ jsx("span", { style: styles.moodLabel, children: mood.label }),
1304
+ /* @__PURE__ */ jsx("span", { style: styles.moodSubtitle, children: mood.subtitle })
1305
+ ]
1306
+ },
1307
+ mood.value
1308
+ )) }),
1309
+ /* @__PURE__ */ jsx("div", { style: styles.footer, children: "Powered by Paceful" })
1310
+ ] });
1311
+ }
1312
+
1313
+ // src/widgets/JournalWidget.tsx
1314
+ import { useState as useState2, useEffect as useEffect2 } from "react";
1315
+ import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
1316
+ var JOURNAL_PROMPTS = [
1317
+ "What would you tell yourself from a year ago?",
1318
+ "What's one thing you're grateful for right now?",
1319
+ "What emotion keeps coming back today?",
1320
+ "What did you learn about yourself this week?",
1321
+ "If your future self could see you now, what would they say?"
1322
+ ];
1323
+ var SENTIMENT_COLORS = {
1324
+ Hopeful: "#5B8A72",
1325
+ Reflective: "#5B7FB5",
1326
+ Processing: "#C4973B",
1327
+ Struggling: "#B56B6B"
1328
+ };
1329
+ function JournalWidget({
1330
+ apiKey: propApiKey,
1331
+ userId: propUserId,
1332
+ baseUrl: propBaseUrl,
1333
+ theme = "light",
1334
+ brandColor = "#5B8A72",
1335
+ showPrompt = true,
1336
+ showAIReflection = true,
1337
+ maxLength = 2e3,
1338
+ placeholder = "What's on your mind?",
1339
+ onComplete,
1340
+ onError,
1341
+ className
1342
+ }) {
1343
+ let contextValue = null;
1344
+ try {
1345
+ const { usePaceful: usePaceful2 } = (init_PacefulProvider(), __toCommonJS(PacefulProvider_exports));
1346
+ contextValue = usePaceful2();
1347
+ } catch {
1348
+ }
1349
+ const apiKey = propApiKey || contextValue?.apiKey;
1350
+ const userId = propUserId || contextValue?.userId;
1351
+ const baseUrl = propBaseUrl || contextValue?.baseUrl || "https://paceful-app.vercel.app/api/v1/partner";
1352
+ const [state, setState] = useState2("WRITING");
1353
+ const [content, setContent] = useState2("");
1354
+ const [prompt, setPrompt] = useState2("");
1355
+ const [result, setResult] = useState2(null);
1356
+ const [fadeIn, setFadeIn] = useState2(false);
1357
+ const isDark = theme === "dark";
1358
+ useEffect2(() => {
1359
+ if (showPrompt && typeof window !== "undefined") {
1360
+ const randomIndex = Math.floor(Math.random() * JOURNAL_PROMPTS.length);
1361
+ setPrompt(JOURNAL_PROMPTS[randomIndex]);
1362
+ }
1363
+ }, [showPrompt]);
1364
+ const wordCount = content.trim().split(/\s+/).filter(Boolean).length;
1365
+ const handleSubmit = async () => {
1366
+ if (!content.trim() || !apiKey || !userId) {
1367
+ onError?.(new Error("Missing required data"));
1368
+ return;
1369
+ }
1370
+ setState("SUBMITTING");
1371
+ try {
1372
+ const response = await fetch(`${baseUrl}/journal/entry`, {
1373
+ method: "POST",
1374
+ headers: {
1375
+ "Content-Type": "application/json",
1376
+ "X-API-Key": apiKey
1377
+ },
1378
+ body: JSON.stringify({
1379
+ externalId: userId,
1380
+ content: content.trim()
1381
+ })
1382
+ });
1383
+ const data = await response.json();
1384
+ if (!response.ok) {
1385
+ throw new Error(data.error?.message || "Failed to save journal entry");
1386
+ }
1387
+ const entryResult = {
1388
+ entryId: data.data?.id || "",
1389
+ sentiment: data.data?.sentiment || "Reflective",
1390
+ aiReflection: data.data?.aiReflection || "Thank you for sharing. Taking time to reflect is an important step in understanding yourself better."
1391
+ };
1392
+ setResult(entryResult);
1393
+ setState("COMPLETE");
1394
+ onComplete?.(entryResult);
1395
+ setTimeout(() => setFadeIn(true), 50);
1396
+ } catch (error) {
1397
+ setState("WRITING");
1398
+ onError?.(error instanceof Error ? error : new Error("Unknown error"));
1399
+ }
1400
+ };
1401
+ const handleWriteAnother = () => {
1402
+ setState("WRITING");
1403
+ setContent("");
1404
+ setResult(null);
1405
+ setFadeIn(false);
1406
+ if (showPrompt) {
1407
+ const randomIndex = Math.floor(Math.random() * JOURNAL_PROMPTS.length);
1408
+ setPrompt(JOURNAL_PROMPTS[randomIndex]);
1409
+ }
1410
+ };
1411
+ const styles = {
1412
+ container: {
1413
+ backgroundColor: isDark ? "#1F1D1A" : "#FFFFFF",
1414
+ borderRadius: 12,
1415
+ padding: 20,
1416
+ fontFamily: 'system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
1417
+ color: isDark ? "#FFFFFF" : "#1F1D1A"
1418
+ },
1419
+ prompt: {
1420
+ fontSize: 16,
1421
+ fontWeight: 500,
1422
+ marginBottom: 16,
1423
+ color: isDark ? "#E5E0D9" : "#3D3D3A",
1424
+ lineHeight: 1.4
1425
+ },
1426
+ textareaWrapper: {
1427
+ position: "relative"
1428
+ },
1429
+ textarea: {
1430
+ width: "100%",
1431
+ minHeight: 120,
1432
+ resize: "vertical",
1433
+ border: `1px solid ${isDark ? "#3D3D3A" : "#E5E0D9"}`,
1434
+ borderRadius: 8,
1435
+ padding: 12,
1436
+ fontFamily: 'system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
1437
+ fontSize: 15,
1438
+ lineHeight: 1.5,
1439
+ backgroundColor: isDark ? "#2D2D2A" : "#FFFFFF",
1440
+ color: isDark ? "#FFFFFF" : "#1F1D1A",
1441
+ outline: "none",
1442
+ boxSizing: "border-box"
1443
+ },
1444
+ wordCount: {
1445
+ position: "absolute",
1446
+ bottom: 8,
1447
+ right: 12,
1448
+ fontSize: 12,
1449
+ color: "#9A938A"
1450
+ },
1451
+ submitButton: {
1452
+ marginTop: 16,
1453
+ width: "100%",
1454
+ backgroundColor: brandColor,
1455
+ color: "#FFFFFF",
1456
+ border: "none",
1457
+ borderRadius: 8,
1458
+ padding: 12,
1459
+ fontSize: 15,
1460
+ fontWeight: 500,
1461
+ cursor: content.trim() ? "pointer" : "not-allowed",
1462
+ opacity: content.trim() ? 1 : 0.5
1463
+ },
1464
+ footer: {
1465
+ marginTop: 16,
1466
+ textAlign: "center",
1467
+ fontSize: 11,
1468
+ color: "#9A938A"
1469
+ },
1470
+ submittingText: {
1471
+ textAlign: "center",
1472
+ padding: 40,
1473
+ fontSize: 15,
1474
+ color: isDark ? "#9A938A" : "#6B6560"
1475
+ },
1476
+ reflectionContainer: {
1477
+ opacity: fadeIn ? 1 : 0,
1478
+ transition: "opacity 0.3s ease"
1479
+ },
1480
+ sentimentBadge: (sentiment) => ({
1481
+ display: "inline-block",
1482
+ padding: "4px 10px",
1483
+ borderRadius: 12,
1484
+ fontSize: 12,
1485
+ fontWeight: 500,
1486
+ backgroundColor: SENTIMENT_COLORS[sentiment] || SENTIMENT_COLORS.Reflective,
1487
+ color: "#FFFFFF",
1488
+ marginBottom: 12
1489
+ }),
1490
+ reflectionBox: {
1491
+ borderLeft: `3px solid ${brandColor}`,
1492
+ padding: 16,
1493
+ backgroundColor: isDark ? "#2D2D2A" : "#F9F6F2",
1494
+ borderRadius: "0 8px 8px 0"
1495
+ },
1496
+ reflectionText: {
1497
+ fontStyle: "italic",
1498
+ lineHeight: 1.6,
1499
+ fontSize: 15,
1500
+ color: isDark ? "#E5E0D9" : "#3D3D3A"
1501
+ },
1502
+ writeAnotherButton: {
1503
+ marginTop: 20,
1504
+ width: "100%",
1505
+ backgroundColor: "transparent",
1506
+ color: brandColor,
1507
+ border: `1px solid ${brandColor}`,
1508
+ borderRadius: 8,
1509
+ padding: 12,
1510
+ fontSize: 15,
1511
+ fontWeight: 500,
1512
+ cursor: "pointer"
1513
+ }
1514
+ };
1515
+ if (state === "SUBMITTING") {
1516
+ return /* @__PURE__ */ jsxs2("div", { style: styles.container, className, children: [
1517
+ /* @__PURE__ */ jsxs2("div", { style: styles.submittingText, children: [
1518
+ /* @__PURE__ */ jsx2(
1519
+ "svg",
1520
+ {
1521
+ width: "32",
1522
+ height: "32",
1523
+ viewBox: "0 0 32 32",
1524
+ style: { display: "block", margin: "0 auto 16px" },
1525
+ children: /* @__PURE__ */ jsx2(
1526
+ "circle",
1527
+ {
1528
+ cx: "16",
1529
+ cy: "16",
1530
+ r: "12",
1531
+ stroke: brandColor,
1532
+ strokeWidth: "3",
1533
+ fill: "none",
1534
+ strokeDasharray: "60",
1535
+ strokeLinecap: "round",
1536
+ children: /* @__PURE__ */ jsx2(
1537
+ "animateTransform",
1538
+ {
1539
+ attributeName: "transform",
1540
+ type: "rotate",
1541
+ from: "0 16 16",
1542
+ to: "360 16 16",
1543
+ dur: "1s",
1544
+ repeatCount: "indefinite"
1545
+ }
1546
+ )
1547
+ }
1548
+ )
1549
+ }
1550
+ ),
1551
+ "Reflecting..."
1552
+ ] }),
1553
+ /* @__PURE__ */ jsx2("div", { style: styles.footer, children: "Powered by Paceful" })
1554
+ ] });
1555
+ }
1556
+ if (state === "COMPLETE" && result) {
1557
+ return /* @__PURE__ */ jsxs2("div", { style: styles.container, className, children: [
1558
+ /* @__PURE__ */ jsxs2("div", { style: styles.reflectionContainer, children: [
1559
+ showAIReflection && /* @__PURE__ */ jsxs2(Fragment, { children: [
1560
+ /* @__PURE__ */ jsx2("span", { style: styles.sentimentBadge(result.sentiment), children: result.sentiment }),
1561
+ /* @__PURE__ */ jsx2("div", { style: styles.reflectionBox, children: /* @__PURE__ */ jsx2("p", { style: styles.reflectionText, children: result.aiReflection }) })
1562
+ ] }),
1563
+ !showAIReflection && /* @__PURE__ */ jsxs2("div", { style: { textAlign: "center", padding: 20 }, children: [
1564
+ /* @__PURE__ */ jsxs2("svg", { width: "48", height: "48", viewBox: "0 0 48 48", children: [
1565
+ /* @__PURE__ */ jsx2("circle", { cx: "24", cy: "24", r: "22", fill: brandColor }),
1566
+ /* @__PURE__ */ jsx2(
1567
+ "path",
1568
+ {
1569
+ d: "M14 24 L21 31 L34 18",
1570
+ stroke: "#FFFFFF",
1571
+ strokeWidth: "3",
1572
+ fill: "none",
1573
+ strokeLinecap: "round",
1574
+ strokeLinejoin: "round"
1575
+ }
1576
+ )
1577
+ ] }),
1578
+ /* @__PURE__ */ jsx2("p", { style: { marginTop: 12, fontWeight: 500 }, children: "Entry Saved" })
1579
+ ] }),
1580
+ /* @__PURE__ */ jsx2("button", { onClick: handleWriteAnother, style: styles.writeAnotherButton, children: "Write Another" })
1581
+ ] }),
1582
+ /* @__PURE__ */ jsx2("div", { style: styles.footer, children: "Powered by Paceful" })
1583
+ ] });
1584
+ }
1585
+ return /* @__PURE__ */ jsxs2("div", { style: styles.container, className, children: [
1586
+ showPrompt && prompt && /* @__PURE__ */ jsx2("div", { style: styles.prompt, children: prompt }),
1587
+ /* @__PURE__ */ jsxs2("div", { style: styles.textareaWrapper, children: [
1588
+ /* @__PURE__ */ jsx2(
1589
+ "textarea",
1590
+ {
1591
+ value: content,
1592
+ onChange: (e) => setContent(e.target.value.slice(0, maxLength)),
1593
+ placeholder,
1594
+ style: styles.textarea
1595
+ }
1596
+ ),
1597
+ /* @__PURE__ */ jsxs2("span", { style: styles.wordCount, children: [
1598
+ wordCount,
1599
+ " words"
1600
+ ] })
1601
+ ] }),
1602
+ /* @__PURE__ */ jsx2(
1603
+ "button",
1604
+ {
1605
+ onClick: handleSubmit,
1606
+ disabled: !content.trim(),
1607
+ style: styles.submitButton,
1608
+ children: "Save Entry"
1609
+ }
1610
+ ),
1611
+ /* @__PURE__ */ jsx2("div", { style: styles.footer, children: "Powered by Paceful" })
1612
+ ] });
1613
+ }
1614
+
1615
+ // src/widgets/ERSDisplay.tsx
1616
+ import { useState as useState3, useEffect as useEffect3 } from "react";
1617
+ import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
1618
+ var STAGE_COLORS = {
1619
+ healing: "#7E71B5",
1620
+ rebuilding: "#5B8A72",
1621
+ ready: "#D4A645"
1622
+ };
1623
+ var DIMENSION_LABELS = [
1624
+ { key: "emotionalStability", label: "Emotional Stability" },
1625
+ { key: "selfAwareness", label: "Self Reflection" },
1626
+ { key: "socialConnection", label: "Engagement" },
1627
+ { key: "purposeClarity", label: "Coping Capacity" },
1628
+ { key: "resilienceGrowth", label: "Social Readiness" }
1629
+ ];
1630
+ function ERSDisplay({
1631
+ apiKey: propApiKey,
1632
+ userId: propUserId,
1633
+ baseUrl: propBaseUrl,
1634
+ theme = "light",
1635
+ brandColor = "#5B8A72",
1636
+ showDimensions = true,
1637
+ showTrend = true,
1638
+ compact = false,
1639
+ onLoad,
1640
+ onError,
1641
+ className
1642
+ }) {
1643
+ let contextValue = null;
1644
+ try {
1645
+ const { usePaceful: usePaceful2 } = (init_PacefulProvider(), __toCommonJS(PacefulProvider_exports));
1646
+ contextValue = usePaceful2();
1647
+ } catch {
1648
+ }
1649
+ const apiKey = propApiKey || contextValue?.apiKey;
1650
+ const userId = propUserId || contextValue?.userId;
1651
+ const baseUrl = propBaseUrl || contextValue?.baseUrl || "https://paceful-app.vercel.app/api/v1/partner";
1652
+ const [state, setState] = useState3("LOADING");
1653
+ const [ersData, setErsData] = useState3(null);
1654
+ const isDark = theme === "dark";
1655
+ const ringSize = compact ? 80 : 120;
1656
+ const strokeWidth = compact ? 6 : 8;
1657
+ const radius = (ringSize - strokeWidth) / 2;
1658
+ const circumference = 2 * Math.PI * radius;
1659
+ const fetchERS = async () => {
1660
+ if (!apiKey || !userId) {
1661
+ setState("ERROR");
1662
+ onError?.(new Error("Missing apiKey or userId"));
1663
+ return;
1664
+ }
1665
+ setState("LOADING");
1666
+ try {
1667
+ const response = await fetch(`${baseUrl}/ers/${userId}`, {
1668
+ headers: { "X-API-Key": apiKey }
1669
+ });
1670
+ const data = await response.json();
1671
+ if (!response.ok) {
1672
+ throw new Error(data.error?.message || "Failed to fetch ERS");
1673
+ }
1674
+ const ersResult = {
1675
+ ersScore: data.data?.ersScore || 0,
1676
+ stage: data.data?.stage || "healing",
1677
+ dimensions: data.data?.dimensions || {
1678
+ emotionalStability: 0,
1679
+ selfAwareness: 0,
1680
+ socialConnection: 0,
1681
+ purposeClarity: 0,
1682
+ resilienceGrowth: 0
1683
+ },
1684
+ trend: data.data?.trend
1685
+ };
1686
+ setErsData(ersResult);
1687
+ setState("LOADED");
1688
+ onLoad?.(ersResult);
1689
+ } catch (error) {
1690
+ setState("ERROR");
1691
+ onError?.(error instanceof Error ? error : new Error("Unknown error"));
1692
+ }
1693
+ };
1694
+ useEffect3(() => {
1695
+ if (typeof window !== "undefined") {
1696
+ fetchERS();
1697
+ }
1698
+ }, [apiKey, userId, baseUrl]);
1699
+ const styles = {
1700
+ container: {
1701
+ backgroundColor: isDark ? "#1F1D1A" : "#FFFFFF",
1702
+ borderRadius: 12,
1703
+ padding: compact ? 16 : 20,
1704
+ fontFamily: 'system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
1705
+ color: isDark ? "#FFFFFF" : "#1F1D1A"
1706
+ },
1707
+ ringContainer: {
1708
+ display: "flex",
1709
+ justifyContent: "center",
1710
+ marginBottom: compact ? 12 : 20
1711
+ },
1712
+ ringWrapper: {
1713
+ position: "relative",
1714
+ width: ringSize,
1715
+ height: ringSize
1716
+ },
1717
+ scoreText: {
1718
+ position: "absolute",
1719
+ top: "50%",
1720
+ left: "50%",
1721
+ transform: "translate(-50%, -50%)",
1722
+ textAlign: "center"
1723
+ },
1724
+ scoreNumber: {
1725
+ fontSize: compact ? 24 : 36,
1726
+ fontWeight: 700,
1727
+ lineHeight: 1
1728
+ },
1729
+ stageLabel: {
1730
+ fontSize: 12,
1731
+ textTransform: "uppercase",
1732
+ letterSpacing: 0.5,
1733
+ marginTop: 4,
1734
+ color: isDark ? "#9A938A" : "#6B6560"
1735
+ },
1736
+ trendBadge: (direction) => ({
1737
+ display: "flex",
1738
+ alignItems: "center",
1739
+ justifyContent: "center",
1740
+ gap: 4,
1741
+ fontSize: 13,
1742
+ color: direction === "up" ? "#5B8A72" : direction === "down" ? "#B56B6B" : "#9A938A",
1743
+ marginBottom: 16
1744
+ }),
1745
+ dimensionsContainer: {
1746
+ display: "flex",
1747
+ flexDirection: "column",
1748
+ gap: 12
1749
+ },
1750
+ dimensionRow: {
1751
+ display: "flex",
1752
+ alignItems: "center",
1753
+ gap: 12
1754
+ },
1755
+ dimensionLabel: {
1756
+ fontSize: 13,
1757
+ color: isDark ? "#9A938A" : "#6B6560",
1758
+ width: 120,
1759
+ flexShrink: 0
1760
+ },
1761
+ dimensionBarBg: {
1762
+ flex: 1,
1763
+ height: 8,
1764
+ backgroundColor: isDark ? "#3D3D3A" : "#E5E0D9",
1765
+ borderRadius: 4,
1766
+ overflow: "hidden"
1767
+ },
1768
+ dimensionBarFill: (value) => ({
1769
+ height: "100%",
1770
+ width: `${value}%`,
1771
+ backgroundColor: brandColor,
1772
+ borderRadius: 4,
1773
+ transition: "width 0.5s ease"
1774
+ }),
1775
+ dimensionScore: {
1776
+ fontSize: 13,
1777
+ fontWeight: 500,
1778
+ width: 32,
1779
+ textAlign: "right"
1780
+ },
1781
+ focusBadge: {
1782
+ fontSize: 10,
1783
+ backgroundColor: "#F5E6E6",
1784
+ color: "#B56B6B",
1785
+ padding: "2px 6px",
1786
+ borderRadius: 4,
1787
+ marginLeft: 8
1788
+ },
1789
+ footer: {
1790
+ marginTop: 16,
1791
+ textAlign: "center",
1792
+ fontSize: 11,
1793
+ color: "#9A938A"
1794
+ },
1795
+ skeleton: {
1796
+ animation: "pulse 1.5s ease-in-out infinite",
1797
+ backgroundColor: isDark ? "#3D3D3A" : "#E5E0D9",
1798
+ borderRadius: 8
1799
+ },
1800
+ errorContainer: {
1801
+ textAlign: "center",
1802
+ padding: 20
1803
+ },
1804
+ errorText: {
1805
+ fontSize: 14,
1806
+ color: isDark ? "#9A938A" : "#6B6560",
1807
+ marginBottom: 12
1808
+ },
1809
+ retryButton: {
1810
+ backgroundColor: "transparent",
1811
+ color: brandColor,
1812
+ border: `1px solid ${brandColor}`,
1813
+ borderRadius: 8,
1814
+ padding: "8px 16px",
1815
+ fontSize: 14,
1816
+ cursor: "pointer"
1817
+ }
1818
+ };
1819
+ if (state === "LOADING") {
1820
+ return /* @__PURE__ */ jsxs3("div", { style: styles.container, className, children: [
1821
+ /* @__PURE__ */ jsx3("style", { children: `@keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.5; } }` }),
1822
+ /* @__PURE__ */ jsx3("div", { style: styles.ringContainer, children: /* @__PURE__ */ jsx3(
1823
+ "div",
1824
+ {
1825
+ style: {
1826
+ ...styles.skeleton,
1827
+ width: ringSize,
1828
+ height: ringSize,
1829
+ borderRadius: "50%"
1830
+ }
1831
+ }
1832
+ ) }),
1833
+ showTrend && /* @__PURE__ */ jsx3("div", { style: { display: "flex", justifyContent: "center", marginBottom: 16 }, children: /* @__PURE__ */ jsx3("div", { style: { ...styles.skeleton, width: 120, height: 20 } }) }),
1834
+ showDimensions && !compact && /* @__PURE__ */ jsx3("div", { style: styles.dimensionsContainer, children: [...Array(5)].map((_, i) => /* @__PURE__ */ jsxs3("div", { style: styles.dimensionRow, children: [
1835
+ /* @__PURE__ */ jsx3("div", { style: { ...styles.skeleton, width: 100, height: 16 } }),
1836
+ /* @__PURE__ */ jsx3("div", { style: { ...styles.skeleton, flex: 1, height: 8 } })
1837
+ ] }, i)) }),
1838
+ /* @__PURE__ */ jsx3("div", { style: styles.footer, children: "Powered by Paceful" })
1839
+ ] });
1840
+ }
1841
+ if (state === "ERROR") {
1842
+ return /* @__PURE__ */ jsxs3("div", { style: styles.container, className, children: [
1843
+ /* @__PURE__ */ jsxs3("div", { style: styles.errorContainer, children: [
1844
+ /* @__PURE__ */ jsx3("p", { style: styles.errorText, children: "Unable to load score" }),
1845
+ /* @__PURE__ */ jsx3("button", { onClick: fetchERS, style: styles.retryButton, children: "Retry" })
1846
+ ] }),
1847
+ /* @__PURE__ */ jsx3("div", { style: styles.footer, children: "Powered by Paceful" })
1848
+ ] });
1849
+ }
1850
+ if (!ersData) return null;
1851
+ const progress = ersData.ersScore / 100 * circumference;
1852
+ const stageColor = STAGE_COLORS[ersData.stage];
1853
+ return /* @__PURE__ */ jsxs3("div", { style: styles.container, className, children: [
1854
+ /* @__PURE__ */ jsx3("div", { style: styles.ringContainer, children: /* @__PURE__ */ jsxs3("div", { style: styles.ringWrapper, children: [
1855
+ /* @__PURE__ */ jsxs3("svg", { width: ringSize, height: ringSize, children: [
1856
+ /* @__PURE__ */ jsx3(
1857
+ "circle",
1858
+ {
1859
+ cx: ringSize / 2,
1860
+ cy: ringSize / 2,
1861
+ r: radius,
1862
+ stroke: isDark ? "#3D3D3A" : "#E5E0D9",
1863
+ strokeWidth,
1864
+ fill: "none"
1865
+ }
1866
+ ),
1867
+ /* @__PURE__ */ jsx3(
1868
+ "circle",
1869
+ {
1870
+ cx: ringSize / 2,
1871
+ cy: ringSize / 2,
1872
+ r: radius,
1873
+ stroke: stageColor,
1874
+ strokeWidth,
1875
+ fill: "none",
1876
+ strokeLinecap: "round",
1877
+ strokeDasharray: circumference,
1878
+ strokeDashoffset: circumference - progress,
1879
+ transform: `rotate(-90 ${ringSize / 2} ${ringSize / 2})`,
1880
+ style: { transition: "stroke-dashoffset 0.5s ease" }
1881
+ }
1882
+ )
1883
+ ] }),
1884
+ /* @__PURE__ */ jsxs3("div", { style: styles.scoreText, children: [
1885
+ /* @__PURE__ */ jsx3("div", { style: styles.scoreNumber, children: Math.round(ersData.ersScore) }),
1886
+ /* @__PURE__ */ jsx3("div", { style: styles.stageLabel, children: ersData.stage })
1887
+ ] })
1888
+ ] }) }),
1889
+ showTrend && ersData.trend && /* @__PURE__ */ jsxs3("div", { style: styles.trendBadge(ersData.trend.direction), children: [
1890
+ ersData.trend.direction === "up" && /* @__PURE__ */ jsxs3(Fragment2, { children: [
1891
+ /* @__PURE__ */ jsx3("svg", { width: "12", height: "12", viewBox: "0 0 12 12", children: /* @__PURE__ */ jsx3("path", { d: "M6 2 L10 6 L7 6 L7 10 L5 10 L5 6 L2 6 Z", fill: "currentColor" }) }),
1892
+ "+",
1893
+ ersData.trend.weeklyChange.toFixed(1),
1894
+ " from last week"
1895
+ ] }),
1896
+ ersData.trend.direction === "down" && /* @__PURE__ */ jsxs3(Fragment2, { children: [
1897
+ /* @__PURE__ */ jsx3("svg", { width: "12", height: "12", viewBox: "0 0 12 12", children: /* @__PURE__ */ jsx3("path", { d: "M6 10 L10 6 L7 6 L7 2 L5 2 L5 6 L2 6 Z", fill: "currentColor" }) }),
1898
+ ersData.trend.weeklyChange.toFixed(1),
1899
+ " from last week"
1900
+ ] }),
1901
+ ersData.trend.direction === "stable" && /* @__PURE__ */ jsxs3(Fragment2, { children: [
1902
+ /* @__PURE__ */ jsx3("span", { style: { fontSize: 16 }, children: "\u2014" }),
1903
+ "No change"
1904
+ ] })
1905
+ ] }),
1906
+ showDimensions && !compact && /* @__PURE__ */ jsx3("div", { style: styles.dimensionsContainer, children: DIMENSION_LABELS.map(({ key, label }) => {
1907
+ const value = ersData.dimensions[key] || 0;
1908
+ return /* @__PURE__ */ jsxs3("div", { style: styles.dimensionRow, children: [
1909
+ /* @__PURE__ */ jsx3("span", { style: styles.dimensionLabel, children: label }),
1910
+ /* @__PURE__ */ jsx3("div", { style: styles.dimensionBarBg, children: /* @__PURE__ */ jsx3("div", { style: styles.dimensionBarFill(value) }) }),
1911
+ /* @__PURE__ */ jsx3("span", { style: styles.dimensionScore, children: Math.round(value) }),
1912
+ value < 50 && /* @__PURE__ */ jsx3("span", { style: styles.focusBadge, children: "Focus" })
1913
+ ] }, key);
1914
+ }) }),
1915
+ /* @__PURE__ */ jsx3("div", { style: styles.footer, children: "Powered by Paceful" })
1916
+ ] });
1917
+ }
1918
+ export {
1919
+ Analytics,
1920
+ ERS,
1921
+ ERSDisplay,
1922
+ Journal,
1923
+ JournalWidget,
1924
+ Mood,
1925
+ MoodWidget,
1926
+ PacefulAuthError,
1927
+ PacefulClient,
1928
+ PacefulError,
1929
+ PacefulNetworkError,
1930
+ PacefulNotFoundError,
1931
+ PacefulProvider,
1932
+ PacefulRateLimitError,
1933
+ PacefulValidationError,
1934
+ Users,
1935
+ Webhooks,
1936
+ PacefulClient as default,
1937
+ usePaceful
1938
+ };