@softwarepatterns/am 0.0.1 → 0.0.2

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.
@@ -1,3 +1,34 @@
1
+ /**
2
+ * Standard error object following RFC 7807 (Problem Details for HTTP APIs).
3
+ *
4
+ * Returned in AuthError.problem when the server responds with application/problem+json.
5
+ *
6
+ * - `type`: A URI reference that identifies the problem type. Often links to human-readable documentation.
7
+ * - `title`: A short, human-readable summary of the problem type.
8
+ * - `status`: The HTTP status code.
9
+ * - `code`: Application-specific error code for programmatic handling. Maps to the final part of the error type.
10
+ * - `detail`: Human-readable explanation specific to this occurrence. Do not rely on this for programmatic handling.
11
+ * - `invalidParams`: Present on validation errors (typically 400). Provides field-level details
12
+ * for building precise UI feedback and can be used for programmatic handling. Each entry includes:
13
+ * - `in`: Location of the invalid parameter (body, cookie, header, query, path).
14
+ * - `path`: Dot-separated path to the invalid parameter.
15
+ * - `type`: Error type code for this parameter (e.g. "required", "email", "min_length").
16
+ * - `received`: The actual value received.
17
+ * - `expected`: (optional) Description of the expected value.
18
+ *
19
+ * @example
20
+ * ```ts
21
+ * catch (e) {
22
+ * if (e instanceof AuthError && e.invalidParams) {
23
+ * const errors = e.invalidParams.reduce((acc, p) => {
24
+ * acc[p.path] = p.type;
25
+ * return acc;
26
+ * }, {} as Record<string, string>);
27
+ * setFieldErrors(errors);
28
+ * }
29
+ * }
30
+ * ```
31
+ */
1
32
  export type ProblemDetails = {
2
33
  type: string;
3
34
  title: string;
@@ -12,36 +43,97 @@ export type ProblemDetails = {
12
43
  expected?: string;
13
44
  }[];
14
45
  };
46
+ /**
47
+ * Opaque identifier for a client application.
48
+ *
49
+ * Used to look up client-specific settings on how authentication should be handled.
50
+ *
51
+ * All client-specific operations (invites, branding, rate limits) are scoped to a ClientId.
52
+ */
15
53
  export type ClientId = `cid${string}`;
54
+ /** Identifier for a user. */
16
55
  export type UserId = `uid${string}`;
56
+ /** Identifier for an account (i.e., a billable entity). */
17
57
  export type AccountId = `acc${string}`;
58
+ /** Identifier for a membership linking a user to an account. */
18
59
  export type MembershipId = `mbr${string}`;
60
+ /**
61
+ * Possible statuses for an account.
62
+ *
63
+ * - active: Normal operation
64
+ * - trial: In trial period
65
+ * - past_due: Payment failed but grace period active
66
+ * - suspended: Access restricted due to billing or policy
67
+ * - closed: Permanently closed
68
+ */
19
69
  export type AccountStatus = "active" | "trial" | "past_due" | "suspended" | "closed";
70
+ /**
71
+ * Accounts are billable entities that can access resources. Users are linked to accounts via memberships with roles.
72
+ *
73
+ * An account with subaccounts is acting as a tenant, and is used to create services with their own billing,
74
+ * accounts, users, memberships, etc. This is useful for SaaS platforms that want to offer isolated environments
75
+ * for different customers, and to allow reselling of their services to other SaaS providers.
76
+ *
77
+ * For example, an email service lets customers sign up. However, some customers want to offer
78
+ * email services to their own clients. Therefore, the email provider has an account for each customer, and those
79
+ * customers have accounts for their own clients as well. Each level is isolated, with separate billing and users.
80
+ */
20
81
  export type AccountResource = {
21
82
  id: AccountId;
83
+ /** Display name chosen by the account owner */
22
84
  name: string | null;
85
+ /** URL to the account's avatar image */
23
86
  avatarUrl: string | null;
87
+ /** Current account status */
24
88
  status: AccountStatus;
89
+ /** ISO 8601 timestamp until which the account is paid (null if never paid or closed) */
25
90
  paidUntil: string | null;
26
91
  };
92
+ /**
93
+ * Possible statuses for a user.
94
+ *
95
+ * - active: Normal operation
96
+ * - trial: In trial period
97
+ * - past_due: Payment failed but grace period active
98
+ * - suspended: Access restricted due to billing or policy
99
+ * - closed: Permanently closed
100
+ */
27
101
  export type UserStatus = "active" | "trial" | "past_due" | "suspended" | "closed";
102
+ /**
103
+ * A reference to a user. Will not be deleted even due to GDPR requests or account closures,
104
+ * to maintain referential integrity in audit logs and historical records.
105
+ */
28
106
  export type UserResource = {
29
107
  id: UserId;
30
108
  accountId: AccountId;
31
109
  status: UserStatus;
32
110
  preferredMembershipId: MembershipId | null;
33
111
  };
112
+ /**
113
+ * Personal identity information (PII) for a user. Will be deleted due to GDPR requests or account
114
+ * closures to respect legal requirements of various regions..
115
+ */
34
116
  export type UserIdentity = {
35
117
  id: UserId;
36
118
  avatarUrl: string | null;
119
+ /** External identifier from third-party provider (i.e., SCIM) */
37
120
  externalId: string | null;
38
121
  givenName: string | null;
39
122
  familyName: string | null;
40
123
  displayName: string | null;
124
+ /** Preferred language code (en-CA, fr-FR, zh-CN, etc.) */
41
125
  preferredLanguage: string | null;
126
+ /** Locale code (e.g., "en-US") */
42
127
  locale: string | null;
43
128
  timezone: string | null;
44
129
  };
130
+ /**
131
+ * Roles within an account membership.
132
+ *
133
+ * - owner: Full administrative access, may perform destructive actions.
134
+ * - member: Standard non-destructive access
135
+ * - viewer: Read-only access
136
+ */
45
137
  export type MembershipRole = "owner" | "member" | "viewer";
46
138
  export type Membership = {
47
139
  id: MembershipId;
@@ -49,29 +141,68 @@ export type Membership = {
49
141
  accountId: AccountId;
50
142
  role: MembershipRole;
51
143
  };
144
+ /**
145
+ * Email credential record attached to a user.
146
+ *
147
+ * Sensitive fields (email) are only included when explicitly requested
148
+ * or when the caller has appropriate permissions.
149
+ */
52
150
  export type EmailCredential = {
53
151
  id: string;
54
152
  email: string | null;
55
- hashedEmail: string | null;
56
- hashedPassword: string | null;
57
153
  emailVerifiedAt: string | null;
58
154
  };
59
155
  export type SessionTokens = {
156
+ /** Signed JWT access token for authenticating API requests */
60
157
  accessToken: string;
158
+ /** Opaque refresh token for obtaining new access tokens */
61
159
  refreshToken: string;
62
160
  tokenType: "Bearer";
161
+ /** Seconds until the access token expires from time of issuance */
63
162
  expiresIn: number;
64
163
  idToken?: string;
164
+ /** Absolute expiration time (milliseconds since epoch) set by the client library */
165
+ expiresAt: number;
65
166
  };
167
+ /**
168
+ * Complete profile of the currently authenticated user.
169
+ *
170
+ * Combines basic user data with identity, credentials, memberships, and freshness timestamp.
171
+ *
172
+ * `lastUpdatedAt` is updated whenever the profile is fetched from the server.
173
+ */
66
174
  export type SessionProfile = UserResource & {
67
- identity: UserIdentity;
175
+ identity: UserIdentity | null;
68
176
  emailCredentials: EmailCredential[];
69
177
  memberships: Membership[];
178
+ /** Currently active membership in the accessToken (determined by preferredMembershipId or context) */
70
179
  activeMembership: Membership | null;
180
+ lastUpdatedAt: number;
71
181
  };
72
- export type AuthenticationResult = {
73
- session: SessionTokens;
74
- profile: SessionProfile;
182
+ /**
183
+ * Combined authentication state containing tokens and optional profile.
184
+ */
185
+ export type Authentication = {
186
+ tokens: SessionTokens;
187
+ profile: SessionProfile | null;
75
188
  };
189
+ /**
190
+ * Result of checkEmail() indicating whether the email is registered.
191
+ */
76
192
  export type EmailCheckStatus = "active" | "inactive";
193
+ /**
194
+ * Supported login methods for an email address.
195
+ *
196
+ * Currently limited to email/password and magic link flows.
197
+ */
77
198
  export type LoginMethod = "email_password" | "magic_link";
199
+ /**
200
+ * Minimal storage interface required for session persistence.
201
+ *
202
+ * Compatible with localStorage, sessionStorage, AsyncStorage (React Native), or any custom implementation.
203
+ */
204
+ export type StorageLike = {
205
+ getItem(key: string): string | null;
206
+ setItem(key: string, value: string): void;
207
+ removeItem(key: string): void;
208
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@softwarepatterns/am",
3
- "version": "0.0.1",
3
+ "version": "0.0.2",
4
4
  "description": "Auth client SDK for AccountMaker (Am)",
5
5
  "keywords": [
6
6
  "authentication",