makethisbetter 1.2.0 → 1.3.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.
Files changed (43) hide show
  1. package/dist/i18n/de.d.ts +2 -0
  2. package/dist/i18n/de.d.ts.map +1 -1
  3. package/dist/i18n/en.d.ts +2 -0
  4. package/dist/i18n/en.d.ts.map +1 -1
  5. package/dist/i18n/es.d.ts +2 -0
  6. package/dist/i18n/es.d.ts.map +1 -1
  7. package/dist/i18n/fr.d.ts +2 -0
  8. package/dist/i18n/fr.d.ts.map +1 -1
  9. package/dist/i18n/ja.d.ts +2 -0
  10. package/dist/i18n/ja.d.ts.map +1 -1
  11. package/dist/i18n/ko.d.ts +2 -0
  12. package/dist/i18n/ko.d.ts.map +1 -1
  13. package/dist/i18n/zh-CN.d.ts +2 -0
  14. package/dist/i18n/zh-CN.d.ts.map +1 -1
  15. package/dist/makethisbetter.cjs.js +19 -19
  16. package/dist/makethisbetter.cjs.js.map +1 -1
  17. package/dist/makethisbetter.esm.js +261 -243
  18. package/dist/makethisbetter.esm.js.map +1 -1
  19. package/dist/makethisbetter.js +17 -17
  20. package/dist/makethisbetter.js.map +1 -1
  21. package/dist/popup/success.d.ts +4 -1
  22. package/dist/popup/success.d.ts.map +1 -1
  23. package/dist/record/session.cdn.test.d.ts +2 -0
  24. package/dist/record/session.cdn.test.d.ts.map +1 -0
  25. package/dist/record/session.d.ts.map +1 -1
  26. package/dist/types.d.ts +1 -0
  27. package/dist/types.d.ts.map +1 -1
  28. package/dist/widget/controller.d.ts.map +1 -1
  29. package/package.json +1 -1
  30. package/src/i18n/de.ts +2 -0
  31. package/src/i18n/en.ts +2 -0
  32. package/src/i18n/es.ts +2 -0
  33. package/src/i18n/fr.ts +2 -0
  34. package/src/i18n/ja.ts +2 -0
  35. package/src/i18n/ko.ts +2 -0
  36. package/src/i18n/zh-CN.ts +2 -0
  37. package/src/popup/success.test.ts +13 -0
  38. package/src/popup/success.ts +10 -3
  39. package/src/record/session.cdn.test.ts +89 -0
  40. package/src/record/session.ts +21 -7
  41. package/src/types.ts +1 -0
  42. package/src/widget/controller.test.ts +4 -1
  43. package/src/widget/controller.ts +8 -5
@@ -1,8 +1,11 @@
1
1
  import type { ShadowContainer } from '../widget/shadow';
2
2
  import type { I18nMessages } from '../i18n';
3
+ export interface SuccessCardOptions {
4
+ skipFollowup?: boolean;
5
+ }
3
6
  export declare class SuccessCard {
4
7
  private el;
5
- constructor(shadow: ShadowContainer, messages: I18nMessages, onClose: () => void, onViewFeedback?: () => void);
8
+ constructor(shadow: ShadowContainer, messages: I18nMessages, onClose: () => void, onViewFeedback?: () => void, options?: SuccessCardOptions);
6
9
  destroy(): void;
7
10
  }
8
11
  //# sourceMappingURL=success.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"success.d.ts","sourceRoot":"","sources":["../../src/popup/success.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AACvD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAK3C,qBAAa,WAAW;IACtB,OAAO,CAAC,EAAE,CAAgB;gBAEd,MAAM,EAAE,eAAe,EAAE,QAAQ,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,IAAI,EAAE,cAAc,CAAC,EAAE,MAAM,IAAI;IA8B7G,OAAO,IAAI,IAAI;CAGhB"}
1
+ {"version":3,"file":"success.d.ts","sourceRoot":"","sources":["../../src/popup/success.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AACvD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAK3C,MAAM,WAAW,kBAAkB;IACjC,YAAY,CAAC,EAAE,OAAO,CAAA;CACvB;AAED,qBAAa,WAAW;IACtB,OAAO,CAAC,EAAE,CAAgB;gBAEd,MAAM,EAAE,eAAe,EAAE,QAAQ,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,IAAI,EAAE,cAAc,CAAC,EAAE,MAAM,IAAI,EAAE,OAAO,CAAC,EAAE,kBAAkB;IAiC3I,OAAO,IAAI,IAAI;CAGhB"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=session.cdn.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.cdn.test.d.ts","sourceRoot":"","sources":["../../src/record/session.cdn.test.ts"],"names":[],"mappings":""}
@@ -1 +1 @@
1
- {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/record/session.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AAEvD,KAAK,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;AAQzC,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,UAAU,EAAE,CAAA;IACpB,QAAQ,EAAE,MAAM,CAAA;CACjB;AAyCD,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAmB;IACjC,OAAO,CAAC,MAAM,CAAsB;IACpC,OAAO,CAAC,SAAS,CAAI;IACrB,OAAO,CAAC,KAAK,CAA6C;IAC1D,OAAO,CAAC,YAAY,CAAyC;IAC7D,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,YAAY,CAAC,CAAY;IACjC,OAAO,CAAC,OAAO,CAAQ;gBAEX,MAAM,EAAE,eAAe,EAAE,YAAY,CAAC,EAAE,MAAM,IAAI;IAKxD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IA2B5B,IAAI,IAAI,eAAe;IAavB,WAAW,IAAI,MAAM;IAKrB,OAAO,IAAI,IAAI;IAUf,OAAO,CAAC,YAAY;IAOpB,OAAO,CAAC,mBAAmB;IAO3B,OAAO,CAAC,eAAe;CAOxB"}
1
+ {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/record/session.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AAEvD,KAAK,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;AAQzC,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,UAAU,EAAE,CAAA;IACpB,QAAQ,EAAE,MAAM,CAAA;CACjB;AAuDD,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAmB;IACjC,OAAO,CAAC,MAAM,CAAsB;IACpC,OAAO,CAAC,SAAS,CAAI;IACrB,OAAO,CAAC,KAAK,CAA6C;IAC1D,OAAO,CAAC,YAAY,CAAyC;IAC7D,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,YAAY,CAAC,CAAY;IACjC,OAAO,CAAC,OAAO,CAAQ;gBAEX,MAAM,EAAE,eAAe,EAAE,YAAY,CAAC,EAAE,MAAM,IAAI;IAKxD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IA2B5B,IAAI,IAAI,eAAe;IAavB,WAAW,IAAI,MAAM;IAKrB,OAAO,IAAI,IAAI;IAUf,OAAO,CAAC,YAAY;IAOpB,OAAO,CAAC,mBAAmB;IAO3B,OAAO,CAAC,eAAe;CAOxB"}
package/dist/types.d.ts CHANGED
@@ -50,6 +50,7 @@ export interface FeedbackResponse {
50
50
  status: string;
51
51
  project_id: string;
52
52
  ai_clarify_available?: boolean;
53
+ skip_followup?: boolean;
53
54
  }
54
55
  export interface ClarifyMessage {
55
56
  role: string;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,oBAAoB;IACnC,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,CAAC,EAAE,QAAQ,CAAA;IACpB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;IAC3B,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,CAAA;IACjC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,oBAAoB,CAAC,EAAE,OAAO,CAAA;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,WAAW,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAA;IACnC,IAAI,CAAC,EAAE;QACL,EAAE,CAAC,EAAE,MAAM,CAAA;QACX,KAAK,CAAC,EAAE,MAAM,CAAA;QACd,IAAI,CAAC,EAAE,MAAM,CAAA;KACd,CAAA;CACF;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,KAAK,GAAG,MAAM,CAAA;IACpB,CAAC,EAAE,MAAM,CAAA;IACT,CAAC,EAAE,MAAM,CAAA;IACT,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,WAAW,EAAE,MAAM,CAAA;IACnB,QAAQ,EAAE,MAAM,CAAA;IAChB,UAAU,EAAE,MAAM,CAAA;IAClB,OAAO,EAAE,MAAM,CAAA;IACf,EAAE,EAAE,MAAM,CAAA;IACV,YAAY,EAAE,MAAM,CAAA;IACpB,aAAa,EAAE,MAAM,CAAA;IACrB,cAAc,EAAE,MAAM,EAAE,CAAA;IACxB,WAAW,EAAE,UAAU,EAAE,CAAA;IACzB,cAAc,CAAC,EAAE;QACf,QAAQ,EAAE,MAAM,CAAA;QAChB,IAAI,EAAE,MAAM,CAAA;QACZ,IAAI,EAAE,MAAM,CAAA;KACb,CAAA;IACD,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAA;IAC5C,kBAAkB,CAAC,EAAE,MAAM,CAAA;CAC5B;AAED,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAA;IACV,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,EAAE,MAAM,CAAA;IAClB,oBAAoB,CAAC,EAAE,OAAO,CAAA;CAC/B;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,cAAc,EAAE,CAAA;IAC1B,IAAI,EAAE,OAAO,CAAA;CACd"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,oBAAoB;IACnC,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,CAAC,EAAE,QAAQ,CAAA;IACpB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;IAC3B,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,CAAA;IACjC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,oBAAoB,CAAC,EAAE,OAAO,CAAA;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,WAAW,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAA;IACnC,IAAI,CAAC,EAAE;QACL,EAAE,CAAC,EAAE,MAAM,CAAA;QACX,KAAK,CAAC,EAAE,MAAM,CAAA;QACd,IAAI,CAAC,EAAE,MAAM,CAAA;KACd,CAAA;CACF;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,KAAK,GAAG,MAAM,CAAA;IACpB,CAAC,EAAE,MAAM,CAAA;IACT,CAAC,EAAE,MAAM,CAAA;IACT,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,WAAW,EAAE,MAAM,CAAA;IACnB,QAAQ,EAAE,MAAM,CAAA;IAChB,UAAU,EAAE,MAAM,CAAA;IAClB,OAAO,EAAE,MAAM,CAAA;IACf,EAAE,EAAE,MAAM,CAAA;IACV,YAAY,EAAE,MAAM,CAAA;IACpB,aAAa,EAAE,MAAM,CAAA;IACrB,cAAc,EAAE,MAAM,EAAE,CAAA;IACxB,WAAW,EAAE,UAAU,EAAE,CAAA;IACzB,cAAc,CAAC,EAAE;QACf,QAAQ,EAAE,MAAM,CAAA;QAChB,IAAI,EAAE,MAAM,CAAA;QACZ,IAAI,EAAE,MAAM,CAAA;KACb,CAAA;IACD,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAA;IAC5C,kBAAkB,CAAC,EAAE,MAAM,CAAA;CAC5B;AAED,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAA;IACV,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,EAAE,MAAM,CAAA;IAClB,oBAAoB,CAAC,EAAE,OAAO,CAAA;IAC9B,aAAa,CAAC,EAAE,OAAO,CAAA;CACxB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,cAAc,EAAE,CAAA;IAC1B,IAAI,EAAE,OAAO,CAAA;CACd"}
@@ -1 +1 @@
1
- {"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../../src/widget/controller.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,oBAAoB,EAAc,MAAM,UAAU,CAAA;AAIhE,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,MAAM,CAAsB;IACpC,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,GAAG,CAA2B;IACtC,OAAO,CAAC,OAAO,CAAiC;IAChD,OAAO,CAAC,OAAO,CAAiC;IAChD,OAAO,CAAC,KAAK,CAA4B;IACzC,OAAO,CAAC,OAAO,CAA2B;IAC1C,OAAO,CAAC,OAAO,CAA2B;IAC1C,OAAO,CAAC,iBAAiB,CAAqC;IAC9D,OAAO,CAAC,SAAS,CAAW;IAC5B,OAAO,CAAC,gBAAgB,CAAuB;IAC/C,OAAO,CAAC,mBAAmB,CAAmC;IAC9D,OAAO,CAAC,QAAQ,CAAgC;IAChD,OAAO,CAAC,IAAI,CAAe;IAC3B,OAAO,CAAC,iBAAiB,CAA0B;IACnD,OAAO,CAAC,gBAAgB,CAAgC;gBAE5C,MAAM,EAAE,oBAAoB;IAcxC,OAAO,CAAC,OAAO;IAYf,OAAO,CAAC,cAAc;IAStB,OAAO,CAAC,iBAAiB;IAYzB,OAAO,CAAC,wBAAwB;IAKhC,OAAO,CAAC,mBAAmB;IAgB3B,OAAO,CAAC,uBAAuB;IA6B/B,OAAO,CAAC,SAAS;YAcH,YAAY;IAuC1B,OAAO,CAAC,WAAW;IAenB,OAAO,CAAC,WAAW;IAiBnB,OAAO,CAAC,OAAO;IAgBf,OAAO,IAAI,IAAI;CAWhB"}
1
+ {"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../../src/widget/controller.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,oBAAoB,EAAc,MAAM,UAAU,CAAA;AAIhE,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,MAAM,CAAsB;IACpC,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,GAAG,CAA2B;IACtC,OAAO,CAAC,OAAO,CAAiC;IAChD,OAAO,CAAC,OAAO,CAAiC;IAChD,OAAO,CAAC,KAAK,CAA4B;IACzC,OAAO,CAAC,OAAO,CAA2B;IAC1C,OAAO,CAAC,OAAO,CAA2B;IAC1C,OAAO,CAAC,iBAAiB,CAAqC;IAC9D,OAAO,CAAC,SAAS,CAAW;IAC5B,OAAO,CAAC,gBAAgB,CAAuB;IAC/C,OAAO,CAAC,mBAAmB,CAAmC;IAC9D,OAAO,CAAC,QAAQ,CAAgC;IAChD,OAAO,CAAC,IAAI,CAAe;IAC3B,OAAO,CAAC,iBAAiB,CAA0B;IACnD,OAAO,CAAC,gBAAgB,CAAgC;gBAE5C,MAAM,EAAE,oBAAoB;IAcxC,OAAO,CAAC,OAAO;IAYf,OAAO,CAAC,cAAc;IAStB,OAAO,CAAC,iBAAiB;IAYzB,OAAO,CAAC,wBAAwB;IAKhC,OAAO,CAAC,mBAAmB;IAgB3B,OAAO,CAAC,uBAAuB;IA8B/B,OAAO,CAAC,SAAS;YAcH,YAAY;IAwC1B,OAAO,CAAC,WAAW;IAenB,OAAO,CAAC,WAAW;IAiBnB,OAAO,CAAC,OAAO;IAgBf,OAAO,IAAI,IAAI;CAWhB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "makethisbetter",
3
- "version": "1.2.0",
3
+ "version": "1.3.0",
4
4
  "description": "Make This Better JS Widget SDK — embed user feedback collection in any website",
5
5
  "type": "module",
6
6
  "main": "./dist/makethisbetter.cjs.js",
package/src/i18n/de.ts CHANGED
@@ -22,6 +22,8 @@ export default {
22
22
  success: {
23
23
  title: 'Vielen Dank!',
24
24
  message: 'Ihr Feedback wurde empfangen.',
25
+ title_no_ai: 'Gesendet!',
26
+ message_no_ai: 'Wir kümmern uns darum. Sie werden benachrichtigt, sobald es gelöst ist.',
25
27
  view_feedback: 'Mein Feedback ansehen',
26
28
  close: 'Schließen',
27
29
  },
package/src/i18n/en.ts CHANGED
@@ -22,6 +22,8 @@ export default {
22
22
  success: {
23
23
  title: 'Thanks!',
24
24
  message: 'Your feedback has been received.',
25
+ title_no_ai: 'Sent — thanks!',
26
+ message_no_ai: "We'll take it from here. You'll hear back when it's resolved.",
25
27
  view_feedback: 'View my feedback',
26
28
  close: 'Close',
27
29
  },
package/src/i18n/es.ts CHANGED
@@ -22,6 +22,8 @@ export default {
22
22
  success: {
23
23
  title: '¡Gracias!',
24
24
  message: 'Tu comentario ha sido recibido.',
25
+ title_no_ai: '¡Enviado!',
26
+ message_no_ai: 'Nos encargamos. Te avisaremos cuando se resuelva.',
25
27
  view_feedback: 'Ver mis comentarios',
26
28
  close: 'Cerrar',
27
29
  },
package/src/i18n/fr.ts CHANGED
@@ -22,6 +22,8 @@ export default {
22
22
  success: {
23
23
  title: 'Merci !',
24
24
  message: 'Votre avis a bien été reçu.',
25
+ title_no_ai: 'Envoyé !',
26
+ message_no_ai: "On s'en occupe. Vous serez informé(e) dès que ce sera résolu.",
25
27
  view_feedback: 'Voir mes avis',
26
28
  close: 'Fermer',
27
29
  },
package/src/i18n/ja.ts CHANGED
@@ -22,6 +22,8 @@ export default {
22
22
  success: {
23
23
  title: 'ありがとうございます!',
24
24
  message: 'フィードバックを受け付けました。',
25
+ title_no_ai: '送信しました!',
26
+ message_no_ai: 'チームが対応します。解決次第お知らせします。',
25
27
  view_feedback: 'フィードバックを確認',
26
28
  close: '閉じる',
27
29
  },
package/src/i18n/ko.ts CHANGED
@@ -22,6 +22,8 @@ export default {
22
22
  success: {
23
23
  title: '감사합니다!',
24
24
  message: '피드백이 접수되었습니다.',
25
+ title_no_ai: '전송 완료!',
26
+ message_no_ai: '팀에서 처리 후 알려드리겠습니다.',
25
27
  view_feedback: '내 피드백 보기',
26
28
  close: '닫기',
27
29
  },
package/src/i18n/zh-CN.ts CHANGED
@@ -22,6 +22,8 @@ export default {
22
22
  success: {
23
23
  title: '感谢!',
24
24
  message: '您的反馈已收到。',
25
+ title_no_ai: '已发送,感谢!',
26
+ message_no_ai: '我们会跟进处理,解决后会通知您。',
25
27
  view_feedback: '查看我的反馈',
26
28
  close: '关闭',
27
29
  },
@@ -72,4 +72,17 @@ describe('SuccessCard', () => {
72
72
 
73
73
  shadow.destroy()
74
74
  })
75
+
76
+ it('shows depleted copy when skipFollowup is true', () => {
77
+ const shadow = new ShadowContainer()
78
+ const onClose = vi.fn()
79
+ const messages = getMessages('en')
80
+ const card = new SuccessCard(shadow, messages, onClose, undefined, { skipFollowup: true })
81
+
82
+ expect(shadow.root.querySelector('.mtb-success-title')?.textContent).toBe(messages.success.title_no_ai)
83
+ expect(shadow.root.querySelector('.mtb-success-msg')?.textContent).toBe(messages.success.message_no_ai)
84
+
85
+ card.destroy()
86
+ shadow.destroy()
87
+ })
75
88
  })
@@ -4,14 +4,21 @@ import { BRAND_COLOR } from '../styles'
4
4
 
5
5
  const SUCCESS_AUTO_CLOSE_MS = 5000
6
6
 
7
+ export interface SuccessCardOptions {
8
+ skipFollowup?: boolean
9
+ }
10
+
7
11
  export class SuccessCard {
8
12
  private el: HTMLDivElement
9
13
 
10
- constructor(shadow: ShadowContainer, messages: I18nMessages, onClose: () => void, onViewFeedback?: () => void) {
14
+ constructor(shadow: ShadowContainer, messages: I18nMessages, onClose: () => void, onViewFeedback?: () => void, options?: SuccessCardOptions) {
11
15
  this.el = shadow.el<HTMLDivElement>('div', 'mtb-success')
12
16
  this.el.style.right = '20px'
13
17
  this.el.style.bottom = '20px'
14
18
 
19
+ const title = options?.skipFollowup ? messages.success.title_no_ai : messages.success.title
20
+ const msg = options?.skipFollowup ? messages.success.message_no_ai : messages.success.message
21
+
15
22
  const viewLink = onViewFeedback
16
23
  ? `<button class="mtb-view-feedback-link">${messages.success.view_feedback}</button>`
17
24
  : ''
@@ -22,8 +29,8 @@ export class SuccessCard {
22
29
  <polyline points="20 6 9 17 4 12"/>
23
30
  </svg>
24
31
  </div>
25
- <div class="mtb-success-title">${messages.success.title}</div>
26
- <div class="mtb-success-msg">${messages.success.message}</div>
32
+ <div class="mtb-success-title">${title}</div>
33
+ <div class="mtb-success-msg">${msg}</div>
27
34
  ${viewLink}
28
35
  <button class="mtb-close-link">${messages.success.close}</button>
29
36
  `
@@ -0,0 +1,89 @@
1
+ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'
2
+ import type { RecordSession } from './session'
3
+ import type { ShadowContainer } from '../widget/shadow'
4
+
5
+ const mockStopFn = vi.fn()
6
+ const mockRecord = Object.assign(
7
+ vi.fn(() => mockStopFn),
8
+ { addCustomEvent: vi.fn() },
9
+ )
10
+
11
+ // Force the bundler import path to fail so start() exercises the CDN fallback,
12
+ // mirroring the IIFE/CDN build where the bare specifier is unresolvable.
13
+ vi.mock('rrweb', () => {
14
+ throw new Error('rrweb not installed')
15
+ })
16
+
17
+ function createMockShadow(): ShadowContainer {
18
+ return {
19
+ el: <T extends HTMLElement>(tag: string, className?: string): T => {
20
+ const el = document.createElement(tag) as T
21
+ if (className) el.className = className
22
+ return el
23
+ },
24
+ append: vi.fn(),
25
+ remove: vi.fn(),
26
+ root: document.createElement('div') as unknown as ShadowRoot,
27
+ destroy: vi.fn(),
28
+ } as unknown as ShadowContainer
29
+ }
30
+
31
+ // session.ts caches the rrweb loader promise at module level, so each test
32
+ // re-imports a fresh module instance.
33
+ async function freshSession(): Promise<RecordSession> {
34
+ vi.resetModules()
35
+ const { RecordSession: Cls } = await import('./session')
36
+ return new Cls(createMockShadow())
37
+ }
38
+
39
+ describe('RecordSession CDN fallback', () => {
40
+ let session: RecordSession | null = null
41
+
42
+ beforeEach(() => {
43
+ vi.clearAllMocks()
44
+ delete (globalThis as Record<string, unknown>).rrwebRecord
45
+ })
46
+
47
+ afterEach(() => {
48
+ session?.destroy()
49
+ session = null
50
+ vi.restoreAllMocks()
51
+ delete (globalThis as Record<string, unknown>).rrwebRecord
52
+ })
53
+
54
+ it('loads @rrweb/record UMD build via classic script tag', async () => {
55
+ const appended: HTMLScriptElement[] = []
56
+ vi.spyOn(document.head, 'appendChild').mockImplementation((node) => {
57
+ const script = node as HTMLScriptElement
58
+ appended.push(script)
59
+ // Simulate the UMD script executing: it sets the global, then load fires
60
+ ;(globalThis as Record<string, unknown>).rrwebRecord = { record: mockRecord }
61
+ script.onload?.(new Event('load'))
62
+ return node
63
+ })
64
+
65
+ session = await freshSession()
66
+ await session.start()
67
+
68
+ expect(appended).toHaveLength(1)
69
+ const script = appended[0]
70
+ // rrweb 2.x publishes no UMD build in the `rrweb` package — its dist files
71
+ // are ESM and throw "Unexpected token 'export'" in a classic script tag.
72
+ // The record-only UMD lives in @rrweb/record's static /umd/ directory.
73
+ expect(script.src).toContain('/npm/@rrweb/record@')
74
+ expect(script.src).toContain('/umd/record.min.js')
75
+ expect(script.integrity).toMatch(/^sha384-/)
76
+ expect(script.crossOrigin).toBe('anonymous')
77
+ expect(mockRecord).toHaveBeenCalledOnce()
78
+ })
79
+
80
+ it('rejects when the CDN script exposes no rrwebRecord global', async () => {
81
+ vi.spyOn(document.head, 'appendChild').mockImplementation((node) => {
82
+ ;(node as HTMLScriptElement).onload?.(new Event('load'))
83
+ return node
84
+ })
85
+
86
+ session = await freshSession()
87
+ await expect(session.start()).rejects.toThrow(/not found after script load/)
88
+ })
89
+ })
@@ -18,8 +18,12 @@ const MAX_DURATION_S = 60
18
18
  // floating tag or unverified content would be a supply-chain hole. Bumping
19
19
  // the version requires recomputing the hash from the exact CDN file:
20
20
  // curl -sL <url> | openssl dgst -sha384 -binary | openssl base64 -A
21
- const RRWEB_CDN = 'https://cdn.jsdelivr.net/npm/rrweb@2.1.0/dist/rrweb.min.js'
22
- const RRWEB_SRI = 'sha384-6qZKf9GE/E2uhA8IdLwXsQiLN/jVx8mhA0i04rQ1aHLrs2URo3ivHlSbaccG59zt'
21
+ // Must stay on @rrweb/record's static /umd/ build: the `rrweb` package ships
22
+ // no UMD in 2.x (its dist files are ESM and throw "Unexpected token 'export'"
23
+ // in a classic script tag), and jsDelivr's auto-minified files are unsafe for
24
+ // SRI because their hash changes when jsDelivr upgrades its minifier.
25
+ const RRWEB_CDN = 'https://cdn.jsdelivr.net/npm/@rrweb/record@2.1.0/umd/record.min.js'
26
+ const RRWEB_SRI = 'sha384-MrD66HBNSykaP2N95+6hQCFlF5oH2tvL3TD/zyvHNkP/sAFWZx98DX9MEDy8MdVT'
23
27
 
24
28
  let rrwebLoaded: Promise<RRWebRecordFn> | null = null
25
29
 
@@ -34,18 +38,28 @@ async function loadViaImport(): Promise<RRWebRecordFn> {
34
38
  return mod.record as unknown as RRWebRecordFn
35
39
  }
36
40
 
41
+ interface RRWebGlobals {
42
+ rrwebRecord?: { record: RRWebRecordFn }
43
+ rrweb?: { record: RRWebRecordFn }
44
+ }
45
+
46
+ function findGlobalRecord(): RRWebRecordFn | undefined {
47
+ const win = globalThis as unknown as Window & RRWebGlobals
48
+ return win.rrwebRecord?.record ?? win.rrweb?.record
49
+ }
50
+
37
51
  function loadViaCdn(): Promise<RRWebRecordFn> {
38
52
  return new Promise((resolve, reject) => {
39
- const win = globalThis as unknown as Window & { rrweb?: { record: RRWebRecordFn } }
40
- if (win.rrweb?.record) { resolve(win.rrweb.record); return }
53
+ const existing = findGlobalRecord()
54
+ if (existing) { resolve(existing); return }
41
55
  const script = document.createElement('script')
42
56
  script.src = RRWEB_CDN
43
57
  script.integrity = RRWEB_SRI
44
58
  script.crossOrigin = 'anonymous'
45
59
  script.onload = () => {
46
- const w = globalThis as unknown as Window & { rrweb?: { record: RRWebRecordFn } }
47
- if (w.rrweb?.record) resolve(w.rrweb.record)
48
- else reject(new Error('rrweb global not found after script load'))
60
+ const record = findGlobalRecord()
61
+ if (record) resolve(record)
62
+ else reject(new Error('rrweb record global not found after script load'))
49
63
  }
50
64
  script.onerror = () => reject(new Error('Failed to load rrweb from CDN'))
51
65
  document.head.appendChild(script)
package/src/types.ts CHANGED
@@ -53,6 +53,7 @@ export interface FeedbackResponse {
53
53
  status: string
54
54
  project_id: string
55
55
  ai_clarify_available?: boolean
56
+ skip_followup?: boolean
56
57
  }
57
58
 
58
59
  export interface ClarifyMessage {
@@ -92,9 +92,12 @@ describe('MakeThisBetter widget flow', () => {
92
92
  shadow.querySelector<HTMLButtonElement>('.mtb-submit-btn')!.click()
93
93
 
94
94
  await vi.waitFor(() => {
95
- expect(shadow.querySelector('.mtb-success-title')?.textContent).toBe('Thanks!')
95
+ expect(shadow.querySelector('.mtb-success-title')?.textContent).toBe('Sent — thanks!')
96
96
  }, { timeout: 5000 })
97
97
 
98
+ expect(shadow.querySelector('.mtb-success-msg')?.textContent).toBe(
99
+ "We'll take it from here. You'll hear back when it's resolved."
100
+ )
98
101
  expect(shadow.querySelector('.mtb-clarify')).toBeNull()
99
102
  expect(fetchSpy).toHaveBeenCalledTimes(1)
100
103
  })
@@ -7,6 +7,7 @@ import { AnnotationSession } from '../annotate/session'
7
7
  import { CommentPopup } from '../popup/comment'
8
8
  import { ClarifyCard } from '../popup/clarify'
9
9
  import { SuccessCard } from '../popup/success'
10
+ import type { SuccessCardOptions } from '../popup/success'
10
11
  import { captureScreenshot } from '../screenshot/capture'
11
12
  import { ConsoleErrorCollector } from '../context/console'
12
13
  import { FrustrationDetector } from '../context/frustration'
@@ -115,8 +116,9 @@ export class WidgetController {
115
116
  if (!this.recordingManager) return
116
117
  this.recordingManager.stop()
117
118
  this.showPopup(window.innerWidth / 2, window.innerHeight / 2, this.messages.record.timer_label)
118
- }).catch(() => {
119
+ }).catch((error) => {
119
120
  // rrweb failed to load (network / SRI mismatch) — fall back to markup
121
+ console.warn('[MakeThisBetter] Screen recording unavailable, falling back to markup:', error)
120
122
  if (this.mode !== 'recording') return
121
123
  this.toolbar?.setMode('markup')
122
124
  this.handleToolbarModeChange('markup')
@@ -176,8 +178,9 @@ export class WidgetController {
176
178
  this.session = null
177
179
  this.recordingManager?.destroy()
178
180
  this.recordingManager = null
179
- if (feedback.ai_clarify_available === false) {
180
- this.showSuccess(feedback.project_id)
181
+ const skipFollowup = feedback.skip_followup === true || feedback.ai_clarify_available === false
182
+ if (skipFollowup) {
183
+ this.showSuccess(feedback.project_id, { skipFollowup: true })
181
184
  } else {
182
185
  this.showClarify(feedback.id, feedback.project_id)
183
186
  }
@@ -202,7 +205,7 @@ export class WidgetController {
202
205
  })
203
206
  }
204
207
 
205
- private showSuccess(projectId: string): void {
208
+ private showSuccess(projectId: string, options?: SuccessCardOptions): void {
206
209
  this.mode = 'idle'
207
210
  this.tab?.setActive(false)
208
211
  const baseUrl = this.config.apiUrl
@@ -216,7 +219,7 @@ export class WidgetController {
216
219
  }, hasIdentity ? async () => {
217
220
  const token = await this.apiClient.resolveUserToken()
218
221
  if (token) window.open(`${boardUrl}?identity=${encodeURIComponent(token)}`, '_blank')
219
- } : undefined)
222
+ } : undefined, options)
220
223
  }
221
224
 
222
225
  private exitAll(): void {