@optare/node 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,40 @@
1
+ # @optare/node
2
+
3
+ Server-side Optare SDK. Two independent pieces.
4
+
5
+ ## Offline JWT verification
6
+
7
+ Trust a bearer token from your front end without a network call or shared secret.
8
+
9
+ ```ts
10
+ import { createOptareJwtVerifier } from "@optare/node";
11
+
12
+ const verifier = createOptareJwtVerifier({
13
+ baseURL: "https://id.optare.one", // JWKS: ${baseURL}/.well-known/jwks.json
14
+ });
15
+
16
+ const claims = await verifier.verify(token); // throws OptareJwtError if invalid
17
+ const maybe = await verifier.tryVerify(token); // null instead of throwing
18
+ ```
19
+
20
+ One JWKS fetch, cached for an hour; every `verify()` after that is local
21
+ (signature + `iss` / `exp` / `aud`). Call `verifier.invalidate()` after key
22
+ rotation, or pass a pre-fetched `jwks` to go fully offline.
23
+
24
+ ## `sk_live_` management calls
25
+
26
+ ```ts
27
+ import { createOptareManagementClient } from "@optare/node";
28
+
29
+ const optare = createOptareManagementClient({
30
+ secretKey: process.env.OPTARE_SECRET_KEY!, // sk_live_… — never ship to a browser
31
+ baseURL: "https://id.optare.one",
32
+ });
33
+
34
+ await optare.organizations.list();
35
+ const org = await optare.organizations.create({ name: "Acme Inc" });
36
+ await optare.organizations.update(org.id, { consumerPlanTemplate: "professional" });
37
+ await optare.organizations.invite(org.id, { email: "user@acme.com", role: "admin" });
38
+ ```
39
+
40
+ Non-2xx responses throw `OptareApiError` with `.status` and the server's message.
package/dist/index.cjs ADDED
@@ -0,0 +1,200 @@
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_OPTARE_ORIGIN: () => DEFAULT_OPTARE_ORIGIN,
24
+ OptareApiError: () => OptareApiError,
25
+ OptareJwtError: () => OptareJwtError,
26
+ createOptareJwtVerifier: () => createOptareJwtVerifier,
27
+ createOptareManagementClient: () => createOptareManagementClient
28
+ });
29
+ module.exports = __toCommonJS(index_exports);
30
+ var import_jose = require("jose");
31
+ var DEFAULT_OPTARE_ORIGIN = "https://id.optare.one";
32
+ var OptareJwtError = class extends Error {
33
+ constructor(message, cause) {
34
+ super(message);
35
+ this.cause = cause;
36
+ this.name = "OptareJwtError";
37
+ }
38
+ cause;
39
+ };
40
+ function trimSlash(s) {
41
+ return s.replace(/\/+$/, "");
42
+ }
43
+ function createOptareJwtVerifier(config = {}) {
44
+ const origin = trimSlash(config.baseURL ?? DEFAULT_OPTARE_ORIGIN);
45
+ const jwksURL = config.jwksURL ?? `${origin}/.well-known/jwks.json`;
46
+ const issuer = config.issuer === null ? void 0 : config.issuer ?? config.baseURL ?? origin;
47
+ const ttl = config.cacheTtlMs ?? 60 * 6e4;
48
+ let keySet = config.jwks ? (0, import_jose.createLocalJWKSet)(config.jwks) : null;
49
+ let fetchedAt = config.jwks ? Date.now() : 0;
50
+ function keys() {
51
+ const stale = Date.now() - fetchedAt > ttl;
52
+ if (!keySet || stale && !config.jwks) {
53
+ keySet = (0, import_jose.createRemoteJWKSet)(new URL(jwksURL), {
54
+ ...config.fetch ? { [import_jose.customFetch]: config.fetch } : {}
55
+ });
56
+ fetchedAt = Date.now();
57
+ }
58
+ return keySet;
59
+ }
60
+ async function verify(token) {
61
+ if (!token || token.split(".").length !== 3) {
62
+ throw new OptareJwtError("Not a JWT");
63
+ }
64
+ try {
65
+ const { payload } = await (0, import_jose.jwtVerify)(token, keys(), {
66
+ ...issuer ? { issuer } : {},
67
+ ...config.audience ? { audience: config.audience } : {}
68
+ });
69
+ return payload;
70
+ } catch (cause) {
71
+ throw new OptareJwtError(
72
+ `Token verification failed: ${cause.message}`,
73
+ cause
74
+ );
75
+ }
76
+ }
77
+ return {
78
+ verify,
79
+ async tryVerify(token) {
80
+ try {
81
+ return await verify(token);
82
+ } catch {
83
+ return null;
84
+ }
85
+ },
86
+ invalidate() {
87
+ if (!config.jwks) {
88
+ keySet = null;
89
+ fetchedAt = 0;
90
+ }
91
+ }
92
+ };
93
+ }
94
+ var OptareApiError = class extends Error {
95
+ constructor(message, status, body) {
96
+ super(message);
97
+ this.status = status;
98
+ this.body = body;
99
+ this.name = "OptareApiError";
100
+ }
101
+ status;
102
+ body;
103
+ };
104
+ var SECRET_KEY_PREFIX = "sk_live_";
105
+ function createOptareManagementClient(config) {
106
+ if (!config.secretKey || !config.secretKey.startsWith(SECRET_KEY_PREFIX)) {
107
+ throw new OptareApiError(
108
+ `Invalid secret key \u2014 expected an "${SECRET_KEY_PREFIX}\u2026" string`,
109
+ 0,
110
+ null
111
+ );
112
+ }
113
+ const origin = trimSlash(config.baseURL ?? DEFAULT_OPTARE_ORIGIN);
114
+ const doFetch = config.fetch ?? globalThis.fetch;
115
+ async function call(method, path, body) {
116
+ let res;
117
+ try {
118
+ res = await doFetch(`${origin}${path}`, {
119
+ method,
120
+ headers: {
121
+ authorization: `Bearer ${config.secretKey}`,
122
+ "content-type": "application/json",
123
+ accept: "application/json"
124
+ },
125
+ ...body !== void 0 ? { body: JSON.stringify(body) } : {}
126
+ });
127
+ } catch (cause) {
128
+ throw new OptareApiError(
129
+ `Request to ${origin}${path} failed: ${cause.message}`,
130
+ 0,
131
+ null
132
+ );
133
+ }
134
+ const text = await res.text();
135
+ const parsed = text ? safeJson(text) : null;
136
+ if (!res.ok) {
137
+ const message = (parsed && typeof parsed === "object" && "error" in parsed ? String(parsed.error) : null) ?? `${res.status} ${res.statusText}`;
138
+ throw new OptareApiError(message, res.status, parsed);
139
+ }
140
+ return parsed;
141
+ }
142
+ return {
143
+ organizations: {
144
+ async list() {
145
+ const out = await call(
146
+ "GET",
147
+ "/api/v1/organizations"
148
+ );
149
+ return out.organizations;
150
+ },
151
+ async create(input) {
152
+ const out = await call(
153
+ "POST",
154
+ "/api/v1/organizations",
155
+ input
156
+ );
157
+ return out.organization;
158
+ },
159
+ async get(id) {
160
+ const out = await call(
161
+ "GET",
162
+ `/api/v1/organizations/${encodeURIComponent(id)}`
163
+ );
164
+ return out.organization;
165
+ },
166
+ async update(id, patch) {
167
+ const out = await call(
168
+ "PATCH",
169
+ `/api/v1/organizations/${encodeURIComponent(id)}`,
170
+ patch
171
+ );
172
+ return out.organization;
173
+ },
174
+ async delete(id) {
175
+ await call(
176
+ "DELETE",
177
+ `/api/v1/organizations/${encodeURIComponent(id)}`
178
+ );
179
+ },
180
+ async invite(id, input) {
181
+ return call("POST", `/api/v1/organizations/${encodeURIComponent(id)}/invite`, input);
182
+ }
183
+ }
184
+ };
185
+ }
186
+ function safeJson(text) {
187
+ try {
188
+ return JSON.parse(text);
189
+ } catch {
190
+ return text;
191
+ }
192
+ }
193
+ // Annotate the CommonJS export names for ESM import in node:
194
+ 0 && (module.exports = {
195
+ DEFAULT_OPTARE_ORIGIN,
196
+ OptareApiError,
197
+ OptareJwtError,
198
+ createOptareJwtVerifier,
199
+ createOptareManagementClient
200
+ });
@@ -0,0 +1,120 @@
1
+ import { JWTPayload } from 'jose';
2
+
3
+ /**
4
+ * `@optare/node` — E3.
5
+ *
6
+ * The server-side counterpart to `@optare/client`. Two independent pieces:
7
+ *
8
+ * 1. {@link createOptareJwtVerifier} — **offline** verification of
9
+ * Optare-issued JWTs against the published JWKS. One key-set fetch, cached;
10
+ * every `verify()` after that is local (signature + `iss`/`exp`/`aud`), no
11
+ * network, no shared secret. This is what an SDK-integrated backend uses to
12
+ * trust a bearer token from its front end.
13
+ *
14
+ * 2. {@link createOptareManagementClient} — thin, typed `fetch` wrappers over
15
+ * the `sk_live_`-authenticated `/api/v1/*` surface (the C19 "wedge":
16
+ * a developer manages *their customers'* organizations). `sk_live_` is a
17
+ * secret — server-side only.
18
+ */
19
+ declare const DEFAULT_OPTARE_ORIGIN = "https://id.optare.one";
20
+ interface JwtVerifierConfig {
21
+ /**
22
+ * Origin the JWKS is published on (`${baseURL}/.well-known/jwks.json`).
23
+ * Defaults to the hosted Optare API.
24
+ */
25
+ baseURL?: string;
26
+ /** Full JWKS URL — overrides `baseURL`. */
27
+ jwksURL?: string;
28
+ /**
29
+ * Expected `iss` claim. Defaults to `baseURL` (that is what the backend
30
+ * signs with). Pass `null` to skip the issuer check.
31
+ */
32
+ issuer?: string | null;
33
+ /** Expected `aud` claim, if your tokens carry one. */
34
+ audience?: string;
35
+ /** Pre-fetched JWKS (`{ keys: [...] }`) — fully offline, no fetch ever. */
36
+ jwks?: {
37
+ keys: Array<Record<string, unknown>>;
38
+ };
39
+ /** `fetch` implementation (Node < 18, tests). */
40
+ fetch?: typeof fetch;
41
+ /** How long to cache the remote key set, ms. Default 1 hour. */
42
+ cacheTtlMs?: number;
43
+ }
44
+ interface OptareJwtVerifier {
45
+ /** Verified claims, or throws `OptareJwtError` if the token is not valid. */
46
+ verify(token: string): Promise<JWTPayload>;
47
+ /** Like {@link verify} but returns `null` instead of throwing. */
48
+ tryVerify(token: string): Promise<JWTPayload | null>;
49
+ /** Drop the cached key set (call after key rotation). */
50
+ invalidate(): void;
51
+ }
52
+ declare class OptareJwtError extends Error {
53
+ readonly cause?: unknown | undefined;
54
+ constructor(message: string, cause?: unknown | undefined);
55
+ }
56
+ declare function createOptareJwtVerifier(config?: JwtVerifierConfig): OptareJwtVerifier;
57
+ interface ManagementClientConfig {
58
+ /** `sk_live_…` — secret. Server-side only. */
59
+ secretKey: string;
60
+ /** Optare API origin. Defaults to the hosted API. */
61
+ baseURL?: string;
62
+ /** `fetch` implementation. */
63
+ fetch?: typeof fetch;
64
+ }
65
+ declare class OptareApiError extends Error {
66
+ readonly status: number;
67
+ readonly body: unknown;
68
+ constructor(message: string, status: number, body: unknown);
69
+ }
70
+ interface ManagedOrganization {
71
+ id: string;
72
+ name: string;
73
+ slug: string;
74
+ type: string | null;
75
+ plan: string | null;
76
+ logoUrl: string | null;
77
+ parentTenantId: string | null;
78
+ metadata: unknown;
79
+ memberCount: number;
80
+ createdAt: string | null;
81
+ consumerPlanTemplate: string | null;
82
+ consumerEntitlements: Record<string, {
83
+ value: number | boolean | "unlimited";
84
+ source: string;
85
+ }>;
86
+ }
87
+ interface CreateOrganizationInput {
88
+ name: string;
89
+ slug?: string;
90
+ metadata?: Record<string, unknown>;
91
+ }
92
+ interface UpdateOrganizationInput {
93
+ name?: string;
94
+ logoUrl?: string;
95
+ plan?: string;
96
+ metadata?: Record<string, unknown>;
97
+ consumerPlanTemplate?: string | null;
98
+ }
99
+ interface InviteInput {
100
+ email: string;
101
+ role?: string;
102
+ }
103
+ interface OptareManagementClient {
104
+ organizations: {
105
+ list(): Promise<ManagedOrganization[]>;
106
+ create(input: CreateOrganizationInput): Promise<ManagedOrganization>;
107
+ get(id: string): Promise<ManagedOrganization>;
108
+ update(id: string, patch: UpdateOrganizationInput): Promise<ManagedOrganization>;
109
+ delete(id: string): Promise<void>;
110
+ invite(id: string, input: InviteInput): Promise<{
111
+ id: string;
112
+ email: string;
113
+ role: string;
114
+ expiresAt: string;
115
+ }>;
116
+ };
117
+ }
118
+ declare function createOptareManagementClient(config: ManagementClientConfig): OptareManagementClient;
119
+
120
+ export { type CreateOrganizationInput, DEFAULT_OPTARE_ORIGIN, type InviteInput, type JwtVerifierConfig, type ManagedOrganization, type ManagementClientConfig, OptareApiError, OptareJwtError, type OptareJwtVerifier, type OptareManagementClient, type UpdateOrganizationInput, createOptareJwtVerifier, createOptareManagementClient };
@@ -0,0 +1,120 @@
1
+ import { JWTPayload } from 'jose';
2
+
3
+ /**
4
+ * `@optare/node` — E3.
5
+ *
6
+ * The server-side counterpart to `@optare/client`. Two independent pieces:
7
+ *
8
+ * 1. {@link createOptareJwtVerifier} — **offline** verification of
9
+ * Optare-issued JWTs against the published JWKS. One key-set fetch, cached;
10
+ * every `verify()` after that is local (signature + `iss`/`exp`/`aud`), no
11
+ * network, no shared secret. This is what an SDK-integrated backend uses to
12
+ * trust a bearer token from its front end.
13
+ *
14
+ * 2. {@link createOptareManagementClient} — thin, typed `fetch` wrappers over
15
+ * the `sk_live_`-authenticated `/api/v1/*` surface (the C19 "wedge":
16
+ * a developer manages *their customers'* organizations). `sk_live_` is a
17
+ * secret — server-side only.
18
+ */
19
+ declare const DEFAULT_OPTARE_ORIGIN = "https://id.optare.one";
20
+ interface JwtVerifierConfig {
21
+ /**
22
+ * Origin the JWKS is published on (`${baseURL}/.well-known/jwks.json`).
23
+ * Defaults to the hosted Optare API.
24
+ */
25
+ baseURL?: string;
26
+ /** Full JWKS URL — overrides `baseURL`. */
27
+ jwksURL?: string;
28
+ /**
29
+ * Expected `iss` claim. Defaults to `baseURL` (that is what the backend
30
+ * signs with). Pass `null` to skip the issuer check.
31
+ */
32
+ issuer?: string | null;
33
+ /** Expected `aud` claim, if your tokens carry one. */
34
+ audience?: string;
35
+ /** Pre-fetched JWKS (`{ keys: [...] }`) — fully offline, no fetch ever. */
36
+ jwks?: {
37
+ keys: Array<Record<string, unknown>>;
38
+ };
39
+ /** `fetch` implementation (Node < 18, tests). */
40
+ fetch?: typeof fetch;
41
+ /** How long to cache the remote key set, ms. Default 1 hour. */
42
+ cacheTtlMs?: number;
43
+ }
44
+ interface OptareJwtVerifier {
45
+ /** Verified claims, or throws `OptareJwtError` if the token is not valid. */
46
+ verify(token: string): Promise<JWTPayload>;
47
+ /** Like {@link verify} but returns `null` instead of throwing. */
48
+ tryVerify(token: string): Promise<JWTPayload | null>;
49
+ /** Drop the cached key set (call after key rotation). */
50
+ invalidate(): void;
51
+ }
52
+ declare class OptareJwtError extends Error {
53
+ readonly cause?: unknown | undefined;
54
+ constructor(message: string, cause?: unknown | undefined);
55
+ }
56
+ declare function createOptareJwtVerifier(config?: JwtVerifierConfig): OptareJwtVerifier;
57
+ interface ManagementClientConfig {
58
+ /** `sk_live_…` — secret. Server-side only. */
59
+ secretKey: string;
60
+ /** Optare API origin. Defaults to the hosted API. */
61
+ baseURL?: string;
62
+ /** `fetch` implementation. */
63
+ fetch?: typeof fetch;
64
+ }
65
+ declare class OptareApiError extends Error {
66
+ readonly status: number;
67
+ readonly body: unknown;
68
+ constructor(message: string, status: number, body: unknown);
69
+ }
70
+ interface ManagedOrganization {
71
+ id: string;
72
+ name: string;
73
+ slug: string;
74
+ type: string | null;
75
+ plan: string | null;
76
+ logoUrl: string | null;
77
+ parentTenantId: string | null;
78
+ metadata: unknown;
79
+ memberCount: number;
80
+ createdAt: string | null;
81
+ consumerPlanTemplate: string | null;
82
+ consumerEntitlements: Record<string, {
83
+ value: number | boolean | "unlimited";
84
+ source: string;
85
+ }>;
86
+ }
87
+ interface CreateOrganizationInput {
88
+ name: string;
89
+ slug?: string;
90
+ metadata?: Record<string, unknown>;
91
+ }
92
+ interface UpdateOrganizationInput {
93
+ name?: string;
94
+ logoUrl?: string;
95
+ plan?: string;
96
+ metadata?: Record<string, unknown>;
97
+ consumerPlanTemplate?: string | null;
98
+ }
99
+ interface InviteInput {
100
+ email: string;
101
+ role?: string;
102
+ }
103
+ interface OptareManagementClient {
104
+ organizations: {
105
+ list(): Promise<ManagedOrganization[]>;
106
+ create(input: CreateOrganizationInput): Promise<ManagedOrganization>;
107
+ get(id: string): Promise<ManagedOrganization>;
108
+ update(id: string, patch: UpdateOrganizationInput): Promise<ManagedOrganization>;
109
+ delete(id: string): Promise<void>;
110
+ invite(id: string, input: InviteInput): Promise<{
111
+ id: string;
112
+ email: string;
113
+ role: string;
114
+ expiresAt: string;
115
+ }>;
116
+ };
117
+ }
118
+ declare function createOptareManagementClient(config: ManagementClientConfig): OptareManagementClient;
119
+
120
+ export { type CreateOrganizationInput, DEFAULT_OPTARE_ORIGIN, type InviteInput, type JwtVerifierConfig, type ManagedOrganization, type ManagementClientConfig, OptareApiError, OptareJwtError, type OptareJwtVerifier, type OptareManagementClient, type UpdateOrganizationInput, createOptareJwtVerifier, createOptareManagementClient };
package/dist/index.js ADDED
@@ -0,0 +1,176 @@
1
+ // src/index.ts
2
+ import {
3
+ createLocalJWKSet,
4
+ createRemoteJWKSet,
5
+ customFetch,
6
+ jwtVerify
7
+ } from "jose";
8
+ var DEFAULT_OPTARE_ORIGIN = "https://id.optare.one";
9
+ var OptareJwtError = class extends Error {
10
+ constructor(message, cause) {
11
+ super(message);
12
+ this.cause = cause;
13
+ this.name = "OptareJwtError";
14
+ }
15
+ cause;
16
+ };
17
+ function trimSlash(s) {
18
+ return s.replace(/\/+$/, "");
19
+ }
20
+ function createOptareJwtVerifier(config = {}) {
21
+ const origin = trimSlash(config.baseURL ?? DEFAULT_OPTARE_ORIGIN);
22
+ const jwksURL = config.jwksURL ?? `${origin}/.well-known/jwks.json`;
23
+ const issuer = config.issuer === null ? void 0 : config.issuer ?? config.baseURL ?? origin;
24
+ const ttl = config.cacheTtlMs ?? 60 * 6e4;
25
+ let keySet = config.jwks ? createLocalJWKSet(config.jwks) : null;
26
+ let fetchedAt = config.jwks ? Date.now() : 0;
27
+ function keys() {
28
+ const stale = Date.now() - fetchedAt > ttl;
29
+ if (!keySet || stale && !config.jwks) {
30
+ keySet = createRemoteJWKSet(new URL(jwksURL), {
31
+ ...config.fetch ? { [customFetch]: config.fetch } : {}
32
+ });
33
+ fetchedAt = Date.now();
34
+ }
35
+ return keySet;
36
+ }
37
+ async function verify(token) {
38
+ if (!token || token.split(".").length !== 3) {
39
+ throw new OptareJwtError("Not a JWT");
40
+ }
41
+ try {
42
+ const { payload } = await jwtVerify(token, keys(), {
43
+ ...issuer ? { issuer } : {},
44
+ ...config.audience ? { audience: config.audience } : {}
45
+ });
46
+ return payload;
47
+ } catch (cause) {
48
+ throw new OptareJwtError(
49
+ `Token verification failed: ${cause.message}`,
50
+ cause
51
+ );
52
+ }
53
+ }
54
+ return {
55
+ verify,
56
+ async tryVerify(token) {
57
+ try {
58
+ return await verify(token);
59
+ } catch {
60
+ return null;
61
+ }
62
+ },
63
+ invalidate() {
64
+ if (!config.jwks) {
65
+ keySet = null;
66
+ fetchedAt = 0;
67
+ }
68
+ }
69
+ };
70
+ }
71
+ var OptareApiError = class extends Error {
72
+ constructor(message, status, body) {
73
+ super(message);
74
+ this.status = status;
75
+ this.body = body;
76
+ this.name = "OptareApiError";
77
+ }
78
+ status;
79
+ body;
80
+ };
81
+ var SECRET_KEY_PREFIX = "sk_live_";
82
+ function createOptareManagementClient(config) {
83
+ if (!config.secretKey || !config.secretKey.startsWith(SECRET_KEY_PREFIX)) {
84
+ throw new OptareApiError(
85
+ `Invalid secret key \u2014 expected an "${SECRET_KEY_PREFIX}\u2026" string`,
86
+ 0,
87
+ null
88
+ );
89
+ }
90
+ const origin = trimSlash(config.baseURL ?? DEFAULT_OPTARE_ORIGIN);
91
+ const doFetch = config.fetch ?? globalThis.fetch;
92
+ async function call(method, path, body) {
93
+ let res;
94
+ try {
95
+ res = await doFetch(`${origin}${path}`, {
96
+ method,
97
+ headers: {
98
+ authorization: `Bearer ${config.secretKey}`,
99
+ "content-type": "application/json",
100
+ accept: "application/json"
101
+ },
102
+ ...body !== void 0 ? { body: JSON.stringify(body) } : {}
103
+ });
104
+ } catch (cause) {
105
+ throw new OptareApiError(
106
+ `Request to ${origin}${path} failed: ${cause.message}`,
107
+ 0,
108
+ null
109
+ );
110
+ }
111
+ const text = await res.text();
112
+ const parsed = text ? safeJson(text) : null;
113
+ if (!res.ok) {
114
+ const message = (parsed && typeof parsed === "object" && "error" in parsed ? String(parsed.error) : null) ?? `${res.status} ${res.statusText}`;
115
+ throw new OptareApiError(message, res.status, parsed);
116
+ }
117
+ return parsed;
118
+ }
119
+ return {
120
+ organizations: {
121
+ async list() {
122
+ const out = await call(
123
+ "GET",
124
+ "/api/v1/organizations"
125
+ );
126
+ return out.organizations;
127
+ },
128
+ async create(input) {
129
+ const out = await call(
130
+ "POST",
131
+ "/api/v1/organizations",
132
+ input
133
+ );
134
+ return out.organization;
135
+ },
136
+ async get(id) {
137
+ const out = await call(
138
+ "GET",
139
+ `/api/v1/organizations/${encodeURIComponent(id)}`
140
+ );
141
+ return out.organization;
142
+ },
143
+ async update(id, patch) {
144
+ const out = await call(
145
+ "PATCH",
146
+ `/api/v1/organizations/${encodeURIComponent(id)}`,
147
+ patch
148
+ );
149
+ return out.organization;
150
+ },
151
+ async delete(id) {
152
+ await call(
153
+ "DELETE",
154
+ `/api/v1/organizations/${encodeURIComponent(id)}`
155
+ );
156
+ },
157
+ async invite(id, input) {
158
+ return call("POST", `/api/v1/organizations/${encodeURIComponent(id)}/invite`, input);
159
+ }
160
+ }
161
+ };
162
+ }
163
+ function safeJson(text) {
164
+ try {
165
+ return JSON.parse(text);
166
+ } catch {
167
+ return text;
168
+ }
169
+ }
170
+ export {
171
+ DEFAULT_OPTARE_ORIGIN,
172
+ OptareApiError,
173
+ OptareJwtError,
174
+ createOptareJwtVerifier,
175
+ createOptareManagementClient
176
+ };
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "@optare/node",
3
+ "version": "0.1.0",
4
+ "description": "Server-side Optare SDK: sk_live_ management calls and offline JWT verification.",
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
+ "jose": "^6.1.1"
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
+ }