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