@softwarepatterns/am 0.0.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.
package/README.md ADDED
@@ -0,0 +1,215 @@
1
+ # `@softwarepatterns/am`
2
+
3
+ Authentication client SDK for **AccountMaker (Am)**.
4
+
5
+ This package provides a small, stable client for interacting with the AccountMaker authentication API. It is designed for **Node.js applications** and **modern bundlers**, with explicit support for both **ESM** and **CommonJS** consumers.
6
+
7
+ The SDK focuses on correctness, predictable behavior, and minimal surface area.
8
+
9
+ ---
10
+
11
+ ## Features
12
+
13
+ * ESM and CommonJS support
14
+ * TypeScript-first API with bundled `.d.ts`
15
+ * Explicit error modeling using Problem Details
16
+ * Token-based authenticated sessions
17
+ * Automatic access-token refresh
18
+ * No runtime dependencies
19
+ * No side effects on import
20
+
21
+ ---
22
+
23
+ ## Requirements
24
+
25
+ * **Node.js ≥ 18**
26
+ * A runtime with a global `fetch` implementation
27
+ (Node 18+, Bun, Deno, or a custom `fetchFn`)
28
+
29
+ ---
30
+
31
+ ## Installation
32
+
33
+ ```bash
34
+ npm install @softwarepatterns/am
35
+ ```
36
+
37
+ ---
38
+
39
+ ## Importing
40
+
41
+ ### ESM
42
+
43
+ ```ts
44
+ import { Am } from "@softwarepatterns/am";
45
+ ```
46
+
47
+ ### CommonJS
48
+
49
+ ```js
50
+ const { Am } = require("@softwarepatterns/am");
51
+ ```
52
+
53
+ ---
54
+
55
+ ## Basic usage
56
+
57
+ ### Create a client
58
+
59
+ ```ts
60
+ import { Am } from "@softwarepatterns/am";
61
+
62
+ const am = new Am({
63
+ baseUrl: "https://api.accountmaker.com"
64
+ });
65
+ ```
66
+
67
+ If no configuration is provided, the client defaults to:
68
+
69
+ * `baseUrl: https://api.accountmaker.com`
70
+ * `fetchFn: globalThis.fetch`
71
+
72
+ ---
73
+
74
+ ## Authentication flows
75
+
76
+ ### Login with email and password
77
+
78
+ ```ts
79
+ const result = await am.login({
80
+ email: "user@example.com",
81
+ password: "password"
82
+ });
83
+ ```
84
+
85
+ The result contains both session tokens and the authenticated profile.
86
+
87
+ ```ts
88
+ result.session;
89
+ result.profile;
90
+ ```
91
+
92
+ ---
93
+
94
+ ### Create an authenticated session
95
+
96
+ ```ts
97
+ const session = am.createAuthSession(result.session);
98
+ ```
99
+
100
+ An `AuthSession` represents an authenticated user and handles token refresh automatically.
101
+
102
+ ---
103
+
104
+ ### Fetch the current user
105
+
106
+ ```ts
107
+ const me = await session.me();
108
+ ```
109
+
110
+ ---
111
+
112
+ ### Refresh tokens explicitly
113
+
114
+ ```ts
115
+ await session.refresh();
116
+ ```
117
+
118
+ ---
119
+
120
+ ## Error handling
121
+
122
+ All API errors are surfaced as `AuthError`.
123
+
124
+ ```ts
125
+ import { AuthError } from "@softwarepatterns/am";
126
+
127
+ try {
128
+ await am.login({ email, password });
129
+ } catch (err) {
130
+ if (err instanceof AuthError) {
131
+ console.log(err.status);
132
+ console.log(err.title);
133
+ console.log(err.detail);
134
+ }
135
+ }
136
+ ```
137
+
138
+ Errors follow the **Problem Details** format (`application/problem+json`).
139
+
140
+ Unknown or unsupported error responses are converted into a generic problem shape without exposing raw response bodies.
141
+
142
+ ---
143
+
144
+ ## Custom fetch implementation
145
+
146
+ If the runtime does not provide a global `fetch`, supply one explicitly.
147
+
148
+ ```ts
149
+ const am = new Am({
150
+ fetchFn: fetch,
151
+ baseUrl: "https://api.accountmaker.com"
152
+ });
153
+ ```
154
+
155
+ This is useful for:
156
+
157
+ * Older Node versions
158
+ * Instrumented HTTP clients
159
+ * Testing
160
+
161
+ ---
162
+
163
+ ## TypeScript support
164
+
165
+ This package ships with bundled type definitions.
166
+
167
+ ```ts
168
+ import type { AuthenticationResult } from "@softwarepatterns/am";
169
+ ```
170
+
171
+ The public API is fully typed. Internal implementation details are not exposed.
172
+
173
+ ---
174
+
175
+ ## Browser support
176
+
177
+ This SDK does **not currently claim browser runtime support**.
178
+
179
+ However:
180
+
181
+ * The package is free of Node-only runtime APIs
182
+ * It can be bundled by modern tools (Vite, Rollup, Webpack)
183
+
184
+ Browser runtime support may be added in a future release, along with explicit guarantees and tests.
185
+
186
+ ---
187
+
188
+ ## Stability guarantees
189
+
190
+ The following are guaranteed:
191
+
192
+ * Stable ESM and CommonJS entry points
193
+ * Stable TypeScript types for exported symbols
194
+ * Compatibility with Node 18, 20, and 22
195
+ * Deterministic build and publish artifacts
196
+
197
+ The following are **not** guaranteed yet:
198
+
199
+ * Browser runtime behavior
200
+ * Backward compatibility prior to `1.0.0`
201
+
202
+ ---
203
+
204
+ ## Versioning
205
+
206
+ This package follows semantic versioning.
207
+
208
+ * `0.x` releases may introduce breaking changes
209
+ * `1.0.0` will mark a frozen public API
210
+
211
+ ---
212
+
213
+ ## License
214
+
215
+ MIT
package/dist/index.cjs ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";function t(t){return t.replace(/_([a-z])/g,(t,e)=>e.toUpperCase())}function e(n){if(null===n||"object"!=typeof n)return n;if(Array.isArray(n))return n.map(t=>e(t));const s=n,r={};for(const n of Object.keys(s))Object.prototype.hasOwnProperty.call(s,n)&&(r[t(n)]=e(s[n]));return r}function n(t){return t.replace(/[A-Z]/g,t=>`_${t.toLowerCase()}`)}function s(t){if(null===t||"object"!=typeof t)return t;if(Array.isArray(t))return t.map(t=>s(t));const e=t,r={};for(const t of Object.keys(e))Object.prototype.hasOwnProperty.call(e,t)&&(r[n(t)]=s(e[t]));return r}class r extends Error{constructor(t){super(t.title),this.name="AuthError",this.problem=Object.freeze(t)}get type(){return this.problem.type}get title(){return this.problem.title}get status(){return this.problem.status}get code(){return this.problem.code}get detail(){return this.problem.detail}get invalidParams(){return this.problem.invalidParams}}const a={fetchFn:function(){const t=globalThis.fetch;return"function"==typeof t?t:async()=>{throw new Error("Missing fetch implementation. Provide config.fetchFn or use a runtime with global fetch.")}}(),baseUrl:"https://api.accountmaker.com"};const i=async t=>{if(204===t.status)return;const n=await async function(t){const e=t.headers.get("Content-Type")||"";if(!e.includes("application/json")&&!e.includes("+json"))return null;try{return await t.json()}catch{return null}}(t),s=e(n);if(!t.ok){if(function(t){return(t.headers.get("Content-Type")||"").includes("application/problem+json")}(t)&&s&&"object"==typeof s)throw new r(s);throw new r(function(t,e){return{type:"about:blank",title:t.statusText||"Request failed",status:t.status,detail:e}}(t,"string"==typeof n?n:void 0))}return s},o=async({fetchFn:t,baseUrl:e},n,r={})=>{const a=new URLSearchParams(s(r)).toString(),o=a?`${e}${n}?${a}`:`${e}${n}`,c=await t(o,{method:"GET",headers:{Accept:"application/json"}});return i(c)},c=async({fetchFn:t,baseUrl:e},n,r)=>{const a=await t(`${e}${n}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(s(r))});return i(a)},h=async({accessToken:t},{fetchFn:e,baseUrl:n},r,a={})=>{const o=new URLSearchParams(s(a)).toString(),c=o?`${n}${r}?${o}`:`${n}${r}`,h=await e(c,{method:"GET",headers:{Accept:"application/json",Authorization:`Bearer ${t}`}});return i(h)};class u{constructor(t,e){this.tokens=t,this.config={...a,...e},this.lastUpdated=new Date}get accessToken(){return this.tokens.accessToken}get refreshToken(){return this.tokens.refreshToken}get idToken(){return this.tokens.idToken}get tokenType(){return this.tokens.tokenType}get expiresIn(){return this.tokens.expiresIn}get lastUpdatedAt(){return this.lastUpdated}get expiresAt(){return new Date(this.lastUpdated.getTime()+1e3*this.expiresIn)}isExpired(){return Date.now()>=this.expiresAt.getTime()-6e4}async fetch(t,e={}){const{fetchFn:n}=this.config;return this.isExpired()&&await this.refresh(),await n(t,{...e,headers:{...e.headers||{},Authorization:`Bearer ${this.tokens.accessToken}`}})}async refresh(){const{fetchFn:t,baseUrl:e}=this.config,n=await t(`${e}/auth/refresh`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(s({refreshToken:this.tokens.refreshToken}))}),r=await i(n);this.tokens=r,this.lastUpdated=new Date}async sendVerificationEmail(){await(async({accessToken:t},{fetchFn:e,baseUrl:n},r,a)=>{const o=await e(`${n}${r}`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${t}`},body:JSON.stringify(s(a))});return i(o)})(this,this.config,"/auth/send-verification-email",{})}async me(){return await h(this,this.config,"/auth/me",{})}async user(t){return await h(this,this.config,`/auth/user/${t}`,{})}}class p{constructor(t){this.options={...a,...t}}static createAuthSession(t,e){return new p(e).createAuthSession(t)}createAuthSession(t){return new u(t,this.options)}static async acceptInvite(t,e){return new p(e).acceptInvite(t)}async acceptInvite(t){return await o(this.options,"/auth/accept-invite",t)}static async checkEmail(t,e){return new p(e).checkEmail(t)}async checkEmail(t){return c(this.options,"/auth/check-email",t)}static async csrfSession(t){return new p(t).csrfSession()}async csrfSession(){return o(this.options,"/auth/csrf-session")}static async csrfToken(t){return new p(t).csrfToken()}async csrfToken(){return o(this.options,"/auth/csrf-token")}static async login(t,e){return new p(e).login(t)}async login(t){return await c(this.options,"/auth/login",t)}static async tokenLogin(t,e){return new p(e).tokenLogin(t)}async tokenLogin(t){const e=this.options;return await o(e,"/auth/token-login",{token:t})}static async refresh(t,e){return new p(e).refresh(t)}async refresh(t){return await c(this.options,"/auth/refresh",{refreshToken:t})}static async register(t,e){return new p(e).register(t)}async register(t){return await c(this.options,"/auth/register",t)}static async resetPassword(t,e){return new p(e).resetPassword(t)}async resetPassword(t){return c(this.options,"/auth/reset-password",t)}static async sendMagicLink(t,e){return new p(e).sendMagicLink(t)}async sendMagicLink(t){return c(this.options,"/auth/send-magic-link",t)}static async sendPasswordReset(t,e){return new p(e).sendPasswordReset(t)}async sendPasswordReset(t){return c(this.options,"/auth/send-password-reset",t)}}exports.Am=p,exports.AuthError=r,exports.AuthSession=u;
2
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","sources":["../src/auth.ts"],"sourcesContent":[null],"names":["camelCaseStr","str","replace","_","letter","toUpperCase","camelCaseObj","input","Array","isArray","map","item","obj","result","key","Object","keys","prototype","hasOwnProperty","call","snakeCaseStr","toLowerCase","snakeCaseObj","AuthError","Error","constructor","problem","super","title","this","name","freeze","type","status","code","detail","invalidParams","defaultConfig","fetchFn","f","globalThis","fetch","async","defaultFetchFn","baseUrl","handleResponse","res","raw","contentType","headers","get","includes","json","readJsonSafe","ok","isProblemJson","statusText","toGenericProblem","undefined","unauthGet","path","query","qs","URLSearchParams","toString","url","method","Accept","unauthPost","body","JSON","stringify","authGet","accessToken","Authorization","AuthSession","tokens","config","lastUpdated","Date","refreshToken","idToken","tokenType","expiresIn","lastUpdatedAt","expiresAt","getTime","isExpired","now","init","refresh","sendVerificationEmail","authPost","me","user","id","Am","options","createAuthSession","acceptInvite","checkEmail","csrfSession","csrfToken","login","tokenLogin","token","register","resetPassword","sendMagicLink","sendPasswordReset"],"mappings":"aAmBA,SAASA,EAAaC,GACpB,OAAOA,EAAIC,QAAQ,YAAa,CAACC,EAAGC,IAAWA,EAAOC,cACxD,CAEA,SAASC,EAAaC,GACpB,GAAc,OAAVA,GAAmC,iBAAVA,EAC3B,OAAOA,EAGT,GAAIC,MAAMC,QAAQF,GAChB,OAAOA,EAAMG,IAAKC,GAASL,EAAaK,IAG1C,MAAMC,EAAML,EACNM,EAAkC,CAAA,EAExC,IAAK,MAAMC,KAAOC,OAAOC,KAAKJ,GACxBG,OAAOE,UAAUC,eAAeC,KAAKP,EAAKE,KAC5CD,EAAOb,EAAac,IAAQR,EAAaM,EAAIE,KAIjD,OAAOD,CACT,CAEA,SAASO,EAAanB,GACpB,OAAOA,EAAIC,QAAQ,SAAWE,GAAW,IAAIA,EAAOiB,gBACtD,CAEA,SAASC,EAAaf,GACpB,GAAc,OAAVA,GAAmC,iBAAVA,EAC3B,OAAOA,EAGT,GAAIC,MAAMC,QAAQF,GAChB,OAAOA,EAAMG,IAAKC,GAASW,EAAaX,IAG1C,MAAMC,EAAML,EACNM,EAAkC,CAAA,EAExC,IAAK,MAAMC,KAAOC,OAAOC,KAAKJ,GACxBG,OAAOE,UAAUC,eAAeC,KAAKP,EAAKE,KAC5CD,EAAOO,EAAaN,IAAQQ,EAAaV,EAAIE,KAIjD,OAAOD,CACT,CAEM,MAAOU,UAAkBC,MAG7B,WAAAC,CAAYC,GACVC,MAAMD,EAAQE,OACdC,KAAKC,KAAO,YACZD,KAAKH,QAAUX,OAAOgB,OAAOL,EAC/B,CACA,QAAIM,GACF,OAAOH,KAAKH,QAAQM,IACtB,CACA,SAAIJ,GACF,OAAOC,KAAKH,QAAQE,KACtB,CACA,UAAIK,GACF,OAAOJ,KAAKH,QAAQO,MACtB,CACA,QAAIC,GACF,OAAOL,KAAKH,QAAQQ,IACtB,CACA,UAAIC,GACF,OAAON,KAAKH,QAAQS,MACtB,CACA,iBAAIC,GACF,OAAOP,KAAKH,QAAQU,aACtB,EAmBF,MAAMC,EAAgB,CACpBC,QAZF,WACE,MAAMC,EAAKC,WAAmBC,MAC9B,MAAiB,mBAANF,EAAyBA,EAE7BG,UACL,MAAM,IAAIlB,MACR,4FAGN,CAGWmB,GACTC,QAAS,gCA+BX,MAAMC,EAAiBH,MAAOI,IAC5B,GAAmB,MAAfA,EAAIb,OACN,OAGF,MAAMc,QA5BRL,eAA4BI,GAC1B,MAAME,EAAcF,EAAIG,QAAQC,IAAI,iBAAmB,GACvD,IACGF,EAAYG,SAAS,sBACrBH,EAAYG,SAAS,SAEtB,OAAO,KACT,IACE,aAAaL,EAAIM,MACnB,CAAE,MACA,OAAO,IACT,CACF,CAgBoBC,CAAaP,GACzBM,EAAO9C,EAAayC,GAE1B,IAAKD,EAAIQ,GAAI,CACX,GArCJ,SAAuBR,GAErB,OADoBA,EAAIG,QAAQC,IAAI,iBAAmB,IACpCC,SAAS,2BAC9B,CAkCQI,CAAcT,IAAQM,GAAwB,iBAATA,EACvC,MAAM,IAAI7B,EAAU6B,GAEtB,MAAM,IAAI7B,EArBd,SAA0BuB,EAAeX,GACvC,MAAO,CACLH,KAAM,cACNJ,MAAOkB,EAAIU,YAAc,iBACzBvB,OAAQa,EAAIb,OACZE,SAEJ,CAeMsB,CAAiBX,EAAoB,iBAARC,EAAmBA,OAAMW,GAE1D,CAEA,OAAON,GAMHO,EAAYjB,OACdJ,UAASM,WACXgB,EACAC,EAAgC,MAEhC,MAAMC,EAAK,IAAIC,gBACbzC,EAAauC,IACbG,WACIC,EAAMH,EAAK,GAAGlB,IAAUgB,KAAQE,IAAO,GAAGlB,IAAUgB,IACpDd,QAAYR,EAAQ2B,EAAK,CAC7BC,OAAQ,MACRjB,QAAS,CACPkB,OAAQ,sBAGZ,OAAOtB,EAAeC,IAMlBsB,EAAa1B,OACfJ,UAASM,WACXgB,EACAS,KAEA,MAAMvB,QAAYR,EAAQ,GAAGM,IAAUgB,IAAQ,CAC7CM,OAAQ,OACRjB,QAAS,CACP,eAAgB,oBAElBoB,KAAMC,KAAKC,UAAUjD,EAAa+C,MAEpC,OAAOxB,EAAeC,IAGlB0B,EAAU9B,OACZ+B,gBACAnC,UAASM,WACXgB,EACAC,EAAgC,MAEhC,MAAMC,EAAK,IAAIC,gBACbzC,EAAauC,IACbG,WACIC,EAAMH,EAAK,GAAGlB,IAAUgB,KAAQE,IAAO,GAAGlB,IAAUgB,IACpDd,QAAYR,EAAQ2B,EAAK,CAC7BC,OAAQ,MACRjB,QAAS,CACPkB,OAAQ,mBACRO,cAAe,UAAUD,OAG7B,OAAO5B,EAAeC,UA2BX6B,EAKX,WAAAlD,CAAYmD,EAAuBC,GACjChD,KAAK+C,OAASA,EACd/C,KAAKgD,OAAS,IACTxC,KACAwC,GAELhD,KAAKiD,YAAc,IAAIC,IACzB,CAEA,eAAIN,GACF,OAAO5C,KAAK+C,OAAOH,WACrB,CACA,gBAAIO,GACF,OAAOnD,KAAK+C,OAAOI,YACrB,CACA,WAAIC,GACF,OAAOpD,KAAK+C,OAAOK,OACrB,CACA,aAAIC,GACF,OAAOrD,KAAK+C,OAAOM,SACrB,CACA,aAAIC,GACF,OAAOtD,KAAK+C,OAAOO,SACrB,CACA,iBAAIC,GACF,OAAOvD,KAAKiD,WACd,CACA,aAAIO,GACF,OAAO,IAAIN,KAAKlD,KAAKiD,YAAYQ,UAA6B,IAAjBzD,KAAKsD,UACpD,CAEA,SAAAI,GACE,OAAOR,KAAKS,OAAS3D,KAAKwD,UAAUC,UAlRtB,GAmRhB,CAQA,WAAM7C,CAAMwB,EAA6BwB,EAAoB,IAC3D,MAAMnD,QAAEA,GAAYT,KAAKgD,OAOzB,OAJIhD,KAAK0D,mBACD1D,KAAK6D,gBAGApD,EAAQ2B,EAAK,IACrBwB,EACHxC,QAAS,IACHwC,EAAKxC,SAAW,GACpByB,cAAe,UAAU7C,KAAK+C,OAAOH,gBAG3C,CAEA,aAAMiB,GACJ,MAAMpD,QAAEA,EAAOM,QAAEA,GAAYf,KAAKgD,OAC5B/B,QAAYR,EAAQ,GAAGM,iBAAwB,CACnDsB,OAAQ,OACRjB,QAAS,CACP,eAAgB,oBAElBoB,KAAMC,KAAKC,UACTjD,EAAa,CAAE0D,aAAcnD,KAAK+C,OAAOI,kBAGvC5B,QAAaP,EAAeC,GAClCjB,KAAK+C,OAASxB,EACdvB,KAAKiD,YAAc,IAAIC,IACzB,CAEA,2BAAMY,QAjGSjD,QACb+B,gBACAnC,UAASM,WACXgB,EACAS,KAEA,MAAMvB,QAAYR,EAAQ,GAAGM,IAAUgB,IAAQ,CAC7CM,OAAQ,OACRjB,QAAS,CACP,eAAgB,mBAChByB,cAAe,UAAUD,KAE3BJ,KAAMC,KAAKC,UAAUjD,EAAa+C,MAGpC,OAAOxB,EAAeC,IAmFd8C,CAAS/D,KAAMA,KAAKgD,OAAQ,gCAAiC,CAAA,EACrE,CAEA,QAAMgB,GACJ,aAAarB,EAAQ3C,KAAMA,KAAKgD,OAAQ,WAAY,GACtD,CAEA,UAAMiB,CAAKC,GACT,aAAavB,EAAQ3C,KAAMA,KAAKgD,OAAQ,cAAckB,IAAM,GAC9D,QAGWC,EAGX,WAAAvE,CAAYoD,GACVhD,KAAKoE,QAAU,IAAK5D,KAAkBwC,EACxC,CAEA,wBAAOqB,CACLtB,EACAC,GAEA,OAAO,IAAImB,EAAGnB,GAAQqB,kBAAkBtB,EAC1C,CAEA,iBAAAsB,CAAkBtB,GAChB,OAAO,IAAID,EAAYC,EAAQ/C,KAAKoE,QACtC,CAEA,yBAAaE,CACXtC,EAIAgB,GAEA,OAAO,IAAImB,EAAGnB,GAAQsB,aAAatC,EACrC,CAEA,kBAAMsC,CAAatC,GAIjB,aAAaF,EAAU9B,KAAKoE,QAAS,sBAAuBpC,EAC9D,CAEA,uBAAauC,CACX/B,EACAQ,GAMA,OAAO,IAAImB,EAAGnB,GAAQuB,WAAW/B,EACnC,CAEA,gBAAM+B,CAAW/B,GASf,OAAOD,EAAWvC,KAAKoE,QAAS,oBAAqB5B,EACvD,CAEA,wBAAagC,CACXxB,GAEA,OAAO,IAAImB,EAAGnB,GAAQwB,aACxB,CAEA,iBAAMA,GACJ,OAAO1C,EAAU9B,KAAKoE,QAAS,qBACjC,CAEA,sBAAaK,CACXzB,GAEA,OAAO,IAAImB,EAAGnB,GAAQyB,WACxB,CAEA,eAAMA,GACJ,OAAO3C,EAAU9B,KAAKoE,QAAS,mBACjC,CAEA,kBAAaM,CACXlC,EAKAQ,GAEA,OAAO,IAAImB,EAAGnB,GAAQ0B,MAAMlC,EAC9B,CAEA,WAAMkC,CAAMlC,GAKV,aAAaD,EAAWvC,KAAKoE,QAAS,cAAe5B,EACvD,CAEA,uBAAamC,CACXC,EACA5B,GAEA,OAAO,IAAImB,EAAGnB,GAAQ2B,WAAWC,EACnC,CAEA,gBAAMD,CAAWC,GACf,MAAMR,EAAUpE,KAAKoE,QACrB,aAAatC,EAAUsC,EAAS,oBAAqB,CACnDQ,SAEJ,CAEA,oBAAaf,CACXV,EACAH,GAEA,OAAO,IAAImB,EAAGnB,GAAQa,QAAQV,EAChC,CAEA,aAAMU,CAAQV,GACZ,aAAaZ,EAAWvC,KAAKoE,QAAS,gBAAiB,CACrDjB,gBAEJ,CAEA,qBAAa0B,CACXrC,EAKAQ,GAEA,OAAO,IAAImB,EAAGnB,GAAQ6B,SAASrC,EACjC,CAEA,cAAMqC,CAASrC,GAKb,aAAaD,EAAWvC,KAAKoE,QAAS,iBAAkB5B,EAC1D,CAEA,0BAAasC,CACXtC,EAIAQ,GAEA,OAAO,IAAImB,EAAGnB,GAAQ8B,cAActC,EACtC,CAEA,mBAAMsC,CAActC,GAIlB,OAAOD,EAAWvC,KAAKoE,QAAS,uBAAwB5B,EAC1D,CAEA,0BAAauC,CACXvC,EAIAQ,GAEA,OAAO,IAAImB,EAAGnB,GAAQ+B,cAAcvC,EACtC,CAEA,mBAAMuC,CAAcvC,GAIlB,OAAOD,EAAWvC,KAAKoE,QAAS,wBAAyB5B,EAC3D,CAEA,8BAAawC,CACXxC,EAIAQ,GAEA,OAAO,IAAImB,EAAGnB,GAAQgC,kBAAkBxC,EAC1C,CAEA,uBAAMwC,CAAkBxC,GAItB,OAAOD,EAAWvC,KAAKoE,QAAS,4BAA6B5B,EAC/D"}
@@ -0,0 +1,205 @@
1
+ type ProblemDetails = {
2
+ type: string;
3
+ title: string;
4
+ status: number;
5
+ code?: string;
6
+ detail?: string;
7
+ invalidParams?: {
8
+ in: "body" | "cookie" | "header" | "query" | "path";
9
+ path: string;
10
+ type: string;
11
+ received: unknown;
12
+ expected?: string;
13
+ }[];
14
+ };
15
+ type ClientId = `cid${string}`;
16
+ type UserId = `uid${string}`;
17
+ type AccountId = `acc${string}`;
18
+ type MembershipId = `mbr${string}`;
19
+ type UserStatus = "active" | "trial" | "past_due" | "suspended" | "closed";
20
+ type UserResource = {
21
+ id: UserId;
22
+ accountId: AccountId;
23
+ status: UserStatus;
24
+ preferredMembershipId: MembershipId | null;
25
+ };
26
+ type UserIdentity = {
27
+ id: UserId;
28
+ avatarUrl: string | null;
29
+ externalId: string | null;
30
+ givenName: string | null;
31
+ familyName: string | null;
32
+ displayName: string | null;
33
+ preferredLanguage: string | null;
34
+ locale: string | null;
35
+ timezone: string | null;
36
+ };
37
+ type MembershipRole = "owner" | "member" | "viewer";
38
+ type Membership = {
39
+ id: MembershipId;
40
+ userId: UserId;
41
+ accountId: AccountId;
42
+ role: MembershipRole;
43
+ };
44
+ type EmailCredential = {
45
+ id: string;
46
+ email: string | null;
47
+ hashedEmail: string | null;
48
+ hashedPassword: string | null;
49
+ emailVerifiedAt: string | null;
50
+ };
51
+ type SessionTokens = {
52
+ accessToken: string;
53
+ refreshToken: string;
54
+ tokenType: "Bearer";
55
+ expiresIn: number;
56
+ idToken?: string;
57
+ };
58
+ type SessionProfile = UserResource & {
59
+ identity: UserIdentity;
60
+ emailCredentials: EmailCredential[];
61
+ memberships: Membership[];
62
+ activeMembership: Membership | null;
63
+ };
64
+ type AuthenticationResult = {
65
+ session: SessionTokens;
66
+ profile: SessionProfile;
67
+ };
68
+ type EmailCheckStatus = "active" | "inactive";
69
+ type LoginMethod = "email_password" | "magic_link";
70
+
71
+ type FetchFn = (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;
72
+ declare class AuthError extends Error {
73
+ readonly problem: ProblemDetails;
74
+ constructor(problem: ProblemDetails);
75
+ get type(): string;
76
+ get title(): string;
77
+ get status(): number;
78
+ get code(): string | undefined;
79
+ get detail(): string | undefined;
80
+ get invalidParams(): ProblemDetails["invalidParams"] | undefined;
81
+ }
82
+ type Config = {
83
+ fetchFn: FetchFn;
84
+ baseUrl: string;
85
+ };
86
+ declare class AuthSession {
87
+ private tokens;
88
+ private config;
89
+ private lastUpdated;
90
+ constructor(tokens: SessionTokens, config: Partial<Config>);
91
+ get accessToken(): string;
92
+ get refreshToken(): string;
93
+ get idToken(): string | undefined;
94
+ get tokenType(): "Bearer";
95
+ get expiresIn(): number;
96
+ get lastUpdatedAt(): Date;
97
+ get expiresAt(): Date;
98
+ isExpired(): boolean;
99
+ /**
100
+ * Fetch with automatic token refresh.
101
+ *
102
+ * If the access token is expired, it will be refreshed before making the request. The
103
+ * Authorization header will be set with the current access token.
104
+ */
105
+ fetch(url: string | URL | Request, init?: RequestInit): Promise<Response>;
106
+ refresh(): Promise<void>;
107
+ sendVerificationEmail(): Promise<void>;
108
+ me(): Promise<SessionProfile>;
109
+ user(id: UserId): Promise<UserResource>;
110
+ }
111
+ declare class Am {
112
+ private options;
113
+ constructor(config?: Partial<Config>);
114
+ static createAuthSession(tokens: SessionTokens, config?: Partial<Config>): AuthSession;
115
+ createAuthSession(tokens: SessionTokens): AuthSession;
116
+ static acceptInvite(query: {
117
+ clientId: ClientId;
118
+ token: string;
119
+ }, config?: Partial<Config>): Promise<AuthenticationResult>;
120
+ acceptInvite(query: {
121
+ clientId: ClientId;
122
+ token: string;
123
+ }): Promise<AuthenticationResult>;
124
+ static checkEmail(body: {
125
+ clientId: ClientId;
126
+ email: string;
127
+ csrfToken?: string;
128
+ }, config?: Partial<Config>): Promise<{
129
+ status: EmailCheckStatus;
130
+ preferred: LoginMethod[];
131
+ available: LoginMethod[];
132
+ }>;
133
+ checkEmail(body: {
134
+ clientId: ClientId;
135
+ email: string;
136
+ csrfToken?: string;
137
+ }): Promise<{
138
+ status: EmailCheckStatus;
139
+ preferred: LoginMethod[];
140
+ available: LoginMethod[];
141
+ }>;
142
+ static csrfSession(config?: Partial<Config>): Promise<{
143
+ csrfToken: string;
144
+ }>;
145
+ csrfSession(): Promise<{
146
+ csrfToken: string;
147
+ }>;
148
+ static csrfToken(config?: Partial<Config>): Promise<{
149
+ csrfToken: string;
150
+ }>;
151
+ csrfToken(): Promise<{
152
+ csrfToken: string;
153
+ }>;
154
+ static login(body: {
155
+ email: string;
156
+ password: string;
157
+ csrfToken?: string;
158
+ }, config?: Partial<Config>): Promise<AuthenticationResult>;
159
+ login(body: {
160
+ email: string;
161
+ password: string;
162
+ csrfToken?: string;
163
+ }): Promise<AuthenticationResult>;
164
+ static tokenLogin(token: string, config?: Partial<Config>): Promise<AuthenticationResult>;
165
+ tokenLogin(token: string): Promise<AuthenticationResult>;
166
+ static refresh(refreshToken: string, config?: Partial<Config>): Promise<SessionTokens>;
167
+ refresh(refreshToken: string): Promise<SessionTokens>;
168
+ static register(body: {
169
+ email: string;
170
+ password: string;
171
+ csrfToken?: string;
172
+ }, config?: Partial<Config>): Promise<AuthenticationResult>;
173
+ register(body: {
174
+ email: string;
175
+ password: string;
176
+ csrfToken?: string;
177
+ }): Promise<AuthenticationResult>;
178
+ static resetPassword(body: {
179
+ token: string;
180
+ newPassword: string;
181
+ }, config?: Partial<Config>): Promise<void>;
182
+ resetPassword(body: {
183
+ token: string;
184
+ newPassword: string;
185
+ }): Promise<void>;
186
+ static sendMagicLink(body: {
187
+ email: string;
188
+ csrfToken?: string;
189
+ }, config?: Partial<Config>): Promise<void>;
190
+ sendMagicLink(body: {
191
+ email: string;
192
+ csrfToken?: string;
193
+ }): Promise<void>;
194
+ static sendPasswordReset(body: {
195
+ email: string;
196
+ csrfToken?: string;
197
+ }, config?: Partial<Config>): Promise<void>;
198
+ sendPasswordReset(body: {
199
+ email: string;
200
+ csrfToken?: string;
201
+ }): Promise<void>;
202
+ }
203
+
204
+ export { Am, AuthError, AuthSession };
205
+ export type { AuthenticationResult, ClientId, EmailCheckStatus, LoginMethod, ProblemDetails, SessionProfile, SessionTokens, UserId, UserResource };
package/dist/index.mjs ADDED
@@ -0,0 +1,2 @@
1
+ function t(t){return t.replace(/_([a-z])/g,(t,e)=>e.toUpperCase())}function e(n){if(null===n||"object"!=typeof n)return n;if(Array.isArray(n))return n.map(t=>e(t));const s=n,r={};for(const n of Object.keys(s))Object.prototype.hasOwnProperty.call(s,n)&&(r[t(n)]=e(s[n]));return r}function n(t){return t.replace(/[A-Z]/g,t=>`_${t.toLowerCase()}`)}function s(t){if(null===t||"object"!=typeof t)return t;if(Array.isArray(t))return t.map(t=>s(t));const e=t,r={};for(const t of Object.keys(e))Object.prototype.hasOwnProperty.call(e,t)&&(r[n(t)]=s(e[t]));return r}class r extends Error{constructor(t){super(t.title),this.name="AuthError",this.problem=Object.freeze(t)}get type(){return this.problem.type}get title(){return this.problem.title}get status(){return this.problem.status}get code(){return this.problem.code}get detail(){return this.problem.detail}get invalidParams(){return this.problem.invalidParams}}const a={fetchFn:function(){const t=globalThis.fetch;return"function"==typeof t?t:async()=>{throw new Error("Missing fetch implementation. Provide config.fetchFn or use a runtime with global fetch.")}}(),baseUrl:"https://api.accountmaker.com"};const i=async t=>{if(204===t.status)return;const n=await async function(t){const e=t.headers.get("Content-Type")||"";if(!e.includes("application/json")&&!e.includes("+json"))return null;try{return await t.json()}catch{return null}}(t),s=e(n);if(!t.ok){if(function(t){return(t.headers.get("Content-Type")||"").includes("application/problem+json")}(t)&&s&&"object"==typeof s)throw new r(s);throw new r(function(t,e){return{type:"about:blank",title:t.statusText||"Request failed",status:t.status,detail:e}}(t,"string"==typeof n?n:void 0))}return s},o=async({fetchFn:t,baseUrl:e},n,r={})=>{const a=new URLSearchParams(s(r)).toString(),o=a?`${e}${n}?${a}`:`${e}${n}`,c=await t(o,{method:"GET",headers:{Accept:"application/json"}});return i(c)},c=async({fetchFn:t,baseUrl:e},n,r)=>{const a=await t(`${e}${n}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(s(r))});return i(a)},h=async({accessToken:t},{fetchFn:e,baseUrl:n},r,a={})=>{const o=new URLSearchParams(s(a)).toString(),c=o?`${n}${r}?${o}`:`${n}${r}`,h=await e(c,{method:"GET",headers:{Accept:"application/json",Authorization:`Bearer ${t}`}});return i(h)};class u{constructor(t,e){this.tokens=t,this.config={...a,...e},this.lastUpdated=new Date}get accessToken(){return this.tokens.accessToken}get refreshToken(){return this.tokens.refreshToken}get idToken(){return this.tokens.idToken}get tokenType(){return this.tokens.tokenType}get expiresIn(){return this.tokens.expiresIn}get lastUpdatedAt(){return this.lastUpdated}get expiresAt(){return new Date(this.lastUpdated.getTime()+1e3*this.expiresIn)}isExpired(){return Date.now()>=this.expiresAt.getTime()-6e4}async fetch(t,e={}){const{fetchFn:n}=this.config;return this.isExpired()&&await this.refresh(),await n(t,{...e,headers:{...e.headers||{},Authorization:`Bearer ${this.tokens.accessToken}`}})}async refresh(){const{fetchFn:t,baseUrl:e}=this.config,n=await t(`${e}/auth/refresh`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(s({refreshToken:this.tokens.refreshToken}))}),r=await i(n);this.tokens=r,this.lastUpdated=new Date}async sendVerificationEmail(){await(async({accessToken:t},{fetchFn:e,baseUrl:n},r,a)=>{const o=await e(`${n}${r}`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${t}`},body:JSON.stringify(s(a))});return i(o)})(this,this.config,"/auth/send-verification-email",{})}async me(){return await h(this,this.config,"/auth/me",{})}async user(t){return await h(this,this.config,`/auth/user/${t}`,{})}}class p{constructor(t){this.options={...a,...t}}static createAuthSession(t,e){return new p(e).createAuthSession(t)}createAuthSession(t){return new u(t,this.options)}static async acceptInvite(t,e){return new p(e).acceptInvite(t)}async acceptInvite(t){return await o(this.options,"/auth/accept-invite",t)}static async checkEmail(t,e){return new p(e).checkEmail(t)}async checkEmail(t){return c(this.options,"/auth/check-email",t)}static async csrfSession(t){return new p(t).csrfSession()}async csrfSession(){return o(this.options,"/auth/csrf-session")}static async csrfToken(t){return new p(t).csrfToken()}async csrfToken(){return o(this.options,"/auth/csrf-token")}static async login(t,e){return new p(e).login(t)}async login(t){return await c(this.options,"/auth/login",t)}static async tokenLogin(t,e){return new p(e).tokenLogin(t)}async tokenLogin(t){const e=this.options;return await o(e,"/auth/token-login",{token:t})}static async refresh(t,e){return new p(e).refresh(t)}async refresh(t){return await c(this.options,"/auth/refresh",{refreshToken:t})}static async register(t,e){return new p(e).register(t)}async register(t){return await c(this.options,"/auth/register",t)}static async resetPassword(t,e){return new p(e).resetPassword(t)}async resetPassword(t){return c(this.options,"/auth/reset-password",t)}static async sendMagicLink(t,e){return new p(e).sendMagicLink(t)}async sendMagicLink(t){return c(this.options,"/auth/send-magic-link",t)}static async sendPasswordReset(t,e){return new p(e).sendPasswordReset(t)}async sendPasswordReset(t){return c(this.options,"/auth/send-password-reset",t)}}export{p as Am,r as AuthError,u as AuthSession};
2
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","sources":["../src/auth.ts"],"sourcesContent":[null],"names":["camelCaseStr","str","replace","_","letter","toUpperCase","camelCaseObj","input","Array","isArray","map","item","obj","result","key","Object","keys","prototype","hasOwnProperty","call","snakeCaseStr","toLowerCase","snakeCaseObj","AuthError","Error","constructor","problem","super","title","this","name","freeze","type","status","code","detail","invalidParams","defaultConfig","fetchFn","f","globalThis","fetch","async","defaultFetchFn","baseUrl","handleResponse","res","raw","contentType","headers","get","includes","json","readJsonSafe","ok","isProblemJson","statusText","toGenericProblem","undefined","unauthGet","path","query","qs","URLSearchParams","toString","url","method","Accept","unauthPost","body","JSON","stringify","authGet","accessToken","Authorization","AuthSession","tokens","config","lastUpdated","Date","refreshToken","idToken","tokenType","expiresIn","lastUpdatedAt","expiresAt","getTime","isExpired","now","init","refresh","sendVerificationEmail","authPost","me","user","id","Am","options","createAuthSession","acceptInvite","checkEmail","csrfSession","csrfToken","login","tokenLogin","token","register","resetPassword","sendMagicLink","sendPasswordReset"],"mappings":"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"}
@@ -0,0 +1,134 @@
1
+ import type { AuthenticationResult, ClientId, EmailCheckStatus, LoginMethod, ProblemDetails, SessionProfile, SessionTokens, UserId, UserResource } from "./types";
2
+ type FetchFn = (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;
3
+ export declare class AuthError extends Error {
4
+ readonly problem: ProblemDetails;
5
+ constructor(problem: ProblemDetails);
6
+ get type(): string;
7
+ get title(): string;
8
+ get status(): number;
9
+ get code(): string | undefined;
10
+ get detail(): string | undefined;
11
+ get invalidParams(): ProblemDetails["invalidParams"] | undefined;
12
+ }
13
+ type Config = {
14
+ fetchFn: FetchFn;
15
+ baseUrl: string;
16
+ };
17
+ export declare class AuthSession {
18
+ private tokens;
19
+ private config;
20
+ private lastUpdated;
21
+ constructor(tokens: SessionTokens, config: Partial<Config>);
22
+ get accessToken(): string;
23
+ get refreshToken(): string;
24
+ get idToken(): string | undefined;
25
+ get tokenType(): "Bearer";
26
+ get expiresIn(): number;
27
+ get lastUpdatedAt(): Date;
28
+ get expiresAt(): Date;
29
+ isExpired(): boolean;
30
+ /**
31
+ * Fetch with automatic token refresh.
32
+ *
33
+ * If the access token is expired, it will be refreshed before making the request. The
34
+ * Authorization header will be set with the current access token.
35
+ */
36
+ fetch(url: string | URL | Request, init?: RequestInit): Promise<Response>;
37
+ refresh(): Promise<void>;
38
+ sendVerificationEmail(): Promise<void>;
39
+ me(): Promise<SessionProfile>;
40
+ user(id: UserId): Promise<UserResource>;
41
+ }
42
+ export declare class Am {
43
+ private options;
44
+ constructor(config?: Partial<Config>);
45
+ static createAuthSession(tokens: SessionTokens, config?: Partial<Config>): AuthSession;
46
+ createAuthSession(tokens: SessionTokens): AuthSession;
47
+ static acceptInvite(query: {
48
+ clientId: ClientId;
49
+ token: string;
50
+ }, config?: Partial<Config>): Promise<AuthenticationResult>;
51
+ acceptInvite(query: {
52
+ clientId: ClientId;
53
+ token: string;
54
+ }): Promise<AuthenticationResult>;
55
+ static checkEmail(body: {
56
+ clientId: ClientId;
57
+ email: string;
58
+ csrfToken?: string;
59
+ }, config?: Partial<Config>): Promise<{
60
+ status: EmailCheckStatus;
61
+ preferred: LoginMethod[];
62
+ available: LoginMethod[];
63
+ }>;
64
+ checkEmail(body: {
65
+ clientId: ClientId;
66
+ email: string;
67
+ csrfToken?: string;
68
+ }): Promise<{
69
+ status: EmailCheckStatus;
70
+ preferred: LoginMethod[];
71
+ available: LoginMethod[];
72
+ }>;
73
+ static csrfSession(config?: Partial<Config>): Promise<{
74
+ csrfToken: string;
75
+ }>;
76
+ csrfSession(): Promise<{
77
+ csrfToken: string;
78
+ }>;
79
+ static csrfToken(config?: Partial<Config>): Promise<{
80
+ csrfToken: string;
81
+ }>;
82
+ csrfToken(): Promise<{
83
+ csrfToken: string;
84
+ }>;
85
+ static login(body: {
86
+ email: string;
87
+ password: string;
88
+ csrfToken?: string;
89
+ }, config?: Partial<Config>): Promise<AuthenticationResult>;
90
+ login(body: {
91
+ email: string;
92
+ password: string;
93
+ csrfToken?: string;
94
+ }): Promise<AuthenticationResult>;
95
+ static tokenLogin(token: string, config?: Partial<Config>): Promise<AuthenticationResult>;
96
+ tokenLogin(token: string): Promise<AuthenticationResult>;
97
+ static refresh(refreshToken: string, config?: Partial<Config>): Promise<SessionTokens>;
98
+ refresh(refreshToken: string): Promise<SessionTokens>;
99
+ static register(body: {
100
+ email: string;
101
+ password: string;
102
+ csrfToken?: string;
103
+ }, config?: Partial<Config>): Promise<AuthenticationResult>;
104
+ register(body: {
105
+ email: string;
106
+ password: string;
107
+ csrfToken?: string;
108
+ }): Promise<AuthenticationResult>;
109
+ static resetPassword(body: {
110
+ token: string;
111
+ newPassword: string;
112
+ }, config?: Partial<Config>): Promise<void>;
113
+ resetPassword(body: {
114
+ token: string;
115
+ newPassword: string;
116
+ }): Promise<void>;
117
+ static sendMagicLink(body: {
118
+ email: string;
119
+ csrfToken?: string;
120
+ }, config?: Partial<Config>): Promise<void>;
121
+ sendMagicLink(body: {
122
+ email: string;
123
+ csrfToken?: string;
124
+ }): Promise<void>;
125
+ static sendPasswordReset(body: {
126
+ email: string;
127
+ csrfToken?: string;
128
+ }, config?: Partial<Config>): Promise<void>;
129
+ sendPasswordReset(body: {
130
+ email: string;
131
+ csrfToken?: string;
132
+ }): Promise<void>;
133
+ }
134
+ export {};
@@ -0,0 +1,2 @@
1
+ export { Am, AuthSession, AuthError } from "./auth";
2
+ export type { AuthenticationResult, ClientId, EmailCheckStatus, LoginMethod, ProblemDetails, SessionProfile, SessionTokens, UserId, UserResource, } from "./types";
@@ -0,0 +1,77 @@
1
+ export type ProblemDetails = {
2
+ type: string;
3
+ title: string;
4
+ status: number;
5
+ code?: string;
6
+ detail?: string;
7
+ invalidParams?: {
8
+ in: "body" | "cookie" | "header" | "query" | "path";
9
+ path: string;
10
+ type: string;
11
+ received: unknown;
12
+ expected?: string;
13
+ }[];
14
+ };
15
+ export type ClientId = `cid${string}`;
16
+ export type UserId = `uid${string}`;
17
+ export type AccountId = `acc${string}`;
18
+ export type MembershipId = `mbr${string}`;
19
+ export type AccountStatus = "active" | "trial" | "past_due" | "suspended" | "closed";
20
+ export type AccountResource = {
21
+ id: AccountId;
22
+ name: string | null;
23
+ avatarUrl: string | null;
24
+ status: AccountStatus;
25
+ paidUntil: string | null;
26
+ };
27
+ export type UserStatus = "active" | "trial" | "past_due" | "suspended" | "closed";
28
+ export type UserResource = {
29
+ id: UserId;
30
+ accountId: AccountId;
31
+ status: UserStatus;
32
+ preferredMembershipId: MembershipId | null;
33
+ };
34
+ export type UserIdentity = {
35
+ id: UserId;
36
+ avatarUrl: string | null;
37
+ externalId: string | null;
38
+ givenName: string | null;
39
+ familyName: string | null;
40
+ displayName: string | null;
41
+ preferredLanguage: string | null;
42
+ locale: string | null;
43
+ timezone: string | null;
44
+ };
45
+ export type MembershipRole = "owner" | "member" | "viewer";
46
+ export type Membership = {
47
+ id: MembershipId;
48
+ userId: UserId;
49
+ accountId: AccountId;
50
+ role: MembershipRole;
51
+ };
52
+ export type EmailCredential = {
53
+ id: string;
54
+ email: string | null;
55
+ hashedEmail: string | null;
56
+ hashedPassword: string | null;
57
+ emailVerifiedAt: string | null;
58
+ };
59
+ export type SessionTokens = {
60
+ accessToken: string;
61
+ refreshToken: string;
62
+ tokenType: "Bearer";
63
+ expiresIn: number;
64
+ idToken?: string;
65
+ };
66
+ export type SessionProfile = UserResource & {
67
+ identity: UserIdentity;
68
+ emailCredentials: EmailCredential[];
69
+ memberships: Membership[];
70
+ activeMembership: Membership | null;
71
+ };
72
+ export type AuthenticationResult = {
73
+ session: SessionTokens;
74
+ profile: SessionProfile;
75
+ };
76
+ export type EmailCheckStatus = "active" | "inactive";
77
+ export type LoginMethod = "email_password" | "magic_link";
package/package.json ADDED
@@ -0,0 +1,56 @@
1
+ {
2
+ "name": "@softwarepatterns/am",
3
+ "version": "0.0.1",
4
+ "description": "Auth client SDK for AccountMaker (Am)",
5
+ "keywords": [
6
+ "authentication",
7
+ "auth",
8
+ "sdk",
9
+ "typescript",
10
+ "oauth",
11
+ "openid-connect",
12
+ "jwt",
13
+ "session-management"
14
+ ],
15
+ "author": "Your Name <info@example.com>",
16
+ "license": "MIT",
17
+ "type": "module",
18
+ "bugs": {
19
+ "url": "https://github.com/softwarepatterns/am/issues"
20
+ },
21
+ "repository": {
22
+ "type": "git",
23
+ "url": "git+https://github.com/softwarepatterns/am.git"
24
+ },
25
+ "homepage": "https://github.com/softwarepatterns/am#readme",
26
+ "sideEffects": false,
27
+ "engines": {
28
+ "node": ">=18"
29
+ },
30
+ "main": "./dist/index.cjs",
31
+ "module": "./dist/index.mjs",
32
+ "types": "./dist/index.d.ts",
33
+ "exports": {
34
+ ".": {
35
+ "types": "./dist/index.d.ts",
36
+ "import": "./dist/index.mjs",
37
+ "require": "./dist/index.cjs"
38
+ }
39
+ },
40
+ "files": [
41
+ "dist"
42
+ ],
43
+ "scripts": {
44
+ "build:clean": "rm -rf dist",
45
+ "build": "npm run build:clean && rollup -c",
46
+ "prepublishOnly": "npm run check",
47
+ "test:unit": "bun test src",
48
+ "test:integration": "NODE_TLS_REJECT_UNAUTHORIZED=0 bun test test/integration",
49
+ "typecheck": "bunx tsc --noEmit",
50
+ "check": "npm run typecheck && npm run build",
51
+ "digest": "bunx ai-digest -i . -o codebase.md --whitespace-removal --show-output-files"
52
+ },
53
+ "publishConfig": {
54
+ "access": "public"
55
+ }
56
+ }