@perspective-ai/sdk 1.0.0-alpha.2

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 (45) hide show
  1. package/README.md +333 -0
  2. package/dist/browser.cjs +1939 -0
  3. package/dist/browser.cjs.map +1 -0
  4. package/dist/browser.d.cts +213 -0
  5. package/dist/browser.d.ts +213 -0
  6. package/dist/browser.js +1900 -0
  7. package/dist/browser.js.map +1 -0
  8. package/dist/cdn/perspective.global.js +406 -0
  9. package/dist/cdn/perspective.global.js.map +1 -0
  10. package/dist/constants.cjs +142 -0
  11. package/dist/constants.cjs.map +1 -0
  12. package/dist/constants.d.cts +104 -0
  13. package/dist/constants.d.ts +104 -0
  14. package/dist/constants.js +127 -0
  15. package/dist/constants.js.map +1 -0
  16. package/dist/index.cjs +1596 -0
  17. package/dist/index.cjs.map +1 -0
  18. package/dist/index.d.cts +155 -0
  19. package/dist/index.d.ts +155 -0
  20. package/dist/index.js +1579 -0
  21. package/dist/index.js.map +1 -0
  22. package/package.json +83 -0
  23. package/src/browser.test.ts +388 -0
  24. package/src/browser.ts +509 -0
  25. package/src/config.test.ts +81 -0
  26. package/src/config.ts +95 -0
  27. package/src/constants.ts +214 -0
  28. package/src/float.test.ts +332 -0
  29. package/src/float.ts +231 -0
  30. package/src/fullpage.test.ts +224 -0
  31. package/src/fullpage.ts +126 -0
  32. package/src/iframe.test.ts +1037 -0
  33. package/src/iframe.ts +421 -0
  34. package/src/index.ts +61 -0
  35. package/src/loading.ts +90 -0
  36. package/src/popup.test.ts +344 -0
  37. package/src/popup.ts +157 -0
  38. package/src/slider.test.ts +277 -0
  39. package/src/slider.ts +158 -0
  40. package/src/styles.ts +395 -0
  41. package/src/types.ts +148 -0
  42. package/src/utils.test.ts +162 -0
  43. package/src/utils.ts +86 -0
  44. package/src/widget.test.ts +375 -0
  45. package/src/widget.ts +195 -0
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Shared constants for Perspective Embed SDK
3
+ * This file is SSR-safe - no DOM access at import time
4
+ * Used by both SDK bundle and the main Perspective app
5
+ */
6
+ /** SDK version for handshake protocol */
7
+ declare const SDK_VERSION = "1.0.0";
8
+ /** Feature flags as bitset for version negotiation */
9
+ declare const FEATURES: {
10
+ readonly RESIZE: number;
11
+ readonly THEME_SYNC: number;
12
+ readonly ANON_ID: number;
13
+ readonly SCROLLBAR_STYLES: number;
14
+ };
15
+ /** Current SDK feature set */
16
+ declare const CURRENT_FEATURES: number;
17
+ declare const PARAM_KEYS: {
18
+ readonly email: "email";
19
+ readonly name: "name";
20
+ readonly returnUrl: "returnUrl";
21
+ readonly voice: "voice";
22
+ readonly scroll: "scroll";
23
+ readonly hideProgress: "hideProgress";
24
+ readonly hideGreeting: "hideGreeting";
25
+ readonly hideBranding: "hideBranding";
26
+ readonly mode: "mode";
27
+ readonly invite: "invite";
28
+ readonly embed: "embed";
29
+ readonly embedType: "embed_type";
30
+ readonly theme: "theme";
31
+ };
32
+ type ParamKey = (typeof PARAM_KEYS)[keyof typeof PARAM_KEYS];
33
+ declare const BRAND_KEYS: {
34
+ readonly primary: "brand.primary";
35
+ readonly secondary: "brand.secondary";
36
+ readonly bg: "brand.bg";
37
+ readonly text: "brand.text";
38
+ readonly darkPrimary: "brand.dark.primary";
39
+ readonly darkSecondary: "brand.dark.secondary";
40
+ readonly darkBg: "brand.dark.bg";
41
+ readonly darkText: "brand.dark.text";
42
+ };
43
+ type BrandKey = (typeof BRAND_KEYS)[keyof typeof BRAND_KEYS];
44
+ declare const UTM_PARAMS: readonly ["utm_source", "utm_medium", "utm_campaign", "utm_term", "utm_content"];
45
+ type UtmParam = (typeof UTM_PARAMS)[number];
46
+ declare const RESERVED_PARAMS: Set<string>;
47
+ declare const DATA_ATTRS: {
48
+ readonly widget: "data-perspective-widget";
49
+ readonly popup: "data-perspective-popup";
50
+ readonly slider: "data-perspective-slider";
51
+ readonly float: "data-perspective-float";
52
+ readonly chat: "data-perspective-chat";
53
+ readonly fullpage: "data-perspective-fullpage";
54
+ readonly params: "data-perspective-params";
55
+ readonly brand: "data-perspective-brand";
56
+ readonly brandDark: "data-perspective-brand-dark";
57
+ readonly theme: "data-perspective-theme";
58
+ readonly noStyle: "data-perspective-no-style";
59
+ };
60
+ type DataAttr = (typeof DATA_ATTRS)[keyof typeof DATA_ATTRS];
61
+ declare const MESSAGE_TYPES: {
62
+ readonly init: "perspective:init";
63
+ readonly ready: "perspective:ready";
64
+ readonly resize: "perspective:resize";
65
+ readonly submit: "perspective:submit";
66
+ readonly close: "perspective:close";
67
+ readonly error: "perspective:error";
68
+ readonly redirect: "perspective:redirect";
69
+ readonly anonId: "perspective:anon-id";
70
+ readonly injectStyles: "perspective:inject-styles";
71
+ readonly themeChange: "perspective:theme-change";
72
+ readonly requestScrollbarStyles: "perspective:request-scrollbar-styles";
73
+ };
74
+ type MessageType = (typeof MESSAGE_TYPES)[keyof typeof MESSAGE_TYPES];
75
+ declare const ERROR_CODES: {
76
+ readonly SDK_OUTDATED: "SDK_OUTDATED";
77
+ readonly INVALID_RESEARCH: "INVALID_RESEARCH";
78
+ readonly UNKNOWN: "UNKNOWN";
79
+ };
80
+ type ErrorCode = (typeof ERROR_CODES)[keyof typeof ERROR_CODES];
81
+ declare const PARAM_VALUES: {
82
+ readonly disabled: "0";
83
+ readonly enabled: "1";
84
+ readonly true: "true";
85
+ readonly false: "false";
86
+ };
87
+ declare const THEME_VALUES: {
88
+ readonly dark: "dark";
89
+ readonly light: "light";
90
+ readonly system: "system";
91
+ };
92
+ type ThemeValue = (typeof THEME_VALUES)[keyof typeof THEME_VALUES];
93
+ declare const MODE_VALUES: {
94
+ readonly preview: "preview";
95
+ readonly restart: "restart";
96
+ readonly normal: "normal";
97
+ readonly simulated: "simulated";
98
+ };
99
+ type ModeValue = (typeof MODE_VALUES)[keyof typeof MODE_VALUES];
100
+ declare const STORAGE_KEYS: {
101
+ readonly anonId: "perspective-anon-id";
102
+ };
103
+
104
+ export { BRAND_KEYS, type BrandKey, CURRENT_FEATURES, DATA_ATTRS, type DataAttr, ERROR_CODES, type ErrorCode, FEATURES, MESSAGE_TYPES, MODE_VALUES, type MessageType, type ModeValue, PARAM_KEYS, PARAM_VALUES, type ParamKey, RESERVED_PARAMS, SDK_VERSION, STORAGE_KEYS, THEME_VALUES, type ThemeValue, UTM_PARAMS, type UtmParam };
@@ -0,0 +1,127 @@
1
+ // src/constants.ts
2
+ var SDK_VERSION = "1.0.0";
3
+ var FEATURES = {
4
+ RESIZE: 1 << 0,
5
+ // 0b0001
6
+ THEME_SYNC: 1 << 1,
7
+ // 0b0010
8
+ ANON_ID: 1 << 2,
9
+ // 0b0100
10
+ SCROLLBAR_STYLES: 1 << 3
11
+ // 0b1000
12
+ };
13
+ var CURRENT_FEATURES = FEATURES.RESIZE | FEATURES.THEME_SYNC | FEATURES.ANON_ID | FEATURES.SCROLLBAR_STYLES;
14
+ var PARAM_KEYS = {
15
+ // User identification
16
+ email: "email",
17
+ name: "name",
18
+ // Navigation
19
+ returnUrl: "returnUrl",
20
+ // Interview behavior
21
+ voice: "voice",
22
+ scroll: "scroll",
23
+ hideProgress: "hideProgress",
24
+ hideGreeting: "hideGreeting",
25
+ hideBranding: "hideBranding",
26
+ // Interview mode & auth
27
+ mode: "mode",
28
+ invite: "invite",
29
+ // System (internal)
30
+ embed: "embed",
31
+ embedType: "embed_type",
32
+ theme: "theme"
33
+ };
34
+ var BRAND_KEYS = {
35
+ // Light mode
36
+ primary: "brand.primary",
37
+ secondary: "brand.secondary",
38
+ bg: "brand.bg",
39
+ text: "brand.text",
40
+ // Dark mode
41
+ darkPrimary: "brand.dark.primary",
42
+ darkSecondary: "brand.dark.secondary",
43
+ darkBg: "brand.dark.bg",
44
+ darkText: "brand.dark.text"
45
+ };
46
+ var UTM_PARAMS = [
47
+ "utm_source",
48
+ "utm_medium",
49
+ "utm_campaign",
50
+ "utm_term",
51
+ "utm_content"
52
+ ];
53
+ var RESERVED_PARAMS = /* @__PURE__ */ new Set([
54
+ PARAM_KEYS.embed,
55
+ PARAM_KEYS.embedType,
56
+ PARAM_KEYS.theme,
57
+ BRAND_KEYS.primary,
58
+ BRAND_KEYS.secondary,
59
+ BRAND_KEYS.bg,
60
+ BRAND_KEYS.text,
61
+ BRAND_KEYS.darkPrimary,
62
+ BRAND_KEYS.darkSecondary,
63
+ BRAND_KEYS.darkBg,
64
+ BRAND_KEYS.darkText,
65
+ ...UTM_PARAMS
66
+ ]);
67
+ var DATA_ATTRS = {
68
+ widget: "data-perspective-widget",
69
+ popup: "data-perspective-popup",
70
+ slider: "data-perspective-slider",
71
+ float: "data-perspective-float",
72
+ // Primary name
73
+ chat: "data-perspective-chat",
74
+ // Legacy alias
75
+ fullpage: "data-perspective-fullpage",
76
+ params: "data-perspective-params",
77
+ brand: "data-perspective-brand",
78
+ brandDark: "data-perspective-brand-dark",
79
+ theme: "data-perspective-theme",
80
+ noStyle: "data-perspective-no-style"
81
+ };
82
+ var MESSAGE_TYPES = {
83
+ // SDK -> Iframe (initialization)
84
+ init: "perspective:init",
85
+ // Iframe -> SDK
86
+ ready: "perspective:ready",
87
+ resize: "perspective:resize",
88
+ submit: "perspective:submit",
89
+ close: "perspective:close",
90
+ error: "perspective:error",
91
+ redirect: "perspective:redirect",
92
+ // SDK -> Iframe (internal)
93
+ anonId: "perspective:anon-id",
94
+ injectStyles: "perspective:inject-styles",
95
+ themeChange: "perspective:theme-change",
96
+ // Iframe -> SDK (internal)
97
+ requestScrollbarStyles: "perspective:request-scrollbar-styles"
98
+ };
99
+ var ERROR_CODES = {
100
+ SDK_OUTDATED: "SDK_OUTDATED",
101
+ INVALID_RESEARCH: "INVALID_RESEARCH",
102
+ UNKNOWN: "UNKNOWN"
103
+ };
104
+ var PARAM_VALUES = {
105
+ disabled: "0",
106
+ enabled: "1",
107
+ true: "true",
108
+ false: "false"
109
+ };
110
+ var THEME_VALUES = {
111
+ dark: "dark",
112
+ light: "light",
113
+ system: "system"
114
+ };
115
+ var MODE_VALUES = {
116
+ preview: "preview",
117
+ restart: "restart",
118
+ normal: "normal",
119
+ simulated: "simulated"
120
+ };
121
+ var STORAGE_KEYS = {
122
+ anonId: "perspective-anon-id"
123
+ };
124
+
125
+ export { BRAND_KEYS, CURRENT_FEATURES, DATA_ATTRS, ERROR_CODES, FEATURES, MESSAGE_TYPES, MODE_VALUES, PARAM_KEYS, PARAM_VALUES, RESERVED_PARAMS, SDK_VERSION, STORAGE_KEYS, THEME_VALUES, UTM_PARAMS };
126
+ //# sourceMappingURL=constants.js.map
127
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/constants.ts"],"names":[],"mappings":"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","file":"constants.js","sourcesContent":["/**\n * Shared constants for Perspective Embed SDK\n * This file is SSR-safe - no DOM access at import time\n * Used by both SDK bundle and the main Perspective app\n */\n\n// ============================================================================\n// SDK Version & Features\n// ============================================================================\n\n/** SDK version for handshake protocol */\nexport const SDK_VERSION = \"1.0.0\";\n\n/** Feature flags as bitset for version negotiation */\nexport const FEATURES = {\n RESIZE: 1 << 0, // 0b0001\n THEME_SYNC: 1 << 1, // 0b0010\n ANON_ID: 1 << 2, // 0b0100\n SCROLLBAR_STYLES: 1 << 3, // 0b1000\n} as const;\n\n/** Current SDK feature set */\nexport const CURRENT_FEATURES =\n FEATURES.RESIZE |\n FEATURES.THEME_SYNC |\n FEATURES.ANON_ID |\n FEATURES.SCROLLBAR_STYLES;\n\n// ============================================================================\n// URL Parameter Keys\n// ============================================================================\n\nexport const PARAM_KEYS = {\n // User identification\n email: \"email\",\n name: \"name\",\n\n // Navigation\n returnUrl: \"returnUrl\",\n\n // Interview behavior\n voice: \"voice\",\n scroll: \"scroll\",\n hideProgress: \"hideProgress\",\n hideGreeting: \"hideGreeting\",\n hideBranding: \"hideBranding\",\n\n // Interview mode & auth\n mode: \"mode\",\n invite: \"invite\",\n\n // System (internal)\n embed: \"embed\",\n embedType: \"embed_type\",\n theme: \"theme\",\n} as const;\n\nexport type ParamKey = (typeof PARAM_KEYS)[keyof typeof PARAM_KEYS];\n\n// ============================================================================\n// Brand Color Keys\n// ============================================================================\n\nexport const BRAND_KEYS = {\n // Light mode\n primary: \"brand.primary\",\n secondary: \"brand.secondary\",\n bg: \"brand.bg\",\n text: \"brand.text\",\n\n // Dark mode\n darkPrimary: \"brand.dark.primary\",\n darkSecondary: \"brand.dark.secondary\",\n darkBg: \"brand.dark.bg\",\n darkText: \"brand.dark.text\",\n} as const;\n\nexport type BrandKey = (typeof BRAND_KEYS)[keyof typeof BRAND_KEYS];\n\n// ============================================================================\n// UTM Parameters (auto-forwarded from parent URL)\n// ============================================================================\n\nexport const UTM_PARAMS = [\n \"utm_source\",\n \"utm_medium\",\n \"utm_campaign\",\n \"utm_term\",\n \"utm_content\",\n] as const;\n\nexport type UtmParam = (typeof UTM_PARAMS)[number];\n\n// ============================================================================\n// Reserved Parameters (cannot be overridden via custom params)\n// ============================================================================\n\nexport const RESERVED_PARAMS: Set<string> = new Set([\n PARAM_KEYS.embed,\n PARAM_KEYS.embedType,\n PARAM_KEYS.theme,\n BRAND_KEYS.primary,\n BRAND_KEYS.secondary,\n BRAND_KEYS.bg,\n BRAND_KEYS.text,\n BRAND_KEYS.darkPrimary,\n BRAND_KEYS.darkSecondary,\n BRAND_KEYS.darkBg,\n BRAND_KEYS.darkText,\n ...UTM_PARAMS,\n]);\n\n// ============================================================================\n// Data Attributes (HTML declarative initialization)\n// ============================================================================\n\nexport const DATA_ATTRS = {\n widget: \"data-perspective-widget\",\n popup: \"data-perspective-popup\",\n slider: \"data-perspective-slider\",\n float: \"data-perspective-float\", // Primary name\n chat: \"data-perspective-chat\", // Legacy alias\n fullpage: \"data-perspective-fullpage\",\n params: \"data-perspective-params\",\n brand: \"data-perspective-brand\",\n brandDark: \"data-perspective-brand-dark\",\n theme: \"data-perspective-theme\",\n noStyle: \"data-perspective-no-style\",\n} as const;\n\nexport type DataAttr = (typeof DATA_ATTRS)[keyof typeof DATA_ATTRS];\n\n// ============================================================================\n// PostMessage Event Types\n// ============================================================================\n\nexport const MESSAGE_TYPES = {\n // SDK -> Iframe (initialization)\n init: \"perspective:init\",\n\n // Iframe -> SDK\n ready: \"perspective:ready\",\n resize: \"perspective:resize\",\n submit: \"perspective:submit\",\n close: \"perspective:close\",\n error: \"perspective:error\",\n redirect: \"perspective:redirect\",\n\n // SDK -> Iframe (internal)\n anonId: \"perspective:anon-id\",\n injectStyles: \"perspective:inject-styles\",\n themeChange: \"perspective:theme-change\",\n\n // Iframe -> SDK (internal)\n requestScrollbarStyles: \"perspective:request-scrollbar-styles\",\n} as const;\n\nexport type MessageType = (typeof MESSAGE_TYPES)[keyof typeof MESSAGE_TYPES];\n\n// ============================================================================\n// Error Codes\n// ============================================================================\n\nexport const ERROR_CODES = {\n SDK_OUTDATED: \"SDK_OUTDATED\",\n INVALID_RESEARCH: \"INVALID_RESEARCH\",\n UNKNOWN: \"UNKNOWN\",\n} as const;\n\nexport type ErrorCode = (typeof ERROR_CODES)[keyof typeof ERROR_CODES];\n\n// ============================================================================\n// Param Values (for boolean-like string params)\n// ============================================================================\n\nexport const PARAM_VALUES = {\n disabled: \"0\",\n enabled: \"1\",\n true: \"true\",\n false: \"false\",\n} as const;\n\n// ============================================================================\n// Theme Values\n// ============================================================================\n\nexport const THEME_VALUES = {\n dark: \"dark\",\n light: \"light\",\n system: \"system\",\n} as const;\n\nexport type ThemeValue = (typeof THEME_VALUES)[keyof typeof THEME_VALUES];\n\n// ============================================================================\n// Interview Mode Values (for mode param)\n// ============================================================================\n\nexport const MODE_VALUES = {\n preview: \"preview\",\n restart: \"restart\",\n normal: \"normal\",\n simulated: \"simulated\",\n} as const;\n\nexport type ModeValue = (typeof MODE_VALUES)[keyof typeof MODE_VALUES];\n\n// ============================================================================\n// localStorage Keys\n// ============================================================================\n\nexport const STORAGE_KEYS = {\n anonId: \"perspective-anon-id\",\n} as const;\n"]}