@togglely/sdk 1.0.0 → 1.1.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.
@@ -0,0 +1,127 @@
1
+ /**
2
+ * Togglely Vanilla JavaScript SDK
3
+ *
4
+ * Simple wrapper around @togglely/sdk-core for vanilla JS projects
5
+ * Can be used directly in browser or Node.js
6
+ *
7
+ * CDN Usage:
8
+ * ```html
9
+ * <script src="https://unpkg.com/@togglely/sdk/dist/index.umd.min.js"></script>
10
+ * <script>
11
+ * const client = new Togglely.TogglelyClient({
12
+ * apiKey: 'your-api-key',
13
+ * environment: 'production',
14
+ * baseUrl: 'https://your-togglely-instance.com'
15
+ * });
16
+ *
17
+ * client.isEnabled('new-feature').then(enabled => {
18
+ * if (enabled) {
19
+ * document.getElementById('new-feature').style.display = 'block';
20
+ * }
21
+ * });
22
+ * </script>
23
+ * ```
24
+ *
25
+ * Module Usage:
26
+ * ```javascript
27
+ * import { TogglelyClient } from '@togglely/sdk';
28
+ *
29
+ * const client = new TogglelyClient({
30
+ * apiKey: 'your-api-key',
31
+ * environment: 'production',
32
+ * baseUrl: 'https://your-togglely-instance.com'
33
+ * });
34
+ *
35
+ * // Check toggle
36
+ * const isEnabled = await client.isEnabled('new-feature', false);
37
+ *
38
+ * // Listen to events
39
+ * client.on('ready', () => console.log('Toggles loaded!'));
40
+ * client.on('offline', () => console.log('Using offline toggles'));
41
+ * ```
42
+ *
43
+ * Offline Mode with Environment Variables:
44
+ *
45
+ * Node.js:
46
+ * ```bash
47
+ * TOGGLELY_NEW_FEATURE=true
48
+ * TOGGLELY_MAX_ITEMS=100
49
+ * TOGGLELY_WELCOME_MESSAGE="Hello World"
50
+ * ```
51
+ *
52
+ * Browser (inject before SDK loads):
53
+ * ```html
54
+ * <script>
55
+ * window.__TOGGLELY_TOGGLES = {
56
+ * 'new-feature': true,
57
+ * 'max-items': 100,
58
+ * 'welcome-message': 'Hello World'
59
+ * };
60
+ * </script>
61
+ * ```
62
+ */
63
+ export { TogglelyClient, TogglelyConfig, ToggleContext, TogglelyState, TogglelyEventType, TogglelyEventHandler, ToggleValue, AllTogglesResponse, createOfflineTogglesScript, togglesToEnvVars } from '@togglely/sdk-core';
64
+ import { TogglelyClient, TogglelyConfig } from '@togglely/sdk-core';
65
+ /**
66
+ * Initialize Togglely with global instance
67
+ * Creates a global `window.togglely` instance for easy access
68
+ */
69
+ export declare function initTogglely(config: TogglelyConfig): TogglelyClient;
70
+ /**
71
+ * Get the global Togglely instance
72
+ */
73
+ export declare function getGlobalTogglely(): TogglelyClient | null;
74
+ /**
75
+ * Check if a feature is enabled using the global instance
76
+ */
77
+ export declare function isEnabled(key: string, defaultValue?: boolean): Promise<boolean>;
78
+ /**
79
+ * Get a string toggle value using the global instance
80
+ */
81
+ export declare function getString(key: string, defaultValue?: string): Promise<string>;
82
+ /**
83
+ * Get a number toggle value using the global instance
84
+ */
85
+ export declare function getNumber(key: string, defaultValue?: number): Promise<number>;
86
+ /**
87
+ * Get a JSON toggle value using the global instance
88
+ */
89
+ export declare function getJSON<T = any>(key: string, defaultValue?: T): Promise<T>;
90
+ /**
91
+ * Show/hide DOM elements based on feature toggles
92
+ *
93
+ * Usage:
94
+ * ```javascript
95
+ * // Show element when toggle is enabled
96
+ * togglelyToggle('#new-feature', 'new-feature');
97
+ *
98
+ * // Hide element when toggle is disabled
99
+ * togglelyToggle('#old-feature', 'new-feature', { invert: true });
100
+ * ```
101
+ */
102
+ export declare function togglelyToggle(selector: string, toggleKey: string, options?: {
103
+ defaultValue?: boolean;
104
+ invert?: boolean;
105
+ hideClass?: string;
106
+ showClass?: string;
107
+ }): Promise<void>;
108
+ /**
109
+ * Initialize togglely toggle for multiple elements
110
+ * Automatically updates when toggles change
111
+ *
112
+ * Usage:
113
+ * ```javascript
114
+ * togglelyInit({
115
+ * 'new-feature': ['.new-feature', '.new-banner'],
116
+ * 'dark-mode': ['body'],
117
+ * 'premium': { selector: '.premium-content', defaultValue: false }
118
+ * });
119
+ * ```
120
+ */
121
+ export declare function togglelyInit(config: Record<string, string | string[] | {
122
+ selector: string;
123
+ defaultValue?: boolean;
124
+ invert?: boolean;
125
+ }>): () => void;
126
+ export default TogglelyClient;
127
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6DG;AAGH,OAAO,EACL,cAAc,EACd,cAAc,EACd,aAAa,EACb,aAAa,EACb,iBAAiB,EACjB,oBAAoB,EACpB,WAAW,EACX,kBAAkB,EAClB,0BAA0B,EAC1B,gBAAgB,EACjB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAIpE;;;GAGG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,cAAc,GAAG,cAAc,CASnE;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,cAAc,GAAG,IAAI,CAKzD;AAED;;GAEG;AACH,wBAAsB,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,GAAE,OAAe,GAAG,OAAO,CAAC,OAAO,CAAC,CAO5F;AAED;;GAEG;AACH,wBAAsB,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,GAAE,MAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAOvF;AAED;;GAEG;AACH,wBAAsB,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,GAAE,MAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAOtF;AAED;;GAEG;AACH,wBAAsB,OAAO,CAAC,CAAC,GAAG,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,YAAY,GAAE,CAAW,GAAG,OAAO,CAAC,CAAC,CAAC,CAOzF;AAID;;;;;;;;;;;GAWG;AACH,wBAAsB,cAAc,CAClC,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE;IACP,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACf,GACL,OAAO,CAAC,IAAI,CAAC,CA6Bf;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,YAAY,CAC1B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,GACzG,MAAM,IAAI,CA0CZ;AAID,eAAe,cAAc,CAAC"}
@@ -0,0 +1,222 @@
1
+ import { TogglelyClient } from '@togglely/sdk-core';
2
+ export { TogglelyClient, createOfflineTogglesScript, TogglelyClient as default, togglesToEnvVars } from '@togglely/sdk-core';
3
+
4
+ /**
5
+ * Togglely Vanilla JavaScript SDK
6
+ *
7
+ * Simple wrapper around @togglely/sdk-core for vanilla JS projects
8
+ * Can be used directly in browser or Node.js
9
+ *
10
+ * CDN Usage:
11
+ * ```html
12
+ * <script src="https://unpkg.com/@togglely/sdk/dist/index.umd.min.js"></script>
13
+ * <script>
14
+ * const client = new Togglely.TogglelyClient({
15
+ * apiKey: 'your-api-key',
16
+ * environment: 'production',
17
+ * baseUrl: 'https://your-togglely-instance.com'
18
+ * });
19
+ *
20
+ * client.isEnabled('new-feature').then(enabled => {
21
+ * if (enabled) {
22
+ * document.getElementById('new-feature').style.display = 'block';
23
+ * }
24
+ * });
25
+ * </script>
26
+ * ```
27
+ *
28
+ * Module Usage:
29
+ * ```javascript
30
+ * import { TogglelyClient } from '@togglely/sdk';
31
+ *
32
+ * const client = new TogglelyClient({
33
+ * apiKey: 'your-api-key',
34
+ * environment: 'production',
35
+ * baseUrl: 'https://your-togglely-instance.com'
36
+ * });
37
+ *
38
+ * // Check toggle
39
+ * const isEnabled = await client.isEnabled('new-feature', false);
40
+ *
41
+ * // Listen to events
42
+ * client.on('ready', () => console.log('Toggles loaded!'));
43
+ * client.on('offline', () => console.log('Using offline toggles'));
44
+ * ```
45
+ *
46
+ * Offline Mode with Environment Variables:
47
+ *
48
+ * Node.js:
49
+ * ```bash
50
+ * TOGGLELY_NEW_FEATURE=true
51
+ * TOGGLELY_MAX_ITEMS=100
52
+ * TOGGLELY_WELCOME_MESSAGE="Hello World"
53
+ * ```
54
+ *
55
+ * Browser (inject before SDK loads):
56
+ * ```html
57
+ * <script>
58
+ * window.__TOGGLELY_TOGGLES = {
59
+ * 'new-feature': true,
60
+ * 'max-items': 100,
61
+ * 'welcome-message': 'Hello World'
62
+ * };
63
+ * </script>
64
+ * ```
65
+ */
66
+ // Re-export everything from core
67
+ // ==================== Helper Functions for Vanilla JS ====================
68
+ /**
69
+ * Initialize Togglely with global instance
70
+ * Creates a global `window.togglely` instance for easy access
71
+ */
72
+ function initTogglely(config) {
73
+ const client = new TogglelyClient(config);
74
+ // Make available globally in browser
75
+ if (typeof window !== 'undefined') {
76
+ window.togglely = client;
77
+ }
78
+ return client;
79
+ }
80
+ /**
81
+ * Get the global Togglely instance
82
+ */
83
+ function getGlobalTogglely() {
84
+ if (typeof window !== 'undefined') {
85
+ return window.togglely || null;
86
+ }
87
+ return null;
88
+ }
89
+ /**
90
+ * Check if a feature is enabled using the global instance
91
+ */
92
+ async function isEnabled(key, defaultValue = false) {
93
+ const client = getGlobalTogglely();
94
+ if (!client) {
95
+ console.error('[Togglely] No global instance found. Call initTogglely() first.');
96
+ return defaultValue;
97
+ }
98
+ return client.isEnabled(key, defaultValue);
99
+ }
100
+ /**
101
+ * Get a string toggle value using the global instance
102
+ */
103
+ async function getString(key, defaultValue = '') {
104
+ const client = getGlobalTogglely();
105
+ if (!client) {
106
+ console.error('[Togglely] No global instance found. Call initTogglely() first.');
107
+ return defaultValue;
108
+ }
109
+ return client.getString(key, defaultValue);
110
+ }
111
+ /**
112
+ * Get a number toggle value using the global instance
113
+ */
114
+ async function getNumber(key, defaultValue = 0) {
115
+ const client = getGlobalTogglely();
116
+ if (!client) {
117
+ console.error('[Togglely] No global instance found. Call initTogglely() first.');
118
+ return defaultValue;
119
+ }
120
+ return client.getNumber(key, defaultValue);
121
+ }
122
+ /**
123
+ * Get a JSON toggle value using the global instance
124
+ */
125
+ async function getJSON(key, defaultValue = {}) {
126
+ const client = getGlobalTogglely();
127
+ if (!client) {
128
+ console.error('[Togglely] No global instance found. Call initTogglely() first.');
129
+ return defaultValue;
130
+ }
131
+ return client.getJSON(key, defaultValue);
132
+ }
133
+ // ==================== DOM Helpers ====================
134
+ /**
135
+ * Show/hide DOM elements based on feature toggles
136
+ *
137
+ * Usage:
138
+ * ```javascript
139
+ * // Show element when toggle is enabled
140
+ * togglelyToggle('#new-feature', 'new-feature');
141
+ *
142
+ * // Hide element when toggle is disabled
143
+ * togglelyToggle('#old-feature', 'new-feature', { invert: true });
144
+ * ```
145
+ */
146
+ async function togglelyToggle(selector, toggleKey, options = {}) {
147
+ const { defaultValue = false, invert = false, hideClass = 'togglely-hidden', showClass = 'togglely-visible' } = options;
148
+ const client = getGlobalTogglely();
149
+ if (!client) {
150
+ console.error('[Togglely] No global instance found. Call initTogglely() first.');
151
+ return;
152
+ }
153
+ const isToggleEnabled = await client.isEnabled(toggleKey, defaultValue);
154
+ const shouldShow = invert ? !isToggleEnabled : isToggleEnabled;
155
+ const elements = document.querySelectorAll(selector);
156
+ elements.forEach(el => {
157
+ if (shouldShow) {
158
+ el.classList.remove(hideClass);
159
+ el.classList.add(showClass);
160
+ el.style.display = '';
161
+ }
162
+ else {
163
+ el.classList.remove(showClass);
164
+ el.classList.add(hideClass);
165
+ el.style.display = 'none';
166
+ }
167
+ });
168
+ }
169
+ /**
170
+ * Initialize togglely toggle for multiple elements
171
+ * Automatically updates when toggles change
172
+ *
173
+ * Usage:
174
+ * ```javascript
175
+ * togglelyInit({
176
+ * 'new-feature': ['.new-feature', '.new-banner'],
177
+ * 'dark-mode': ['body'],
178
+ * 'premium': { selector: '.premium-content', defaultValue: false }
179
+ * });
180
+ * ```
181
+ */
182
+ function togglelyInit(config) {
183
+ const client = getGlobalTogglely();
184
+ if (!client) {
185
+ console.error('[Togglely] No global instance found. Call initTogglely() first.');
186
+ return () => { };
187
+ }
188
+ const updateAll = async () => {
189
+ for (const [toggleKey, value] of Object.entries(config)) {
190
+ let selectors;
191
+ let defaultValue = false;
192
+ let invert = false;
193
+ if (typeof value === 'string') {
194
+ selectors = [value];
195
+ }
196
+ else if (Array.isArray(value)) {
197
+ selectors = value;
198
+ }
199
+ else {
200
+ selectors = [value.selector];
201
+ defaultValue = value.defaultValue ?? false;
202
+ invert = value.invert ?? false;
203
+ }
204
+ const isToggleEnabled = await client.isEnabled(toggleKey, defaultValue);
205
+ const shouldShow = invert ? !isToggleEnabled : isToggleEnabled;
206
+ selectors.forEach(selector => {
207
+ const elements = document.querySelectorAll(selector);
208
+ elements.forEach(el => {
209
+ el.style.display = shouldShow ? '' : 'none';
210
+ });
211
+ });
212
+ }
213
+ };
214
+ // Initial update
215
+ updateAll();
216
+ // Subscribe to updates
217
+ const unsubscribe = client.on('update', updateAll);
218
+ return unsubscribe;
219
+ }
220
+
221
+ export { getGlobalTogglely, getJSON, getNumber, getString, initTogglely, isEnabled, togglelyInit, togglelyToggle };
222
+ //# sourceMappingURL=index.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.esm.js","sources":["../src/index.ts"],"sourcesContent":[null],"names":[],"mappings":"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"}
package/dist/index.js ADDED
@@ -0,0 +1,248 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var sdkCore = require('@togglely/sdk-core');
6
+
7
+ /**
8
+ * Togglely Vanilla JavaScript SDK
9
+ *
10
+ * Simple wrapper around @togglely/sdk-core for vanilla JS projects
11
+ * Can be used directly in browser or Node.js
12
+ *
13
+ * CDN Usage:
14
+ * ```html
15
+ * <script src="https://unpkg.com/@togglely/sdk/dist/index.umd.min.js"></script>
16
+ * <script>
17
+ * const client = new Togglely.TogglelyClient({
18
+ * apiKey: 'your-api-key',
19
+ * environment: 'production',
20
+ * baseUrl: 'https://your-togglely-instance.com'
21
+ * });
22
+ *
23
+ * client.isEnabled('new-feature').then(enabled => {
24
+ * if (enabled) {
25
+ * document.getElementById('new-feature').style.display = 'block';
26
+ * }
27
+ * });
28
+ * </script>
29
+ * ```
30
+ *
31
+ * Module Usage:
32
+ * ```javascript
33
+ * import { TogglelyClient } from '@togglely/sdk';
34
+ *
35
+ * const client = new TogglelyClient({
36
+ * apiKey: 'your-api-key',
37
+ * environment: 'production',
38
+ * baseUrl: 'https://your-togglely-instance.com'
39
+ * });
40
+ *
41
+ * // Check toggle
42
+ * const isEnabled = await client.isEnabled('new-feature', false);
43
+ *
44
+ * // Listen to events
45
+ * client.on('ready', () => console.log('Toggles loaded!'));
46
+ * client.on('offline', () => console.log('Using offline toggles'));
47
+ * ```
48
+ *
49
+ * Offline Mode with Environment Variables:
50
+ *
51
+ * Node.js:
52
+ * ```bash
53
+ * TOGGLELY_NEW_FEATURE=true
54
+ * TOGGLELY_MAX_ITEMS=100
55
+ * TOGGLELY_WELCOME_MESSAGE="Hello World"
56
+ * ```
57
+ *
58
+ * Browser (inject before SDK loads):
59
+ * ```html
60
+ * <script>
61
+ * window.__TOGGLELY_TOGGLES = {
62
+ * 'new-feature': true,
63
+ * 'max-items': 100,
64
+ * 'welcome-message': 'Hello World'
65
+ * };
66
+ * </script>
67
+ * ```
68
+ */
69
+ // Re-export everything from core
70
+ // ==================== Helper Functions for Vanilla JS ====================
71
+ /**
72
+ * Initialize Togglely with global instance
73
+ * Creates a global `window.togglely` instance for easy access
74
+ */
75
+ function initTogglely(config) {
76
+ const client = new sdkCore.TogglelyClient(config);
77
+ // Make available globally in browser
78
+ if (typeof window !== 'undefined') {
79
+ window.togglely = client;
80
+ }
81
+ return client;
82
+ }
83
+ /**
84
+ * Get the global Togglely instance
85
+ */
86
+ function getGlobalTogglely() {
87
+ if (typeof window !== 'undefined') {
88
+ return window.togglely || null;
89
+ }
90
+ return null;
91
+ }
92
+ /**
93
+ * Check if a feature is enabled using the global instance
94
+ */
95
+ async function isEnabled(key, defaultValue = false) {
96
+ const client = getGlobalTogglely();
97
+ if (!client) {
98
+ console.error('[Togglely] No global instance found. Call initTogglely() first.');
99
+ return defaultValue;
100
+ }
101
+ return client.isEnabled(key, defaultValue);
102
+ }
103
+ /**
104
+ * Get a string toggle value using the global instance
105
+ */
106
+ async function getString(key, defaultValue = '') {
107
+ const client = getGlobalTogglely();
108
+ if (!client) {
109
+ console.error('[Togglely] No global instance found. Call initTogglely() first.');
110
+ return defaultValue;
111
+ }
112
+ return client.getString(key, defaultValue);
113
+ }
114
+ /**
115
+ * Get a number toggle value using the global instance
116
+ */
117
+ async function getNumber(key, defaultValue = 0) {
118
+ const client = getGlobalTogglely();
119
+ if (!client) {
120
+ console.error('[Togglely] No global instance found. Call initTogglely() first.');
121
+ return defaultValue;
122
+ }
123
+ return client.getNumber(key, defaultValue);
124
+ }
125
+ /**
126
+ * Get a JSON toggle value using the global instance
127
+ */
128
+ async function getJSON(key, defaultValue = {}) {
129
+ const client = getGlobalTogglely();
130
+ if (!client) {
131
+ console.error('[Togglely] No global instance found. Call initTogglely() first.');
132
+ return defaultValue;
133
+ }
134
+ return client.getJSON(key, defaultValue);
135
+ }
136
+ // ==================== DOM Helpers ====================
137
+ /**
138
+ * Show/hide DOM elements based on feature toggles
139
+ *
140
+ * Usage:
141
+ * ```javascript
142
+ * // Show element when toggle is enabled
143
+ * togglelyToggle('#new-feature', 'new-feature');
144
+ *
145
+ * // Hide element when toggle is disabled
146
+ * togglelyToggle('#old-feature', 'new-feature', { invert: true });
147
+ * ```
148
+ */
149
+ async function togglelyToggle(selector, toggleKey, options = {}) {
150
+ const { defaultValue = false, invert = false, hideClass = 'togglely-hidden', showClass = 'togglely-visible' } = options;
151
+ const client = getGlobalTogglely();
152
+ if (!client) {
153
+ console.error('[Togglely] No global instance found. Call initTogglely() first.');
154
+ return;
155
+ }
156
+ const isToggleEnabled = await client.isEnabled(toggleKey, defaultValue);
157
+ const shouldShow = invert ? !isToggleEnabled : isToggleEnabled;
158
+ const elements = document.querySelectorAll(selector);
159
+ elements.forEach(el => {
160
+ if (shouldShow) {
161
+ el.classList.remove(hideClass);
162
+ el.classList.add(showClass);
163
+ el.style.display = '';
164
+ }
165
+ else {
166
+ el.classList.remove(showClass);
167
+ el.classList.add(hideClass);
168
+ el.style.display = 'none';
169
+ }
170
+ });
171
+ }
172
+ /**
173
+ * Initialize togglely toggle for multiple elements
174
+ * Automatically updates when toggles change
175
+ *
176
+ * Usage:
177
+ * ```javascript
178
+ * togglelyInit({
179
+ * 'new-feature': ['.new-feature', '.new-banner'],
180
+ * 'dark-mode': ['body'],
181
+ * 'premium': { selector: '.premium-content', defaultValue: false }
182
+ * });
183
+ * ```
184
+ */
185
+ function togglelyInit(config) {
186
+ const client = getGlobalTogglely();
187
+ if (!client) {
188
+ console.error('[Togglely] No global instance found. Call initTogglely() first.');
189
+ return () => { };
190
+ }
191
+ const updateAll = async () => {
192
+ for (const [toggleKey, value] of Object.entries(config)) {
193
+ let selectors;
194
+ let defaultValue = false;
195
+ let invert = false;
196
+ if (typeof value === 'string') {
197
+ selectors = [value];
198
+ }
199
+ else if (Array.isArray(value)) {
200
+ selectors = value;
201
+ }
202
+ else {
203
+ selectors = [value.selector];
204
+ defaultValue = value.defaultValue ?? false;
205
+ invert = value.invert ?? false;
206
+ }
207
+ const isToggleEnabled = await client.isEnabled(toggleKey, defaultValue);
208
+ const shouldShow = invert ? !isToggleEnabled : isToggleEnabled;
209
+ selectors.forEach(selector => {
210
+ const elements = document.querySelectorAll(selector);
211
+ elements.forEach(el => {
212
+ el.style.display = shouldShow ? '' : 'none';
213
+ });
214
+ });
215
+ }
216
+ };
217
+ // Initial update
218
+ updateAll();
219
+ // Subscribe to updates
220
+ const unsubscribe = client.on('update', updateAll);
221
+ return unsubscribe;
222
+ }
223
+
224
+ Object.defineProperty(exports, "TogglelyClient", {
225
+ enumerable: true,
226
+ get: function () { return sdkCore.TogglelyClient; }
227
+ });
228
+ Object.defineProperty(exports, "createOfflineTogglesScript", {
229
+ enumerable: true,
230
+ get: function () { return sdkCore.createOfflineTogglesScript; }
231
+ });
232
+ Object.defineProperty(exports, "default", {
233
+ enumerable: true,
234
+ get: function () { return sdkCore.TogglelyClient; }
235
+ });
236
+ Object.defineProperty(exports, "togglesToEnvVars", {
237
+ enumerable: true,
238
+ get: function () { return sdkCore.togglesToEnvVars; }
239
+ });
240
+ exports.getGlobalTogglely = getGlobalTogglely;
241
+ exports.getJSON = getJSON;
242
+ exports.getNumber = getNumber;
243
+ exports.getString = getString;
244
+ exports.initTogglely = initTogglely;
245
+ exports.isEnabled = isEnabled;
246
+ exports.togglelyInit = togglelyInit;
247
+ exports.togglelyToggle = togglelyToggle;
248
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":["../src/index.ts"],"sourcesContent":[null],"names":["TogglelyClient"],"mappings":"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"}
@@ -0,0 +1,584 @@
1
+ (function (global, factory) {
2
+ typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
3
+ typeof define === 'function' && define.amd ? define(['exports'], factory) :
4
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.Togglely = {}));
5
+ })(this, (function (exports) { 'use strict';
6
+
7
+ /**
8
+ * Togglely Core SDK - Framework agnostic
9
+ *
10
+ * Supports offline fallback via environment variables
11
+ */
12
+ /**
13
+ * Core Togglely Client
14
+ */
15
+ class TogglelyClient {
16
+ constructor(config) {
17
+ this.toggles = new Map();
18
+ this.context = {};
19
+ this.state = {
20
+ isReady: false,
21
+ isOffline: false,
22
+ lastError: null,
23
+ lastFetch: null
24
+ };
25
+ this.eventHandlers = new Map();
26
+ this.offlineTogglesLoaded = false;
27
+ this.config = {
28
+ refreshInterval: 60000,
29
+ timeout: 5000,
30
+ offlineFallback: true,
31
+ envPrefix: 'TOGGLELY_',
32
+ ...config
33
+ };
34
+ // Initialize event handlers
35
+ this.eventHandlers.set('ready', new Set());
36
+ this.eventHandlers.set('update', new Set());
37
+ this.eventHandlers.set('error', new Set());
38
+ this.eventHandlers.set('offline', new Set());
39
+ this.eventHandlers.set('online', new Set());
40
+ // Load offline toggles first (if enabled)
41
+ if (this.config.offlineFallback) {
42
+ this.loadOfflineToggles();
43
+ }
44
+ // Start polling
45
+ this.startPolling();
46
+ }
47
+ // ==================== Event Handling ====================
48
+ on(event, handler) {
49
+ const handlers = this.eventHandlers.get(event);
50
+ if (handlers) {
51
+ handlers.add(handler);
52
+ }
53
+ return () => this.off(event, handler);
54
+ }
55
+ off(event, handler) {
56
+ const handlers = this.eventHandlers.get(event);
57
+ if (handlers) {
58
+ handlers.delete(handler);
59
+ }
60
+ }
61
+ emit(event) {
62
+ const handlers = this.eventHandlers.get(event);
63
+ if (handlers) {
64
+ handlers.forEach(handler => handler({ ...this.state }));
65
+ }
66
+ }
67
+ // ==================== Context ====================
68
+ setContext(context) {
69
+ this.context = { ...this.context, ...context };
70
+ }
71
+ getContext() {
72
+ return { ...this.context };
73
+ }
74
+ clearContext() {
75
+ this.context = {};
76
+ }
77
+ // ==================== State ====================
78
+ getState() {
79
+ return { ...this.state };
80
+ }
81
+ isReady() {
82
+ return this.state.isReady;
83
+ }
84
+ isOffline() {
85
+ return this.state.isOffline;
86
+ }
87
+ // ==================== Toggle Accessors ====================
88
+ async isEnabled(key, defaultValue = false) {
89
+ const value = await this.getValue(key);
90
+ if (value === null)
91
+ return defaultValue;
92
+ return value.enabled && value.value === true;
93
+ }
94
+ async getString(key, defaultValue = '') {
95
+ const value = await this.getValue(key);
96
+ if (value === null || !value.enabled)
97
+ return defaultValue;
98
+ return String(value.value);
99
+ }
100
+ async getNumber(key, defaultValue = 0) {
101
+ const value = await this.getValue(key);
102
+ if (value === null || !value.enabled)
103
+ return defaultValue;
104
+ return Number(value.value);
105
+ }
106
+ async getJSON(key, defaultValue = {}) {
107
+ const value = await this.getValue(key);
108
+ if (value === null || !value.enabled)
109
+ return defaultValue;
110
+ if (typeof value.value === 'string') {
111
+ try {
112
+ return JSON.parse(value.value);
113
+ }
114
+ catch {
115
+ return defaultValue;
116
+ }
117
+ }
118
+ return value.value;
119
+ }
120
+ async getValue(key) {
121
+ // Try cache first
122
+ const cached = this.toggles.get(key);
123
+ if (cached) {
124
+ return cached;
125
+ }
126
+ // Fetch from server
127
+ try {
128
+ const response = await this.fetchWithTimeout(`${this.config.baseUrl}/sdk/flags/${this.config.environment}/${key}`, {
129
+ headers: {
130
+ 'Authorization': `Bearer ${this.config.apiKey}`,
131
+ 'Content-Type': 'application/json'
132
+ }
133
+ });
134
+ if (!response.ok) {
135
+ if (response.status === 404) {
136
+ return null;
137
+ }
138
+ throw new Error(`HTTP ${response.status}`);
139
+ }
140
+ const data = await response.json();
141
+ this.toggles.set(key, data);
142
+ // Update state if we were offline
143
+ if (this.state.isOffline) {
144
+ this.state.isOffline = false;
145
+ this.emit('online');
146
+ }
147
+ return data;
148
+ }
149
+ catch (error) {
150
+ // Try offline fallback
151
+ const offlineValue = this.getOfflineToggle(key);
152
+ if (offlineValue !== null) {
153
+ return offlineValue;
154
+ }
155
+ console.error(`[Togglely] Failed to fetch toggle "${key}":`, error);
156
+ return null;
157
+ }
158
+ }
159
+ getAllToggles() {
160
+ const result = {};
161
+ this.toggles.forEach((value, key) => {
162
+ result[key] = value;
163
+ });
164
+ return result;
165
+ }
166
+ // ==================== Offline Fallback ====================
167
+ /**
168
+ * Load toggles from environment variables
169
+ * Format: TOGGLELY_<TOGGLE_KEY>=<value> or TOGGLELY_<TOGGLE_KEY>_ENABLED=true
170
+ */
171
+ loadOfflineToggles() {
172
+ try {
173
+ // Browser environment - check window.__TOGGLELY_TOGGLES
174
+ if (typeof window !== 'undefined' && window.__TOGGLELY_TOGGLES) {
175
+ const offlineToggles = window.__TOGGLELY_TOGGLES;
176
+ for (const [key, value] of Object.entries(offlineToggles)) {
177
+ this.toggles.set(key, this.parseOfflineValue(value));
178
+ }
179
+ this.offlineTogglesLoaded = true;
180
+ console.log('[Togglely] Loaded offline toggles from window.__TOGGLELY_TOGGLES');
181
+ return;
182
+ }
183
+ // Node.js / Bun / Deno environment - check process.env
184
+ if (typeof process !== 'undefined' && process.env) {
185
+ const prefix = this.config.envPrefix;
186
+ for (const [envKey, envValue] of Object.entries(process.env)) {
187
+ if (envKey?.startsWith(prefix) && envValue !== undefined) {
188
+ // Parse toggle key: TOGGLELY_MY_FEATURE -> my-feature
189
+ const toggleKey = envKey
190
+ .slice(prefix.length)
191
+ .toLowerCase()
192
+ .replace(/_/g, '-');
193
+ this.toggles.set(toggleKey, this.parseOfflineValue(envValue));
194
+ }
195
+ }
196
+ this.offlineTogglesLoaded = true;
197
+ console.log('[Togglely] Loaded offline toggles from environment variables');
198
+ }
199
+ }
200
+ catch (error) {
201
+ console.warn('[Togglely] Failed to load offline toggles:', error);
202
+ }
203
+ }
204
+ getOfflineToggle(key) {
205
+ if (!this.config.offlineFallback)
206
+ return null;
207
+ // Try to get from already loaded offline toggles
208
+ const cached = this.toggles.get(key);
209
+ if (cached) {
210
+ // If we haven't emitted offline event yet, do it now
211
+ if (!this.state.isOffline) {
212
+ this.state.isOffline = true;
213
+ this.emit('offline');
214
+ }
215
+ return cached;
216
+ }
217
+ return null;
218
+ }
219
+ parseOfflineValue(value) {
220
+ // Handle boolean strings
221
+ if (typeof value === 'string') {
222
+ const lower = value.toLowerCase();
223
+ if (lower === 'true')
224
+ return { value: true, enabled: true };
225
+ if (lower === 'false')
226
+ return { value: false, enabled: true };
227
+ // Try to parse as number
228
+ if (!isNaN(Number(value))) {
229
+ return { value: Number(value), enabled: true };
230
+ }
231
+ // Try to parse as JSON
232
+ try {
233
+ const parsed = JSON.parse(value);
234
+ return { value: parsed, enabled: true };
235
+ }
236
+ catch {
237
+ // Return as string
238
+ return { value, enabled: true };
239
+ }
240
+ }
241
+ return { value, enabled: true };
242
+ }
243
+ // ==================== Refresh / Polling ====================
244
+ async refresh() {
245
+ try {
246
+ const response = await this.fetchWithTimeout(`${this.config.baseUrl}/sdk/toggles/${this.config.environment}`, {
247
+ headers: {
248
+ 'Authorization': `Bearer ${this.config.apiKey}`,
249
+ 'Content-Type': 'application/json'
250
+ }
251
+ });
252
+ if (!response.ok) {
253
+ throw new Error(`HTTP ${response.status}`);
254
+ }
255
+ const data = await response.json();
256
+ this.toggles.clear();
257
+ for (const [key, value] of Object.entries(data)) {
258
+ this.toggles.set(key, value);
259
+ }
260
+ this.state.lastFetch = new Date();
261
+ this.state.lastError = null;
262
+ if (!this.state.isReady) {
263
+ this.state.isReady = true;
264
+ this.emit('ready');
265
+ }
266
+ // If we were offline, go online
267
+ if (this.state.isOffline) {
268
+ this.state.isOffline = false;
269
+ this.emit('online');
270
+ }
271
+ this.emit('update');
272
+ }
273
+ catch (error) {
274
+ this.state.lastError = error;
275
+ // If we have offline toggles, switch to offline mode
276
+ if (this.config.offlineFallback && this.offlineTogglesLoaded) {
277
+ if (!this.state.isOffline) {
278
+ this.state.isOffline = true;
279
+ this.emit('offline');
280
+ }
281
+ }
282
+ this.emit('error');
283
+ console.error('[Togglely] Failed to refresh toggles:', error);
284
+ }
285
+ }
286
+ forceOfflineMode() {
287
+ this.state.isOffline = true;
288
+ this.emit('offline');
289
+ }
290
+ forceOnlineMode() {
291
+ this.state.isOffline = false;
292
+ this.refresh();
293
+ this.emit('online');
294
+ }
295
+ // ==================== Cleanup ====================
296
+ destroy() {
297
+ if (this.refreshTimer) {
298
+ clearInterval(this.refreshTimer);
299
+ }
300
+ this.toggles.clear();
301
+ this.eventHandlers.forEach(handlers => handlers.clear());
302
+ }
303
+ // ==================== Private Helpers ====================
304
+ startPolling() {
305
+ // Initial fetch
306
+ this.refresh();
307
+ // Set up polling
308
+ this.refreshTimer = setInterval(() => {
309
+ if (!this.state.isOffline) {
310
+ this.refresh();
311
+ }
312
+ }, this.config.refreshInterval);
313
+ }
314
+ fetchWithTimeout(url, options) {
315
+ return new Promise((resolve, reject) => {
316
+ const timeoutId = setTimeout(() => {
317
+ reject(new Error('Request timeout'));
318
+ }, this.config.timeout);
319
+ fetch(url, options)
320
+ .then(response => {
321
+ clearTimeout(timeoutId);
322
+ resolve(response);
323
+ })
324
+ .catch(error => {
325
+ clearTimeout(timeoutId);
326
+ reject(error);
327
+ });
328
+ });
329
+ }
330
+ }
331
+ // ==================== Utility Functions ====================
332
+ /**
333
+ * Create a client-side toggle loader script
334
+ * Use this to inject offline toggles into your HTML
335
+ */
336
+ function createOfflineTogglesScript(toggles) {
337
+ return `<script>window.__TOGGLELY_TOGGLES = ${JSON.stringify(toggles)};</script>`;
338
+ }
339
+ /**
340
+ * Helper to convert toggles to environment variables
341
+ */
342
+ function togglesToEnvVars(toggles, prefix = 'TOGGLELY_') {
343
+ const envVars = {};
344
+ for (const [key, value] of Object.entries(toggles)) {
345
+ const envKey = prefix + key.toUpperCase().replace(/-/g, '_');
346
+ envVars[envKey] = typeof value === 'object' ? JSON.stringify(value) : String(value);
347
+ }
348
+ return envVars;
349
+ }
350
+
351
+ /**
352
+ * Togglely Vanilla JavaScript SDK
353
+ *
354
+ * Simple wrapper around @togglely/sdk-core for vanilla JS projects
355
+ * Can be used directly in browser or Node.js
356
+ *
357
+ * CDN Usage:
358
+ * ```html
359
+ * <script src="https://unpkg.com/@togglely/sdk/dist/index.umd.min.js"></script>
360
+ * <script>
361
+ * const client = new Togglely.TogglelyClient({
362
+ * apiKey: 'your-api-key',
363
+ * environment: 'production',
364
+ * baseUrl: 'https://your-togglely-instance.com'
365
+ * });
366
+ *
367
+ * client.isEnabled('new-feature').then(enabled => {
368
+ * if (enabled) {
369
+ * document.getElementById('new-feature').style.display = 'block';
370
+ * }
371
+ * });
372
+ * </script>
373
+ * ```
374
+ *
375
+ * Module Usage:
376
+ * ```javascript
377
+ * import { TogglelyClient } from '@togglely/sdk';
378
+ *
379
+ * const client = new TogglelyClient({
380
+ * apiKey: 'your-api-key',
381
+ * environment: 'production',
382
+ * baseUrl: 'https://your-togglely-instance.com'
383
+ * });
384
+ *
385
+ * // Check toggle
386
+ * const isEnabled = await client.isEnabled('new-feature', false);
387
+ *
388
+ * // Listen to events
389
+ * client.on('ready', () => console.log('Toggles loaded!'));
390
+ * client.on('offline', () => console.log('Using offline toggles'));
391
+ * ```
392
+ *
393
+ * Offline Mode with Environment Variables:
394
+ *
395
+ * Node.js:
396
+ * ```bash
397
+ * TOGGLELY_NEW_FEATURE=true
398
+ * TOGGLELY_MAX_ITEMS=100
399
+ * TOGGLELY_WELCOME_MESSAGE="Hello World"
400
+ * ```
401
+ *
402
+ * Browser (inject before SDK loads):
403
+ * ```html
404
+ * <script>
405
+ * window.__TOGGLELY_TOGGLES = {
406
+ * 'new-feature': true,
407
+ * 'max-items': 100,
408
+ * 'welcome-message': 'Hello World'
409
+ * };
410
+ * </script>
411
+ * ```
412
+ */
413
+ // Re-export everything from core
414
+ // ==================== Helper Functions for Vanilla JS ====================
415
+ /**
416
+ * Initialize Togglely with global instance
417
+ * Creates a global `window.togglely` instance for easy access
418
+ */
419
+ function initTogglely(config) {
420
+ const client = new TogglelyClient(config);
421
+ // Make available globally in browser
422
+ if (typeof window !== 'undefined') {
423
+ window.togglely = client;
424
+ }
425
+ return client;
426
+ }
427
+ /**
428
+ * Get the global Togglely instance
429
+ */
430
+ function getGlobalTogglely() {
431
+ if (typeof window !== 'undefined') {
432
+ return window.togglely || null;
433
+ }
434
+ return null;
435
+ }
436
+ /**
437
+ * Check if a feature is enabled using the global instance
438
+ */
439
+ async function isEnabled(key, defaultValue = false) {
440
+ const client = getGlobalTogglely();
441
+ if (!client) {
442
+ console.error('[Togglely] No global instance found. Call initTogglely() first.');
443
+ return defaultValue;
444
+ }
445
+ return client.isEnabled(key, defaultValue);
446
+ }
447
+ /**
448
+ * Get a string toggle value using the global instance
449
+ */
450
+ async function getString(key, defaultValue = '') {
451
+ const client = getGlobalTogglely();
452
+ if (!client) {
453
+ console.error('[Togglely] No global instance found. Call initTogglely() first.');
454
+ return defaultValue;
455
+ }
456
+ return client.getString(key, defaultValue);
457
+ }
458
+ /**
459
+ * Get a number toggle value using the global instance
460
+ */
461
+ async function getNumber(key, defaultValue = 0) {
462
+ const client = getGlobalTogglely();
463
+ if (!client) {
464
+ console.error('[Togglely] No global instance found. Call initTogglely() first.');
465
+ return defaultValue;
466
+ }
467
+ return client.getNumber(key, defaultValue);
468
+ }
469
+ /**
470
+ * Get a JSON toggle value using the global instance
471
+ */
472
+ async function getJSON(key, defaultValue = {}) {
473
+ const client = getGlobalTogglely();
474
+ if (!client) {
475
+ console.error('[Togglely] No global instance found. Call initTogglely() first.');
476
+ return defaultValue;
477
+ }
478
+ return client.getJSON(key, defaultValue);
479
+ }
480
+ // ==================== DOM Helpers ====================
481
+ /**
482
+ * Show/hide DOM elements based on feature toggles
483
+ *
484
+ * Usage:
485
+ * ```javascript
486
+ * // Show element when toggle is enabled
487
+ * togglelyToggle('#new-feature', 'new-feature');
488
+ *
489
+ * // Hide element when toggle is disabled
490
+ * togglelyToggle('#old-feature', 'new-feature', { invert: true });
491
+ * ```
492
+ */
493
+ async function togglelyToggle(selector, toggleKey, options = {}) {
494
+ const { defaultValue = false, invert = false, hideClass = 'togglely-hidden', showClass = 'togglely-visible' } = options;
495
+ const client = getGlobalTogglely();
496
+ if (!client) {
497
+ console.error('[Togglely] No global instance found. Call initTogglely() first.');
498
+ return;
499
+ }
500
+ const isToggleEnabled = await client.isEnabled(toggleKey, defaultValue);
501
+ const shouldShow = invert ? !isToggleEnabled : isToggleEnabled;
502
+ const elements = document.querySelectorAll(selector);
503
+ elements.forEach(el => {
504
+ if (shouldShow) {
505
+ el.classList.remove(hideClass);
506
+ el.classList.add(showClass);
507
+ el.style.display = '';
508
+ }
509
+ else {
510
+ el.classList.remove(showClass);
511
+ el.classList.add(hideClass);
512
+ el.style.display = 'none';
513
+ }
514
+ });
515
+ }
516
+ /**
517
+ * Initialize togglely toggle for multiple elements
518
+ * Automatically updates when toggles change
519
+ *
520
+ * Usage:
521
+ * ```javascript
522
+ * togglelyInit({
523
+ * 'new-feature': ['.new-feature', '.new-banner'],
524
+ * 'dark-mode': ['body'],
525
+ * 'premium': { selector: '.premium-content', defaultValue: false }
526
+ * });
527
+ * ```
528
+ */
529
+ function togglelyInit(config) {
530
+ const client = getGlobalTogglely();
531
+ if (!client) {
532
+ console.error('[Togglely] No global instance found. Call initTogglely() first.');
533
+ return () => { };
534
+ }
535
+ const updateAll = async () => {
536
+ for (const [toggleKey, value] of Object.entries(config)) {
537
+ let selectors;
538
+ let defaultValue = false;
539
+ let invert = false;
540
+ if (typeof value === 'string') {
541
+ selectors = [value];
542
+ }
543
+ else if (Array.isArray(value)) {
544
+ selectors = value;
545
+ }
546
+ else {
547
+ selectors = [value.selector];
548
+ defaultValue = value.defaultValue ?? false;
549
+ invert = value.invert ?? false;
550
+ }
551
+ const isToggleEnabled = await client.isEnabled(toggleKey, defaultValue);
552
+ const shouldShow = invert ? !isToggleEnabled : isToggleEnabled;
553
+ selectors.forEach(selector => {
554
+ const elements = document.querySelectorAll(selector);
555
+ elements.forEach(el => {
556
+ el.style.display = shouldShow ? '' : 'none';
557
+ });
558
+ });
559
+ }
560
+ };
561
+ // Initial update
562
+ updateAll();
563
+ // Subscribe to updates
564
+ const unsubscribe = client.on('update', updateAll);
565
+ return unsubscribe;
566
+ }
567
+
568
+ exports.TogglelyClient = TogglelyClient;
569
+ exports.createOfflineTogglesScript = createOfflineTogglesScript;
570
+ exports.default = TogglelyClient;
571
+ exports.getGlobalTogglely = getGlobalTogglely;
572
+ exports.getJSON = getJSON;
573
+ exports.getNumber = getNumber;
574
+ exports.getString = getString;
575
+ exports.initTogglely = initTogglely;
576
+ exports.isEnabled = isEnabled;
577
+ exports.togglelyInit = togglelyInit;
578
+ exports.togglelyToggle = togglelyToggle;
579
+ exports.togglesToEnvVars = togglesToEnvVars;
580
+
581
+ Object.defineProperty(exports, '__esModule', { value: true });
582
+
583
+ }));
584
+ //# sourceMappingURL=index.umd.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.umd.js","sources":["../../core/dist/index.esm.js","../src/index.ts"],"sourcesContent":["/**\n * Togglely Core SDK - Framework agnostic\n *\n * Supports offline fallback via environment variables\n */\n/**\n * Core Togglely Client\n */\nclass TogglelyClient {\n constructor(config) {\n this.toggles = new Map();\n this.context = {};\n this.state = {\n isReady: false,\n isOffline: false,\n lastError: null,\n lastFetch: null\n };\n this.eventHandlers = new Map();\n this.offlineTogglesLoaded = false;\n this.config = {\n refreshInterval: 60000,\n timeout: 5000,\n offlineFallback: true,\n envPrefix: 'TOGGLELY_',\n ...config\n };\n // Initialize event handlers\n this.eventHandlers.set('ready', new Set());\n this.eventHandlers.set('update', new Set());\n this.eventHandlers.set('error', new Set());\n this.eventHandlers.set('offline', new Set());\n this.eventHandlers.set('online', new Set());\n // Load offline toggles first (if enabled)\n if (this.config.offlineFallback) {\n this.loadOfflineToggles();\n }\n // Start polling\n this.startPolling();\n }\n // ==================== Event Handling ====================\n on(event, handler) {\n const handlers = this.eventHandlers.get(event);\n if (handlers) {\n handlers.add(handler);\n }\n return () => this.off(event, handler);\n }\n off(event, handler) {\n const handlers = this.eventHandlers.get(event);\n if (handlers) {\n handlers.delete(handler);\n }\n }\n emit(event) {\n const handlers = this.eventHandlers.get(event);\n if (handlers) {\n handlers.forEach(handler => handler({ ...this.state }));\n }\n }\n // ==================== Context ====================\n setContext(context) {\n this.context = { ...this.context, ...context };\n }\n getContext() {\n return { ...this.context };\n }\n clearContext() {\n this.context = {};\n }\n // ==================== State ====================\n getState() {\n return { ...this.state };\n }\n isReady() {\n return this.state.isReady;\n }\n isOffline() {\n return this.state.isOffline;\n }\n // ==================== Toggle Accessors ====================\n async isEnabled(key, defaultValue = false) {\n const value = await this.getValue(key);\n if (value === null)\n return defaultValue;\n return value.enabled && value.value === true;\n }\n async getString(key, defaultValue = '') {\n const value = await this.getValue(key);\n if (value === null || !value.enabled)\n return defaultValue;\n return String(value.value);\n }\n async getNumber(key, defaultValue = 0) {\n const value = await this.getValue(key);\n if (value === null || !value.enabled)\n return defaultValue;\n return Number(value.value);\n }\n async getJSON(key, defaultValue = {}) {\n const value = await this.getValue(key);\n if (value === null || !value.enabled)\n return defaultValue;\n if (typeof value.value === 'string') {\n try {\n return JSON.parse(value.value);\n }\n catch {\n return defaultValue;\n }\n }\n return value.value;\n }\n async getValue(key) {\n // Try cache first\n const cached = this.toggles.get(key);\n if (cached) {\n return cached;\n }\n // Fetch from server\n try {\n const response = await this.fetchWithTimeout(`${this.config.baseUrl}/sdk/flags/${this.config.environment}/${key}`, {\n headers: {\n 'Authorization': `Bearer ${this.config.apiKey}`,\n 'Content-Type': 'application/json'\n }\n });\n if (!response.ok) {\n if (response.status === 404) {\n return null;\n }\n throw new Error(`HTTP ${response.status}`);\n }\n const data = await response.json();\n this.toggles.set(key, data);\n // Update state if we were offline\n if (this.state.isOffline) {\n this.state.isOffline = false;\n this.emit('online');\n }\n return data;\n }\n catch (error) {\n // Try offline fallback\n const offlineValue = this.getOfflineToggle(key);\n if (offlineValue !== null) {\n return offlineValue;\n }\n console.error(`[Togglely] Failed to fetch toggle \"${key}\":`, error);\n return null;\n }\n }\n getAllToggles() {\n const result = {};\n this.toggles.forEach((value, key) => {\n result[key] = value;\n });\n return result;\n }\n // ==================== Offline Fallback ====================\n /**\n * Load toggles from environment variables\n * Format: TOGGLELY_<TOGGLE_KEY>=<value> or TOGGLELY_<TOGGLE_KEY>_ENABLED=true\n */\n loadOfflineToggles() {\n try {\n // Browser environment - check window.__TOGGLELY_TOGGLES\n if (typeof window !== 'undefined' && window.__TOGGLELY_TOGGLES) {\n const offlineToggles = window.__TOGGLELY_TOGGLES;\n for (const [key, value] of Object.entries(offlineToggles)) {\n this.toggles.set(key, this.parseOfflineValue(value));\n }\n this.offlineTogglesLoaded = true;\n console.log('[Togglely] Loaded offline toggles from window.__TOGGLELY_TOGGLES');\n return;\n }\n // Node.js / Bun / Deno environment - check process.env\n if (typeof process !== 'undefined' && process.env) {\n const prefix = this.config.envPrefix;\n for (const [envKey, envValue] of Object.entries(process.env)) {\n if (envKey?.startsWith(prefix) && envValue !== undefined) {\n // Parse toggle key: TOGGLELY_MY_FEATURE -> my-feature\n const toggleKey = envKey\n .slice(prefix.length)\n .toLowerCase()\n .replace(/_/g, '-');\n this.toggles.set(toggleKey, this.parseOfflineValue(envValue));\n }\n }\n this.offlineTogglesLoaded = true;\n console.log('[Togglely] Loaded offline toggles from environment variables');\n }\n }\n catch (error) {\n console.warn('[Togglely] Failed to load offline toggles:', error);\n }\n }\n getOfflineToggle(key) {\n if (!this.config.offlineFallback)\n return null;\n // Try to get from already loaded offline toggles\n const cached = this.toggles.get(key);\n if (cached) {\n // If we haven't emitted offline event yet, do it now\n if (!this.state.isOffline) {\n this.state.isOffline = true;\n this.emit('offline');\n }\n return cached;\n }\n return null;\n }\n parseOfflineValue(value) {\n // Handle boolean strings\n if (typeof value === 'string') {\n const lower = value.toLowerCase();\n if (lower === 'true')\n return { value: true, enabled: true };\n if (lower === 'false')\n return { value: false, enabled: true };\n // Try to parse as number\n if (!isNaN(Number(value))) {\n return { value: Number(value), enabled: true };\n }\n // Try to parse as JSON\n try {\n const parsed = JSON.parse(value);\n return { value: parsed, enabled: true };\n }\n catch {\n // Return as string\n return { value, enabled: true };\n }\n }\n return { value, enabled: true };\n }\n // ==================== Refresh / Polling ====================\n async refresh() {\n try {\n const response = await this.fetchWithTimeout(`${this.config.baseUrl}/sdk/toggles/${this.config.environment}`, {\n headers: {\n 'Authorization': `Bearer ${this.config.apiKey}`,\n 'Content-Type': 'application/json'\n }\n });\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}`);\n }\n const data = await response.json();\n this.toggles.clear();\n for (const [key, value] of Object.entries(data)) {\n this.toggles.set(key, value);\n }\n this.state.lastFetch = new Date();\n this.state.lastError = null;\n if (!this.state.isReady) {\n this.state.isReady = true;\n this.emit('ready');\n }\n // If we were offline, go online\n if (this.state.isOffline) {\n this.state.isOffline = false;\n this.emit('online');\n }\n this.emit('update');\n }\n catch (error) {\n this.state.lastError = error;\n // If we have offline toggles, switch to offline mode\n if (this.config.offlineFallback && this.offlineTogglesLoaded) {\n if (!this.state.isOffline) {\n this.state.isOffline = true;\n this.emit('offline');\n }\n }\n this.emit('error');\n console.error('[Togglely] Failed to refresh toggles:', error);\n }\n }\n forceOfflineMode() {\n this.state.isOffline = true;\n this.emit('offline');\n }\n forceOnlineMode() {\n this.state.isOffline = false;\n this.refresh();\n this.emit('online');\n }\n // ==================== Cleanup ====================\n destroy() {\n if (this.refreshTimer) {\n clearInterval(this.refreshTimer);\n }\n this.toggles.clear();\n this.eventHandlers.forEach(handlers => handlers.clear());\n }\n // ==================== Private Helpers ====================\n startPolling() {\n // Initial fetch\n this.refresh();\n // Set up polling\n this.refreshTimer = setInterval(() => {\n if (!this.state.isOffline) {\n this.refresh();\n }\n }, this.config.refreshInterval);\n }\n fetchWithTimeout(url, options) {\n return new Promise((resolve, reject) => {\n const timeoutId = setTimeout(() => {\n reject(new Error('Request timeout'));\n }, this.config.timeout);\n fetch(url, options)\n .then(response => {\n clearTimeout(timeoutId);\n resolve(response);\n })\n .catch(error => {\n clearTimeout(timeoutId);\n reject(error);\n });\n });\n }\n}\n// ==================== Utility Functions ====================\n/**\n * Create a client-side toggle loader script\n * Use this to inject offline toggles into your HTML\n */\nfunction createOfflineTogglesScript(toggles) {\n return `<script>window.__TOGGLELY_TOGGLES = ${JSON.stringify(toggles)};</script>`;\n}\n/**\n * Helper to convert toggles to environment variables\n */\nfunction togglesToEnvVars(toggles, prefix = 'TOGGLELY_') {\n const envVars = {};\n for (const [key, value] of Object.entries(toggles)) {\n const envKey = prefix + key.toUpperCase().replace(/-/g, '_');\n envVars[envKey] = typeof value === 'object' ? JSON.stringify(value) : String(value);\n }\n return envVars;\n}\n\nexport { TogglelyClient, createOfflineTogglesScript, TogglelyClient as default, togglesToEnvVars };\n//# sourceMappingURL=index.esm.js.map\n",null],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).Flagify={})}(this,function(e){"use strict";class t{constructor(e){this.toggles=new Map,this.context={},this.state={isReady:!1,isOffline:!1,lastError:null,lastFetch:null},this.eventHandlers=new Map,this.offlineTogglesLoaded=!1,this.config={refreshInterval:6e4,timeout:5e3,offlineFallback:!0,envPrefix:"TOGGLELY_",...e},this.eventHandlers.set("ready",new Set),this.eventHandlers.set("update",new Set),this.eventHandlers.set("error",new Set),this.eventHandlers.set("offline",new Set),this.eventHandlers.set("online",new Set),this.config.offlineFallback&&this.loadOfflineToggles(),this.startPolling()}on(e,t){const n=this.eventHandlers.get(e);return n&&n.add(t),()=>this.off(e,t)}off(e,t){const n=this.eventHandlers.get(e);n&&n.delete(t)}emit(e){const t=this.eventHandlers.get(e);t&&t.forEach(e=>e({...this.state}))}setContext(e){this.context={...this.context,...e}}getContext(){return{...this.context}}clearContext(){this.context={}}getState(){return{...this.state}}isReady(){return this.state.isReady}isOffline(){return this.state.isOffline}async isEnabled(e,t=!1){const n=await this.getValue(e);return null===n?t:n.enabled&&!0===n.value}async getString(e,t=""){const n=await this.getValue(e);return null!==n&&n.enabled?String(n.value):t}async getNumber(e,t=0){const n=await this.getValue(e);return null!==n&&n.enabled?Number(n.value):t}async getJSON(e,t={}){const n=await this.getValue(e);if(null===n||!n.enabled)return t;if("string"==typeof n.value)try{return JSON.parse(n.value)}catch{return t}return n.value}async getValue(e){const t=this.toggles.get(e);if(t)return t;try{const t=await this.fetchWithTimeout(`${this.config.baseUrl}/sdk/flags/${this.config.environment}/${e}`,{headers:{Authorization:`Bearer ${this.config.apiKey}`,"Content-Type":"application/json"}});if(!t.ok){if(404===t.status)return null;throw new Error(`HTTP ${t.status}`)}const n=await t.json();return this.toggles.set(e,n),this.state.isOffline&&(this.state.isOffline=!1,this.emit("online")),n}catch(t){const n=this.getOfflineToggle(e);return null!==n?n:(console.error(`[Togglely] Failed to fetch toggle "${e}":`,t),null)}}getAllToggles(){const e={};return this.toggles.forEach((t,n)=>{e[n]=t}),e}loadOfflineToggles(){try{if("undefined"!=typeof window&&window.__TOGGLELY_TOGGLES){const e=window.__TOGGLELY_TOGGLES;for(const[t,n]of Object.entries(e))this.toggles.set(t,this.parseOfflineValue(n));return this.offlineTogglesLoaded=!0,void console.log("[Togglely] Loaded offline toggles from window.__TOGGLELY_TOGGLES")}if("undefined"!=typeof process&&process.env){const e=this.config.envPrefix;for(const[t,n]of Object.entries(process.env))if(t?.startsWith(e)&&void 0!==n){const s=t.slice(e.length).toLowerCase().replace(/_/g,"-");this.toggles.set(s,this.parseOfflineValue(n))}this.offlineTogglesLoaded=!0,console.log("[Togglely] Loaded offline toggles from environment variables")}}catch(e){console.warn("[Togglely] Failed to load offline toggles:",e)}}getOfflineToggle(e){if(!this.config.offlineFallback)return null;const t=this.toggles.get(e);return t?(this.state.isOffline||(this.state.isOffline=!0,this.emit("offline")),t):null}parseOfflineValue(e){if("string"==typeof e){const t=e.toLowerCase();if("true"===t)return{value:!0,enabled:!0};if("false"===t)return{value:!1,enabled:!0};if(!isNaN(Number(e)))return{value:Number(e),enabled:!0};try{return{value:JSON.parse(e),enabled:!0}}catch{return{value:e,enabled:!0}}}return{value:e,enabled:!0}}async refresh(){try{const e=await this.fetchWithTimeout(`${this.config.baseUrl}/sdk/toggles/${this.config.environment}`,{headers:{Authorization:`Bearer ${this.config.apiKey}`,"Content-Type":"application/json"}});if(!e.ok)throw new Error(`HTTP ${e.status}`);const t=await e.json();this.toggles.clear();for(const[e,n]of Object.entries(t))this.toggles.set(e,n);this.state.lastFetch=new Date,this.state.lastError=null,this.state.isReady||(this.state.isReady=!0,this.emit("ready")),this.state.isOffline&&(this.state.isOffline=!1,this.emit("online")),this.emit("update")}catch(e){this.state.lastError=e,this.config.offlineFallback&&this.offlineTogglesLoaded&&(this.state.isOffline||(this.state.isOffline=!0,this.emit("offline"))),this.emit("error"),console.error("[Togglely] Failed to refresh toggles:",e)}}forceOfflineMode(){this.state.isOffline=!0,this.emit("offline")}forceOnlineMode(){this.state.isOffline=!1,this.refresh(),this.emit("online")}destroy(){this.refreshTimer&&clearInterval(this.refreshTimer),this.toggles.clear(),this.eventHandlers.forEach(e=>e.clear())}startPolling(){this.refresh(),this.refreshTimer=setInterval(()=>{this.state.isOffline||this.refresh()},this.config.refreshInterval)}fetchWithTimeout(e,t){return new Promise((n,s)=>{const i=setTimeout(()=>{s(new Error("Request timeout"))},this.config.timeout);fetch(e,t).then(e=>{clearTimeout(i),n(e)}).catch(e=>{clearTimeout(i),s(e)})})}}function n(){return"undefined"!=typeof window&&window.togglely||null}e.TogglelyClient=t,e.createOfflineTogglesScript=function(e){return`<script>window.__TOGGLELY_TOGGLES = ${JSON.stringify(e)};<\/script>`},e.default=t,e.getGlobalTogglely=n,e.getJSON=async function(e,t={}){const s=n();return s?s.getJSON(e,t):(console.error("[Togglely] No global instance found. Call initTogglely() first."),t)},e.getNumber=async function(e,t=0){const s=n();return s?s.getNumber(e,t):(console.error("[Togglely] No global instance found. Call initTogglely() first."),t)},e.getString=async function(e,t=""){const s=n();return s?s.getString(e,t):(console.error("[Togglely] No global instance found. Call initTogglely() first."),t)},e.initTogglely=function(e){const n=new t(e);return"undefined"!=typeof window&&(window.togglely=n),n},e.isEnabled=async function(e,t=!1){const s=n();return s?s.isEnabled(e,t):(console.error("[Togglely] No global instance found. Call initTogglely() first."),t)},e.togglelyInit=function(e){const t=n();if(!t)return console.error("[Togglely] No global instance found. Call initTogglely() first."),()=>{};const s=async()=>{for(const[n,s]of Object.entries(e)){let e,i=!1,o=!1;"string"==typeof s?e=[s]:Array.isArray(s)?e=s:(e=[s.selector],i=s.defaultValue??!1,o=s.invert??!1);const l=await t.isEnabled(n,i),r=o?!l:l;e.forEach(e=>{document.querySelectorAll(e).forEach(e=>{e.style.display=r?"":"none"})})}};return s(),t.on("update",s)},e.togglelyToggle=async function(e,t,s={}){const{defaultValue:i=!1,invert:o=!1,hideClass:l="togglely-hidden",showClass:r="togglely-visible"}=s,a=n();if(!a)return void console.error("[Togglely] No global instance found. Call initTogglely() first.");const f=await a.isEnabled(t,i),g=o?!f:f;document.querySelectorAll(e).forEach(e=>{g?(e.classList.remove(l),e.classList.add(r),e.style.display=""):(e.classList.remove(r),e.classList.add(l),e.style.display="none")})},e.togglesToEnvVars=function(e,t="TOGGLELY_"){const n={};for(const[s,i]of Object.entries(e)){n[t+s.toUpperCase().replace(/-/g,"_")]="object"==typeof i?JSON.stringify(i):String(i)}return n},Object.defineProperty(e,"__esModule",{value:!0})});
2
+ //# sourceMappingURL=index.umd.min.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.umd.min.js","sources":["../../core/dist/index.esm.js","../src/index.ts"],"sourcesContent":["/**\n * Togglely Core SDK - Framework agnostic\n *\n * Supports offline fallback via environment variables\n */\n/**\n * Core Togglely Client\n */\nclass TogglelyClient {\n constructor(config) {\n this.toggles = new Map();\n this.context = {};\n this.state = {\n isReady: false,\n isOffline: false,\n lastError: null,\n lastFetch: null\n };\n this.eventHandlers = new Map();\n this.offlineTogglesLoaded = false;\n this.config = {\n refreshInterval: 60000,\n timeout: 5000,\n offlineFallback: true,\n envPrefix: 'TOGGLELY_',\n ...config\n };\n // Initialize event handlers\n this.eventHandlers.set('ready', new Set());\n this.eventHandlers.set('update', new Set());\n this.eventHandlers.set('error', new Set());\n this.eventHandlers.set('offline', new Set());\n this.eventHandlers.set('online', new Set());\n // Load offline toggles first (if enabled)\n if (this.config.offlineFallback) {\n this.loadOfflineToggles();\n }\n // Start polling\n this.startPolling();\n }\n // ==================== Event Handling ====================\n on(event, handler) {\n const handlers = this.eventHandlers.get(event);\n if (handlers) {\n handlers.add(handler);\n }\n return () => this.off(event, handler);\n }\n off(event, handler) {\n const handlers = this.eventHandlers.get(event);\n if (handlers) {\n handlers.delete(handler);\n }\n }\n emit(event) {\n const handlers = this.eventHandlers.get(event);\n if (handlers) {\n handlers.forEach(handler => handler({ ...this.state }));\n }\n }\n // ==================== Context ====================\n setContext(context) {\n this.context = { ...this.context, ...context };\n }\n getContext() {\n return { ...this.context };\n }\n clearContext() {\n this.context = {};\n }\n // ==================== State ====================\n getState() {\n return { ...this.state };\n }\n isReady() {\n return this.state.isReady;\n }\n isOffline() {\n return this.state.isOffline;\n }\n // ==================== Toggle Accessors ====================\n async isEnabled(key, defaultValue = false) {\n const value = await this.getValue(key);\n if (value === null)\n return defaultValue;\n return value.enabled && value.value === true;\n }\n async getString(key, defaultValue = '') {\n const value = await this.getValue(key);\n if (value === null || !value.enabled)\n return defaultValue;\n return String(value.value);\n }\n async getNumber(key, defaultValue = 0) {\n const value = await this.getValue(key);\n if (value === null || !value.enabled)\n return defaultValue;\n return Number(value.value);\n }\n async getJSON(key, defaultValue = {}) {\n const value = await this.getValue(key);\n if (value === null || !value.enabled)\n return defaultValue;\n if (typeof value.value === 'string') {\n try {\n return JSON.parse(value.value);\n }\n catch {\n return defaultValue;\n }\n }\n return value.value;\n }\n async getValue(key) {\n // Try cache first\n const cached = this.toggles.get(key);\n if (cached) {\n return cached;\n }\n // Fetch from server\n try {\n const response = await this.fetchWithTimeout(`${this.config.baseUrl}/sdk/flags/${this.config.environment}/${key}`, {\n headers: {\n 'Authorization': `Bearer ${this.config.apiKey}`,\n 'Content-Type': 'application/json'\n }\n });\n if (!response.ok) {\n if (response.status === 404) {\n return null;\n }\n throw new Error(`HTTP ${response.status}`);\n }\n const data = await response.json();\n this.toggles.set(key, data);\n // Update state if we were offline\n if (this.state.isOffline) {\n this.state.isOffline = false;\n this.emit('online');\n }\n return data;\n }\n catch (error) {\n // Try offline fallback\n const offlineValue = this.getOfflineToggle(key);\n if (offlineValue !== null) {\n return offlineValue;\n }\n console.error(`[Togglely] Failed to fetch toggle \"${key}\":`, error);\n return null;\n }\n }\n getAllToggles() {\n const result = {};\n this.toggles.forEach((value, key) => {\n result[key] = value;\n });\n return result;\n }\n // ==================== Offline Fallback ====================\n /**\n * Load toggles from environment variables\n * Format: TOGGLELY_<TOGGLE_KEY>=<value> or TOGGLELY_<TOGGLE_KEY>_ENABLED=true\n */\n loadOfflineToggles() {\n try {\n // Browser environment - check window.__TOGGLELY_TOGGLES\n if (typeof window !== 'undefined' && window.__TOGGLELY_TOGGLES) {\n const offlineToggles = window.__TOGGLELY_TOGGLES;\n for (const [key, value] of Object.entries(offlineToggles)) {\n this.toggles.set(key, this.parseOfflineValue(value));\n }\n this.offlineTogglesLoaded = true;\n console.log('[Togglely] Loaded offline toggles from window.__TOGGLELY_TOGGLES');\n return;\n }\n // Node.js / Bun / Deno environment - check process.env\n if (typeof process !== 'undefined' && process.env) {\n const prefix = this.config.envPrefix;\n for (const [envKey, envValue] of Object.entries(process.env)) {\n if (envKey?.startsWith(prefix) && envValue !== undefined) {\n // Parse toggle key: TOGGLELY_MY_FEATURE -> my-feature\n const toggleKey = envKey\n .slice(prefix.length)\n .toLowerCase()\n .replace(/_/g, '-');\n this.toggles.set(toggleKey, this.parseOfflineValue(envValue));\n }\n }\n this.offlineTogglesLoaded = true;\n console.log('[Togglely] Loaded offline toggles from environment variables');\n }\n }\n catch (error) {\n console.warn('[Togglely] Failed to load offline toggles:', error);\n }\n }\n getOfflineToggle(key) {\n if (!this.config.offlineFallback)\n return null;\n // Try to get from already loaded offline toggles\n const cached = this.toggles.get(key);\n if (cached) {\n // If we haven't emitted offline event yet, do it now\n if (!this.state.isOffline) {\n this.state.isOffline = true;\n this.emit('offline');\n }\n return cached;\n }\n return null;\n }\n parseOfflineValue(value) {\n // Handle boolean strings\n if (typeof value === 'string') {\n const lower = value.toLowerCase();\n if (lower === 'true')\n return { value: true, enabled: true };\n if (lower === 'false')\n return { value: false, enabled: true };\n // Try to parse as number\n if (!isNaN(Number(value))) {\n return { value: Number(value), enabled: true };\n }\n // Try to parse as JSON\n try {\n const parsed = JSON.parse(value);\n return { value: parsed, enabled: true };\n }\n catch {\n // Return as string\n return { value, enabled: true };\n }\n }\n return { value, enabled: true };\n }\n // ==================== Refresh / Polling ====================\n async refresh() {\n try {\n const response = await this.fetchWithTimeout(`${this.config.baseUrl}/sdk/toggles/${this.config.environment}`, {\n headers: {\n 'Authorization': `Bearer ${this.config.apiKey}`,\n 'Content-Type': 'application/json'\n }\n });\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}`);\n }\n const data = await response.json();\n this.toggles.clear();\n for (const [key, value] of Object.entries(data)) {\n this.toggles.set(key, value);\n }\n this.state.lastFetch = new Date();\n this.state.lastError = null;\n if (!this.state.isReady) {\n this.state.isReady = true;\n this.emit('ready');\n }\n // If we were offline, go online\n if (this.state.isOffline) {\n this.state.isOffline = false;\n this.emit('online');\n }\n this.emit('update');\n }\n catch (error) {\n this.state.lastError = error;\n // If we have offline toggles, switch to offline mode\n if (this.config.offlineFallback && this.offlineTogglesLoaded) {\n if (!this.state.isOffline) {\n this.state.isOffline = true;\n this.emit('offline');\n }\n }\n this.emit('error');\n console.error('[Togglely] Failed to refresh toggles:', error);\n }\n }\n forceOfflineMode() {\n this.state.isOffline = true;\n this.emit('offline');\n }\n forceOnlineMode() {\n this.state.isOffline = false;\n this.refresh();\n this.emit('online');\n }\n // ==================== Cleanup ====================\n destroy() {\n if (this.refreshTimer) {\n clearInterval(this.refreshTimer);\n }\n this.toggles.clear();\n this.eventHandlers.forEach(handlers => handlers.clear());\n }\n // ==================== Private Helpers ====================\n startPolling() {\n // Initial fetch\n this.refresh();\n // Set up polling\n this.refreshTimer = setInterval(() => {\n if (!this.state.isOffline) {\n this.refresh();\n }\n }, this.config.refreshInterval);\n }\n fetchWithTimeout(url, options) {\n return new Promise((resolve, reject) => {\n const timeoutId = setTimeout(() => {\n reject(new Error('Request timeout'));\n }, this.config.timeout);\n fetch(url, options)\n .then(response => {\n clearTimeout(timeoutId);\n resolve(response);\n })\n .catch(error => {\n clearTimeout(timeoutId);\n reject(error);\n });\n });\n }\n}\n// ==================== Utility Functions ====================\n/**\n * Create a client-side toggle loader script\n * Use this to inject offline toggles into your HTML\n */\nfunction createOfflineTogglesScript(toggles) {\n return `<script>window.__TOGGLELY_TOGGLES = ${JSON.stringify(toggles)};</script>`;\n}\n/**\n * Helper to convert toggles to environment variables\n */\nfunction togglesToEnvVars(toggles, prefix = 'TOGGLELY_') {\n const envVars = {};\n for (const [key, value] of Object.entries(toggles)) {\n const envKey = prefix + key.toUpperCase().replace(/-/g, '_');\n envVars[envKey] = typeof value === 'object' ? JSON.stringify(value) : String(value);\n }\n return envVars;\n}\n\nexport { TogglelyClient, createOfflineTogglesScript, TogglelyClient as default, togglesToEnvVars };\n//# sourceMappingURL=index.esm.js.map\n",null],"names":["TogglelyClient","constructor","config","this","toggles","Map","context","state","isReady","isOffline","lastError","lastFetch","eventHandlers","offlineTogglesLoaded","refreshInterval","timeout","offlineFallback","envPrefix","set","Set","loadOfflineToggles","startPolling","on","event","handler","handlers","get","add","off","delete","emit","forEach","setContext","getContext","clearContext","getState","isEnabled","key","defaultValue","value","getValue","enabled","getString","String","getNumber","Number","getJSON","JSON","parse","cached","response","fetchWithTimeout","baseUrl","environment","headers","Authorization","apiKey","ok","status","Error","data","json","error","offlineValue","getOfflineToggle","console","getAllToggles","result","window","__TOGGLELY_TOGGLES","offlineToggles","Object","entries","parseOfflineValue","log","process","env","prefix","envKey","envValue","startsWith","undefined","toggleKey","slice","length","toLowerCase","replace","warn","lower","isNaN","refresh","clear","Date","forceOfflineMode","forceOnlineMode","destroy","refreshTimer","clearInterval","setInterval","url","options","Promise","resolve","reject","timeoutId","setTimeout","fetch","then","clearTimeout","catch","getGlobalTogglely","togglely","stringify","async","client","updateAll","selectors","invert","Array","isArray","selector","isToggleEnabled","shouldShow","document","querySelectorAll","el","style","display","hideClass","showClass","classList","remove","envVars","toUpperCase"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@togglely/sdk",
3
- "version": "1.0.0",
3
+ "version": "1.1.1",
4
4
  "description": "Vanilla JavaScript SDK for Togglely - Feature toggles for any framework",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.esm.js",