@vuoma/sdk 0.2.0 → 0.2.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.
- package/README.md +10 -4
- package/package.json +1 -1
- package/src/index.d.ts +1 -1
- package/src/index.js +5 -4
- package/src/member-contracts.js +1 -1
package/README.md
CHANGED
|
@@ -10,11 +10,11 @@ Install the public package in your own application; access to Vuoma's private
|
|
|
10
10
|
repository is not required:
|
|
11
11
|
|
|
12
12
|
```sh
|
|
13
|
-
npm install @vuoma/sdk@0.2.
|
|
13
|
+
npm install @vuoma/sdk@0.2.2
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
-
Use SvelteKit and SvelteKit UI with `@vuoma/
|
|
17
|
-
and same-origin server sessions. Use `@vuoma/native-ui` for React Native account and booking UI and this SDK as
|
|
16
|
+
Use SvelteKit and SvelteKit UI with `@vuoma/svelte` for website account components
|
|
17
|
+
and same-origin server sessions. Use `@vuoma/react-native-ui` for React Native account and booking UI and this SDK as
|
|
18
18
|
its framework-neutral API transport. The complete `@vuoma/react-native` studio
|
|
19
19
|
app core remains a private workspace; independent apps do not depend on it.
|
|
20
20
|
The public setup guide is at `/developers` and `/o/<organization_slug>/developers`
|
|
@@ -42,6 +42,11 @@ The organization slug is public routing configuration, built into each studio ap
|
|
|
42
42
|
Sign-in authenticates a person for that studio. Private calls require their bearer
|
|
43
43
|
token; the server verifies the live session, studio membership and permissions.
|
|
44
44
|
Public schedule and catalog reads need no registration or app key.
|
|
45
|
+
Use `getCatalog({ includeUnavailable: true })` to show published memberships and
|
|
46
|
+
prices before online checkout is enabled. `purchases_available` remains the
|
|
47
|
+
checkout-readiness signal; a displayed offer never authorizes a purchase. This
|
|
48
|
+
option is explicit so existing clients retain their established empty-catalog
|
|
49
|
+
response while checkout is unavailable.
|
|
45
50
|
Schedule timestamps are normalized to
|
|
46
51
|
UTC, and ranges must be positive and at most 63 days. The response preserves
|
|
47
52
|
`schedule.has_more`; when it is true, split the requested range and fetch each
|
|
@@ -102,7 +107,8 @@ the response text and against a supplied Content-Length header.
|
|
|
102
107
|
## Signup, activation and password reset
|
|
103
108
|
|
|
104
109
|
Email confirmation and password creation stay within the host UI; the person
|
|
105
|
-
reads the
|
|
110
|
+
reads the complete code in their email app. The client accepts the supported
|
|
111
|
+
six- and eight-digit codes and preserves leading zeroes. No access token, cookie or API key
|
|
106
112
|
is sent by these methods. For new or automatically resolved accounts, collect a
|
|
107
113
|
display name. Choose `auto` to let verified email ownership resolve a new profile,
|
|
108
114
|
an imported profile or an existing studio account; `activate` performs the same
|
package/package.json
CHANGED
package/src/index.d.ts
CHANGED
|
@@ -161,7 +161,7 @@ export interface VuomaClient {
|
|
|
161
161
|
getBookingCatalog(options?: RequestOptions): Promise<MemberBookingCatalog>
|
|
162
162
|
/** One half-open range, up to 14 days. Split when has_more is true. */
|
|
163
163
|
getAppointmentAvailability(options: RequestOptions & { from: string; to: string }): Promise<MemberPublicAvailability>
|
|
164
|
-
getCatalog(options?: RequestOptions & { includeCreditPurchases?: boolean }): Promise<MemberPublicCatalog>
|
|
164
|
+
getCatalog(options?: RequestOptions & { includeCreditPurchases?: boolean; includeUnavailable?: boolean }): Promise<MemberPublicCatalog>
|
|
165
165
|
}
|
|
166
166
|
readonly auth: {
|
|
167
167
|
requestAccountCode(options: MemberAccountCodeRequest): Promise<{ ok: true; mode: 'signup' | 'recovery'; requires_email_code: true }>
|
package/src/index.js
CHANGED
|
@@ -103,8 +103,7 @@ function catalog(value) {
|
|
|
103
103
|
envelope(value)
|
|
104
104
|
if (!timestamp(value.generated_at) || typeof value.purchases_available !== "boolean" ||
|
|
105
105
|
!object(value.catalog) || !Array.isArray(value.catalog.offers) || value.catalog.offers.length > 100 ||
|
|
106
|
-
value.catalog.offers.some(offer => !object(offer) || !uuid(offer.id) || typeof offer.name !== "string" || !Array.isArray(offer.prices) || offer.prices.some(price => !object(price)))
|
|
107
|
-
(!value.purchases_available && value.catalog.offers.length)) throw invalidResponse()
|
|
106
|
+
value.catalog.offers.some(offer => !object(offer) || !uuid(offer.id) || typeof offer.name !== "string" || !Array.isArray(offer.prices) || offer.prices.some(price => !object(price)))) throw invalidResponse()
|
|
108
107
|
return value
|
|
109
108
|
}
|
|
110
109
|
|
|
@@ -256,8 +255,10 @@ export function createVuomaClient(options) {
|
|
|
256
255
|
const range = availabilityRange({ from, to })
|
|
257
256
|
return checked(await request(`${memberRoot}/availability`, { query: range, signal }), value => validAvailability(value, range))
|
|
258
257
|
},
|
|
259
|
-
async getCatalog({ includeCreditPurchases = false, signal } = {}) {
|
|
260
|
-
|
|
258
|
+
async getCatalog({ includeCreditPurchases = false, includeUnavailable = false, signal } = {}) {
|
|
259
|
+
const query = { ...(includeCreditPurchases ? { include_credit_purchases: "true" } : {}),
|
|
260
|
+
...(includeUnavailable ? { include_unavailable: "true" } : {}) }
|
|
261
|
+
return catalog(await request(`${memberRoot}/catalog`, { signal, query }))
|
|
261
262
|
},
|
|
262
263
|
}),
|
|
263
264
|
auth: Object.freeze({
|
package/src/member-contracts.js
CHANGED
|
@@ -90,7 +90,7 @@ export function accountInput({ mode, email, signupIntent }) {
|
|
|
90
90
|
if (mode === 'signup') check(['new', 'migrate', 'auto', 'activate'].includes(signupIntent), 'Choose a signup intent explicitly.')
|
|
91
91
|
}
|
|
92
92
|
export function displayName(value) { check(text(value, 160, 1) && Boolean(value.trim()) && !/[\u0000-\u001f\u007f]/u.test(value), 'Provide a display name.'); return value }
|
|
93
|
-
export function emailCode(value) { check(typeof value === 'string' &&
|
|
93
|
+
export function emailCode(value) { check(typeof value === 'string' && /^(?:\d{6}|\d{8})$/u.test(value.trim()), 'Provide the email code from your message.'); return value.trim() }
|
|
94
94
|
export function validCapability(value) { return typeof value === 'string' && /^[A-Za-z0-9_-]{43}$/u.test(value) }
|
|
95
95
|
export function accountResolution(value) {
|
|
96
96
|
check(object(value) && ['existing_account', 'existing_profile', 'new_profile'].includes(value.kind) && text(value.display_name, 160, 1) && Boolean(value.display_name.trim()) && !/[\u0000-\u001f\u007f]/u.test(value.display_name) && text(value.masked_email, 320) && /^[^@\s*]\*{3}@[^@\s*]\*{3}(?:\.[a-z0-9.-]+)?$/iu.test(value.masked_email) && (value.masked_phone === null || /^\*{3} \*{3} [0-9]{4}$/u.test(value.masked_phone ?? '')))
|