@vexillo/react-sdk 1.0.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/dist/index.cjs +92 -0
- package/dist/index.d.cts +27 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.js +69 -0
- package/package.json +40 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var src_exports = {};
|
|
22
|
+
__export(src_exports, {
|
|
23
|
+
VexilloProvider: () => VexilloProvider,
|
|
24
|
+
useFlag: () => useFlag
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(src_exports);
|
|
27
|
+
|
|
28
|
+
// src/provider.tsx
|
|
29
|
+
var import_react = require("react");
|
|
30
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
31
|
+
var VexilloContext = (0, import_react.createContext)(null);
|
|
32
|
+
function VexilloProvider({
|
|
33
|
+
baseUrl,
|
|
34
|
+
apiKey,
|
|
35
|
+
fallbacks = {},
|
|
36
|
+
children
|
|
37
|
+
}) {
|
|
38
|
+
const [flags, setFlags] = (0, import_react.useState)(null);
|
|
39
|
+
const [error, setError] = (0, import_react.useState)(null);
|
|
40
|
+
(0, import_react.useEffect)(() => {
|
|
41
|
+
let cancelled = false;
|
|
42
|
+
fetch(`${baseUrl}/api/flags`, {
|
|
43
|
+
headers: { Authorization: `Bearer ${apiKey}` }
|
|
44
|
+
}).then((res) => {
|
|
45
|
+
if (!res.ok) {
|
|
46
|
+
throw new Error(
|
|
47
|
+
`Vexillo: API responded with status ${res.status} ${res.statusText}`
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
return res.json();
|
|
51
|
+
}).then((data) => {
|
|
52
|
+
if (cancelled) return;
|
|
53
|
+
const map = {};
|
|
54
|
+
for (const f of data.flags) {
|
|
55
|
+
map[f.key] = f.enabled;
|
|
56
|
+
}
|
|
57
|
+
setFlags(map);
|
|
58
|
+
}).catch((err) => {
|
|
59
|
+
if (cancelled) return;
|
|
60
|
+
setError(
|
|
61
|
+
err instanceof Error ? err : new Error(`Vexillo: unexpected error \u2014 ${String(err)}`)
|
|
62
|
+
);
|
|
63
|
+
});
|
|
64
|
+
return () => {
|
|
65
|
+
cancelled = true;
|
|
66
|
+
};
|
|
67
|
+
}, [apiKey, baseUrl]);
|
|
68
|
+
if (error) throw error;
|
|
69
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(VexilloContext.Provider, { value: { flags, fallbacks }, children });
|
|
70
|
+
}
|
|
71
|
+
function useVexilloContext() {
|
|
72
|
+
const ctx = (0, import_react.useContext)(VexilloContext);
|
|
73
|
+
if (ctx === null) {
|
|
74
|
+
throw new Error("useFlag must be called inside a <VexilloProvider>.");
|
|
75
|
+
}
|
|
76
|
+
return ctx;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// src/use-flag.ts
|
|
80
|
+
function useFlag(key) {
|
|
81
|
+
var _a;
|
|
82
|
+
const { flags, fallbacks } = useVexilloContext();
|
|
83
|
+
if (flags !== null && key in flags) {
|
|
84
|
+
return flags[key];
|
|
85
|
+
}
|
|
86
|
+
return (_a = fallbacks[key]) != null ? _a : false;
|
|
87
|
+
}
|
|
88
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
89
|
+
0 && (module.exports = {
|
|
90
|
+
VexilloProvider,
|
|
91
|
+
useFlag
|
|
92
|
+
});
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
interface VexilloProviderProps {
|
|
4
|
+
/** Base URL of your Vexillo deployment (e.g. "https://vexillo.example.com") */
|
|
5
|
+
baseUrl: string;
|
|
6
|
+
/** SDK API key for the target environment */
|
|
7
|
+
apiKey: string;
|
|
8
|
+
/** Environment slug — stored in context for consumer reference */
|
|
9
|
+
environment: string;
|
|
10
|
+
/** Flag values used before the fetch resolves and for unknown keys */
|
|
11
|
+
fallbacks?: Record<string, boolean>;
|
|
12
|
+
children: ReactNode;
|
|
13
|
+
}
|
|
14
|
+
declare function VexilloProvider({ baseUrl, apiKey, fallbacks, children, }: VexilloProviderProps): ReactNode;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Returns the current boolean value for a feature flag key.
|
|
18
|
+
*
|
|
19
|
+
* - Before the provider's fetch resolves (including SSR), returns the value
|
|
20
|
+
* from `fallbacks`, or `false` if the key is absent.
|
|
21
|
+
* - After the fetch resolves, returns the live value from the API, falling
|
|
22
|
+
* back to `fallbacks[key] ?? false` for keys not present in the response.
|
|
23
|
+
* - Throws if called outside a `<VexilloProvider>`.
|
|
24
|
+
*/
|
|
25
|
+
declare function useFlag(key: string): boolean;
|
|
26
|
+
|
|
27
|
+
export { VexilloProvider, type VexilloProviderProps, useFlag };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
interface VexilloProviderProps {
|
|
4
|
+
/** Base URL of your Vexillo deployment (e.g. "https://vexillo.example.com") */
|
|
5
|
+
baseUrl: string;
|
|
6
|
+
/** SDK API key for the target environment */
|
|
7
|
+
apiKey: string;
|
|
8
|
+
/** Environment slug — stored in context for consumer reference */
|
|
9
|
+
environment: string;
|
|
10
|
+
/** Flag values used before the fetch resolves and for unknown keys */
|
|
11
|
+
fallbacks?: Record<string, boolean>;
|
|
12
|
+
children: ReactNode;
|
|
13
|
+
}
|
|
14
|
+
declare function VexilloProvider({ baseUrl, apiKey, fallbacks, children, }: VexilloProviderProps): ReactNode;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Returns the current boolean value for a feature flag key.
|
|
18
|
+
*
|
|
19
|
+
* - Before the provider's fetch resolves (including SSR), returns the value
|
|
20
|
+
* from `fallbacks`, or `false` if the key is absent.
|
|
21
|
+
* - After the fetch resolves, returns the live value from the API, falling
|
|
22
|
+
* back to `fallbacks[key] ?? false` for keys not present in the response.
|
|
23
|
+
* - Throws if called outside a `<VexilloProvider>`.
|
|
24
|
+
*/
|
|
25
|
+
declare function useFlag(key: string): boolean;
|
|
26
|
+
|
|
27
|
+
export { VexilloProvider, type VexilloProviderProps, useFlag };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
// src/provider.tsx
|
|
2
|
+
import {
|
|
3
|
+
createContext,
|
|
4
|
+
useContext,
|
|
5
|
+
useEffect,
|
|
6
|
+
useState
|
|
7
|
+
} from "react";
|
|
8
|
+
import { jsx } from "react/jsx-runtime";
|
|
9
|
+
var VexilloContext = createContext(null);
|
|
10
|
+
function VexilloProvider({
|
|
11
|
+
baseUrl,
|
|
12
|
+
apiKey,
|
|
13
|
+
fallbacks = {},
|
|
14
|
+
children
|
|
15
|
+
}) {
|
|
16
|
+
const [flags, setFlags] = useState(null);
|
|
17
|
+
const [error, setError] = useState(null);
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
let cancelled = false;
|
|
20
|
+
fetch(`${baseUrl}/api/flags`, {
|
|
21
|
+
headers: { Authorization: `Bearer ${apiKey}` }
|
|
22
|
+
}).then((res) => {
|
|
23
|
+
if (!res.ok) {
|
|
24
|
+
throw new Error(
|
|
25
|
+
`Vexillo: API responded with status ${res.status} ${res.statusText}`
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
return res.json();
|
|
29
|
+
}).then((data) => {
|
|
30
|
+
if (cancelled) return;
|
|
31
|
+
const map = {};
|
|
32
|
+
for (const f of data.flags) {
|
|
33
|
+
map[f.key] = f.enabled;
|
|
34
|
+
}
|
|
35
|
+
setFlags(map);
|
|
36
|
+
}).catch((err) => {
|
|
37
|
+
if (cancelled) return;
|
|
38
|
+
setError(
|
|
39
|
+
err instanceof Error ? err : new Error(`Vexillo: unexpected error \u2014 ${String(err)}`)
|
|
40
|
+
);
|
|
41
|
+
});
|
|
42
|
+
return () => {
|
|
43
|
+
cancelled = true;
|
|
44
|
+
};
|
|
45
|
+
}, [apiKey, baseUrl]);
|
|
46
|
+
if (error) throw error;
|
|
47
|
+
return /* @__PURE__ */ jsx(VexilloContext.Provider, { value: { flags, fallbacks }, children });
|
|
48
|
+
}
|
|
49
|
+
function useVexilloContext() {
|
|
50
|
+
const ctx = useContext(VexilloContext);
|
|
51
|
+
if (ctx === null) {
|
|
52
|
+
throw new Error("useFlag must be called inside a <VexilloProvider>.");
|
|
53
|
+
}
|
|
54
|
+
return ctx;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// src/use-flag.ts
|
|
58
|
+
function useFlag(key) {
|
|
59
|
+
var _a;
|
|
60
|
+
const { flags, fallbacks } = useVexilloContext();
|
|
61
|
+
if (flags !== null && key in flags) {
|
|
62
|
+
return flags[key];
|
|
63
|
+
}
|
|
64
|
+
return (_a = fallbacks[key]) != null ? _a : false;
|
|
65
|
+
}
|
|
66
|
+
export {
|
|
67
|
+
VexilloProvider,
|
|
68
|
+
useFlag
|
|
69
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@vexillo/react-sdk",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"publishConfig": {
|
|
6
|
+
"registry": "https://registry.npmjs.org",
|
|
7
|
+
"access": "public"
|
|
8
|
+
},
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.mjs",
|
|
13
|
+
"require": "./dist/index.cjs"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist"
|
|
18
|
+
],
|
|
19
|
+
"peerDependencies": {
|
|
20
|
+
"react": "^18 || ^19",
|
|
21
|
+
"react-dom": "^18 || ^19"
|
|
22
|
+
},
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"@testing-library/react": "^16",
|
|
25
|
+
"@types/react": "^19",
|
|
26
|
+
"@types/react-dom": "^19",
|
|
27
|
+
"jsdom": "^26",
|
|
28
|
+
"react": "^19",
|
|
29
|
+
"react-dom": "^19",
|
|
30
|
+
"tsup": "^8",
|
|
31
|
+
"typescript": "^5",
|
|
32
|
+
"vitest": "^3"
|
|
33
|
+
},
|
|
34
|
+
"scripts": {
|
|
35
|
+
"build": "tsup",
|
|
36
|
+
"dev": "tsup --watch",
|
|
37
|
+
"lint": "tsc --noEmit",
|
|
38
|
+
"test": "vitest run"
|
|
39
|
+
}
|
|
40
|
+
}
|