@vuoma/sdk 0.1.0 → 0.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.
package/README.md CHANGED
@@ -4,15 +4,28 @@ Framework-neutral JavaScript and TypeScript client for the existing Vuoma v1
4
4
  public organization and member account APIs. Works with a host-provided Fetch
5
5
  implementation; it imports no React, Svelte, Expo or Supabase runtime. The package
6
6
  does not store credentials, read environment variables, create accounts, or
7
- grant access. This is a local package foundation; registry publication is a
8
- separate step.
7
+ grant access. Install the public package and pin the reviewed version:
8
+
9
+ ```sh
10
+ npm install @vuoma/sdk@0.1.1
11
+ ```
12
+
13
+ Use SvelteKit and SvelteKit UI with `@vuoma/web` for website account components
14
+ and same-origin server sessions. Use React Native for mobile UI and this SDK as
15
+ its framework-neutral API transport. The complete `@vuoma/react-native` studio
16
+ app core remains a private workspace; independent apps do not depend on it.
17
+ The public setup guide is at `/developers` and `/o/<organization_slug>/developers`
18
+ on the same combined Vuoma application and landing-page deployment. The current
19
+ origin is `https://vuoma.vercel.app`; use `https://vuoma.com` only after domain
20
+ cutover and exact-origin configuration have been verified.
9
21
 
10
22
  ```js
11
23
  import { createVuomaClient } from '@vuoma/sdk'
12
24
 
13
25
  const vuoma = createVuomaClient({
14
- apiOrigin: 'http://localhost:5173', // Use your verified Vuoma HTTPS origin in production.
26
+ apiOrigin: 'https://vuoma.vercel.app', // Use your verified Vuoma origin.
15
27
  organizationSlug: 'your-studio',
28
+ appKey: publishableAppKey, // The organization's registered vuoma_pk_ app key.
16
29
  fetch: globalThis.fetch,
17
30
  })
18
31
 
@@ -24,7 +37,12 @@ const schedule = await vuoma.public.getSchedule({
24
37
  })
25
38
  ```
26
39
 
27
- No key is needed for these public reads. Schedule timestamps are normalized to
40
+ The optional `appKey` identifies a registered organization app. Obtain its
41
+ publishable `vuoma_pk_` key from the organization's app registration and use the
42
+ same key for public reads, sign-in, refresh, sign-out and member requests. Public
43
+ reads also work without an app key where the API allows anonymous access. The
44
+ organization slug is a route hint; the server validates the app's organization
45
+ binding. Schedule timestamps are normalized to
28
46
  UTC, and ranges must be positive and at most 63 days. The response preserves
29
47
  `schedule.has_more`; when it is true, split the requested range and fetch each
30
48
  part rather than displaying the first response as a complete schedule.
@@ -39,8 +57,9 @@ server or native host; it does not establish a browser cookie session.
39
57
  ```js
40
58
  let session = null // Example in-memory host state; no SDK persistence.
41
59
  const vuoma = createVuomaClient({
42
- apiOrigin: 'http://localhost:5173',
60
+ apiOrigin: 'https://vuoma.vercel.app',
43
61
  organizationSlug: 'your-studio',
62
+ appKey: publishableAppKey,
44
63
  tokenAdapter: { getSession: () => session },
45
64
  })
46
65
 
@@ -63,6 +82,12 @@ Native, keep refresh tokens in Keychain/Keystore through a secure-storage adapte
63
82
  keep access tokens in memory, and refresh through the documented member route.
64
83
  Refresh scheduling, retries and persistence remain host responsibilities.
65
84
 
85
+ An app-bound member session requires the same active app registration on each
86
+ request. Revoking that registration invalidates its bound sessions. Re-enabling
87
+ or replacing an app key does not restore those sessions: remove the rejected
88
+ session from your host adapter and require a fresh member sign-in. The SDK does
89
+ not retry authorization failures or silently change registrations.
90
+
66
91
  The SDK uses `credentials: 'omit'`, prevents redirects, and sends member access
67
92
  tokens only to its exact configured origin and organization. It rejects missing,
68
93
  expired, cross-organization, platform-account, organization API, identity-only
@@ -80,6 +105,14 @@ the response text and against a supplied Content-Length header.
80
105
 
81
106
  ## Keys and client IDs
82
107
 
108
+ - **Publishable Vuoma app keys** have the exact format `vuoma_pk_` followed by
109
+ 32 lowercase hexadecimal characters. They may be included in an app bundle
110
+ and identify its organization registration. The SDK sends them only in
111
+ `X-Vuoma-App-Key` to its configured origin, never in `Authorization`, a URL
112
+ or a request body. They do not sign a customer in or grant private access;
113
+ member access/refresh tokens and the server's live app/session checks remain
114
+ required. Confidential organization or Supabase service keys are rejected
115
+ as `appKey` values.
83
116
  - **Organization integration/delegated API keys** are confidential server
84
117
  credentials. Never put them in a website bundle, native binary, URL or SDK
85
118
  token adapter. They do not sign a customer in.
@@ -93,9 +126,9 @@ the response text and against a supplied Content-Length header.
93
126
  accepted by this member client.
94
127
 
95
128
  This package adds no OAuth grant, CORS policy or backend permission. A third-party
96
- website still needs its backend adapter. Independent app authorization and
97
- app-scoped member grants are separate platform work; a public app ID alone must
98
- never authorize private account data.
129
+ website still needs its backend adapter. App registration and app-scoped member
130
+ session grants are enforced by the API; a publishable app key alone never
131
+ authorizes private account data.
99
132
 
100
133
  Supported routes are public `/api/v1/o/{slug}/member/{bootstrap,schedule,catalog}`;
101
134
  member sign-in, profile GET/PATCH and commerce GET; plus the existing global
@@ -112,6 +145,6 @@ npm run verify
112
145
  Verification tests the actual wire route/header/session boundaries and creates
113
146
  an installable npm archive under `artifacts/`. It checks the archive's public
114
147
  file list and loads the packed module in an isolated temporary directory.
115
- Nothing is published and no registry authentication is attempted. The inherited
148
+ The verification command does not publish or attempt registry authentication. The inherited
116
149
  license remains `UNLICENSED`; `private: false` prepares packaging without granting
117
150
  open-source licensing rights.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vuoma/sdk",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Framework-neutral client for Vuoma public organization and member account APIs",
5
5
  "type": "module",
6
6
  "private": false,
package/src/index.d.ts CHANGED
@@ -22,6 +22,8 @@ export interface VuomaClientOptions {
22
22
  organizationSlug: string
23
23
  /** Optional stronger client-side tenant check against the member JWT claim. */
24
24
  organizationId?: string
25
+ /** Publishable vuoma_pk_ app identity; private calls still require member auth. */
26
+ appKey?: string
25
27
  fetch?: typeof globalThis.fetch
26
28
  tokenAdapter?: MemberTokenAdapter
27
29
  /** Default 2 MiB; accepted range 1 KiB–16 MiB. */
package/src/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  // Public package: no environment reads, provider clients, persistence or secrets.
2
2
  const slugPattern = /^[a-z0-9]+(?:-[a-z0-9]+)*$/u
3
+ const appKeyPattern = /^vuoma_pk_[0-9a-f]{32}$/u
3
4
  const uuidPattern = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iu
4
5
  const timestampPattern = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})$/u
5
6
  const maximumRange = 63 * 24 * 60 * 60 * 1000
@@ -134,6 +135,8 @@ export function createVuomaClient(options) {
134
135
  if (typeof organizationSlug !== "string" || organizationSlug.length < 2 || organizationSlug.length > 80 || !slugPattern.test(organizationSlug)) throw new TypeError("Use an exact organization slug.")
135
136
  const organizationId = options.organizationId
136
137
  if (organizationId !== undefined && !uuid(organizationId)) throw new TypeError("Use a valid organization ID.")
138
+ const appKey = options.appKey
139
+ if (appKey !== undefined && (typeof appKey !== "string" || !appKeyPattern.test(appKey))) throw new TypeError("Use a publishable Vuoma app key.")
137
140
  const requestFetch = options.fetch ?? globalThis.fetch
138
141
  if (typeof requestFetch !== "function") throw new TypeError("A fetch implementation is required.")
139
142
  const tokenAdapter = options.tokenAdapter
@@ -151,6 +154,7 @@ export function createVuomaClient(options) {
151
154
  const url = new URL(path, origin)
152
155
  if (query) for (const [key, value] of Object.entries(query)) url.searchParams.set(key, value)
153
156
  const headers = { accept: "application/json" }
157
+ if (appKey !== undefined) headers["x-vuoma-app-key"] = appKey
154
158
  if (body !== undefined) headers["content-type"] = "application/json"
155
159
  if (accessToken) headers.authorization = `Bearer ${accessToken}`
156
160
  const response = await requestFetch(url.href, {