@mymehq/sdk 4.0.0 → 4.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,129 @@
1
+ /**
2
+ * Token storage interface and default implementations.
3
+ *
4
+ * Browser default: localStorage keyed by `(origin, client_id)`.
5
+ * Node default: in-memory; Node consumers can pass a file-backed
6
+ * implementation if they need cross-process persistence.
7
+ */
8
+ interface TokenStorage {
9
+ get(key: string): Promise<string | null>;
10
+ set(key: string, value: string): Promise<void>;
11
+ delete(key: string): Promise<void>;
12
+ }
13
+ declare class InMemoryTokenStorage implements TokenStorage {
14
+ private map;
15
+ get(key: string): Promise<string | null>;
16
+ set(key: string, value: string): Promise<void>;
17
+ delete(key: string): Promise<void>;
18
+ }
19
+ declare class LocalStorageTokenStorage implements TokenStorage {
20
+ get(key: string): Promise<string | null>;
21
+ set(key: string, value: string): Promise<void>;
22
+ delete(key: string): Promise<void>;
23
+ }
24
+ /** Pick the most appropriate default storage for the current runtime. */
25
+ declare function defaultTokenStorage(): TokenStorage;
26
+
27
+ /** TokenProvider gives MymeClient an access token for every request. */
28
+ interface TokenProvider {
29
+ /** Returns a non-expired access token. Refreshes proactively if < 60s
30
+ * remain on the current one. Single-flight: concurrent callers await
31
+ * the same in-flight refresh promise. */
32
+ getAccessToken(): Promise<string>;
33
+ /** Subscribe to sign-out events (fired on invalid_grant /
34
+ * token_reuse_detected). Returns an unsubscribe fn. */
35
+ onSignOut(handler: () => void): () => void;
36
+ /** Force a sign-out — clears local storage, fires onSignOut handlers. */
37
+ signOut(): Promise<void>;
38
+ }
39
+
40
+ /**
41
+ * MymeAuth — owns the OAuth dance for browser apps signing into Myme.
42
+ *
43
+ * Flow:
44
+ * const auth = new MymeAuth({ issuer, clientId, redirectUri, scopes });
45
+ * // On a "Sign in" click:
46
+ * window.location.href = await auth.buildAuthorizeUrl();
47
+ * // On the callback page:
48
+ * const provider = await auth.handleCallback(window.location.href);
49
+ * const client = new MymeClient({ url: issuer, tokenProvider: provider });
50
+ *
51
+ * Restoration on page load: `await auth.restore()` returns a TokenProvider
52
+ * if a session is in storage, null otherwise.
53
+ *
54
+ * Sign-out: `await auth.signOut(provider)` revokes locally and clears
55
+ * persisted tokens; visible "session expired" UX is the caller's
56
+ * responsibility (subscribe via provider.onSignOut).
57
+ */
58
+ interface MymeAuthConfig {
59
+ /** Myme server URL — protocol + host (and port). */
60
+ issuer: string;
61
+ /** OAuth client id, registered via POST /auth/clients. */
62
+ clientId: string;
63
+ /** Exact-match redirect URI. Must be registered for this client. */
64
+ redirectUri: string;
65
+ /** Scopes to request (e.g. ["core.note:read", "core.note:write"]). */
66
+ scopes: string[];
67
+ /** Token storage. Defaults to localStorage in browser, in-memory in Node. */
68
+ storage?: TokenStorage;
69
+ /** Override for the global fetch (testing). */
70
+ fetch?: typeof globalThis.fetch;
71
+ }
72
+ declare class MymeAuth {
73
+ private readonly issuer;
74
+ private readonly clientId;
75
+ private readonly redirectUri;
76
+ private readonly scopes;
77
+ private readonly storage;
78
+ private readonly fetch;
79
+ private readonly pendingKey;
80
+ private readonly tokensKey;
81
+ constructor(config: MymeAuthConfig);
82
+ /** Build the authorize URL and persist the PKCE verifier + state. */
83
+ buildAuthorizeUrl(opts?: {
84
+ state?: string;
85
+ }): Promise<string>;
86
+ /**
87
+ * Exchange the authorization code for tokens. Call from your `/callback`
88
+ * route handler with `window.location.href` (or the equivalent server-
89
+ * side request URL). Throws OAuthError on failure.
90
+ */
91
+ handleCallback(callbackUrl: string): Promise<TokenProvider>;
92
+ /** Restore a TokenProvider from persisted storage; null if no session. */
93
+ restore(): Promise<TokenProvider | null>;
94
+ /** Sign out — clears persisted tokens. */
95
+ signOut(provider: TokenProvider): Promise<void>;
96
+ }
97
+
98
+ /**
99
+ * Typed OAuth error surface. Mirrors the wire `error` codes from
100
+ * RFC 6749 §5.2 and the rotation-replay extension.
101
+ */
102
+ type OAuthErrorCode = "invalid_request" | "invalid_client" | "invalid_grant" | "invalid_scope" | "invalid_token" | "unauthorized_client" | "unsupported_grant_type" | "unsupported_response_type" | "access_denied" | "insufficient_scope" | "token_reuse_detected" | "server_error" | "temporarily_unavailable";
103
+ declare class OAuthError extends Error {
104
+ readonly code: OAuthErrorCode;
105
+ readonly status: number;
106
+ constructor(code: OAuthErrorCode, message: string, status?: number);
107
+ }
108
+
109
+ /**
110
+ * PKCE primitives — RFC 7636. Verifier is 43–128 chars of base64url
111
+ * generated from random bytes; challenge is BASE64URL(SHA-256(verifier)).
112
+ *
113
+ * Uses Web Crypto so the auth subpath is universal (browser + Node 15+
114
+ * + Cloudflare Workers + Deno). The SDK's data-plane root path keeps
115
+ * its node:crypto dependency for HMAC webhook verification; nothing
116
+ * Node-only leaks into ./auth.
117
+ */
118
+ /**
119
+ * Generate a fresh PKCE code verifier. Default length 64 — within RFC's
120
+ * 43–128 range; longer is harder to brute force, shorter speeds up dev
121
+ * tooling. 64 is a balanced default.
122
+ */
123
+ declare function generateCodeVerifier(length?: number): string;
124
+ /** Compute the S256 challenge: BASE64URL(SHA-256(verifier)). */
125
+ declare function computeCodeChallenge(verifier: string): Promise<string>;
126
+ /** Generate a random opaque state value for CSRF protection on the redirect. */
127
+ declare function generateState(byteLength?: number): string;
128
+
129
+ export { InMemoryTokenStorage, LocalStorageTokenStorage, MymeAuth, type MymeAuthConfig, OAuthError, type OAuthErrorCode, type TokenProvider, type TokenStorage, computeCodeChallenge, defaultTokenStorage, generateCodeVerifier, generateState };
@@ -0,0 +1,331 @@
1
+ // src/auth/storage.ts
2
+ var InMemoryTokenStorage = class {
3
+ map = /* @__PURE__ */ new Map();
4
+ // eslint-disable-next-line @typescript-eslint/require-await
5
+ async get(key) {
6
+ return this.map.get(key) ?? null;
7
+ }
8
+ // eslint-disable-next-line @typescript-eslint/require-await
9
+ async set(key, value) {
10
+ this.map.set(key, value);
11
+ }
12
+ // eslint-disable-next-line @typescript-eslint/require-await
13
+ async delete(key) {
14
+ this.map.delete(key);
15
+ }
16
+ };
17
+ var LocalStorageTokenStorage = class {
18
+ // eslint-disable-next-line @typescript-eslint/require-await
19
+ async get(key) {
20
+ return globalThis.localStorage.getItem(key);
21
+ }
22
+ // eslint-disable-next-line @typescript-eslint/require-await
23
+ async set(key, value) {
24
+ globalThis.localStorage.setItem(key, value);
25
+ }
26
+ // eslint-disable-next-line @typescript-eslint/require-await
27
+ async delete(key) {
28
+ globalThis.localStorage.removeItem(key);
29
+ }
30
+ };
31
+ function defaultTokenStorage() {
32
+ if (typeof globalThis.localStorage !== "undefined") {
33
+ return new LocalStorageTokenStorage();
34
+ }
35
+ return new InMemoryTokenStorage();
36
+ }
37
+
38
+ // src/auth/pkce.ts
39
+ var ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~";
40
+ function base64url(bytes) {
41
+ let s = "";
42
+ for (const b of bytes) s += String.fromCharCode(b);
43
+ return btoa(s).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
44
+ }
45
+ function generateCodeVerifier(length = 64) {
46
+ if (length < 43 || length > 128) {
47
+ throw new Error(
48
+ `PKCE verifier length must be 43-128, got ${String(length)}`
49
+ );
50
+ }
51
+ const bytes = new Uint8Array(length);
52
+ crypto.getRandomValues(bytes);
53
+ let out = "";
54
+ for (const byte of bytes) {
55
+ out += ALPHABET.charAt(byte % ALPHABET.length);
56
+ }
57
+ return out;
58
+ }
59
+ async function computeCodeChallenge(verifier) {
60
+ const data = new TextEncoder().encode(verifier);
61
+ const hash = await crypto.subtle.digest("SHA-256", data);
62
+ return base64url(new Uint8Array(hash));
63
+ }
64
+ function generateState(byteLength = 16) {
65
+ const bytes = new Uint8Array(byteLength);
66
+ crypto.getRandomValues(bytes);
67
+ return base64url(bytes);
68
+ }
69
+
70
+ // src/auth/errors.ts
71
+ var OAuthError = class extends Error {
72
+ code;
73
+ status;
74
+ constructor(code, message, status = 400) {
75
+ super(message);
76
+ this.name = "OAuthError";
77
+ this.code = code;
78
+ this.status = status;
79
+ }
80
+ };
81
+
82
+ // src/auth/token-provider.ts
83
+ var PROACTIVE_WINDOW_MS = 6e4;
84
+ var StoredTokenProvider = class {
85
+ issuer;
86
+ clientId;
87
+ storage;
88
+ storageKey;
89
+ fetch;
90
+ cache = null;
91
+ inflightRefresh = null;
92
+ signOutHandlers = /* @__PURE__ */ new Set();
93
+ constructor(config) {
94
+ this.issuer = config.issuer.replace(/\/+$/, "");
95
+ this.clientId = config.clientId;
96
+ this.storage = config.storage;
97
+ this.storageKey = config.storageKey;
98
+ this.fetch = config.fetch ?? globalThis.fetch.bind(globalThis);
99
+ }
100
+ async hydrateFromStorage() {
101
+ const raw = await this.storage.get(this.storageKey);
102
+ if (!raw) return false;
103
+ try {
104
+ this.cache = JSON.parse(raw);
105
+ return true;
106
+ } catch {
107
+ await this.storage.delete(this.storageKey);
108
+ return false;
109
+ }
110
+ }
111
+ async persist(tokens) {
112
+ this.cache = tokens;
113
+ await this.storage.set(this.storageKey, JSON.stringify(tokens));
114
+ }
115
+ async getAccessToken() {
116
+ if (!this.cache) {
117
+ const ok = await this.hydrateFromStorage();
118
+ if (!ok) {
119
+ throw new OAuthError("invalid_grant", "No active session", 401);
120
+ }
121
+ }
122
+ if (!this.cache) {
123
+ throw new OAuthError("invalid_grant", "No active session", 401);
124
+ }
125
+ const remaining = this.cache.access_expires_at - Date.now();
126
+ if (remaining > PROACTIVE_WINDOW_MS) {
127
+ return this.cache.access_token;
128
+ }
129
+ return this.refresh();
130
+ }
131
+ /** Single-flight refresh — concurrent callers await the same promise. */
132
+ async refresh() {
133
+ if (this.inflightRefresh) return this.inflightRefresh;
134
+ if (!this.cache) {
135
+ throw new OAuthError("invalid_grant", "No refresh token available", 401);
136
+ }
137
+ const refreshToken = this.cache.refresh_token;
138
+ const previousScope = this.cache.scope;
139
+ this.inflightRefresh = (async () => {
140
+ try {
141
+ const res = await this.fetch(`${this.issuer}/auth/token`, {
142
+ method: "POST",
143
+ headers: { "Content-Type": "application/json" },
144
+ body: JSON.stringify({
145
+ grant_type: "refresh_token",
146
+ refresh_token: refreshToken,
147
+ client_id: this.clientId
148
+ })
149
+ });
150
+ const body = await res.json();
151
+ if (!res.ok || !body.access_token) {
152
+ await this.signOut();
153
+ throw new OAuthError(
154
+ body.error ?? "invalid_grant",
155
+ body.error ?? "Refresh failed",
156
+ res.status
157
+ );
158
+ }
159
+ const expiresInMs = (body.expires_in ?? 3600) * 1e3;
160
+ const updated = {
161
+ access_token: body.access_token,
162
+ refresh_token: body.refresh_token ?? refreshToken,
163
+ access_expires_at: Date.now() + expiresInMs,
164
+ scope: body.scope ?? previousScope
165
+ };
166
+ await this.persist(updated);
167
+ return updated.access_token;
168
+ } finally {
169
+ this.inflightRefresh = null;
170
+ }
171
+ })();
172
+ return this.inflightRefresh;
173
+ }
174
+ onSignOut(handler) {
175
+ this.signOutHandlers.add(handler);
176
+ return () => this.signOutHandlers.delete(handler);
177
+ }
178
+ async signOut() {
179
+ this.cache = null;
180
+ await this.storage.delete(this.storageKey);
181
+ for (const h of this.signOutHandlers) {
182
+ try {
183
+ h();
184
+ } catch {
185
+ }
186
+ }
187
+ }
188
+ };
189
+
190
+ // src/auth/auth.ts
191
+ var MymeAuth = class {
192
+ issuer;
193
+ clientId;
194
+ redirectUri;
195
+ scopes;
196
+ storage;
197
+ fetch;
198
+ pendingKey;
199
+ tokensKey;
200
+ constructor(config) {
201
+ this.issuer = config.issuer.replace(/\/+$/, "");
202
+ this.clientId = config.clientId;
203
+ this.redirectUri = config.redirectUri;
204
+ this.scopes = config.scopes;
205
+ this.storage = config.storage ?? defaultTokenStorage();
206
+ this.fetch = config.fetch ?? globalThis.fetch.bind(globalThis);
207
+ const origin = (() => {
208
+ try {
209
+ return new URL(this.issuer).origin;
210
+ } catch {
211
+ return this.issuer;
212
+ }
213
+ })();
214
+ this.pendingKey = `myme.auth.pending:${origin}:${config.clientId}`;
215
+ this.tokensKey = `myme.auth.tokens:${origin}:${config.clientId}`;
216
+ }
217
+ /** Build the authorize URL and persist the PKCE verifier + state. */
218
+ async buildAuthorizeUrl(opts) {
219
+ const verifier = generateCodeVerifier();
220
+ const challenge = await computeCodeChallenge(verifier);
221
+ const state = opts?.state ?? generateState();
222
+ const pending = {
223
+ verifier,
224
+ state,
225
+ redirectUri: this.redirectUri
226
+ };
227
+ await this.storage.set(this.pendingKey, JSON.stringify(pending));
228
+ const url = new URL(`${this.issuer}/auth/authorize`);
229
+ url.searchParams.set("response_type", "code");
230
+ url.searchParams.set("client_id", this.clientId);
231
+ url.searchParams.set("redirect_uri", this.redirectUri);
232
+ url.searchParams.set("scope", this.scopes.join(" "));
233
+ url.searchParams.set("code_challenge", challenge);
234
+ url.searchParams.set("code_challenge_method", "S256");
235
+ url.searchParams.set("state", state);
236
+ return url.toString();
237
+ }
238
+ /**
239
+ * Exchange the authorization code for tokens. Call from your `/callback`
240
+ * route handler with `window.location.href` (or the equivalent server-
241
+ * side request URL). Throws OAuthError on failure.
242
+ */
243
+ async handleCallback(callbackUrl) {
244
+ const url = new URL(callbackUrl);
245
+ const error = url.searchParams.get("error");
246
+ if (error) {
247
+ throw new OAuthError(
248
+ error === "access_denied" ? "access_denied" : "invalid_request",
249
+ url.searchParams.get("error_description") ?? error
250
+ );
251
+ }
252
+ const code = url.searchParams.get("code");
253
+ const incomingState = url.searchParams.get("state");
254
+ if (!code) {
255
+ throw new OAuthError("invalid_request", "Missing authorization code");
256
+ }
257
+ const pendingRaw = await this.storage.get(this.pendingKey);
258
+ if (!pendingRaw) {
259
+ throw new OAuthError(
260
+ "invalid_request",
261
+ "No pending PKCE verifier \u2014 did you call buildAuthorizeUrl in a different browser context?"
262
+ );
263
+ }
264
+ const pending = JSON.parse(pendingRaw);
265
+ if (pending.state !== incomingState) {
266
+ throw new OAuthError("invalid_request", "State mismatch on callback");
267
+ }
268
+ const res = await this.fetch(`${this.issuer}/auth/token`, {
269
+ method: "POST",
270
+ headers: { "Content-Type": "application/json" },
271
+ body: JSON.stringify({
272
+ grant_type: "authorization_code",
273
+ code,
274
+ code_verifier: pending.verifier,
275
+ redirect_uri: pending.redirectUri,
276
+ client_id: this.clientId
277
+ })
278
+ });
279
+ const body = await res.json();
280
+ if (!res.ok || !body.access_token || !body.refresh_token) {
281
+ const errCode = body.error ? body.error : "invalid_grant";
282
+ throw new OAuthError(
283
+ errCode,
284
+ body.error_description ?? body.error ?? "Token exchange failed",
285
+ res.status
286
+ );
287
+ }
288
+ await this.storage.delete(this.pendingKey);
289
+ const provider = new StoredTokenProvider({
290
+ issuer: this.issuer,
291
+ clientId: this.clientId,
292
+ storage: this.storage,
293
+ storageKey: this.tokensKey,
294
+ fetch: this.fetch
295
+ });
296
+ await provider.persist({
297
+ access_token: body.access_token,
298
+ refresh_token: body.refresh_token,
299
+ access_expires_at: Date.now() + (body.expires_in ?? 3600) * 1e3,
300
+ scope: body.scope ?? this.scopes.join(" ")
301
+ });
302
+ return provider;
303
+ }
304
+ /** Restore a TokenProvider from persisted storage; null if no session. */
305
+ async restore() {
306
+ const provider = new StoredTokenProvider({
307
+ issuer: this.issuer,
308
+ clientId: this.clientId,
309
+ storage: this.storage,
310
+ storageKey: this.tokensKey,
311
+ fetch: this.fetch
312
+ });
313
+ const ok = await provider.hydrateFromStorage();
314
+ return ok ? provider : null;
315
+ }
316
+ /** Sign out — clears persisted tokens. */
317
+ async signOut(provider) {
318
+ await provider.signOut();
319
+ await this.storage.delete(this.pendingKey);
320
+ }
321
+ };
322
+ export {
323
+ InMemoryTokenStorage,
324
+ LocalStorageTokenStorage,
325
+ MymeAuth,
326
+ OAuthError,
327
+ computeCodeChallenge,
328
+ defaultTokenStorage,
329
+ generateCodeVerifier,
330
+ generateState
331
+ };
package/dist/index.d.ts CHANGED
@@ -47,9 +47,25 @@ interface ConflictAutoMergedEvent {
47
47
  /** Optional callback fired when the auto-merge path completes successfully. */
48
48
  type ConflictAutoMergeListener = (event: ConflictAutoMergedEvent) => void | Promise<void>;
49
49
 
50
- interface ClientConfig {
51
- url: string;
50
+ /** Minimal token provider shape — full interface lives in
51
+ * @mymehq/sdk/auth. Kept loose here so the data root doesn't depend
52
+ * on the auth subpath. */
53
+ interface TokenProviderLike {
54
+ getAccessToken(): Promise<string>;
55
+ }
56
+ /**
57
+ * Credentials are mutually exclusive at the type level: pass either a
58
+ * static API key (myme_k1_*) or an OAuth token provider (myme_at_*).
59
+ */
60
+ type ClientCredential = {
52
61
  apiKey: string;
62
+ tokenProvider?: never;
63
+ } | {
64
+ tokenProvider: TokenProviderLike;
65
+ apiKey?: never;
66
+ };
67
+ type ClientConfig = ClientCredential & {
68
+ url: string;
53
69
  fetch?: typeof globalThis.fetch;
54
70
  /**
55
71
  * Default conflict resolution strategy for all updates.
@@ -67,7 +83,7 @@ interface ClientConfig {
67
83
  onConflictAutoMerge?: ConflictAutoMergeListener;
68
84
  timeoutMs?: number;
69
85
  cdnBaseUrl?: string;
70
- }
86
+ };
71
87
  interface UpdateOptions {
72
88
  /**
73
89
  * Version the caller expects the item to currently be at. When provided,
@@ -510,9 +526,9 @@ declare class MymeClient {
510
526
  limit?: number;
511
527
  }) => Promise<WebhookDelivery[]>;
512
528
  };
513
- /** Tenant-scoped configuration (per-type ambient retention overrides
514
- * today; future tenant-level settings will live here). All endpoints
515
- * are admin-only. */
529
+ /** Tenant-scoped configuration. Controls feed-tier retention per type
530
+ * and the three optional schema-enforcement levers (TSC42 §5). All
531
+ * endpoints are admin-only. */
516
532
  readonly tenants: {
517
533
  /** Returns the current tenant's config. Empty object when nothing
518
534
  * is configured. */
package/dist/index.js CHANGED
@@ -55,14 +55,35 @@ var DEFAULT_TIMEOUT_MS = 3e4;
55
55
  var HttpTransport = class {
56
56
  baseUrl;
57
57
  apiKey;
58
+ tokenProvider;
58
59
  fetch;
59
60
  timeoutMs;
60
61
  constructor(config) {
61
62
  this.baseUrl = config.baseUrl.replace(/\/+$/, "");
62
63
  this.apiKey = config.apiKey;
64
+ this.tokenProvider = config.tokenProvider;
65
+ if (!this.apiKey && !this.tokenProvider) {
66
+ throw new Error(
67
+ "MymeClient requires either { apiKey } or { tokenProvider }"
68
+ );
69
+ }
63
70
  this.fetch = config.fetch ?? globalThis.fetch.bind(globalThis);
64
71
  this.timeoutMs = config.timeoutMs ?? DEFAULT_TIMEOUT_MS;
65
72
  }
73
+ /** Resolves the current Authorization header value. For tokenProvider
74
+ * callers this may trigger a proactive refresh under the hood. */
75
+ async getAuthHeader() {
76
+ if (this.apiKey) return `Bearer ${this.apiKey}`;
77
+ if (!this.tokenProvider) {
78
+ throw new MymeError(
79
+ "configuration_error",
80
+ "MymeClient has no apiKey or tokenProvider \u2014 this should be unreachable",
81
+ 0
82
+ );
83
+ }
84
+ const token = await this.tokenProvider.getAccessToken();
85
+ return `Bearer ${token}`;
86
+ }
66
87
  async request(method, path, options) {
67
88
  const response = await this.rawRequest(method, path, options);
68
89
  if (response.status === 204) {
@@ -93,7 +114,7 @@ var HttpTransport = class {
93
114
  async rawRequest(method, path, options) {
94
115
  const url = this.buildUrl(path, options?.query);
95
116
  const headers = {
96
- Authorization: `Bearer ${this.apiKey}`,
117
+ Authorization: await this.getAuthHeader(),
97
118
  ...options?.headers
98
119
  };
99
120
  const controller = new AbortController();
@@ -320,6 +341,7 @@ var MymeClient = class {
320
341
  this.transport = new HttpTransport({
321
342
  baseUrl: config.url,
322
343
  apiKey: config.apiKey,
344
+ tokenProvider: config.tokenProvider,
323
345
  fetch: config.fetch,
324
346
  timeoutMs: config.timeoutMs
325
347
  });
@@ -814,9 +836,9 @@ var MymeClient = class {
814
836
  }
815
837
  };
816
838
  // ---- Tenants (admin) ----
817
- /** Tenant-scoped configuration (per-type ambient retention overrides
818
- * today; future tenant-level settings will live here). All endpoints
819
- * are admin-only. */
839
+ /** Tenant-scoped configuration. Controls feed-tier retention per type
840
+ * and the three optional schema-enforcement levers (TSC42 §5). All
841
+ * endpoints are admin-only. */
820
842
  tenants = {
821
843
  /** Returns the current tenant's config. Empty object when nothing
822
844
  * is configured. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mymehq/sdk",
3
- "version": "4.0.0",
3
+ "version": "4.1.1",
4
4
  "type": "module",
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org",
@@ -10,13 +10,17 @@
10
10
  ".": {
11
11
  "types": "./dist/index.d.ts",
12
12
  "import": "./dist/index.js"
13
+ },
14
+ "./auth": {
15
+ "types": "./dist/auth/index.d.ts",
16
+ "import": "./dist/auth/index.js"
13
17
  }
14
18
  },
15
19
  "files": [
16
20
  "dist"
17
21
  ],
18
22
  "dependencies": {
19
- "@mymehq/shared": "4.0.0"
23
+ "@mymehq/shared": "4.1.1"
20
24
  },
21
25
  "devDependencies": {
22
26
  "@types/node": "^22.0.0",