@~lyre/auth 0.1.1 → 0.4.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/README.md CHANGED
@@ -5,7 +5,7 @@ and identity handling (HMAC-signed cookies, the accounts login → callback →
5
5
  logout exchange, tenant resolution), plus an optional turnkey **SvelteKit**
6
6
  adapter that wires it all up in a few lines.
7
7
 
8
- Ships as raw TypeScript source.
8
+ Ships built ESM output from `dist/`, with type declarations.
9
9
 
10
10
  ## Install
11
11
 
@@ -0,0 +1,206 @@
1
+ interface AccountsAdminOptions {
2
+ /** Accounts base URL, e.g. `https://accounts.example.com`. */
3
+ baseUrl: string;
4
+ /** A user session id (bearer) for session-authed endpoints (invites, profile update, user list). */
5
+ sessionToken?: string;
6
+ /** A machine service key (`sk_…`) for `x-api-key`-authed reads (group members). */
7
+ serviceKey?: string;
8
+ /** Override the fetch implementation (defaults to the global). */
9
+ fetchImpl?: typeof fetch;
10
+ }
11
+ interface AccountsUser {
12
+ id: string;
13
+ email: string;
14
+ name?: string | null;
15
+ firstName?: string | null;
16
+ lastName?: string | null;
17
+ emailVerified?: boolean;
18
+ /** The user's avatar URL (from their latest OAuth sign-in with a picture, or their upload). */
19
+ avatarUrl?: string | null;
20
+ profileData?: Record<string, string>;
21
+ userGroups?: Array<{
22
+ id: string;
23
+ slug?: string;
24
+ displayName?: string;
25
+ role?: string;
26
+ }>;
27
+ apps?: Array<{
28
+ id: string;
29
+ slug: string;
30
+ name?: string;
31
+ }>;
32
+ [key: string]: unknown;
33
+ }
34
+ interface ChangePasswordResult {
35
+ success: boolean;
36
+ mode?: 'set' | 'changed';
37
+ revokedCount?: number;
38
+ error?: string;
39
+ }
40
+ interface ListUsersQuery {
41
+ tenantId?: string;
42
+ appId?: string;
43
+ q?: string;
44
+ name?: string;
45
+ email?: string;
46
+ limit?: number;
47
+ offset?: number;
48
+ }
49
+ interface ListUsersResult {
50
+ users: AccountsUser[];
51
+ pagination?: {
52
+ total: number;
53
+ limit: number;
54
+ offset: number;
55
+ };
56
+ }
57
+ interface AppMember {
58
+ id: string;
59
+ email: string;
60
+ name?: string | null;
61
+ via?: 'member' | 'role';
62
+ }
63
+ interface InviteResult {
64
+ /** `invited` = an invite was created and an accept link emailed;
65
+ * `already_member` = that email already has access to the app (returned with HTTP 409).
66
+ * (`added` is legacy: Accounts no longer grants access without acceptance.) */
67
+ status: 'invited' | 'already_member' | 'added';
68
+ /** The workspace the invitee joins on acceptance, echoed back; null when none was requested. */
69
+ userGroupId?: string | null;
70
+ [key: string]: unknown;
71
+ }
72
+ /** A pending (not yet accepted, not yet expired) app invitation. */
73
+ interface PendingInvite {
74
+ id: string;
75
+ email: string;
76
+ /** The workspace the invitee joins on acceptance; null for a group-less invite. */
77
+ userGroupId: string | null;
78
+ createdAt: string;
79
+ expiresAt: string;
80
+ /** The inviter's email, when still resolvable. */
81
+ invitedByEmail?: string | null;
82
+ }
83
+ interface GroupMember {
84
+ id: string;
85
+ email: string;
86
+ name?: string | null;
87
+ firstName?: string | null;
88
+ lastName?: string | null;
89
+ role?: string | null;
90
+ }
91
+ /** Thrown on a non-2xx Accounts response so callers can surface the upstream message + status. */
92
+ declare class AccountsAdminError extends Error {
93
+ readonly status: number;
94
+ readonly body?: unknown | undefined;
95
+ constructor(status: number, message: string, body?: unknown | undefined);
96
+ }
97
+ declare class AccountsAdmin {
98
+ private readonly opts;
99
+ private readonly base;
100
+ private readonly f;
101
+ constructor(opts: AccountsAdminOptions);
102
+ /** List/search users in a tenant. Session-authed (caller must be privileged in the tenant). */
103
+ listUsers(query?: ListUsersQuery): Promise<ListUsersResult>;
104
+ /** One user's full detail (includes `profileData`, `userGroups`, `apps`). Session-authed. */
105
+ getUser(userId: string): Promise<AccountsUser>;
106
+ /** Update a user (self, or admin/owner/super-admin). `profileData` requires `appId`. Session-authed.
107
+ * Password is NOT set here — use {@link changePassword} (Accounts verifies the current password). */
108
+ updateUser(userId: string, input: {
109
+ name?: string;
110
+ email?: string;
111
+ appId?: string;
112
+ profileData?: Record<string, string>;
113
+ }): Promise<AccountsUser>;
114
+ /** Change the signed-in user's password. Session-authed; Accounts verifies `currentPassword` and,
115
+ * with `revokeOtherSessions`, logs the user out everywhere else. The target is the session's own
116
+ * user — no id is passed. */
117
+ changePassword(input: {
118
+ currentPassword: string;
119
+ newPassword: string;
120
+ confirmPassword?: string;
121
+ revokeOtherSessions?: boolean;
122
+ }): Promise<ChangePasswordResult>;
123
+ /**
124
+ * Invite an email to an app, emailing them an accept link. Session-authed (the caller must have
125
+ * access to the app).
126
+ *
127
+ * Pass `userGroupId` to say which WORKSPACE the invitee joins when they accept. Omit it and they
128
+ * join the app but no workspace — Accounts then treats them as a brand-new user on first login and
129
+ * sends them to create their own, instead of landing in the workspace that invited them. Accounts
130
+ * validates the group against the CALLER's own memberships, so this cannot target a foreign group.
131
+ */
132
+ inviteToApp(appSlug: string, input: {
133
+ email: string;
134
+ userGroupId?: string | null;
135
+ }): Promise<InviteResult>;
136
+ /** Revoke a pending invite (withdraw one sent in error). Session-authed. */
137
+ revokeAppInvite(appSlug: string, inviteId: string): Promise<void>;
138
+ /** Everyone with access to an app. Session-authed. */
139
+ listAppUsers(appSlug: string): Promise<AppMember[]>;
140
+ /** Revoke a user's access to an app. Session-authed. */
141
+ removeAppUser(appSlug: string, userId: string): Promise<void>;
142
+ /** Members of a user_group (the workspace's agents). Service-key authed (`stats:read`). */
143
+ listGroupMembers(groupId: string, opts?: {
144
+ appId?: string;
145
+ search?: string;
146
+ limit?: number;
147
+ offset?: number;
148
+ }): Promise<GroupMember[]>;
149
+ /**
150
+ * A PAGE of a group's members, plus the total before paging — what a paginated, searchable user
151
+ * list needs. `listGroupMembers` stays the "give me everyone" convenience for the agent picker.
152
+ *
153
+ * Search and paging are applied by Accounts in SQL: fetching every member to filter in the browser
154
+ * does not scale, and leaves the pager unable to know how many pages exist. Omit `limit` and the
155
+ * full list comes back (with `totalCount` equal to its length).
156
+ */
157
+ listGroupMembersPage(groupId: string, opts?: {
158
+ appId?: string;
159
+ search?: string;
160
+ limit?: number;
161
+ offset?: number;
162
+ }): Promise<{
163
+ members: GroupMember[];
164
+ totalCount: number;
165
+ }>;
166
+ /**
167
+ * The app's PENDING invites — people invited but not yet accepted. Session-authed.
168
+ *
169
+ * An invitee is not a membership, so they appear in no member list; without this a successful
170
+ * invite looks like nothing happened until the person accepts. Pass `userGroupId` to scope to one
171
+ * workspace. Accounts excludes consumed and expired invites.
172
+ */
173
+ listAppInvites(appSlug: string, opts?: {
174
+ userGroupId?: string;
175
+ search?: string;
176
+ limit?: number;
177
+ offset?: number;
178
+ }): Promise<{
179
+ invites: PendingInvite[];
180
+ totalCount: number;
181
+ }>;
182
+ /** Read a user's app-scoped `profileData` (the store for per-app preferences). Session-authed. */
183
+ getAppProfile(userId: string): Promise<Record<string, string>>;
184
+ /** Write app-scoped `profileData` fields for a user (e.g. availability, soundEnabled). All values
185
+ * are stored as strings by Accounts; booleans are serialised. Session-authed. */
186
+ setAppProfile(userId: string, appId: string, profile: Record<string, string | number | boolean>): Promise<AccountsUser>;
187
+ /** Upload a user's avatar image. The bytes are stored by Accounts and a public URL is returned +
188
+ * persisted (source = 'upload', which survives later OAuth sign-ins). Session-authed, self-only.
189
+ * `image` is the file bytes (Blob/Buffer/Uint8Array); `mimeType` + `filename` describe it. */
190
+ uploadAvatar(userId: string, image: Blob | ArrayBuffer | Uint8Array, opts?: {
191
+ mimeType?: string;
192
+ filename?: string;
193
+ }): Promise<{
194
+ avatarUrl: string;
195
+ }>;
196
+ /** Remove a user's uploaded avatar (clears it, or reverts to their latest OAuth picture if any).
197
+ * Session-authed, self-only. */
198
+ removeAvatar(userId: string): Promise<{
199
+ avatarUrl: string | null;
200
+ }>;
201
+ private request;
202
+ }
203
+ /** Convenience factory mirroring the SDK's other `create*` helpers. */
204
+ declare function createAccountsAdmin(opts: AccountsAdminOptions): AccountsAdmin;
205
+
206
+ export { AccountsAdmin, AccountsAdminError, type AccountsAdminOptions, type AccountsUser, type AppMember, type ChangePasswordResult, type GroupMember, type InviteResult, type ListUsersQuery, type ListUsersResult, type PendingInvite, createAccountsAdmin };
package/dist/admin.js ADDED
@@ -0,0 +1,248 @@
1
+ // src/admin.ts
2
+ var AccountsAdminError = class extends Error {
3
+ constructor(status, message, body) {
4
+ super(message);
5
+ this.status = status;
6
+ this.body = body;
7
+ this.name = "AccountsAdminError";
8
+ }
9
+ status;
10
+ body;
11
+ };
12
+ var AccountsAdmin = class {
13
+ constructor(opts) {
14
+ this.opts = opts;
15
+ const base = (opts.baseUrl ?? "").trim();
16
+ if (!base) throw new Error("AccountsAdmin: baseUrl is required.");
17
+ this.base = base.replace(/\/+$/, "");
18
+ this.f = opts.fetchImpl ?? fetch;
19
+ }
20
+ opts;
21
+ base;
22
+ f;
23
+ // ── Users ──────────────────────────────────────────────────────────────────
24
+ /** List/search users in a tenant. Session-authed (caller must be privileged in the tenant). */
25
+ async listUsers(query = {}) {
26
+ const qs = new URLSearchParams();
27
+ for (const [k, v] of Object.entries(query)) {
28
+ if (v !== void 0 && v !== null) qs.set(k, String(v));
29
+ }
30
+ const suffix = qs.toString() ? `?${qs.toString()}` : "";
31
+ const data = await this.request(
32
+ "GET",
33
+ `/api/auth/users${suffix}`,
34
+ { auth: "session" }
35
+ );
36
+ return { users: data.users ?? [], ...data.pagination ? { pagination: data.pagination } : {} };
37
+ }
38
+ /** One user's full detail (includes `profileData`, `userGroups`, `apps`). Session-authed. */
39
+ async getUser(userId) {
40
+ return this.request("GET", `/api/auth/users/${encodeURIComponent(userId)}`, {
41
+ auth: "session"
42
+ });
43
+ }
44
+ /** Update a user (self, or admin/owner/super-admin). `profileData` requires `appId`. Session-authed.
45
+ * Password is NOT set here — use {@link changePassword} (Accounts verifies the current password). */
46
+ async updateUser(userId, input) {
47
+ return this.request("PATCH", `/api/auth/users/${encodeURIComponent(userId)}`, {
48
+ auth: "session",
49
+ body: input
50
+ });
51
+ }
52
+ /** Change the signed-in user's password. Session-authed; Accounts verifies `currentPassword` and,
53
+ * with `revokeOtherSessions`, logs the user out everywhere else. The target is the session's own
54
+ * user — no id is passed. */
55
+ async changePassword(input) {
56
+ return this.request("POST", "/api/auth/change-password", {
57
+ auth: "session",
58
+ body: {
59
+ currentPassword: input.currentPassword,
60
+ newPassword: input.newPassword,
61
+ confirmPassword: input.confirmPassword ?? input.newPassword,
62
+ ...input.revokeOtherSessions !== void 0 ? { revokeOtherSessions: input.revokeOtherSessions } : {}
63
+ }
64
+ });
65
+ }
66
+ // ── App membership (invite / list / remove) ─────────────────────────────────
67
+ /**
68
+ * Invite an email to an app, emailing them an accept link. Session-authed (the caller must have
69
+ * access to the app).
70
+ *
71
+ * Pass `userGroupId` to say which WORKSPACE the invitee joins when they accept. Omit it and they
72
+ * join the app but no workspace — Accounts then treats them as a brand-new user on first login and
73
+ * sends them to create their own, instead of landing in the workspace that invited them. Accounts
74
+ * validates the group against the CALLER's own memberships, so this cannot target a foreign group.
75
+ */
76
+ async inviteToApp(appSlug, input) {
77
+ return this.request("POST", `/api/auth/apps/${encodeURIComponent(appSlug)}/invites`, {
78
+ auth: "session",
79
+ body: input
80
+ });
81
+ }
82
+ /** Revoke a pending invite (withdraw one sent in error). Session-authed. */
83
+ async revokeAppInvite(appSlug, inviteId) {
84
+ await this.request(
85
+ "DELETE",
86
+ `/api/auth/apps/${encodeURIComponent(appSlug)}/invites?inviteId=${encodeURIComponent(inviteId)}`,
87
+ { auth: "session" }
88
+ );
89
+ }
90
+ /** Everyone with access to an app. Session-authed. */
91
+ async listAppUsers(appSlug) {
92
+ const data = await this.request(
93
+ "GET",
94
+ `/api/auth/apps/${encodeURIComponent(appSlug)}/users`,
95
+ { auth: "session" }
96
+ );
97
+ return data.users ?? [];
98
+ }
99
+ /** Revoke a user's access to an app. Session-authed. */
100
+ async removeAppUser(appSlug, userId) {
101
+ await this.request(
102
+ "DELETE",
103
+ `/api/auth/apps/${encodeURIComponent(appSlug)}/users?userId=${encodeURIComponent(userId)}`,
104
+ { auth: "session" }
105
+ );
106
+ }
107
+ // ── Groups (agent picker) ───────────────────────────────────────────────────
108
+ /** Members of a user_group (the workspace's agents). Service-key authed (`stats:read`). */
109
+ async listGroupMembers(groupId, opts = {}) {
110
+ const { members } = await this.listGroupMembersPage(groupId, opts);
111
+ return members;
112
+ }
113
+ /**
114
+ * A PAGE of a group's members, plus the total before paging — what a paginated, searchable user
115
+ * list needs. `listGroupMembers` stays the "give me everyone" convenience for the agent picker.
116
+ *
117
+ * Search and paging are applied by Accounts in SQL: fetching every member to filter in the browser
118
+ * does not scale, and leaves the pager unable to know how many pages exist. Omit `limit` and the
119
+ * full list comes back (with `totalCount` equal to its length).
120
+ */
121
+ async listGroupMembersPage(groupId, opts = {}) {
122
+ const qs = new URLSearchParams();
123
+ if (opts.appId) qs.set("appId", opts.appId);
124
+ if (opts.search) qs.set("search", opts.search);
125
+ if (opts.limit !== void 0) qs.set("limit", String(opts.limit));
126
+ if (opts.offset !== void 0) qs.set("offset", String(opts.offset));
127
+ const suffix = qs.size ? `?${qs}` : "";
128
+ const data = await this.request(
129
+ "GET",
130
+ `/api/auth/user-groups/${encodeURIComponent(groupId)}/members${suffix}`,
131
+ { auth: "key" }
132
+ );
133
+ const members = data.members ?? [];
134
+ return { members, totalCount: data.totalCount ?? members.length };
135
+ }
136
+ /**
137
+ * The app's PENDING invites — people invited but not yet accepted. Session-authed.
138
+ *
139
+ * An invitee is not a membership, so they appear in no member list; without this a successful
140
+ * invite looks like nothing happened until the person accepts. Pass `userGroupId` to scope to one
141
+ * workspace. Accounts excludes consumed and expired invites.
142
+ */
143
+ async listAppInvites(appSlug, opts = {}) {
144
+ const qs = new URLSearchParams();
145
+ if (opts.userGroupId) qs.set("userGroupId", opts.userGroupId);
146
+ if (opts.search) qs.set("search", opts.search);
147
+ if (opts.limit !== void 0) qs.set("limit", String(opts.limit));
148
+ if (opts.offset !== void 0) qs.set("offset", String(opts.offset));
149
+ const suffix = qs.size ? `?${qs}` : "";
150
+ const data = await this.request(
151
+ "GET",
152
+ `/api/auth/apps/${encodeURIComponent(appSlug)}/invites${suffix}`,
153
+ { auth: "session" }
154
+ );
155
+ const invites = data.invites ?? [];
156
+ return { invites, totalCount: data.totalCount ?? invites.length };
157
+ }
158
+ // ── App-scoped profile (availability / sound / any per-app preference) ───────
159
+ /** Read a user's app-scoped `profileData` (the store for per-app preferences). Session-authed. */
160
+ async getAppProfile(userId) {
161
+ const user = await this.getUser(userId);
162
+ return user.profileData ?? {};
163
+ }
164
+ /** Write app-scoped `profileData` fields for a user (e.g. availability, soundEnabled). All values
165
+ * are stored as strings by Accounts; booleans are serialised. Session-authed. */
166
+ async setAppProfile(userId, appId, profile) {
167
+ const profileData = {};
168
+ for (const [k, v] of Object.entries(profile)) profileData[k] = String(v);
169
+ return this.updateUser(userId, { appId, profileData });
170
+ }
171
+ // ── Avatar (uploaded image; social avatars are captured server-side on sign-in) ─
172
+ /** Upload a user's avatar image. The bytes are stored by Accounts and a public URL is returned +
173
+ * persisted (source = 'upload', which survives later OAuth sign-ins). Session-authed, self-only.
174
+ * `image` is the file bytes (Blob/Buffer/Uint8Array); `mimeType` + `filename` describe it. */
175
+ async uploadAvatar(userId, image, opts = {}) {
176
+ if (!this.opts.sessionToken) {
177
+ throw new Error("AccountsAdmin: a session token is required to upload an avatar.");
178
+ }
179
+ const mimeType = opts.mimeType ?? "application/octet-stream";
180
+ const blob = image instanceof Blob ? image : new Blob([image], { type: mimeType });
181
+ const form = new FormData();
182
+ form.append("avatar", blob, opts.filename ?? "avatar");
183
+ const res = await this.f(
184
+ new URL(`/api/auth/users/${encodeURIComponent(userId)}/avatar`, this.base),
185
+ {
186
+ method: "POST",
187
+ headers: { authorization: `Bearer ${this.opts.sessionToken}`, accept: "application/json" },
188
+ body: form
189
+ }
190
+ );
191
+ const text = await res.text();
192
+ const parsed = text ? JSON.parse(text) : {};
193
+ if (!res.ok) {
194
+ throw new AccountsAdminError(res.status, parsed?.error ?? "Avatar upload failed.", parsed);
195
+ }
196
+ return parsed;
197
+ }
198
+ /** Remove a user's uploaded avatar (clears it, or reverts to their latest OAuth picture if any).
199
+ * Session-authed, self-only. */
200
+ async removeAvatar(userId) {
201
+ return this.request(
202
+ "DELETE",
203
+ `/api/auth/users/${encodeURIComponent(userId)}/avatar`,
204
+ { auth: "session" }
205
+ );
206
+ }
207
+ // ── internals ───────────────────────────────────────────────────────────────
208
+ async request(method, path, opts) {
209
+ const headers = { accept: "application/json" };
210
+ if (opts.auth === "session") {
211
+ if (!this.opts.sessionToken) {
212
+ throw new Error(`AccountsAdmin: a session token is required for ${method} ${path}.`);
213
+ }
214
+ headers.authorization = `Bearer ${this.opts.sessionToken}`;
215
+ } else {
216
+ if (!this.opts.serviceKey) {
217
+ throw new Error(`AccountsAdmin: a service key is required for ${method} ${path}.`);
218
+ }
219
+ headers["x-api-key"] = this.opts.serviceKey;
220
+ }
221
+ let bodyStr;
222
+ if (opts.body !== void 0) {
223
+ bodyStr = JSON.stringify(opts.body);
224
+ headers["content-type"] = "application/json";
225
+ }
226
+ const res = await this.f(new URL(path, this.base), { method, headers, body: bodyStr });
227
+ const text = await res.text();
228
+ let parsed;
229
+ try {
230
+ parsed = text ? JSON.parse(text) : void 0;
231
+ } catch {
232
+ parsed = text;
233
+ }
234
+ if (!res.ok) {
235
+ const message = (parsed && typeof parsed === "object" && "error" in parsed ? String(parsed.error) : void 0) ?? `Accounts request failed with status ${res.status}.`;
236
+ throw new AccountsAdminError(res.status, message, parsed);
237
+ }
238
+ return parsed;
239
+ }
240
+ };
241
+ function createAccountsAdmin(opts) {
242
+ return new AccountsAdmin(opts);
243
+ }
244
+ export {
245
+ AccountsAdmin,
246
+ AccountsAdminError,
247
+ createAccountsAdmin
248
+ };
package/package.json CHANGED
@@ -1,69 +1,73 @@
1
1
  {
2
- "name": "@~lyre/auth",
3
- "version": "0.1.1",
4
- "description": "Shared Axis Accounts auth SDK — framework-agnostic session/identity core (HMAC-signed cookies, accounts login/callback/logout) plus an optional turnkey SvelteKit adapter.",
5
- "type": "module",
6
- "sideEffects": false,
7
- "license": "MIT",
8
- "author": "Britam Trust Services / Lyre",
9
- "repository": {
10
- "type": "git",
11
- "url": "git+https://github.com/kigathi-chege/lyre-auth-sdk.git"
12
- },
13
- "homepage": "https://github.com/kigathi-chege/lyre-auth-sdk#readme",
14
- "bugs": {
15
- "url": "https://github.com/kigathi-chege/lyre-auth-sdk/issues"
16
- },
17
- "keywords": [
18
- "auth",
19
- "sso",
20
- "accounts",
21
- "session",
22
- "sveltekit",
23
- "hmac",
24
- "lyre"
25
- ],
26
- "main": "./dist/index.js",
27
- "types": "./dist/index.d.ts",
28
- "exports": {
29
- ".": {
30
- "types": "./dist/index.d.ts",
31
- "import": "./dist/index.js"
32
- },
33
- "./sveltekit": {
34
- "types": "./dist/sveltekit.d.ts",
35
- "import": "./dist/sveltekit.js"
36
- },
37
- "./nest": {
38
- "types": "./dist/nest.d.ts",
39
- "import": "./dist/nest.js"
40
- },
41
- "./package.json": "./package.json"
42
- },
43
- "files": [
44
- "dist",
45
- "README.md",
46
- "LICENSE"
47
- ],
48
- "scripts": {
49
- "build": "tsup src/index.ts src/sveltekit.ts src/nest.ts --format esm --dts --clean",
50
- "check": "tsc --noEmit"
51
- },
52
- "peerDependencies": {
53
- "@sveltejs/kit": "^2.0.0"
54
- },
55
- "peerDependenciesMeta": {
56
- "@sveltejs/kit": {
57
- "optional": true
58
- }
59
- },
60
- "devDependencies": {
61
- "@sveltejs/kit": "^2.0.0",
62
- "@types/node": "^22",
63
- "tsup": "^8.3.5",
64
- "typescript": "^6.0.2"
65
- },
66
- "publishConfig": {
67
- "access": "public"
68
- }
2
+ "name": "@~lyre/auth",
3
+ "version": "0.4.0",
4
+ "description": "Shared Axis Accounts auth SDK \u2014 framework-agnostic session/identity core (HMAC-signed cookies, accounts login/callback/logout) plus an optional turnkey SvelteKit adapter.",
5
+ "type": "module",
6
+ "sideEffects": false,
7
+ "license": "MIT",
8
+ "author": "Britam Trust Services / Lyre",
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/kigathi-chege/lyre-auth-sdk.git"
12
+ },
13
+ "homepage": "https://github.com/kigathi-chege/lyre-auth-sdk#readme",
14
+ "bugs": {
15
+ "url": "https://github.com/kigathi-chege/lyre-auth-sdk/issues"
16
+ },
17
+ "keywords": [
18
+ "auth",
19
+ "sso",
20
+ "accounts",
21
+ "session",
22
+ "sveltekit",
23
+ "hmac",
24
+ "lyre"
25
+ ],
26
+ "main": "./dist/index.js",
27
+ "types": "./dist/index.d.ts",
28
+ "exports": {
29
+ ".": {
30
+ "types": "./dist/index.d.ts",
31
+ "import": "./dist/index.js"
32
+ },
33
+ "./sveltekit": {
34
+ "types": "./dist/sveltekit.d.ts",
35
+ "import": "./dist/sveltekit.js"
36
+ },
37
+ "./nest": {
38
+ "types": "./dist/nest.d.ts",
39
+ "import": "./dist/nest.js"
40
+ },
41
+ "./admin": {
42
+ "types": "./dist/admin.d.ts",
43
+ "import": "./dist/admin.js"
44
+ },
45
+ "./package.json": "./package.json"
46
+ },
47
+ "files": [
48
+ "dist",
49
+ "README.md",
50
+ "LICENSE"
51
+ ],
52
+ "scripts": {
53
+ "build": "tsup src/index.ts src/sveltekit.ts src/nest.ts src/admin.ts --format esm --dts --clean",
54
+ "check": "tsc --noEmit"
55
+ },
56
+ "peerDependencies": {
57
+ "@sveltejs/kit": "^2.0.0"
58
+ },
59
+ "peerDependenciesMeta": {
60
+ "@sveltejs/kit": {
61
+ "optional": true
62
+ }
63
+ },
64
+ "devDependencies": {
65
+ "@sveltejs/kit": "^2.0.0",
66
+ "@types/node": "^22",
67
+ "tsup": "^8.3.5",
68
+ "typescript": "^6.0.2"
69
+ },
70
+ "publishConfig": {
71
+ "access": "public"
72
+ }
69
73
  }