@optare/client 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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Optare
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,39 @@
1
+ # @optare/client
2
+
3
+ Headless, framework-agnostic client SDK for Optare. The entire integration
4
+ contract is one string — a publishable key (`pk_live_…`).
5
+
6
+ ```ts
7
+ import { createOptareClient } from "@optare/client";
8
+
9
+ const { auth, config } = await createOptareClient({
10
+ publishableKey: "pk_live_xxx",
11
+ // baseURL / configURL optional — defaults to the hosted Optare API
12
+ });
13
+
14
+ // `auth` is a better-auth client
15
+ await auth.signIn.email({ email, password });
16
+ const { data: session } = await auth.getSession();
17
+
18
+ // `config` is the resolved endpoint + white-label branding
19
+ config.baseURL; // where the auth API lives
20
+ config.branding.name; // customer's org name
21
+ config.branding.logoUrl; // customer's logo
22
+ ```
23
+
24
+ ## What it does
25
+
26
+ 1. `resolveOptareConfig()` calls `GET /api/public/config?pk=…` and learns the
27
+ auth API origin and the project's branding. `pk_live_` is not a secret, so
28
+ this is safe from a browser.
29
+ 2. `createOptareClient()` builds a better-auth client pointed at that origin
30
+ with the Optare plugin set (organization, 2FA, email OTP, magic link,
31
+ multi-session, JWT) and the publishable key attached to every request.
32
+
33
+ For SSR, call `resolveOptareConfig()` on the server and pass the result back as
34
+ `bootstrap` to skip the client-side fetch.
35
+
36
+ ## Server-side use
37
+
38
+ For `sk_live_` management calls or offline JWT verification, use
39
+ [`@optare/node`](../node) instead — this package is for the front end.
package/dist/index.cjs ADDED
@@ -0,0 +1,147 @@
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 index_exports = {};
22
+ __export(index_exports, {
23
+ DEFAULT_AUTH_METHODS: () => DEFAULT_AUTH_METHODS,
24
+ DEFAULT_OPTARE_ORIGIN: () => DEFAULT_OPTARE_ORIGIN,
25
+ OptareConfigError: () => OptareConfigError,
26
+ createOptareClient: () => createOptareClient,
27
+ resolveOptareConfig: () => resolveOptareConfig
28
+ });
29
+ module.exports = __toCommonJS(index_exports);
30
+ var import_client = require("better-auth/client");
31
+ var import_plugins = require("better-auth/client/plugins");
32
+ var DEFAULT_OPTARE_ORIGIN = "https://id.optare.one";
33
+ var DEFAULT_AUTH_METHODS = {
34
+ emailPassword: true,
35
+ magicLink: false,
36
+ emailOtp: false,
37
+ sso: false,
38
+ passkey: false,
39
+ social: []
40
+ };
41
+ var PUBLISHABLE_KEY_PREFIX = "pk_live_";
42
+ var OptareConfigError = class extends Error {
43
+ constructor(message) {
44
+ super(message);
45
+ this.name = "OptareConfigError";
46
+ }
47
+ };
48
+ function assertPublishableKey(key) {
49
+ if (!key || !key.startsWith(PUBLISHABLE_KEY_PREFIX)) {
50
+ throw new OptareConfigError(
51
+ `Invalid publishable key \u2014 expected a "${PUBLISHABLE_KEY_PREFIX}\u2026" string`
52
+ );
53
+ }
54
+ }
55
+ async function resolveOptareConfig(config) {
56
+ assertPublishableKey(config.publishableKey);
57
+ if (config.bootstrap) {
58
+ return {
59
+ ...config.bootstrap,
60
+ authMethods: normalizeAuthMethods(config.bootstrap.authMethods)
61
+ };
62
+ }
63
+ const doFetch = config.fetch ?? globalThis.fetch;
64
+ if (typeof doFetch !== "function") {
65
+ throw new OptareConfigError(
66
+ "No fetch implementation available \u2014 pass `fetch` in the config"
67
+ );
68
+ }
69
+ const origin = (config.configURL ?? config.baseURL ?? DEFAULT_OPTARE_ORIGIN).replace(/\/+$/, "");
70
+ const url = `${origin}/api/public/config?pk=${encodeURIComponent(config.publishableKey)}`;
71
+ let res;
72
+ try {
73
+ res = await doFetch(url, { headers: { accept: "application/json" } });
74
+ } catch (cause) {
75
+ throw new OptareConfigError(
76
+ `Could not reach the Optare config endpoint at ${origin}: ${cause.message}`
77
+ );
78
+ }
79
+ if (res.status === 404) {
80
+ throw new OptareConfigError("Publishable key was not recognised by the server");
81
+ }
82
+ if (!res.ok) {
83
+ throw new OptareConfigError(
84
+ `Config endpoint returned ${res.status} ${res.statusText}`
85
+ );
86
+ }
87
+ const body = await res.json();
88
+ if (!body.baseURL || !body.branding || !body.project) {
89
+ throw new OptareConfigError("Config endpoint returned an unexpected shape");
90
+ }
91
+ return {
92
+ baseURL: config.baseURL ?? body.baseURL,
93
+ project: body.project,
94
+ branding: body.branding,
95
+ authMethods: normalizeAuthMethods(body.authMethods)
96
+ };
97
+ }
98
+ function normalizeAuthMethods(raw) {
99
+ const known = [
100
+ "google",
101
+ "github",
102
+ "microsoft",
103
+ "facebook",
104
+ "twitter"
105
+ ];
106
+ return {
107
+ emailPassword: raw?.emailPassword ?? DEFAULT_AUTH_METHODS.emailPassword,
108
+ magicLink: raw?.magicLink ?? DEFAULT_AUTH_METHODS.magicLink,
109
+ emailOtp: raw?.emailOtp ?? DEFAULT_AUTH_METHODS.emailOtp,
110
+ sso: raw?.sso ?? DEFAULT_AUTH_METHODS.sso,
111
+ passkey: raw?.passkey ?? DEFAULT_AUTH_METHODS.passkey,
112
+ social: Array.isArray(raw?.social) ? known.filter((p) => raw.social.includes(p)) : DEFAULT_AUTH_METHODS.social
113
+ };
114
+ }
115
+ function optarePlugins() {
116
+ return [
117
+ (0, import_plugins.organizationClient)(),
118
+ (0, import_plugins.twoFactorClient)(),
119
+ (0, import_plugins.emailOTPClient)(),
120
+ (0, import_plugins.magicLinkClient)(),
121
+ (0, import_plugins.multiSessionClient)(),
122
+ (0, import_plugins.jwtClient)()
123
+ ];
124
+ }
125
+ async function createOptareClient(config) {
126
+ const bootstrap = await resolveOptareConfig(config);
127
+ const auth = (0, import_client.createAuthClient)({
128
+ baseURL: bootstrap.baseURL,
129
+ fetchOptions: {
130
+ ...config.fetch ? { customFetchImpl: config.fetch } : {},
131
+ headers: {
132
+ "x-optare-publishable-key": config.publishableKey,
133
+ ...config.headers
134
+ }
135
+ },
136
+ plugins: optarePlugins()
137
+ });
138
+ return { auth, config: bootstrap };
139
+ }
140
+ // Annotate the CommonJS export names for ESM import in node:
141
+ 0 && (module.exports = {
142
+ DEFAULT_AUTH_METHODS,
143
+ DEFAULT_OPTARE_ORIGIN,
144
+ OptareConfigError,
145
+ createOptareClient,
146
+ resolveOptareConfig
147
+ });
@@ -0,0 +1,115 @@
1
+ import { createAuthClient } from 'better-auth/client';
2
+
3
+ /**
4
+ * `@optare/client` — E1.
5
+ *
6
+ * Headless, framework-agnostic. The entire integration contract is one string:
7
+ * a publishable key (`pk_live_…`). The key is *not* a secret — it ships in
8
+ * browser bundles — so the SDK can safely use it to look up, from a public
9
+ * endpoint, (a) which origin the auth API lives on and (b) the project's
10
+ * white-label branding. Everything else is a thin, fully-typed wrapper around
11
+ * better-auth's client with the same plugin set the Optare backend runs.
12
+ *
13
+ * `@optare/react` builds its provider/hooks/components on top of this; a Node
14
+ * service that only needs `sk_live_` management calls or offline JWT checks
15
+ * uses `@optare/node` instead.
16
+ */
17
+ /** The hosted Optare API origin used when neither `baseURL` nor `configURL` is given. */
18
+ declare const DEFAULT_OPTARE_ORIGIN = "https://id.optare.one";
19
+ interface OptareBranding {
20
+ name: string;
21
+ logoUrl: string | null;
22
+ primaryColor: string | null;
23
+ radius: string | null;
24
+ }
25
+ interface OptareProjectInfo {
26
+ id: string;
27
+ name: string;
28
+ slug: string;
29
+ plan: string;
30
+ }
31
+ /** Social providers Optare can broker, in a stable display order. */
32
+ type OptareSocialProvider = "google" | "github" | "microsoft" | "facebook" | "twitter";
33
+ /**
34
+ * Which sign-in methods the Optare instance has enabled. The SDK components use
35
+ * this to decide what to render — a project can't turn individual methods on or
36
+ * off in v1 (they're instance-wide), but the deployment can, so the components
37
+ * must not assume e.g. social buttons exist.
38
+ */
39
+ interface OptareAuthMethods {
40
+ emailPassword: boolean;
41
+ magicLink: boolean;
42
+ emailOtp: boolean;
43
+ sso: boolean;
44
+ passkey: boolean;
45
+ social: OptareSocialProvider[];
46
+ }
47
+ /**
48
+ * Safe default for a server that predates the `authMethods` field — email +
49
+ * password only, so a `<SignIn>` still renders something usable.
50
+ */
51
+ declare const DEFAULT_AUTH_METHODS: OptareAuthMethods;
52
+ interface OptareBootstrap {
53
+ /** Origin the auth API (`/api/auth/*`) is served from. */
54
+ baseURL: string;
55
+ project: OptareProjectInfo;
56
+ branding: OptareBranding;
57
+ /** Enabled sign-in methods for this deployment. */
58
+ authMethods: OptareAuthMethods;
59
+ }
60
+ interface OptareClientConfig {
61
+ /** `pk_live_…` — identifies the project. Required. */
62
+ publishableKey: string;
63
+ /**
64
+ * Skip endpoint discovery: if set, this is used as the auth API origin and
65
+ * only branding is fetched (from `${baseURL}/api/public/config`).
66
+ */
67
+ baseURL?: string;
68
+ /**
69
+ * Where `GET /api/public/config` lives. Defaults to `baseURL`, then to the
70
+ * hosted Optare origin. Set this for self-hosted / preview deployments.
71
+ */
72
+ configURL?: string;
73
+ /**
74
+ * Pre-resolved bootstrap — skips the network call entirely. Useful for SSR,
75
+ * tests, or when the host app already fetched the config.
76
+ */
77
+ bootstrap?: OptareBootstrap;
78
+ /** `fetch` implementation (Node < 18, tests, custom agents). */
79
+ fetch?: typeof fetch;
80
+ /** Extra headers to attach to every auth request. */
81
+ headers?: Record<string, string>;
82
+ }
83
+ declare class OptareConfigError extends Error {
84
+ constructor(message: string);
85
+ }
86
+ /**
87
+ * Resolve a publishable key to its endpoint + branding via the public config
88
+ * endpoint. Framework-agnostic; call it directly for SSR or to warm a cache.
89
+ */
90
+ declare function resolveOptareConfig(config: OptareClientConfig): Promise<OptareBootstrap>;
91
+ type OptareAuthClient = ReturnType<typeof createAuthClient>;
92
+ type Session = OptareAuthClient["$Infer"]["Session"];
93
+ type User = Session["user"];
94
+ interface OptareClient {
95
+ /**
96
+ * The better-auth client — `signIn`, `signUp`, `getSession`, `signOut`,
97
+ * `organization.*`, `twoFactor.*`, etc. A drop-in better-auth client; every
98
+ * request carries the publishable key.
99
+ */
100
+ auth: OptareAuthClient;
101
+ /** Resolved endpoint + white-label branding for this publishable key. */
102
+ config: OptareBootstrap;
103
+ }
104
+ /**
105
+ * Build a fully-configured Optare client. Async because it resolves the
106
+ * endpoint + branding from the publishable key first (unless `baseURL` +
107
+ * `bootstrap` let it skip the network).
108
+ *
109
+ * The better-auth client is a dynamic RPC proxy — arbitrary property access is
110
+ * meaningful — so the resolved config is returned *alongside* it, never
111
+ * attached to it.
112
+ */
113
+ declare function createOptareClient(config: OptareClientConfig): Promise<OptareClient>;
114
+
115
+ export { DEFAULT_AUTH_METHODS, DEFAULT_OPTARE_ORIGIN, type OptareAuthClient, type OptareAuthMethods, type OptareBootstrap, type OptareBranding, type OptareClient, type OptareClientConfig, OptareConfigError, type OptareProjectInfo, type OptareSocialProvider, type Session, type User, createOptareClient, resolveOptareConfig };
@@ -0,0 +1,115 @@
1
+ import { createAuthClient } from 'better-auth/client';
2
+
3
+ /**
4
+ * `@optare/client` — E1.
5
+ *
6
+ * Headless, framework-agnostic. The entire integration contract is one string:
7
+ * a publishable key (`pk_live_…`). The key is *not* a secret — it ships in
8
+ * browser bundles — so the SDK can safely use it to look up, from a public
9
+ * endpoint, (a) which origin the auth API lives on and (b) the project's
10
+ * white-label branding. Everything else is a thin, fully-typed wrapper around
11
+ * better-auth's client with the same plugin set the Optare backend runs.
12
+ *
13
+ * `@optare/react` builds its provider/hooks/components on top of this; a Node
14
+ * service that only needs `sk_live_` management calls or offline JWT checks
15
+ * uses `@optare/node` instead.
16
+ */
17
+ /** The hosted Optare API origin used when neither `baseURL` nor `configURL` is given. */
18
+ declare const DEFAULT_OPTARE_ORIGIN = "https://id.optare.one";
19
+ interface OptareBranding {
20
+ name: string;
21
+ logoUrl: string | null;
22
+ primaryColor: string | null;
23
+ radius: string | null;
24
+ }
25
+ interface OptareProjectInfo {
26
+ id: string;
27
+ name: string;
28
+ slug: string;
29
+ plan: string;
30
+ }
31
+ /** Social providers Optare can broker, in a stable display order. */
32
+ type OptareSocialProvider = "google" | "github" | "microsoft" | "facebook" | "twitter";
33
+ /**
34
+ * Which sign-in methods the Optare instance has enabled. The SDK components use
35
+ * this to decide what to render — a project can't turn individual methods on or
36
+ * off in v1 (they're instance-wide), but the deployment can, so the components
37
+ * must not assume e.g. social buttons exist.
38
+ */
39
+ interface OptareAuthMethods {
40
+ emailPassword: boolean;
41
+ magicLink: boolean;
42
+ emailOtp: boolean;
43
+ sso: boolean;
44
+ passkey: boolean;
45
+ social: OptareSocialProvider[];
46
+ }
47
+ /**
48
+ * Safe default for a server that predates the `authMethods` field — email +
49
+ * password only, so a `<SignIn>` still renders something usable.
50
+ */
51
+ declare const DEFAULT_AUTH_METHODS: OptareAuthMethods;
52
+ interface OptareBootstrap {
53
+ /** Origin the auth API (`/api/auth/*`) is served from. */
54
+ baseURL: string;
55
+ project: OptareProjectInfo;
56
+ branding: OptareBranding;
57
+ /** Enabled sign-in methods for this deployment. */
58
+ authMethods: OptareAuthMethods;
59
+ }
60
+ interface OptareClientConfig {
61
+ /** `pk_live_…` — identifies the project. Required. */
62
+ publishableKey: string;
63
+ /**
64
+ * Skip endpoint discovery: if set, this is used as the auth API origin and
65
+ * only branding is fetched (from `${baseURL}/api/public/config`).
66
+ */
67
+ baseURL?: string;
68
+ /**
69
+ * Where `GET /api/public/config` lives. Defaults to `baseURL`, then to the
70
+ * hosted Optare origin. Set this for self-hosted / preview deployments.
71
+ */
72
+ configURL?: string;
73
+ /**
74
+ * Pre-resolved bootstrap — skips the network call entirely. Useful for SSR,
75
+ * tests, or when the host app already fetched the config.
76
+ */
77
+ bootstrap?: OptareBootstrap;
78
+ /** `fetch` implementation (Node < 18, tests, custom agents). */
79
+ fetch?: typeof fetch;
80
+ /** Extra headers to attach to every auth request. */
81
+ headers?: Record<string, string>;
82
+ }
83
+ declare class OptareConfigError extends Error {
84
+ constructor(message: string);
85
+ }
86
+ /**
87
+ * Resolve a publishable key to its endpoint + branding via the public config
88
+ * endpoint. Framework-agnostic; call it directly for SSR or to warm a cache.
89
+ */
90
+ declare function resolveOptareConfig(config: OptareClientConfig): Promise<OptareBootstrap>;
91
+ type OptareAuthClient = ReturnType<typeof createAuthClient>;
92
+ type Session = OptareAuthClient["$Infer"]["Session"];
93
+ type User = Session["user"];
94
+ interface OptareClient {
95
+ /**
96
+ * The better-auth client — `signIn`, `signUp`, `getSession`, `signOut`,
97
+ * `organization.*`, `twoFactor.*`, etc. A drop-in better-auth client; every
98
+ * request carries the publishable key.
99
+ */
100
+ auth: OptareAuthClient;
101
+ /** Resolved endpoint + white-label branding for this publishable key. */
102
+ config: OptareBootstrap;
103
+ }
104
+ /**
105
+ * Build a fully-configured Optare client. Async because it resolves the
106
+ * endpoint + branding from the publishable key first (unless `baseURL` +
107
+ * `bootstrap` let it skip the network).
108
+ *
109
+ * The better-auth client is a dynamic RPC proxy — arbitrary property access is
110
+ * meaningful — so the resolved config is returned *alongside* it, never
111
+ * attached to it.
112
+ */
113
+ declare function createOptareClient(config: OptareClientConfig): Promise<OptareClient>;
114
+
115
+ export { DEFAULT_AUTH_METHODS, DEFAULT_OPTARE_ORIGIN, type OptareAuthClient, type OptareAuthMethods, type OptareBootstrap, type OptareBranding, type OptareClient, type OptareClientConfig, OptareConfigError, type OptareProjectInfo, type OptareSocialProvider, type Session, type User, createOptareClient, resolveOptareConfig };
package/dist/index.js ADDED
@@ -0,0 +1,125 @@
1
+ // src/index.ts
2
+ import { createAuthClient } from "better-auth/client";
3
+ import {
4
+ organizationClient,
5
+ twoFactorClient,
6
+ emailOTPClient,
7
+ magicLinkClient,
8
+ multiSessionClient,
9
+ jwtClient
10
+ } from "better-auth/client/plugins";
11
+ var DEFAULT_OPTARE_ORIGIN = "https://id.optare.one";
12
+ var DEFAULT_AUTH_METHODS = {
13
+ emailPassword: true,
14
+ magicLink: false,
15
+ emailOtp: false,
16
+ sso: false,
17
+ passkey: false,
18
+ social: []
19
+ };
20
+ var PUBLISHABLE_KEY_PREFIX = "pk_live_";
21
+ var OptareConfigError = class extends Error {
22
+ constructor(message) {
23
+ super(message);
24
+ this.name = "OptareConfigError";
25
+ }
26
+ };
27
+ function assertPublishableKey(key) {
28
+ if (!key || !key.startsWith(PUBLISHABLE_KEY_PREFIX)) {
29
+ throw new OptareConfigError(
30
+ `Invalid publishable key \u2014 expected a "${PUBLISHABLE_KEY_PREFIX}\u2026" string`
31
+ );
32
+ }
33
+ }
34
+ async function resolveOptareConfig(config) {
35
+ assertPublishableKey(config.publishableKey);
36
+ if (config.bootstrap) {
37
+ return {
38
+ ...config.bootstrap,
39
+ authMethods: normalizeAuthMethods(config.bootstrap.authMethods)
40
+ };
41
+ }
42
+ const doFetch = config.fetch ?? globalThis.fetch;
43
+ if (typeof doFetch !== "function") {
44
+ throw new OptareConfigError(
45
+ "No fetch implementation available \u2014 pass `fetch` in the config"
46
+ );
47
+ }
48
+ const origin = (config.configURL ?? config.baseURL ?? DEFAULT_OPTARE_ORIGIN).replace(/\/+$/, "");
49
+ const url = `${origin}/api/public/config?pk=${encodeURIComponent(config.publishableKey)}`;
50
+ let res;
51
+ try {
52
+ res = await doFetch(url, { headers: { accept: "application/json" } });
53
+ } catch (cause) {
54
+ throw new OptareConfigError(
55
+ `Could not reach the Optare config endpoint at ${origin}: ${cause.message}`
56
+ );
57
+ }
58
+ if (res.status === 404) {
59
+ throw new OptareConfigError("Publishable key was not recognised by the server");
60
+ }
61
+ if (!res.ok) {
62
+ throw new OptareConfigError(
63
+ `Config endpoint returned ${res.status} ${res.statusText}`
64
+ );
65
+ }
66
+ const body = await res.json();
67
+ if (!body.baseURL || !body.branding || !body.project) {
68
+ throw new OptareConfigError("Config endpoint returned an unexpected shape");
69
+ }
70
+ return {
71
+ baseURL: config.baseURL ?? body.baseURL,
72
+ project: body.project,
73
+ branding: body.branding,
74
+ authMethods: normalizeAuthMethods(body.authMethods)
75
+ };
76
+ }
77
+ function normalizeAuthMethods(raw) {
78
+ const known = [
79
+ "google",
80
+ "github",
81
+ "microsoft",
82
+ "facebook",
83
+ "twitter"
84
+ ];
85
+ return {
86
+ emailPassword: raw?.emailPassword ?? DEFAULT_AUTH_METHODS.emailPassword,
87
+ magicLink: raw?.magicLink ?? DEFAULT_AUTH_METHODS.magicLink,
88
+ emailOtp: raw?.emailOtp ?? DEFAULT_AUTH_METHODS.emailOtp,
89
+ sso: raw?.sso ?? DEFAULT_AUTH_METHODS.sso,
90
+ passkey: raw?.passkey ?? DEFAULT_AUTH_METHODS.passkey,
91
+ social: Array.isArray(raw?.social) ? known.filter((p) => raw.social.includes(p)) : DEFAULT_AUTH_METHODS.social
92
+ };
93
+ }
94
+ function optarePlugins() {
95
+ return [
96
+ organizationClient(),
97
+ twoFactorClient(),
98
+ emailOTPClient(),
99
+ magicLinkClient(),
100
+ multiSessionClient(),
101
+ jwtClient()
102
+ ];
103
+ }
104
+ async function createOptareClient(config) {
105
+ const bootstrap = await resolveOptareConfig(config);
106
+ const auth = createAuthClient({
107
+ baseURL: bootstrap.baseURL,
108
+ fetchOptions: {
109
+ ...config.fetch ? { customFetchImpl: config.fetch } : {},
110
+ headers: {
111
+ "x-optare-publishable-key": config.publishableKey,
112
+ ...config.headers
113
+ }
114
+ },
115
+ plugins: optarePlugins()
116
+ });
117
+ return { auth, config: bootstrap };
118
+ }
119
+ export {
120
+ DEFAULT_AUTH_METHODS,
121
+ DEFAULT_OPTARE_ORIGIN,
122
+ OptareConfigError,
123
+ createOptareClient,
124
+ resolveOptareConfig
125
+ };
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "@optare/client",
3
+ "version": "0.1.0",
4
+ "description": "Headless, framework-agnostic client SDK for Optare. Takes a pk_live_ key and resolves endpoint + branding.",
5
+ "author": "Optare Team <admin@optare.one>",
6
+ "license": "MIT",
7
+ "publishConfig": {
8
+ "access": "public"
9
+ },
10
+ "type": "module",
11
+ "files": [
12
+ "dist"
13
+ ],
14
+ "main": "./dist/index.cjs",
15
+ "module": "./dist/index.js",
16
+ "types": "./dist/index.d.ts",
17
+ "exports": {
18
+ ".": {
19
+ "types": "./dist/index.d.ts",
20
+ "import": "./dist/index.js",
21
+ "require": "./dist/index.cjs"
22
+ }
23
+ },
24
+ "dependencies": {
25
+ "better-auth": "^1.7.3"
26
+ },
27
+ "devDependencies": {
28
+ "tsup": "^8.0.0",
29
+ "typescript": "^5.4.0"
30
+ },
31
+ "scripts": {
32
+ "build": "tsup src/index.ts --format cjs,esm --dts --clean",
33
+ "dev": "tsup src/index.ts --format cjs,esm --dts --watch"
34
+ }
35
+ }