@kitesdk/sdk 0.1.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/README.md ADDED
@@ -0,0 +1,76 @@
1
+ # Kite SDK for JavaScript
2
+
3
+ Zero-dependency JavaScript and TypeScript SDK for sending Kite SDK success signals from browser or Node.js 18+ apps.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ pnpm add @kitesdk/sdk
9
+ ```
10
+
11
+ ## Quickstart
12
+
13
+ ```ts
14
+ import { KiteSDK } from "@kitesdk/sdk";
15
+
16
+ const journey = new KiteSDK({
17
+ writeKey: "kite_prod_xxx",
18
+ debug: true,
19
+ });
20
+ ```
21
+
22
+ ```ts
23
+ await journey.identify("usr_123", {
24
+ email: "user@company.com",
25
+ plan: "pro",
26
+ });
27
+
28
+ await journey.context({
29
+ plan: "pro",
30
+ product_type: "analytics_saas",
31
+ });
32
+ ```
33
+
34
+ ```ts
35
+ await journey.define({
36
+ activation: ["integration_connected", "report_generated"],
37
+ ahaMoment: ["report_shared"],
38
+ retention: [{ event: "report_generated", minCount: 3, withinDays: 14 }],
39
+ expansion: ["subscription_upgraded"],
40
+ });
41
+ ```
42
+
43
+ ```ts
44
+ await journey.track("integration_connected", { integration_type: "slack" });
45
+ await journey.value("report_generated", { rows: 240 });
46
+ await journey.revenue("subscription_upgraded", {
47
+ mrr_delta: 49,
48
+ currency: "USD",
49
+ from_plan: "starter",
50
+ to_plan: "pro",
51
+ });
52
+ ```
53
+
54
+ ## Error Handling
55
+
56
+ ```ts
57
+ import { KiteSDKAPIError, KiteSDKNetworkError } from "@kitesdk/sdk";
58
+
59
+ try {
60
+ await journey.track("integration_connected");
61
+ } catch (error) {
62
+ if (error instanceof KiteSDKAPIError) {
63
+ console.error(error.status, error.body);
64
+ }
65
+
66
+ if (error instanceof KiteSDKNetworkError) {
67
+ console.error("Network failure", error.cause);
68
+ }
69
+ }
70
+ ```
71
+
72
+ ## Notes
73
+
74
+ - Call `identify()` before `track()`, `value()`, or `revenue()`.
75
+ - Event names should use `snake_case`; debug mode warns without blocking ingestion.
76
+ - Runtime dependencies: none. The SDK uses native `fetch`, available in browsers and Node.js 18+.
@@ -0,0 +1,72 @@
1
+ declare class KiteSDKConfigError extends Error {
2
+ constructor(message: string);
3
+ }
4
+ declare class KiteSDKValidationError extends Error {
5
+ constructor(message: string);
6
+ }
7
+ declare class KiteSDKStateError extends Error {
8
+ constructor(message: string);
9
+ }
10
+ declare class KiteSDKNetworkError extends Error {
11
+ readonly cause?: unknown;
12
+ constructor(message: string, cause?: unknown);
13
+ }
14
+ declare class KiteSDKAPIError extends Error {
15
+ readonly body: unknown;
16
+ readonly status: number;
17
+ constructor(status: number, body: unknown);
18
+ }
19
+
20
+ interface KiteSDKConfig {
21
+ writeKey: string;
22
+ debug?: boolean;
23
+ apiUrl?: string;
24
+ }
25
+ type UserTraits = Record<string, unknown>;
26
+ type EventProperties = Record<string, unknown>;
27
+ interface RevenueProperties extends EventProperties {
28
+ mrr_delta: number;
29
+ currency: string;
30
+ from_plan?: string;
31
+ to_plan?: string;
32
+ }
33
+ interface MilestoneCondition {
34
+ event: string;
35
+ minCount?: number;
36
+ withinDays?: number;
37
+ }
38
+ interface JourneyDefinition {
39
+ activation?: (string | MilestoneCondition)[];
40
+ ahaMoment?: (string | MilestoneCondition)[];
41
+ retention?: MilestoneCondition[];
42
+ expansion?: (string | MilestoneCondition)[];
43
+ }
44
+ interface JourneyContext {
45
+ plan?: string;
46
+ product_type?: string;
47
+ [key: string]: string | undefined;
48
+ }
49
+ type TrackType = "identify" | "track" | "value" | "revenue";
50
+ interface TrackPayload {
51
+ type: TrackType;
52
+ userId: string;
53
+ event?: string;
54
+ traits?: UserTraits;
55
+ properties?: EventProperties | RevenueProperties;
56
+ context?: JourneyContext;
57
+ timestamp: string;
58
+ sdkVersion: string;
59
+ }
60
+
61
+ declare class KiteSDK {
62
+ #private;
63
+ constructor(config: KiteSDKConfig);
64
+ identify(userId: string, traits?: UserTraits): Promise<void>;
65
+ track(event: string, properties?: EventProperties): Promise<void>;
66
+ value(event: string, properties?: EventProperties): Promise<void>;
67
+ revenue(event: string, properties: RevenueProperties): Promise<void>;
68
+ define(definition: JourneyDefinition): Promise<void>;
69
+ context(ctx: JourneyContext): Promise<void>;
70
+ }
71
+
72
+ export { type EventProperties, type JourneyContext, type JourneyDefinition, KiteSDK, KiteSDKAPIError, type KiteSDKConfig, KiteSDKConfigError, KiteSDKNetworkError, KiteSDKStateError, KiteSDKValidationError, type MilestoneCondition, type RevenueProperties, type TrackPayload, type UserTraits };
@@ -0,0 +1,72 @@
1
+ declare class KiteSDKConfigError extends Error {
2
+ constructor(message: string);
3
+ }
4
+ declare class KiteSDKValidationError extends Error {
5
+ constructor(message: string);
6
+ }
7
+ declare class KiteSDKStateError extends Error {
8
+ constructor(message: string);
9
+ }
10
+ declare class KiteSDKNetworkError extends Error {
11
+ readonly cause?: unknown;
12
+ constructor(message: string, cause?: unknown);
13
+ }
14
+ declare class KiteSDKAPIError extends Error {
15
+ readonly body: unknown;
16
+ readonly status: number;
17
+ constructor(status: number, body: unknown);
18
+ }
19
+
20
+ interface KiteSDKConfig {
21
+ writeKey: string;
22
+ debug?: boolean;
23
+ apiUrl?: string;
24
+ }
25
+ type UserTraits = Record<string, unknown>;
26
+ type EventProperties = Record<string, unknown>;
27
+ interface RevenueProperties extends EventProperties {
28
+ mrr_delta: number;
29
+ currency: string;
30
+ from_plan?: string;
31
+ to_plan?: string;
32
+ }
33
+ interface MilestoneCondition {
34
+ event: string;
35
+ minCount?: number;
36
+ withinDays?: number;
37
+ }
38
+ interface JourneyDefinition {
39
+ activation?: (string | MilestoneCondition)[];
40
+ ahaMoment?: (string | MilestoneCondition)[];
41
+ retention?: MilestoneCondition[];
42
+ expansion?: (string | MilestoneCondition)[];
43
+ }
44
+ interface JourneyContext {
45
+ plan?: string;
46
+ product_type?: string;
47
+ [key: string]: string | undefined;
48
+ }
49
+ type TrackType = "identify" | "track" | "value" | "revenue";
50
+ interface TrackPayload {
51
+ type: TrackType;
52
+ userId: string;
53
+ event?: string;
54
+ traits?: UserTraits;
55
+ properties?: EventProperties | RevenueProperties;
56
+ context?: JourneyContext;
57
+ timestamp: string;
58
+ sdkVersion: string;
59
+ }
60
+
61
+ declare class KiteSDK {
62
+ #private;
63
+ constructor(config: KiteSDKConfig);
64
+ identify(userId: string, traits?: UserTraits): Promise<void>;
65
+ track(event: string, properties?: EventProperties): Promise<void>;
66
+ value(event: string, properties?: EventProperties): Promise<void>;
67
+ revenue(event: string, properties: RevenueProperties): Promise<void>;
68
+ define(definition: JourneyDefinition): Promise<void>;
69
+ context(ctx: JourneyContext): Promise<void>;
70
+ }
71
+
72
+ export { type EventProperties, type JourneyContext, type JourneyDefinition, KiteSDK, KiteSDKAPIError, type KiteSDKConfig, KiteSDKConfigError, KiteSDKNetworkError, KiteSDKStateError, KiteSDKValidationError, type MilestoneCondition, type RevenueProperties, type TrackPayload, type UserTraits };
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ 'use strict';var o=class extends Error{constructor(e){super(e),this.name="KiteSDKConfigError";}},s=class extends Error{constructor(e){super(e),this.name="KiteSDKValidationError";}},a=class extends Error{constructor(e){super(e),this.name="KiteSDKStateError";}},c=class extends Error{cause;constructor(e,n){super(e),this.name="KiteSDKNetworkError",this.cause=n;}},h=class extends Error{body;status;constructor(e,n){super(`KiteSDK API request failed with status ${e}`),this.name="KiteSDKAPIError",this.body=n,this.status=e;}};var l="0.1.0";var m="https://api.kitesdk.com",w=/^[a-z][a-z0-9]*(?:_[a-z0-9]+)*$/,p=class{#u;#t={};#e;#n;#c=false;#r=0;#s;#h;constructor(e){if(!e.writeKey)throw new o("writeKey is required");if(!e.writeKey.startsWith("kite_"))throw new o("writeKey must start with 'kite_'");this.#u=g(e.apiUrl??m),this.#e=e.debug===true,this.#h=e.writeKey;}identify(e,n={}){y(e,"userId");let i={type:"identify",userId:e,traits:n,timestamp:new Date().toISOString(),sdkVersion:l};return this.#i("/v1/track",i).then(()=>{this.#s=e,this.#e&&console.info(`[KiteSDK] Identified user: ${e}`);})}track(e,n={}){return this.#a("track",e),this.#o("track",e,n)}value(e,n={}){return this.#a("value",e),this.#o("value",e,n).then(()=>{this.#e&&console.info(`[KiteSDK] Value event fired: ${e} - this is a candidate for AhaMoment/Activation mapping.`);})}revenue(e,n){if(this.#a("revenue",e),!n||typeof n.mrr_delta!="number")throw new s("mrr_delta is required and must be a number");if(typeof n.currency!="string"||n.currency.trim()==="")throw new s("currency is required and must be a non-empty string");return this.#o("revenue",e,n)}async define(e){!v(e)&&this.#e&&console.warn("[KiteSDK] No milestones defined. Add at least one to activation[]."),await this.#i("/v1/journey/define",{definition:e}),this.#n=e,this.#r=0,this.#e&&console.info(`[KiteSDK] Journey defined: ${S(e)}`);}async context(e){this.#t={...this.#t,...e},await this.#i("/v1/journey/context",{context:this.#t});}async#o(e,n,i){let r=this.#s;if(!r)throw new a(`Call identify() before ${e}()`);this.#d(n),this.#l(),this.#p(n);let u={type:e,userId:r,event:n,properties:i,timestamp:new Date().toISOString(),sdkVersion:l};Object.keys(this.#t).length>0&&(u.context=this.#t);let d=await this.#i("/v1/track",u);this.#e&&d?.milestone_achieved&&console.info(`[KiteSDK] User ${r} reached ${d.milestone??"a milestone"} in ${d.time??"an unknown time"}`);}#a(e,n){if(y(n,"event"),!this.#s)throw new a(`Call identify() before ${e}()`)}async#i(e,n){let i;try{i=await fetch(`${this.#u}${e}`,{body:JSON.stringify(n),headers:{Authorization:`Bearer ${this.#h}`,"Content-Type":"application/json"},method:"POST"});}catch(u){throw new c("KiteSDK network request failed",u)}let r=await K(i);if(!i.ok)throw new h(i.status,r);return r}#d(e){this.#e&&!w.test(e)&&console.warn(`[KiteSDK] Event name '${e}' is not snake_case. Consider using '${D(e)}'`);}#l(){!this.#e||this.#n||this.#c||(this.#r+=1,this.#r>=5&&(this.#c=true,console.warn("[KiteSDK] No journey defined yet. Call journey.define() to map your events to success milestones.")));}#p(e){!this.#e||!this.#n||k(this.#n,e)||console.warn(`[KiteSDK] Unmapped event detected: '${e}'. Is this a success signal? Add it to your journey.define() call.`);}};function y(t,e){if(typeof t!="string"||t.trim()==="")throw new s(`${e} must be a non-empty string`)}function g(t){return t.replace(/\/+$/,"")}async function K(t){let e=await t.text();if(e)try{return JSON.parse(e)}catch{return e}}function v(t){return f(t).some(e=>e.length>0)}function S(t){return [`activation(${t.activation?.length??0})`,`ahaMoment(${t.ahaMoment?.length??0})`,`retention(${t.retention?.length??0})`,`expansion(${t.expansion?.length??0})`].join(" . ")}function f(t){return [t.activation??[],t.ahaMoment??[],t.retention??[],t.expansion??[]]}function k(t,e){return f(t).some(n=>n.some(i=>typeof i=="string"?i===e:i.event===e))}function D(t){return t.replace(/([a-z0-9])([A-Z])/g,"$1_$2").replace(/[^a-zA-Z0-9]+/g,"_").replace(/^_+|_+$/g,"").toLowerCase()}
2
+ exports.KiteSDK=p;exports.KiteSDKAPIError=h;exports.KiteSDKConfigError=o;exports.KiteSDKNetworkError=c;exports.KiteSDKStateError=a;exports.KiteSDKValidationError=s;//# sourceMappingURL=index.js.map
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/errors.ts","../src/version.ts","../src/index.ts"],"names":["KiteSDKConfigError","message","KiteSDKValidationError","KiteSDKStateError","KiteSDKNetworkError","cause","KiteSDKAPIError","status","body","SDK_VERSION","DEFAULT_API_URL","SNAKE_CASE_EVENT","KiteSDK","#apiUrl","#context","#debug","#definition","#hasWarnedMissingDefinition","#trackCountWithoutDefinition","#userId","#writeKey","config","normalizeApiUrl","userId","traits","assertNonEmptyString","payload","#post","event","properties","#assertCanSendEvent","#event","definition","hasMilestones","definitionSummary","ctx","type","#warnForEventName","#warnForMissingDefinition","#warnForUnmappedEvent","response","path","error","responseBody","parseResponseBody","toSnakeCase","isEventMapped","value","field","apiUrl","text","milestoneGroups","group","item"],"mappings":"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","file":"index.js","sourcesContent":["export class KiteSDKConfigError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"KiteSDKConfigError\";\n }\n}\n\nexport class KiteSDKValidationError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"KiteSDKValidationError\";\n }\n}\n\nexport class KiteSDKStateError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"KiteSDKStateError\";\n }\n}\n\nexport class KiteSDKNetworkError extends Error {\n readonly cause?: unknown;\n\n constructor(message: string, cause?: unknown) {\n super(message);\n this.name = \"KiteSDKNetworkError\";\n this.cause = cause;\n }\n}\n\nexport class KiteSDKAPIError extends Error {\n readonly body: unknown;\n readonly status: number;\n\n constructor(status: number, body: unknown) {\n super(`KiteSDK API request failed with status ${status}`);\n this.name = \"KiteSDKAPIError\";\n this.body = body;\n this.status = status;\n }\n}\n","export const SDK_VERSION = \"0.1.0\";\n","import {\n KiteSDKAPIError,\n KiteSDKConfigError,\n KiteSDKNetworkError,\n KiteSDKStateError,\n KiteSDKValidationError,\n} from \"./errors\";\nimport type {\n EventProperties,\n JourneyContext,\n JourneyDefinition,\n KiteSDKConfig,\n MilestoneCondition,\n MilestoneResponse,\n RevenueProperties,\n TrackPayload,\n TrackType,\n UserTraits,\n} from \"./types\";\nimport { SDK_VERSION } from \"./version\";\n\nconst DEFAULT_API_URL = \"https://api.kitesdk.com\";\nconst SNAKE_CASE_EVENT = /^[a-z][a-z0-9]*(?:_[a-z0-9]+)*$/;\n\nexport class KiteSDK {\n #apiUrl: string;\n #context: JourneyContext = {};\n #debug: boolean;\n #definition?: JourneyDefinition;\n #hasWarnedMissingDefinition = false;\n #trackCountWithoutDefinition = 0;\n #userId?: string;\n #writeKey: string;\n\n constructor(config: KiteSDKConfig) {\n if (!config.writeKey) {\n throw new KiteSDKConfigError(\"writeKey is required\");\n }\n\n if (!config.writeKey.startsWith(\"kite_\")) {\n throw new KiteSDKConfigError(\"writeKey must start with 'kite_'\");\n }\n\n this.#apiUrl = normalizeApiUrl(config.apiUrl ?? DEFAULT_API_URL);\n this.#debug = config.debug === true;\n this.#writeKey = config.writeKey;\n }\n\n identify(userId: string, traits: UserTraits = {}): Promise<void> {\n assertNonEmptyString(userId, \"userId\");\n\n const payload: TrackPayload = {\n type: \"identify\",\n userId,\n traits,\n timestamp: new Date().toISOString(),\n sdkVersion: SDK_VERSION,\n };\n\n return this.#post(\"/v1/track\", payload).then(() => {\n this.#userId = userId;\n\n if (this.#debug) {\n console.info(`[KiteSDK] Identified user: ${userId}`);\n }\n });\n }\n\n track(event: string, properties: EventProperties = {}): Promise<void> {\n this.#assertCanSendEvent(\"track\", event);\n return this.#event(\"track\", event, properties);\n }\n\n value(event: string, properties: EventProperties = {}): Promise<void> {\n this.#assertCanSendEvent(\"value\", event);\n return this.#event(\"value\", event, properties).then(() => {\n if (this.#debug) {\n console.info(\n `[KiteSDK] Value event fired: ${event} - this is a candidate for AhaMoment/Activation mapping.`,\n );\n }\n });\n }\n\n revenue(event: string, properties: RevenueProperties): Promise<void> {\n this.#assertCanSendEvent(\"revenue\", event);\n\n if (!properties || typeof properties.mrr_delta !== \"number\") {\n throw new KiteSDKValidationError(\n \"mrr_delta is required and must be a number\",\n );\n }\n\n if (\n typeof properties.currency !== \"string\" ||\n properties.currency.trim() === \"\"\n ) {\n throw new KiteSDKValidationError(\n \"currency is required and must be a non-empty string\",\n );\n }\n\n return this.#event(\"revenue\", event, properties);\n }\n\n async define(definition: JourneyDefinition): Promise<void> {\n if (!hasMilestones(definition) && this.#debug) {\n console.warn(\n \"[KiteSDK] No milestones defined. Add at least one to activation[].\",\n );\n }\n\n await this.#post(\"/v1/journey/define\", { definition });\n this.#definition = definition;\n this.#trackCountWithoutDefinition = 0;\n\n if (this.#debug) {\n console.info(\n `[KiteSDK] Journey defined: ${definitionSummary(definition)}`,\n );\n }\n }\n\n async context(ctx: JourneyContext): Promise<void> {\n this.#context = { ...this.#context, ...ctx };\n await this.#post(\"/v1/journey/context\", { context: this.#context });\n }\n\n async #event(\n type: Exclude<TrackType, \"identify\">,\n event: string,\n properties: EventProperties | RevenueProperties,\n ): Promise<void> {\n const userId = this.#userId;\n\n if (!userId) {\n throw new KiteSDKStateError(`Call identify() before ${type}()`);\n }\n\n this.#warnForEventName(event);\n this.#warnForMissingDefinition();\n this.#warnForUnmappedEvent(event);\n\n const payload: TrackPayload = {\n type,\n userId,\n event,\n properties,\n timestamp: new Date().toISOString(),\n sdkVersion: SDK_VERSION,\n };\n\n if (Object.keys(this.#context).length > 0) {\n payload.context = this.#context;\n }\n\n const response = await this.#post<MilestoneResponse>(\"/v1/track\", payload);\n\n if (this.#debug && response?.milestone_achieved) {\n console.info(\n `[KiteSDK] User ${userId} reached ${response.milestone ?? \"a milestone\"} in ${\n response.time ?? \"an unknown time\"\n }`,\n );\n }\n }\n\n #assertCanSendEvent(\n type: Exclude<TrackType, \"identify\">,\n event: string,\n ): void {\n assertNonEmptyString(event, \"event\");\n\n if (!this.#userId) {\n throw new KiteSDKStateError(`Call identify() before ${type}()`);\n }\n }\n\n async #post<TResponse = unknown>(\n path: string,\n body: unknown,\n ): Promise<TResponse | undefined> {\n let response: Response;\n\n try {\n response = await fetch(`${this.#apiUrl}${path}`, {\n body: JSON.stringify(body),\n headers: {\n Authorization: `Bearer ${this.#writeKey}`,\n \"Content-Type\": \"application/json\",\n },\n method: \"POST\",\n });\n } catch (error) {\n throw new KiteSDKNetworkError(\"KiteSDK network request failed\", error);\n }\n\n const responseBody = await parseResponseBody(response);\n\n if (!response.ok) {\n throw new KiteSDKAPIError(response.status, responseBody);\n }\n\n return responseBody as TResponse | undefined;\n }\n\n #warnForEventName(event: string): void {\n if (this.#debug && !SNAKE_CASE_EVENT.test(event)) {\n console.warn(\n `[KiteSDK] Event name '${event}' is not snake_case. Consider using '${toSnakeCase(event)}'`,\n );\n }\n }\n\n #warnForMissingDefinition(): void {\n if (!this.#debug || this.#definition || this.#hasWarnedMissingDefinition) {\n return;\n }\n\n this.#trackCountWithoutDefinition += 1;\n\n if (this.#trackCountWithoutDefinition >= 5) {\n this.#hasWarnedMissingDefinition = true;\n console.warn(\n \"[KiteSDK] No journey defined yet. Call journey.define() to map your events to success milestones.\",\n );\n }\n }\n\n #warnForUnmappedEvent(event: string): void {\n if (\n !this.#debug ||\n !this.#definition ||\n isEventMapped(this.#definition, event)\n ) {\n return;\n }\n\n console.warn(\n `[KiteSDK] Unmapped event detected: '${event}'. Is this a success signal? Add it to your journey.define() call.`,\n );\n }\n}\n\nexport {\n KiteSDKAPIError,\n KiteSDKConfigError,\n KiteSDKNetworkError,\n KiteSDKStateError,\n KiteSDKValidationError,\n};\n\nexport type {\n EventProperties,\n JourneyContext,\n JourneyDefinition,\n KiteSDKConfig,\n MilestoneCondition,\n RevenueProperties,\n TrackPayload,\n UserTraits,\n} from \"./types\";\n\nfunction assertNonEmptyString(value: string, field: string): void {\n if (typeof value !== \"string\" || value.trim() === \"\") {\n throw new KiteSDKValidationError(`${field} must be a non-empty string`);\n }\n}\n\nfunction normalizeApiUrl(apiUrl: string): string {\n return apiUrl.replace(/\\/+$/, \"\");\n}\n\nasync function parseResponseBody(response: Response): Promise<unknown> {\n const text = await response.text();\n\n if (!text) {\n return undefined;\n }\n\n try {\n return JSON.parse(text);\n } catch {\n return text;\n }\n}\n\nfunction hasMilestones(definition: JourneyDefinition): boolean {\n return milestoneGroups(definition).some((group) => group.length > 0);\n}\n\nfunction definitionSummary(definition: JourneyDefinition): string {\n return [\n `activation(${definition.activation?.length ?? 0})`,\n `ahaMoment(${definition.ahaMoment?.length ?? 0})`,\n `retention(${definition.retention?.length ?? 0})`,\n `expansion(${definition.expansion?.length ?? 0})`,\n ].join(\" . \");\n}\n\nfunction milestoneGroups(\n definition: JourneyDefinition,\n): (string | MilestoneCondition)[][] {\n return [\n definition.activation ?? [],\n definition.ahaMoment ?? [],\n definition.retention ?? [],\n definition.expansion ?? [],\n ];\n}\n\nfunction isEventMapped(definition: JourneyDefinition, event: string): boolean {\n return milestoneGroups(definition).some((group) =>\n group.some((item) =>\n typeof item === \"string\" ? item === event : item.event === event,\n ),\n );\n}\n\nfunction toSnakeCase(value: string): string {\n return value\n .replace(/([a-z0-9])([A-Z])/g, \"$1_$2\")\n .replace(/[^a-zA-Z0-9]+/g, \"_\")\n .replace(/^_+|_+$/g, \"\")\n .toLowerCase();\n}\n"]}
package/dist/index.mjs ADDED
@@ -0,0 +1,3 @@
1
+ var o=class extends Error{constructor(e){super(e),this.name="KiteSDKConfigError";}},s=class extends Error{constructor(e){super(e),this.name="KiteSDKValidationError";}},a=class extends Error{constructor(e){super(e),this.name="KiteSDKStateError";}},c=class extends Error{cause;constructor(e,n){super(e),this.name="KiteSDKNetworkError",this.cause=n;}},h=class extends Error{body;status;constructor(e,n){super(`KiteSDK API request failed with status ${e}`),this.name="KiteSDKAPIError",this.body=n,this.status=e;}};var l="0.1.0";var m="https://api.kitesdk.com",w=/^[a-z][a-z0-9]*(?:_[a-z0-9]+)*$/,p=class{#u;#t={};#e;#n;#c=false;#r=0;#s;#h;constructor(e){if(!e.writeKey)throw new o("writeKey is required");if(!e.writeKey.startsWith("kite_"))throw new o("writeKey must start with 'kite_'");this.#u=g(e.apiUrl??m),this.#e=e.debug===true,this.#h=e.writeKey;}identify(e,n={}){y(e,"userId");let i={type:"identify",userId:e,traits:n,timestamp:new Date().toISOString(),sdkVersion:l};return this.#i("/v1/track",i).then(()=>{this.#s=e,this.#e&&console.info(`[KiteSDK] Identified user: ${e}`);})}track(e,n={}){return this.#a("track",e),this.#o("track",e,n)}value(e,n={}){return this.#a("value",e),this.#o("value",e,n).then(()=>{this.#e&&console.info(`[KiteSDK] Value event fired: ${e} - this is a candidate for AhaMoment/Activation mapping.`);})}revenue(e,n){if(this.#a("revenue",e),!n||typeof n.mrr_delta!="number")throw new s("mrr_delta is required and must be a number");if(typeof n.currency!="string"||n.currency.trim()==="")throw new s("currency is required and must be a non-empty string");return this.#o("revenue",e,n)}async define(e){!v(e)&&this.#e&&console.warn("[KiteSDK] No milestones defined. Add at least one to activation[]."),await this.#i("/v1/journey/define",{definition:e}),this.#n=e,this.#r=0,this.#e&&console.info(`[KiteSDK] Journey defined: ${S(e)}`);}async context(e){this.#t={...this.#t,...e},await this.#i("/v1/journey/context",{context:this.#t});}async#o(e,n,i){let r=this.#s;if(!r)throw new a(`Call identify() before ${e}()`);this.#d(n),this.#l(),this.#p(n);let u={type:e,userId:r,event:n,properties:i,timestamp:new Date().toISOString(),sdkVersion:l};Object.keys(this.#t).length>0&&(u.context=this.#t);let d=await this.#i("/v1/track",u);this.#e&&d?.milestone_achieved&&console.info(`[KiteSDK] User ${r} reached ${d.milestone??"a milestone"} in ${d.time??"an unknown time"}`);}#a(e,n){if(y(n,"event"),!this.#s)throw new a(`Call identify() before ${e}()`)}async#i(e,n){let i;try{i=await fetch(`${this.#u}${e}`,{body:JSON.stringify(n),headers:{Authorization:`Bearer ${this.#h}`,"Content-Type":"application/json"},method:"POST"});}catch(u){throw new c("KiteSDK network request failed",u)}let r=await K(i);if(!i.ok)throw new h(i.status,r);return r}#d(e){this.#e&&!w.test(e)&&console.warn(`[KiteSDK] Event name '${e}' is not snake_case. Consider using '${D(e)}'`);}#l(){!this.#e||this.#n||this.#c||(this.#r+=1,this.#r>=5&&(this.#c=true,console.warn("[KiteSDK] No journey defined yet. Call journey.define() to map your events to success milestones.")));}#p(e){!this.#e||!this.#n||k(this.#n,e)||console.warn(`[KiteSDK] Unmapped event detected: '${e}'. Is this a success signal? Add it to your journey.define() call.`);}};function y(t,e){if(typeof t!="string"||t.trim()==="")throw new s(`${e} must be a non-empty string`)}function g(t){return t.replace(/\/+$/,"")}async function K(t){let e=await t.text();if(e)try{return JSON.parse(e)}catch{return e}}function v(t){return f(t).some(e=>e.length>0)}function S(t){return [`activation(${t.activation?.length??0})`,`ahaMoment(${t.ahaMoment?.length??0})`,`retention(${t.retention?.length??0})`,`expansion(${t.expansion?.length??0})`].join(" . ")}function f(t){return [t.activation??[],t.ahaMoment??[],t.retention??[],t.expansion??[]]}function k(t,e){return f(t).some(n=>n.some(i=>typeof i=="string"?i===e:i.event===e))}function D(t){return t.replace(/([a-z0-9])([A-Z])/g,"$1_$2").replace(/[^a-zA-Z0-9]+/g,"_").replace(/^_+|_+$/g,"").toLowerCase()}
2
+ export{p as KiteSDK,h as KiteSDKAPIError,o as KiteSDKConfigError,c as KiteSDKNetworkError,a as KiteSDKStateError,s as KiteSDKValidationError};//# sourceMappingURL=index.mjs.map
3
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/errors.ts","../src/version.ts","../src/index.ts"],"names":["KiteSDKConfigError","message","KiteSDKValidationError","KiteSDKStateError","KiteSDKNetworkError","cause","KiteSDKAPIError","status","body","SDK_VERSION","DEFAULT_API_URL","SNAKE_CASE_EVENT","KiteSDK","#apiUrl","#context","#debug","#definition","#hasWarnedMissingDefinition","#trackCountWithoutDefinition","#userId","#writeKey","config","normalizeApiUrl","userId","traits","assertNonEmptyString","payload","#post","event","properties","#assertCanSendEvent","#event","definition","hasMilestones","definitionSummary","ctx","type","#warnForEventName","#warnForMissingDefinition","#warnForUnmappedEvent","response","path","error","responseBody","parseResponseBody","toSnakeCase","isEventMapped","value","field","apiUrl","text","milestoneGroups","group","item"],"mappings":"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","file":"index.mjs","sourcesContent":["export class KiteSDKConfigError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"KiteSDKConfigError\";\n }\n}\n\nexport class KiteSDKValidationError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"KiteSDKValidationError\";\n }\n}\n\nexport class KiteSDKStateError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"KiteSDKStateError\";\n }\n}\n\nexport class KiteSDKNetworkError extends Error {\n readonly cause?: unknown;\n\n constructor(message: string, cause?: unknown) {\n super(message);\n this.name = \"KiteSDKNetworkError\";\n this.cause = cause;\n }\n}\n\nexport class KiteSDKAPIError extends Error {\n readonly body: unknown;\n readonly status: number;\n\n constructor(status: number, body: unknown) {\n super(`KiteSDK API request failed with status ${status}`);\n this.name = \"KiteSDKAPIError\";\n this.body = body;\n this.status = status;\n }\n}\n","export const SDK_VERSION = \"0.1.0\";\n","import {\n KiteSDKAPIError,\n KiteSDKConfigError,\n KiteSDKNetworkError,\n KiteSDKStateError,\n KiteSDKValidationError,\n} from \"./errors\";\nimport type {\n EventProperties,\n JourneyContext,\n JourneyDefinition,\n KiteSDKConfig,\n MilestoneCondition,\n MilestoneResponse,\n RevenueProperties,\n TrackPayload,\n TrackType,\n UserTraits,\n} from \"./types\";\nimport { SDK_VERSION } from \"./version\";\n\nconst DEFAULT_API_URL = \"https://api.kitesdk.com\";\nconst SNAKE_CASE_EVENT = /^[a-z][a-z0-9]*(?:_[a-z0-9]+)*$/;\n\nexport class KiteSDK {\n #apiUrl: string;\n #context: JourneyContext = {};\n #debug: boolean;\n #definition?: JourneyDefinition;\n #hasWarnedMissingDefinition = false;\n #trackCountWithoutDefinition = 0;\n #userId?: string;\n #writeKey: string;\n\n constructor(config: KiteSDKConfig) {\n if (!config.writeKey) {\n throw new KiteSDKConfigError(\"writeKey is required\");\n }\n\n if (!config.writeKey.startsWith(\"kite_\")) {\n throw new KiteSDKConfigError(\"writeKey must start with 'kite_'\");\n }\n\n this.#apiUrl = normalizeApiUrl(config.apiUrl ?? DEFAULT_API_URL);\n this.#debug = config.debug === true;\n this.#writeKey = config.writeKey;\n }\n\n identify(userId: string, traits: UserTraits = {}): Promise<void> {\n assertNonEmptyString(userId, \"userId\");\n\n const payload: TrackPayload = {\n type: \"identify\",\n userId,\n traits,\n timestamp: new Date().toISOString(),\n sdkVersion: SDK_VERSION,\n };\n\n return this.#post(\"/v1/track\", payload).then(() => {\n this.#userId = userId;\n\n if (this.#debug) {\n console.info(`[KiteSDK] Identified user: ${userId}`);\n }\n });\n }\n\n track(event: string, properties: EventProperties = {}): Promise<void> {\n this.#assertCanSendEvent(\"track\", event);\n return this.#event(\"track\", event, properties);\n }\n\n value(event: string, properties: EventProperties = {}): Promise<void> {\n this.#assertCanSendEvent(\"value\", event);\n return this.#event(\"value\", event, properties).then(() => {\n if (this.#debug) {\n console.info(\n `[KiteSDK] Value event fired: ${event} - this is a candidate for AhaMoment/Activation mapping.`,\n );\n }\n });\n }\n\n revenue(event: string, properties: RevenueProperties): Promise<void> {\n this.#assertCanSendEvent(\"revenue\", event);\n\n if (!properties || typeof properties.mrr_delta !== \"number\") {\n throw new KiteSDKValidationError(\n \"mrr_delta is required and must be a number\",\n );\n }\n\n if (\n typeof properties.currency !== \"string\" ||\n properties.currency.trim() === \"\"\n ) {\n throw new KiteSDKValidationError(\n \"currency is required and must be a non-empty string\",\n );\n }\n\n return this.#event(\"revenue\", event, properties);\n }\n\n async define(definition: JourneyDefinition): Promise<void> {\n if (!hasMilestones(definition) && this.#debug) {\n console.warn(\n \"[KiteSDK] No milestones defined. Add at least one to activation[].\",\n );\n }\n\n await this.#post(\"/v1/journey/define\", { definition });\n this.#definition = definition;\n this.#trackCountWithoutDefinition = 0;\n\n if (this.#debug) {\n console.info(\n `[KiteSDK] Journey defined: ${definitionSummary(definition)}`,\n );\n }\n }\n\n async context(ctx: JourneyContext): Promise<void> {\n this.#context = { ...this.#context, ...ctx };\n await this.#post(\"/v1/journey/context\", { context: this.#context });\n }\n\n async #event(\n type: Exclude<TrackType, \"identify\">,\n event: string,\n properties: EventProperties | RevenueProperties,\n ): Promise<void> {\n const userId = this.#userId;\n\n if (!userId) {\n throw new KiteSDKStateError(`Call identify() before ${type}()`);\n }\n\n this.#warnForEventName(event);\n this.#warnForMissingDefinition();\n this.#warnForUnmappedEvent(event);\n\n const payload: TrackPayload = {\n type,\n userId,\n event,\n properties,\n timestamp: new Date().toISOString(),\n sdkVersion: SDK_VERSION,\n };\n\n if (Object.keys(this.#context).length > 0) {\n payload.context = this.#context;\n }\n\n const response = await this.#post<MilestoneResponse>(\"/v1/track\", payload);\n\n if (this.#debug && response?.milestone_achieved) {\n console.info(\n `[KiteSDK] User ${userId} reached ${response.milestone ?? \"a milestone\"} in ${\n response.time ?? \"an unknown time\"\n }`,\n );\n }\n }\n\n #assertCanSendEvent(\n type: Exclude<TrackType, \"identify\">,\n event: string,\n ): void {\n assertNonEmptyString(event, \"event\");\n\n if (!this.#userId) {\n throw new KiteSDKStateError(`Call identify() before ${type}()`);\n }\n }\n\n async #post<TResponse = unknown>(\n path: string,\n body: unknown,\n ): Promise<TResponse | undefined> {\n let response: Response;\n\n try {\n response = await fetch(`${this.#apiUrl}${path}`, {\n body: JSON.stringify(body),\n headers: {\n Authorization: `Bearer ${this.#writeKey}`,\n \"Content-Type\": \"application/json\",\n },\n method: \"POST\",\n });\n } catch (error) {\n throw new KiteSDKNetworkError(\"KiteSDK network request failed\", error);\n }\n\n const responseBody = await parseResponseBody(response);\n\n if (!response.ok) {\n throw new KiteSDKAPIError(response.status, responseBody);\n }\n\n return responseBody as TResponse | undefined;\n }\n\n #warnForEventName(event: string): void {\n if (this.#debug && !SNAKE_CASE_EVENT.test(event)) {\n console.warn(\n `[KiteSDK] Event name '${event}' is not snake_case. Consider using '${toSnakeCase(event)}'`,\n );\n }\n }\n\n #warnForMissingDefinition(): void {\n if (!this.#debug || this.#definition || this.#hasWarnedMissingDefinition) {\n return;\n }\n\n this.#trackCountWithoutDefinition += 1;\n\n if (this.#trackCountWithoutDefinition >= 5) {\n this.#hasWarnedMissingDefinition = true;\n console.warn(\n \"[KiteSDK] No journey defined yet. Call journey.define() to map your events to success milestones.\",\n );\n }\n }\n\n #warnForUnmappedEvent(event: string): void {\n if (\n !this.#debug ||\n !this.#definition ||\n isEventMapped(this.#definition, event)\n ) {\n return;\n }\n\n console.warn(\n `[KiteSDK] Unmapped event detected: '${event}'. Is this a success signal? Add it to your journey.define() call.`,\n );\n }\n}\n\nexport {\n KiteSDKAPIError,\n KiteSDKConfigError,\n KiteSDKNetworkError,\n KiteSDKStateError,\n KiteSDKValidationError,\n};\n\nexport type {\n EventProperties,\n JourneyContext,\n JourneyDefinition,\n KiteSDKConfig,\n MilestoneCondition,\n RevenueProperties,\n TrackPayload,\n UserTraits,\n} from \"./types\";\n\nfunction assertNonEmptyString(value: string, field: string): void {\n if (typeof value !== \"string\" || value.trim() === \"\") {\n throw new KiteSDKValidationError(`${field} must be a non-empty string`);\n }\n}\n\nfunction normalizeApiUrl(apiUrl: string): string {\n return apiUrl.replace(/\\/+$/, \"\");\n}\n\nasync function parseResponseBody(response: Response): Promise<unknown> {\n const text = await response.text();\n\n if (!text) {\n return undefined;\n }\n\n try {\n return JSON.parse(text);\n } catch {\n return text;\n }\n}\n\nfunction hasMilestones(definition: JourneyDefinition): boolean {\n return milestoneGroups(definition).some((group) => group.length > 0);\n}\n\nfunction definitionSummary(definition: JourneyDefinition): string {\n return [\n `activation(${definition.activation?.length ?? 0})`,\n `ahaMoment(${definition.ahaMoment?.length ?? 0})`,\n `retention(${definition.retention?.length ?? 0})`,\n `expansion(${definition.expansion?.length ?? 0})`,\n ].join(\" . \");\n}\n\nfunction milestoneGroups(\n definition: JourneyDefinition,\n): (string | MilestoneCondition)[][] {\n return [\n definition.activation ?? [],\n definition.ahaMoment ?? [],\n definition.retention ?? [],\n definition.expansion ?? [],\n ];\n}\n\nfunction isEventMapped(definition: JourneyDefinition, event: string): boolean {\n return milestoneGroups(definition).some((group) =>\n group.some((item) =>\n typeof item === \"string\" ? item === event : item.event === event,\n ),\n );\n}\n\nfunction toSnakeCase(value: string): string {\n return value\n .replace(/([a-z0-9])([A-Z])/g, \"$1_$2\")\n .replace(/[^a-zA-Z0-9]+/g, \"_\")\n .replace(/^_+|_+$/g, \"\")\n .toLowerCase();\n}\n"]}
package/package.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "@kitesdk/sdk",
3
+ "version": "0.1.0",
4
+ "description": "Kite SDK for JavaScript and TypeScript",
5
+ "license": "MIT",
6
+ "sideEffects": false,
7
+ "type": "commonjs",
8
+ "main": "./dist/index.js",
9
+ "module": "./dist/index.mjs",
10
+ "types": "./dist/index.d.ts",
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/index.d.ts",
14
+ "import": "./dist/index.mjs",
15
+ "require": "./dist/index.js"
16
+ }
17
+ },
18
+ "files": [
19
+ "dist",
20
+ "README.md"
21
+ ],
22
+ "scripts": {
23
+ "build": "tsup && node scripts/check-size.mjs",
24
+ "lint": "eslint .",
25
+ "test": "vitest run --coverage"
26
+ },
27
+ "dependencies": {},
28
+ "devDependencies": {
29
+ "@vitest/coverage-v8": "^2.1.8",
30
+ "tsup": "^8.3.5",
31
+ "vitest": "^2.1.8"
32
+ },
33
+ "engines": {
34
+ "node": ">=18"
35
+ }
36
+ }