@frigade/js 0.0.1

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023 Frigade
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,83 @@
1
+ [![npm version](https://img.shields.io/npm/v/@frigade/js)](https://www.npmjs.com/package/@frigade/js)
2
+ [![npm version](https://github.com/FrigadeHQ/frigade-js/actions/workflows/tests.yml/badge.svg)](https://github.com/FrigadeHQ/frigade-js/actions/workflows/tests.yml)
3
+ [![typescript](https://camo.githubusercontent.com/0f9fcc0ac1b8617ad4989364f60f78b2d6b32985ad6a508f215f14d8f897b8d3/68747470733a2f2f62616467656e2e6e65742f62616467652f547970655363726970742f7374726963742532302546302539462539322541412f626c7565)](https://www.npmjs.com/package/@frigade/js)
4
+ [![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg)](https://github.com/prettier/prettier)
5
+
6
+ <H3 align="center"><strong>Frigade Javascript SDK</strong></H3>
7
+ <div align="center">The easiest way for developers to build high-quality product onboarding and education.</div>
8
+ <br />
9
+ <div align="center">
10
+ <a href="https://frigade.com">Website</a>
11
+ <span> · </span>
12
+ <a href="https://demo.frigade.com">Demo</a>
13
+ <span> · </span>
14
+ <a href="https://github.com/FrigadeHQ">GitHub</a>
15
+ <span> · </span>
16
+ <a href="https://docs.frigade.com">Docs</a></div>
17
+
18
+ <br />
19
+
20
+ ![Frigade iamge](https://frigade.com/img/frigademetaimage-v2.png)
21
+
22
+ ## Install
23
+
24
+ Install the package from your command line.
25
+
26
+ #### With yarn
27
+
28
+ ```bash
29
+ yarn add @frigade/js
30
+ ```
31
+
32
+ #### With npm
33
+
34
+ ```bash
35
+ npm install @frigade/js
36
+ ```
37
+
38
+ ### About Frigade
39
+
40
+ [Frigade](<https://frigade.com>) is a developer-first platform for building quality product onboarding. A powerful,
41
+ flexible API and native SDKs allow you to build onboarding 10x faster, experiment more easily, and drive customer
42
+ success.
43
+
44
+ Frigade supports a series of use cases such as:
45
+
46
+ - **Registration**: Maximize the number of users getting through your sign up flows with beautiful explainers, progress
47
+ bars, and forms.
48
+ - **Activation**: Convert more customers by taking them through a series of key onboarding items specific to their role,
49
+ permissions, or goals.
50
+ - **Adoption**: Introduce audiences to specific features that deliver value with native hotspots, tooltips, tours, and
51
+ interactive product guides.
52
+ - **Engagement**: Keep active customers engaged, announce new product features, and create lifecycle specific
53
+ re-onboarding flows for dormant or churned customers.
54
+ - **Retention**: Increase retention by delivering the right content at the right time, and by asking your users for
55
+ feedback on the product.
56
+
57
+ # Features
58
+
59
+ **Component Library**
60
+
61
+ Unstyled, ready-made components for building high‑quality user onboarding, faster. Onboarding checklists, tooltips,
62
+ product walkthroughs, and much more. [See components](https://frigade.com/components)
63
+
64
+ **Integrations**
65
+
66
+ Integrations with Segment, Mixpanel, Posthog, and more to power targeting, analytics, and communications.
67
+
68
+ **Content Management**
69
+
70
+ Lightweight CMS built-in to update and test onboarding copy and content.
71
+
72
+ **Versioning**
73
+
74
+ Frigade makes it easy to manage multiple versions of onboarding across staging and production. Revisit previous versions
75
+ of onboarding to see how they performed and make improvements.
76
+
77
+ **Customer Journeys**
78
+
79
+ Frigade automatically tracks state management and onboarding progress. Give your team full observability into the
80
+ customer journey, and use Frigade to kick off automated workflows.
81
+
82
+ To learn more, visit [frigade.com](<https://frigade.com>)
83
+
package/lib/index.d.ts ADDED
@@ -0,0 +1,188 @@
1
+ interface FlowStepData {
2
+ /**
3
+ * Unique identifier for the step.
4
+ */
5
+ id: string;
6
+ /**
7
+ * Name of the step when shown in a list view
8
+ */
9
+ stepName?: string;
10
+ /**
11
+ * Title of the step
12
+ */
13
+ title?: string;
14
+ /**
15
+ * Subtitle of the step
16
+ */
17
+ subtitle?: string;
18
+ /**
19
+ * Primary button title. If omitted, the primary button will not be shown.
20
+ */
21
+ primaryButtonTitle?: string;
22
+ /**
23
+ * Primary button URI.
24
+ */
25
+ primaryButtonUri?: string;
26
+ /**
27
+ * Primary button URI target (either _blank or _self)
28
+ */
29
+ primaryButtonUriTarget?: string;
30
+ /**
31
+ * Secondary button title. If omitted, the secondary button will not be shown.
32
+ */
33
+ secondaryButtonTitle?: string;
34
+ /**
35
+ * Secondary button URI.
36
+ */
37
+ secondaryButtonUri?: string;
38
+ /**
39
+ * Secondary button URI target (either _blank or _self)
40
+ */
41
+ secondaryButtonUriTarget?: string;
42
+ /**
43
+ * Text on button if a back button is present
44
+ */
45
+ backButtonTitle?: string;
46
+ /**
47
+ * If true, the step will be marked as completed when the secondary button is clicked.
48
+ */
49
+ skippable?: boolean;
50
+ /**
51
+ * Video url to be shown for components supporting video.
52
+ */
53
+ videoUri?: string;
54
+ /**
55
+ * Image url to be shown for components supporting image.
56
+ */
57
+ imageUri?: string | null;
58
+ /**
59
+ * Automatically mark the step as completed when the primary button is clicked. Default is false.
60
+ */
61
+ autoMarkCompleted?: boolean;
62
+ /**
63
+ * Whether the step has been completed (equivalent to step status === COMPLETED_STEP)
64
+ */
65
+ complete: boolean;
66
+ /**
67
+ * Whether the step is blocked (can't be accessed yet) based on `startCriteria`
68
+ */
69
+ blocked?: boolean;
70
+ /**
71
+ * Whether the step is hidden (not shown in the list view) based on `visibilityCriteria`
72
+ */
73
+ hidden?: boolean;
74
+ /**
75
+ * Handler for when the primary button is clicked.
76
+ */
77
+ handlePrimaryButtonClick?: () => void;
78
+ /**
79
+ * Handler for when the secondary button is clicked.
80
+ */
81
+ handleSecondaryButtonClick?: () => void;
82
+ props?: any;
83
+ /**
84
+ * Criteria that needs to be met for the step to complete
85
+ */
86
+ completionCriteria?: string;
87
+ /**
88
+ * Criteria that needs to be met for the step to start
89
+ */
90
+ startCriteria?: string;
91
+ /**
92
+ * Progress if the step is tied to another Frigade Flow through completionCriteria
93
+ */
94
+ progress?: number;
95
+ /**
96
+ * Whether the step is dismissible (for instance, tooltips or other non-essential steps)
97
+ */
98
+ dismissible?: boolean;
99
+ }
100
+ interface FrigadeConfig {
101
+ /**
102
+ * API url to use for all requests. Defaults to https://api.frigade.com
103
+ */
104
+ apiUrl?: string;
105
+ }
106
+
107
+ interface FlowMetadata {
108
+ id: number;
109
+ name: string;
110
+ description: string;
111
+ data: string;
112
+ createdAt: string;
113
+ modifiedAt: string;
114
+ slug: string;
115
+ targetingLogic: string;
116
+ type: FlowType;
117
+ triggerType: TriggerType;
118
+ status: FlowStatus;
119
+ version: number;
120
+ active: boolean;
121
+ }
122
+ declare enum FlowType {
123
+ CHECKLIST = "CHECKLIST",
124
+ FORM = "FORM",
125
+ TOUR = "TOUR",
126
+ SUPPORT = "SUPPORT",
127
+ CUSTOM = "CUSTOM",
128
+ BANNER = "BANNER",
129
+ EMBEDDED_TIP = "EMBEDDED_TIP",
130
+ NPS_SURVEY = "NPS_SURVEY"
131
+ }
132
+ declare enum TriggerType {
133
+ MANUAL = "MANUAL",
134
+ AUTOMATIC = "AUTOMATIC"
135
+ }
136
+ declare enum FlowStatus {
137
+ DRAFT = "DRAFT",
138
+ ACTIVE = "ACTIVE",
139
+ ARCHIVED = "ARCHIVED"
140
+ }
141
+
142
+ declare class Flow {
143
+ /**
144
+ * THe Flow ID / slug of the flow
145
+ */
146
+ readonly id: string;
147
+ /**
148
+ * The status of the flow
149
+ */
150
+ readonly status: FlowStatus;
151
+ /**
152
+ * The raw data defined in `flow-data.yml` as a JSON decoded object
153
+ */
154
+ readonly flowData: Record<any, any>;
155
+ /**
156
+ * The steps contained in the `data` array in `flow-data.yml`
157
+ */
158
+ readonly steps: FlowStepData[];
159
+ /**
160
+ * The user-facing title of the flow, if defined at the top level of `flow-data.yml`
161
+ */
162
+ readonly title?: string;
163
+ /**
164
+ * The user-facing description of the flow, if defined at the top level of `flow-data.yml`
165
+ */
166
+ readonly subtitle?: string;
167
+ /**
168
+ * The metadata of the flow.
169
+ */
170
+ readonly metadata: FlowMetadata;
171
+ constructor(id: string, status: FlowStatus, rawData: Record<any, any>, steps: FlowStepData[], title?: string, subtitle?: string);
172
+ }
173
+
174
+ declare class Frigade {
175
+ readonly apiKey?: string;
176
+ readonly userId?: string;
177
+ readonly organizationId?: string;
178
+ readonly config?: FrigadeConfig;
179
+ hasInitialized: boolean;
180
+ private flows;
181
+ constructor(apiKey: string, userId?: string, organizationId?: string, config?: FrigadeConfig);
182
+ init(): Promise<void>;
183
+ getFlow(flowId: string): Promise<Flow>;
184
+ private errorOnUninitialized;
185
+ private refreshFlows;
186
+ }
187
+
188
+ export { Flow, Frigade as default };
package/lib/index.js ADDED
@@ -0,0 +1,3 @@
1
+ "use client";
2
+ var d=Object.defineProperty;var S=Object.getOwnPropertyDescriptor;var w=Object.getOwnPropertyNames;var E=Object.prototype.hasOwnProperty;var y=(e,t)=>{for(var o in t)d(e,o,{get:t[o],enumerable:!0})},h=(e,t,o,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of w(t))!E.call(e,i)&&i!==o&&d(e,i,{get:()=>t[i],enumerable:!(r=S(t,i))||r.enumerable});return e};var F=e=>h(d({},"__esModule",{value:!0}),e);var R={};y(R,{Flow:()=>a,default:()=>A});module.exports=F(R);var f="1.32.18";var O="frigade-last-call-at-",_="frigade-last-call-data-";function D(e){return{config:{headers:{Authorization:`Bearer ${e}`,"Content-Type":"application/json","X-Frigade-SDK-Version":f,"X-Frigade-SDK-Platform":"Javascript"}}}}function g(e){return window&&window.localStorage?window.localStorage.getItem(e):null}function T(e,t){window&&window.localStorage&&window.localStorage.setItem(e,t)}async function m(e,t){let o=O+e,r=_+e;if(window&&window.localStorage&&t&&t.body&&t.method==="POST"){let n=g(o),l=g(r);if(n&&l&&l==t.body){let p=new Date(n);if(new Date().getTime()-p.getTime()<1e3)return c()}T(o,new Date().toISOString()),T(r,t.body)}let i;try{i=await fetch(e,t)}catch(n){return c(n)}return i?i.ok?i:c(i.statusText):c()}function c(e){return e&&console.log("Call to Frigade failed",e),{json:()=>({})}}function u(e,t,o){return m(L(e,t),{...o??{},...D(e)})}function L(e,t){return`${e}/public/v1${t}`}var a=class{constructor(t,o,r,i,n,l){this.id=t,this.status=o,this.flowData=r,this.steps=i,this.title=n,this.subtitle=l}};var s=class{constructor(t,o,r,i){this.hasInitialized=!1;this.flows=[];this.apiKey=t,this.userId=o,this.organizationId=r,this.config=i}async init(){return await this.refreshFlows(),this.hasInitialized=!0,Promise.any(null)}async getFlow(t){return this.errorOnUninitialized(),this.flows.find(o=>o.id==t)}errorOnUninitialized(){if(!this.hasInitialized)throw new Error("Frigade has not been initialized yet. Please call Frigade.init() before using any other methods.")}async refreshFlows(){this.flows=[];let t=await u(this.apiKey,"/flows");t&&t.data&&t.data.forEach(r=>{let i=JSON.parse(r.data);this.flows.push(new a(r.slug,r.status,i,(i==null?void 0:i.data)??[],i==null?void 0:i.title,i==null?void 0:i.subtitle))})}};var A=s;0&&(module.exports={Flow});
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/core/version.ts","../src/shared/utils.ts","../src/core/flow.ts","../src/core/frigade.ts"],"sourcesContent":["import Frigade from './core/frigade'\nimport Flow from './core/flow'\n\nexport { Flow }\nexport default Frigade\n","export const VERSION_NUMBER = '1.32.18'\n","import { VERSION_NUMBER } from '../core/version'\n\nexport const NOT_STARTED_STEP = 'NOT_STARTED_STEP'\nexport const COMPLETED_FLOW = 'COMPLETED_FLOW'\nexport const ABORTED_FLOW = 'ABORTED_FLOW'\nexport const STARTED_FLOW = 'STARTED_FLOW'\nexport const NOT_STARTED_FLOW = 'NOT_STARTED_FLOW'\nexport const COMPLETED_STEP = 'COMPLETED_STEP'\nexport const STARTED_STEP = 'STARTED_STEP'\nexport type StepActionType = 'STARTED_STEP' | 'COMPLETED_STEP' | 'NOT_STARTED_STEP'\nexport type UserFlowStatus = 'NOT_STARTED_FLOW' | 'STARTED_FLOW' | 'COMPLETED_FLOW' | 'ABORTED_FLOW'\nconst LAST_POST_CALL_AT = 'frigade-last-call-at-'\nconst LAST_POST_CALL_DATA = 'frigade-last-call-data-'\n\nfunction getConfig(apiKey: string) {\n return {\n config: {\n headers: {\n Authorization: `Bearer ${apiKey}`,\n 'Content-Type': 'application/json',\n 'X-Frigade-SDK-Version': VERSION_NUMBER,\n 'X-Frigade-SDK-Platform': 'Javascript',\n },\n },\n }\n}\n\nfunction getLocalStorage(key: string) {\n if (window && window.localStorage) {\n return window.localStorage.getItem(key)\n }\n return null\n}\n\nfunction setLocalStorage(key: string, value: string) {\n if (window && window.localStorage) {\n window.localStorage.setItem(key, value)\n }\n}\n\nexport async function gracefulFetch(url: string, options: any) {\n const lastCallAtKey = LAST_POST_CALL_AT + url\n const lastCallDataKey = LAST_POST_CALL_DATA + url\n if (window && window.localStorage && options && options.body && options.method === 'POST') {\n const lastCall = getLocalStorage(lastCallAtKey)\n const lastCallData = getLocalStorage(lastCallDataKey)\n if (lastCall && lastCallData && lastCallData == options.body) {\n const lastCallDate = new Date(lastCall)\n const now = new Date()\n const diff = now.getTime() - lastCallDate.getTime()\n // Throttle consecutive POST calls to 1 second\n if (diff < 1000) {\n return getEmptyResponse()\n }\n }\n setLocalStorage(lastCallAtKey, new Date().toISOString())\n setLocalStorage(lastCallDataKey, options.body)\n }\n\n let response\n try {\n response = await fetch(url, options)\n } catch (error) {\n return getEmptyResponse(error)\n }\n\n if (!response) {\n return getEmptyResponse()\n }\n\n if (!response.ok) {\n return getEmptyResponse(response.statusText)\n }\n\n return response\n}\n\nfunction getEmptyResponse(error?: any) {\n if (error) {\n console.log('Call to Frigade failed', error)\n }\n\n // Create empty response that contains the .json method and returns an empty object\n return {\n json: () => ({}),\n }\n}\n\nexport function fetcher(apiKey: string, url: string, options?: Record<any, any>) {\n return gracefulFetch(getUrl(apiKey, url), {\n ...(options ?? {}),\n ...getConfig(apiKey),\n })\n}\n\nfunction getUrl(apiUrl: string, postfix: string) {\n return `${apiUrl}/public/v1${postfix}`\n}\n","import { FlowStepData } from '../types'\nimport { FlowMetadata, FlowStatus } from './types'\n\nexport default class Flow {\n /**\n * THe Flow ID / slug of the flow\n */\n public readonly id: string\n /**\n * The status of the flow\n */\n public readonly status: FlowStatus\n /**\n * The raw data defined in `flow-data.yml` as a JSON decoded object\n */\n public readonly flowData: Record<any, any>\n /**\n * The steps contained in the `data` array in `flow-data.yml`\n */\n public readonly steps: FlowStepData[]\n /**\n * The user-facing title of the flow, if defined at the top level of `flow-data.yml`\n */\n public readonly title?: string\n /**\n * The user-facing description of the flow, if defined at the top level of `flow-data.yml`\n */\n public readonly subtitle?: string\n /**\n * The metadata of the flow.\n */\n public readonly metadata: FlowMetadata\n\n constructor(\n id: string,\n status: FlowStatus,\n rawData: Record<any, any>,\n steps: FlowStepData[],\n title?: string,\n subtitle?: string\n ) {\n this.id = id\n this.status = status\n this.flowData = rawData\n this.steps = steps\n this.title = title\n this.subtitle = subtitle\n }\n}\n","import { FrigadeConfig } from '../types'\nimport { fetcher } from '../shared/utils'\nimport Flow from './flow'\nimport { FlowMetadata } from './types'\n\nexport default class Frigade {\n public readonly apiKey?: string\n public readonly userId?: string\n public readonly organizationId?: string\n public readonly config?: FrigadeConfig\n public hasInitialized = false\n\n private flows: Flow[] = []\n\n constructor(apiKey: string, userId?: string, organizationId?: string, config?: FrigadeConfig) {\n this.apiKey = apiKey\n this.userId = userId\n this.organizationId = organizationId\n this.config = config\n }\n\n public async init(): Promise<void> {\n await this.refreshFlows()\n this.hasInitialized = true\n return Promise.any(null)\n }\n\n public async getFlow(flowId: string) {\n this.errorOnUninitialized()\n return this.flows.find((flow) => flow.id == flowId)\n }\n\n private errorOnUninitialized() {\n if (!this.hasInitialized) {\n throw new Error(\n 'Frigade has not been initialized yet. Please call Frigade.init() before using any other methods.'\n )\n }\n }\n\n private async refreshFlows() {\n this.flows = []\n const flowDataRaw = await fetcher(this.apiKey, '/flows')\n if (flowDataRaw && flowDataRaw.data) {\n let flowMetadatas = flowDataRaw.data as FlowMetadata[]\n flowMetadatas.forEach((flowMetadata) => {\n const rawData = JSON.parse(flowMetadata.data)\n this.flows.push(\n new Flow(\n flowMetadata.slug,\n flowMetadata.status,\n rawData,\n rawData?.data ?? [],\n rawData?.title,\n rawData?.subtitle\n )\n )\n })\n }\n }\n}\n"],"mappings":"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","names":["src_exports","__export","Flow","src_default","__toCommonJS","VERSION_NUMBER","LAST_POST_CALL_AT","LAST_POST_CALL_DATA","getConfig","apiKey","VERSION_NUMBER","getLocalStorage","key","setLocalStorage","value","gracefulFetch","url","options","lastCallAtKey","lastCallDataKey","lastCall","lastCallData","lastCallDate","getEmptyResponse","response","error","fetcher","getUrl","apiUrl","postfix","Flow","id","status","rawData","steps","title","subtitle","Frigade","apiKey","userId","organizationId","config","flowId","flow","flowDataRaw","fetcher","flowMetadata","rawData","Flow","src_default","Frigade"]}
package/lib/index.mjs ADDED
@@ -0,0 +1,3 @@
1
+ "use client";
2
+ var d="1.32.18";var p="frigade-last-call-at-",S="frigade-last-call-data-";function w(i){return{config:{headers:{Authorization:`Bearer ${i}`,"Content-Type":"application/json","X-Frigade-SDK-Version":d,"X-Frigade-SDK-Platform":"Javascript"}}}}function f(i){return window&&window.localStorage?window.localStorage.getItem(i):null}function g(i,t){window&&window.localStorage&&window.localStorage.setItem(i,t)}async function E(i,t){let o=p+i,r=S+i;if(window&&window.localStorage&&t&&t.body&&t.method==="POST"){let a=f(o),l=f(r);if(a&&l&&l==t.body){let u=new Date(a);if(new Date().getTime()-u.getTime()<1e3)return c()}g(o,new Date().toISOString()),g(r,t.body)}let e;try{e=await fetch(i,t)}catch(a){return c(a)}return e?e.ok?e:c(e.statusText):c()}function c(i){return i&&console.log("Call to Frigade failed",i),{json:()=>({})}}function T(i,t,o){return E(y(i,t),{...o??{},...w(i)})}function y(i,t){return`${i}/public/v1${t}`}var n=class{constructor(t,o,r,e,a,l){this.id=t,this.status=o,this.flowData=r,this.steps=e,this.title=a,this.subtitle=l}};var s=class{constructor(t,o,r,e){this.hasInitialized=!1;this.flows=[];this.apiKey=t,this.userId=o,this.organizationId=r,this.config=e}async init(){return await this.refreshFlows(),this.hasInitialized=!0,Promise.any(null)}async getFlow(t){return this.errorOnUninitialized(),this.flows.find(o=>o.id==t)}errorOnUninitialized(){if(!this.hasInitialized)throw new Error("Frigade has not been initialized yet. Please call Frigade.init() before using any other methods.")}async refreshFlows(){this.flows=[];let t=await T(this.apiKey,"/flows");t&&t.data&&t.data.forEach(r=>{let e=JSON.parse(r.data);this.flows.push(new n(r.slug,r.status,e,(e==null?void 0:e.data)??[],e==null?void 0:e.title,e==null?void 0:e.subtitle))})}};var C=s;export{n as Flow,C as default};
3
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/version.ts","../src/shared/utils.ts","../src/core/flow.ts","../src/core/frigade.ts","../src/index.ts"],"sourcesContent":["export const VERSION_NUMBER = '1.32.18'\n","import { VERSION_NUMBER } from '../core/version'\n\nexport const NOT_STARTED_STEP = 'NOT_STARTED_STEP'\nexport const COMPLETED_FLOW = 'COMPLETED_FLOW'\nexport const ABORTED_FLOW = 'ABORTED_FLOW'\nexport const STARTED_FLOW = 'STARTED_FLOW'\nexport const NOT_STARTED_FLOW = 'NOT_STARTED_FLOW'\nexport const COMPLETED_STEP = 'COMPLETED_STEP'\nexport const STARTED_STEP = 'STARTED_STEP'\nexport type StepActionType = 'STARTED_STEP' | 'COMPLETED_STEP' | 'NOT_STARTED_STEP'\nexport type UserFlowStatus = 'NOT_STARTED_FLOW' | 'STARTED_FLOW' | 'COMPLETED_FLOW' | 'ABORTED_FLOW'\nconst LAST_POST_CALL_AT = 'frigade-last-call-at-'\nconst LAST_POST_CALL_DATA = 'frigade-last-call-data-'\n\nfunction getConfig(apiKey: string) {\n return {\n config: {\n headers: {\n Authorization: `Bearer ${apiKey}`,\n 'Content-Type': 'application/json',\n 'X-Frigade-SDK-Version': VERSION_NUMBER,\n 'X-Frigade-SDK-Platform': 'Javascript',\n },\n },\n }\n}\n\nfunction getLocalStorage(key: string) {\n if (window && window.localStorage) {\n return window.localStorage.getItem(key)\n }\n return null\n}\n\nfunction setLocalStorage(key: string, value: string) {\n if (window && window.localStorage) {\n window.localStorage.setItem(key, value)\n }\n}\n\nexport async function gracefulFetch(url: string, options: any) {\n const lastCallAtKey = LAST_POST_CALL_AT + url\n const lastCallDataKey = LAST_POST_CALL_DATA + url\n if (window && window.localStorage && options && options.body && options.method === 'POST') {\n const lastCall = getLocalStorage(lastCallAtKey)\n const lastCallData = getLocalStorage(lastCallDataKey)\n if (lastCall && lastCallData && lastCallData == options.body) {\n const lastCallDate = new Date(lastCall)\n const now = new Date()\n const diff = now.getTime() - lastCallDate.getTime()\n // Throttle consecutive POST calls to 1 second\n if (diff < 1000) {\n return getEmptyResponse()\n }\n }\n setLocalStorage(lastCallAtKey, new Date().toISOString())\n setLocalStorage(lastCallDataKey, options.body)\n }\n\n let response\n try {\n response = await fetch(url, options)\n } catch (error) {\n return getEmptyResponse(error)\n }\n\n if (!response) {\n return getEmptyResponse()\n }\n\n if (!response.ok) {\n return getEmptyResponse(response.statusText)\n }\n\n return response\n}\n\nfunction getEmptyResponse(error?: any) {\n if (error) {\n console.log('Call to Frigade failed', error)\n }\n\n // Create empty response that contains the .json method and returns an empty object\n return {\n json: () => ({}),\n }\n}\n\nexport function fetcher(apiKey: string, url: string, options?: Record<any, any>) {\n return gracefulFetch(getUrl(apiKey, url), {\n ...(options ?? {}),\n ...getConfig(apiKey),\n })\n}\n\nfunction getUrl(apiUrl: string, postfix: string) {\n return `${apiUrl}/public/v1${postfix}`\n}\n","import { FlowStepData } from '../types'\nimport { FlowMetadata, FlowStatus } from './types'\n\nexport default class Flow {\n /**\n * THe Flow ID / slug of the flow\n */\n public readonly id: string\n /**\n * The status of the flow\n */\n public readonly status: FlowStatus\n /**\n * The raw data defined in `flow-data.yml` as a JSON decoded object\n */\n public readonly flowData: Record<any, any>\n /**\n * The steps contained in the `data` array in `flow-data.yml`\n */\n public readonly steps: FlowStepData[]\n /**\n * The user-facing title of the flow, if defined at the top level of `flow-data.yml`\n */\n public readonly title?: string\n /**\n * The user-facing description of the flow, if defined at the top level of `flow-data.yml`\n */\n public readonly subtitle?: string\n /**\n * The metadata of the flow.\n */\n public readonly metadata: FlowMetadata\n\n constructor(\n id: string,\n status: FlowStatus,\n rawData: Record<any, any>,\n steps: FlowStepData[],\n title?: string,\n subtitle?: string\n ) {\n this.id = id\n this.status = status\n this.flowData = rawData\n this.steps = steps\n this.title = title\n this.subtitle = subtitle\n }\n}\n","import { FrigadeConfig } from '../types'\nimport { fetcher } from '../shared/utils'\nimport Flow from './flow'\nimport { FlowMetadata } from './types'\n\nexport default class Frigade {\n public readonly apiKey?: string\n public readonly userId?: string\n public readonly organizationId?: string\n public readonly config?: FrigadeConfig\n public hasInitialized = false\n\n private flows: Flow[] = []\n\n constructor(apiKey: string, userId?: string, organizationId?: string, config?: FrigadeConfig) {\n this.apiKey = apiKey\n this.userId = userId\n this.organizationId = organizationId\n this.config = config\n }\n\n public async init(): Promise<void> {\n await this.refreshFlows()\n this.hasInitialized = true\n return Promise.any(null)\n }\n\n public async getFlow(flowId: string) {\n this.errorOnUninitialized()\n return this.flows.find((flow) => flow.id == flowId)\n }\n\n private errorOnUninitialized() {\n if (!this.hasInitialized) {\n throw new Error(\n 'Frigade has not been initialized yet. Please call Frigade.init() before using any other methods.'\n )\n }\n }\n\n private async refreshFlows() {\n this.flows = []\n const flowDataRaw = await fetcher(this.apiKey, '/flows')\n if (flowDataRaw && flowDataRaw.data) {\n let flowMetadatas = flowDataRaw.data as FlowMetadata[]\n flowMetadatas.forEach((flowMetadata) => {\n const rawData = JSON.parse(flowMetadata.data)\n this.flows.push(\n new Flow(\n flowMetadata.slug,\n flowMetadata.status,\n rawData,\n rawData?.data ?? [],\n rawData?.title,\n rawData?.subtitle\n )\n )\n })\n }\n }\n}\n","import Frigade from './core/frigade'\nimport Flow from './core/flow'\n\nexport { Flow }\nexport default Frigade\n"],"mappings":"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","names":["VERSION_NUMBER","LAST_POST_CALL_AT","LAST_POST_CALL_DATA","getConfig","apiKey","VERSION_NUMBER","getLocalStorage","key","setLocalStorage","value","gracefulFetch","url","options","lastCallAtKey","lastCallDataKey","lastCall","lastCallData","lastCallDate","getEmptyResponse","response","error","fetcher","getUrl","apiUrl","postfix","Flow","id","status","rawData","steps","title","subtitle","Frigade","apiKey","userId","organizationId","config","flowId","flow","flowDataRaw","fetcher","flowMetadata","rawData","Flow","src_default","Frigade"]}
package/package.json ADDED
@@ -0,0 +1,99 @@
1
+ {
2
+ "name": "@frigade/js",
3
+ "version": "0.0.1",
4
+ "description": "The official Javascript SDK for Frigade.",
5
+ "main": "./lib/index.js",
6
+ "types": "./lib/index.d.ts",
7
+ "files": [
8
+ "./lib"
9
+ ],
10
+ "scripts": {
11
+ "clean": "rimraf ./lib",
12
+ "test": "build",
13
+ "semantic-release": "semantic-release",
14
+ "lint": "eslint --fix --ext .ts,.tsx .",
15
+ "copy-files": "copyfiles -u 1 src/**/*.html src/**/*.css ./lib",
16
+ "build": "yarn clean && tsup && yarn copy-files",
17
+ "local-release": "tsup",
18
+ "storybook": "storybook dev -p 6006",
19
+ "build-storybook": "storybook build"
20
+ },
21
+ "repository": {
22
+ "type": "git",
23
+ "url": "git+https://github.com/FrigadeHQ/frigade-js.git"
24
+ },
25
+ "keywords": [
26
+ "Onboarding",
27
+ "Tutorial",
28
+ "Intro",
29
+ "Checklist",
30
+ "Welcome",
31
+ "Tooltips",
32
+ "Tour",
33
+ "Walkthrough",
34
+ "Javascript"
35
+ ],
36
+ "devDependencies": {
37
+ "@babel/core": "^7.15.8",
38
+ "@babel/plugin-transform-runtime": "^7.19.6",
39
+ "@babel/preset-env": "^7.21.5",
40
+ "@babel/preset-typescript": "^7.21.5",
41
+ "@storybook/addon-essentials": "^7.0.9",
42
+ "@storybook/addon-interactions": "^7.0.9",
43
+ "@storybook/addon-links": "^7.0.9",
44
+ "@storybook/blocks": "^7.0.9",
45
+ "@storybook/testing-library": "^0.0.14-next.2",
46
+ "@types/jest": "^23.3.1",
47
+ "babel-jest": "^29.4.1",
48
+ "copyfiles": "^2.4.1",
49
+ "jest": "^29.4.1",
50
+ "jest-config": "^29.3.1",
51
+ "jest-environment-jsdom": "^29.4.1",
52
+ "lint-staged": "^13.0.0",
53
+ "prettier": "^2.4.1",
54
+ "prop-types": "^15.8.1",
55
+ "rimraf": "^4.1.2",
56
+ "semantic-release": "^19.0.3",
57
+ "storybook": "^7.0.9",
58
+ "ts-jest": "^29.1.0",
59
+ "tsup": "^6.7.0",
60
+ "typedoc": "^0.24.8",
61
+ "typedoc-plugin-markdown": "^3.15.3",
62
+ "typescript": "^4.9.4"
63
+ },
64
+ "release": {
65
+ "branches": [
66
+ "main"
67
+ ]
68
+ },
69
+ "plugins": [
70
+ "@semantic-release/commit-analyzer",
71
+ "@semantic-release/changelog",
72
+ [
73
+ "@semantic-release/npm",
74
+ {
75
+ "npmPublish": true
76
+ }
77
+ ],
78
+ [
79
+ "@semantic-release/git",
80
+ {
81
+ "assets": [
82
+ "src/api/version.ts",
83
+ "package.json"
84
+ ],
85
+ "message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
86
+ }
87
+ ],
88
+ "@semantic-release/github"
89
+ ],
90
+ "author": "Frigade Inc.",
91
+ "license": "MIT",
92
+ "bugs": {
93
+ "url": "https://github.com/FrigadeHQ/frigade-js/issues"
94
+ },
95
+ "homepage": "https://github.com/FrigadeHQ/frigade-js#readme",
96
+ "dependencies": {
97
+ "uuid": "^9.0.0"
98
+ }
99
+ }