@de./sdk 2.1.0 → 2.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.
@@ -1,3 +1,4 @@
1
+ import type { SigninBody, CreateAccountBody, VerificationBody } from '@de./types'
1
2
  import type { AccessOptions, UserSession } from '../../types/access'
2
3
  import AccessManager from '../Access'
3
4
  import { qs, type Res } from '../../utils'
@@ -16,15 +17,23 @@ import { qs, type Res } from '../../utils'
16
17
  // single method it had could never succeed. Route shapes are taken from
17
18
  // de.auth/src/routes/{auth,user}/index.ts.
18
19
  //
20
+ // The paths now say what they do — `/auth/otp/send` rather than `/signin`,
21
+ // which sent a code and signed nobody in. The method names here are kept as
22
+ // they were: `signin` is what a caller is doing, even when what it costs is
23
+ // one SMS.
24
+ //
19
25
  // ─────────────────────────────────────────────────────────────────────────────
20
26
 
21
- export type SigninBody = {
22
- phone: string
23
- /** Device fingerprint — an object or its JSON string. */
24
- device: string | Record<string, any>
25
- /** ISO 3166-1 alpha-2. */
26
- country?: string
27
- }
27
+ /**
28
+ * Request bodies come from `@de./types`, which is what de.auth validates
29
+ * against — these were hand-declared here, and said `country?: string` where
30
+ * de.auth wants the Country OBJECT. Its schema is additionalProperties:false,
31
+ * so a caller trusting the SDK's type was answered `body/country must be
32
+ * object`. Nothing caught it because this client could not be constructed at
33
+ * all: AccessManager demanded a workspace context and a bearer token, which
34
+ * sign-in is what produces.
35
+ */
36
+ export type { SigninBody, CreateAccountBody, VerificationBody, Country } from '@de./types'
28
37
 
29
38
  export type SigninResult = {
30
39
  /** What the caller must do next — verification, or account creation first. */
@@ -38,17 +47,6 @@ export type SigninResult = {
38
47
  testVCode?: number
39
48
  }
40
49
 
41
- export type CreateAccountBody = {
42
- phone: string
43
- agreeTerms: boolean | string
44
- firstName?: string
45
- lastName?: string
46
- photo?: string
47
- type?: string
48
- country?: string
49
- newsletters?: boolean | string
50
- }
51
-
52
50
  export type VerifyResult = {
53
51
  ctoken?: string
54
52
  deviceId?: string
@@ -57,7 +55,17 @@ export type VerifyResult = {
57
55
 
58
56
  export default class OTPAuth extends AccessManager {
59
57
  constructor( access: AccessOptions ){
60
- super( access, 'ASI' )
58
+ /**
59
+ * de.auth admits an agent that does not start with `De.service` only if
60
+ * the request carries an Authorization header — and the whole point of
61
+ * this client is the flow that has no token yet. The SDK's default
62
+ * platform is `proxy`, so every sign-in through it was answered 412
63
+ * before reaching a handler.
64
+ *
65
+ * `service` is the platform this client is for; a caller that knows
66
+ * better can still say so.
67
+ */
68
+ super({ ...access, platform: access.platform || 'service' }, 'ASI' )
61
69
  }
62
70
 
63
71
  // ── Sign-in ───────────────────────────────────────────────────────────────
@@ -66,26 +74,26 @@ export default class OTPAuth extends AccessManager {
66
74
  async signin( body: SigninBody ): Promise<Res<SigninResult>> {
67
75
  if( !body.phone ) throw new Error('<phone> argument required')
68
76
 
69
- return this.request<Res<SigninResult>>({ url: '/signin', method: 'POST', body })
77
+ return this.request<Res<SigninResult>>({ url: '/auth/otp/send', method: 'POST', body })
70
78
  }
71
79
 
72
80
  /** Step 2 — exchanges the code for a session. */
73
81
  async verify( body: { phone: string, pvc: number, new_phone?: string }): Promise<Res<VerifyResult>> {
74
- return this.request<Res<VerifyResult>>({ url: '/verification', method: 'POST', body })
82
+ return this.request<Res<VerifyResult>>({ url: '/auth/otp/verify', method: 'POST', body })
75
83
  }
76
84
 
77
85
  /** Step 1a — for a phone de.auth has never seen. */
78
86
  async setAccount( body: CreateAccountBody ): Promise<Res<{ next: string }>> {
79
- return this.request<Res<{ next: string }>>({ url: '/set-account', method: 'POST', body })
87
+ return this.request<Res<{ next: string }>>({ url: '/auth/account/create', method: 'POST', body })
80
88
  }
81
89
 
82
90
  async resendSms( body: { phone: string }): Promise<Res<void>> {
83
- return this.request<Res<void>>({ url: '/resend/sms', method: 'POST', body })
91
+ return this.request<Res<void>>({ url: '/auth/otp/resend', method: 'POST', body })
84
92
  }
85
93
 
86
- /** GET, with the scope in the querystring — not a POST. */
94
+ /** A state change, so a POST — it was a GET, which is cacheable. */
87
95
  async signout( querystring?: { allDevices?: boolean | string }): Promise<Res<void>> {
88
- return this.request<Res<void>>({ url: `/signout${qs( querystring )}`, method: 'GET' })
96
+ return this.request<Res<void>>({ url: `/auth/session/revoke${qs( querystring )}`, method: 'POST' })
89
97
  }
90
98
 
91
99
  // ── The signed-in person ──────────────────────────────────────────────────
@@ -21,16 +21,35 @@ export type Res<T = any> = { error: boolean, status?: string, message?: string,
21
21
  */
22
22
  export type Data<T> = 'data' extends keyof T ? T['data'] : undefined
23
23
 
24
+ /**
25
+ * Serialize a querystring for a De. route.
26
+ *
27
+ * Array values are appended as repeated keys — `state=A&state=B` — which is
28
+ * what Fastify's query parser turns back into an array. `String( value )` on
29
+ * an array produces `A,B`, a single comma-joined string, and the route answers
30
+ * `querystring/state must be array`: the schema is right, the request never
31
+ * matched it. Every array parameter the SDK sent was malformed this way, the
32
+ * same shape of fault as the coordinates object that once serialized to
33
+ * `[object Object]`.
34
+ *
35
+ * @param params - Query parameters; null and undefined values are dropped
36
+ * @return - `?a=1&b=2`, or an empty string when there is nothing to send
37
+ */
24
38
  export const qs = ( params?: Record<string, any> ): string => {
25
39
  if( !params ) return ''
26
- const q = new URLSearchParams(
27
- Object.fromEntries(
28
- Object.entries( params )
29
- .filter( ( [, v] ) => v != null )
30
- .map( ( [k, v] ) => [k, String( v )] )
31
- )
32
- ).toString()
33
- return q ? `?${q}` : ''
40
+
41
+ const q = new URLSearchParams()
42
+
43
+ for( const [ key, value ] of Object.entries( params ) ){
44
+ if( value === null || value === undefined ) continue
45
+
46
+ Array.isArray( value )
47
+ ? value.forEach( each => each !== null && each !== undefined && q.append( key, String( each ) ) )
48
+ : q.append( key, String( value ) )
49
+ }
50
+
51
+ const query = q.toString()
52
+ return query ? `?${query}` : ''
34
53
  }
35
54
 
36
55
  export default { Stream }