@capxul/sdk-react 0.1.0-alpha.6 → 0.1.0-alpha.8
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/CHANGELOG.md +2 -16
- package/README.md +21 -1
- package/dist/index.cjs +50 -3
- package/dist/index.js +50 -3
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @capxul/sdk-react
|
|
2
2
|
|
|
3
|
-
## 0.1.0-alpha.
|
|
3
|
+
## 0.1.0-alpha.8
|
|
4
4
|
|
|
5
5
|
### Minor Changes
|
|
6
6
|
|
|
@@ -32,21 +32,7 @@
|
|
|
32
32
|
### Patch Changes
|
|
33
33
|
|
|
34
34
|
- Updated dependencies [57203a4]
|
|
35
|
-
- @capxul/sdk@0.1.0-alpha.
|
|
36
|
-
|
|
37
|
-
## 0.1.0-alpha.5
|
|
38
|
-
|
|
39
|
-
### Patch Changes
|
|
40
|
-
|
|
41
|
-
- Widen the React peer dependency to `>=18.2.0 <20` so React 18-era Ink 5
|
|
42
|
-
CLI apps can install `@capxul/sdk-react` without forcing React 19 into
|
|
43
|
-
Ink's React reconciler. The provider and hooks only use React 18-compatible
|
|
44
|
-
APIs (`createContext`, `useContext`, `useMemo`, `useEffect`, `useState`, and
|
|
45
|
-
`useSyncExternalStore`), preserving React 19 compatibility while unblocking
|
|
46
|
-
React 18 hosts.
|
|
47
|
-
|
|
48
|
-
- Updated dependencies
|
|
49
|
-
- @capxul/sdk@0.1.0-alpha.5
|
|
35
|
+
- @capxul/sdk@0.1.0-alpha.8
|
|
50
36
|
|
|
51
37
|
## 0.1.0-alpha.4
|
|
52
38
|
|
package/README.md
CHANGED
|
@@ -40,7 +40,12 @@ import { CapxulProvider } from "@capxul/sdk-react";
|
|
|
40
40
|
|
|
41
41
|
export default function RootLayout({ children }) {
|
|
42
42
|
return (
|
|
43
|
-
<CapxulProvider
|
|
43
|
+
<CapxulProvider
|
|
44
|
+
config={{
|
|
45
|
+
mode: "publishable-key",
|
|
46
|
+
publishableKey: process.env.NEXT_PUBLIC_CAPXUL_PUBLISHABLE_KEY!,
|
|
47
|
+
}}
|
|
48
|
+
>
|
|
44
49
|
{children}
|
|
45
50
|
</CapxulProvider>
|
|
46
51
|
);
|
|
@@ -119,6 +124,21 @@ subscription against the transport singleton — only the components
|
|
|
119
124
|
that actually call it re-render when state changes. The provider
|
|
120
125
|
itself never re-renders.
|
|
121
126
|
|
|
127
|
+
## Publishable-key proof status
|
|
128
|
+
|
|
129
|
+
The publishable-key path is runtime-proven where the repo can run it
|
|
130
|
+
without secrets:
|
|
131
|
+
|
|
132
|
+
| Surface | Runtime proof | Expected safe signal |
|
|
133
|
+
|---|---|---|
|
|
134
|
+
| Provider + `useMe()` | `corepack pnpm --filter @capxul/sdk-react check-types` plus the headless proof tests under `packages/sdk-react/ops/proof` | provider reaches `useCapxulStatus().status === "ready"` after one bootstrap request |
|
|
135
|
+
| Reference CLI mock | `corepack pnpm --filter @capxul/reference-cli build && node apps/reference-cli/dist/cli.js bootstrap probe --mock --json` | `ok:true`, `mode:"publishable-key"`, `bootstrapRequests:1`, `authRequests:1`, `keyLengthClass:"provided"` |
|
|
136
|
+
| Reference CLI live | same command without `--mock`, with `CAPXUL_REF_PUBLISHABLE_KEY` and optional `CAPXUL_REF_BOOTSTRAP_URL` set locally | success only when the key/origin/runtime are valid; otherwise sanitized SDK error JSON |
|
|
137
|
+
|
|
138
|
+
Do not paste or commit publishable keys, session tokens, Convex JWTs,
|
|
139
|
+
cookies, or provider payloads. Proof output reports only
|
|
140
|
+
`keyLengthClass`.
|
|
141
|
+
|
|
122
142
|
## Hooks catalogue
|
|
123
143
|
|
|
124
144
|
| Surface | Hook |
|
package/dist/index.cjs
CHANGED
|
@@ -110,7 +110,12 @@ var Errors = {
|
|
|
110
110
|
"Idempotency key was already used for a different request",
|
|
111
111
|
{ details }
|
|
112
112
|
),
|
|
113
|
-
emailDeliveryFailed: (detail) => new CapxulError("EMAIL_DELIVERY_FAILED", `Failed to send email: ${detail}
|
|
113
|
+
emailDeliveryFailed: (detail, details) => new CapxulError("EMAIL_DELIVERY_FAILED", `Failed to send email: ${detail}`, {
|
|
114
|
+
details
|
|
115
|
+
}),
|
|
116
|
+
rateLimited: (details) => new CapxulError("RATE_LIMITED", "Request was rate limited", {
|
|
117
|
+
details: { ...details }
|
|
118
|
+
}),
|
|
114
119
|
internalError: (reason) => new CapxulError("INTERNAL_ERROR", `Internal error: ${reason}`),
|
|
115
120
|
/**
|
|
116
121
|
* Verification gate. Surfaced when a request hits a verification
|
|
@@ -217,6 +222,48 @@ function createReactDataClient(convexUrl, sessionStore) {
|
|
|
217
222
|
}
|
|
218
223
|
};
|
|
219
224
|
}
|
|
225
|
+
function createLazyReactDataClient(transport, sessionStore, createClient = createReactDataClient) {
|
|
226
|
+
let client = null;
|
|
227
|
+
let initializeClient = null;
|
|
228
|
+
let closed = false;
|
|
229
|
+
function closedError() {
|
|
230
|
+
return new Error("Capxul React data client is closed");
|
|
231
|
+
}
|
|
232
|
+
async function getClient() {
|
|
233
|
+
if (closed) throw closedError();
|
|
234
|
+
if (client) return client;
|
|
235
|
+
initializeClient ??= (async () => {
|
|
236
|
+
const runtime = await transport.ensureRuntime();
|
|
237
|
+
if (closed) throw closedError();
|
|
238
|
+
const nextClient = createClient(runtime.convexUrl, sessionStore);
|
|
239
|
+
if (closed) {
|
|
240
|
+
nextClient.close();
|
|
241
|
+
throw closedError();
|
|
242
|
+
}
|
|
243
|
+
client = nextClient;
|
|
244
|
+
return nextClient;
|
|
245
|
+
})().catch((error) => {
|
|
246
|
+
if (!closed) {
|
|
247
|
+
initializeClient = null;
|
|
248
|
+
}
|
|
249
|
+
throw error;
|
|
250
|
+
});
|
|
251
|
+
return initializeClient;
|
|
252
|
+
}
|
|
253
|
+
return {
|
|
254
|
+
query: async (name, args) => (await getClient()).query(name, args),
|
|
255
|
+
mutation: async (name, args) => (await getClient()).mutation(name, args),
|
|
256
|
+
action: async (name, args) => (await getClient()).action?.(name, args),
|
|
257
|
+
refreshAuth: () => {
|
|
258
|
+
client?.refreshAuth();
|
|
259
|
+
},
|
|
260
|
+
close: () => {
|
|
261
|
+
closed = true;
|
|
262
|
+
client?.close();
|
|
263
|
+
client = null;
|
|
264
|
+
}
|
|
265
|
+
};
|
|
266
|
+
}
|
|
220
267
|
function CapxulProvider({
|
|
221
268
|
config,
|
|
222
269
|
sessionStore,
|
|
@@ -246,12 +293,12 @@ function CapxulProvider({
|
|
|
246
293
|
function buildWiring(config, sessionStore) {
|
|
247
294
|
const validated = createCapxulConfig(config);
|
|
248
295
|
const transport = sdk.makeHttpTransport(validated);
|
|
249
|
-
const dataClient = validated.mode === "build-time-urls" ? createReactDataClient(validated.convexUrl, sessionStore) :
|
|
296
|
+
const dataClient = validated.mode === "build-time-urls" ? createReactDataClient(validated.convexUrl, sessionStore) : createLazyReactDataClient(transport, sessionStore);
|
|
250
297
|
const sdkConfig = {
|
|
251
298
|
_transport: transport,
|
|
252
299
|
publishableKey: validated.mode === "publishable-key" ? validated.publishableKey : void 0,
|
|
253
300
|
data: dataClient ?? void 0,
|
|
254
|
-
auth:
|
|
301
|
+
auth: validated.mode === "build-time-urls" || validated.mode === "publishable-key" ? {
|
|
255
302
|
// The auth client builds the BetterAuth root URL from this
|
|
256
303
|
// value. Convex's `.cloud` URL is the wrong host (BetterAuth
|
|
257
304
|
// is mounted on the `.site` URL), but the build-time-urls
|
package/dist/index.js
CHANGED
|
@@ -108,7 +108,12 @@ var Errors = {
|
|
|
108
108
|
"Idempotency key was already used for a different request",
|
|
109
109
|
{ details }
|
|
110
110
|
),
|
|
111
|
-
emailDeliveryFailed: (detail) => new CapxulError("EMAIL_DELIVERY_FAILED", `Failed to send email: ${detail}
|
|
111
|
+
emailDeliveryFailed: (detail, details) => new CapxulError("EMAIL_DELIVERY_FAILED", `Failed to send email: ${detail}`, {
|
|
112
|
+
details
|
|
113
|
+
}),
|
|
114
|
+
rateLimited: (details) => new CapxulError("RATE_LIMITED", "Request was rate limited", {
|
|
115
|
+
details: { ...details }
|
|
116
|
+
}),
|
|
112
117
|
internalError: (reason) => new CapxulError("INTERNAL_ERROR", `Internal error: ${reason}`),
|
|
113
118
|
/**
|
|
114
119
|
* Verification gate. Surfaced when a request hits a verification
|
|
@@ -215,6 +220,48 @@ function createReactDataClient(convexUrl, sessionStore) {
|
|
|
215
220
|
}
|
|
216
221
|
};
|
|
217
222
|
}
|
|
223
|
+
function createLazyReactDataClient(transport, sessionStore, createClient = createReactDataClient) {
|
|
224
|
+
let client = null;
|
|
225
|
+
let initializeClient = null;
|
|
226
|
+
let closed = false;
|
|
227
|
+
function closedError() {
|
|
228
|
+
return new Error("Capxul React data client is closed");
|
|
229
|
+
}
|
|
230
|
+
async function getClient() {
|
|
231
|
+
if (closed) throw closedError();
|
|
232
|
+
if (client) return client;
|
|
233
|
+
initializeClient ??= (async () => {
|
|
234
|
+
const runtime = await transport.ensureRuntime();
|
|
235
|
+
if (closed) throw closedError();
|
|
236
|
+
const nextClient = createClient(runtime.convexUrl, sessionStore);
|
|
237
|
+
if (closed) {
|
|
238
|
+
nextClient.close();
|
|
239
|
+
throw closedError();
|
|
240
|
+
}
|
|
241
|
+
client = nextClient;
|
|
242
|
+
return nextClient;
|
|
243
|
+
})().catch((error) => {
|
|
244
|
+
if (!closed) {
|
|
245
|
+
initializeClient = null;
|
|
246
|
+
}
|
|
247
|
+
throw error;
|
|
248
|
+
});
|
|
249
|
+
return initializeClient;
|
|
250
|
+
}
|
|
251
|
+
return {
|
|
252
|
+
query: async (name, args) => (await getClient()).query(name, args),
|
|
253
|
+
mutation: async (name, args) => (await getClient()).mutation(name, args),
|
|
254
|
+
action: async (name, args) => (await getClient()).action?.(name, args),
|
|
255
|
+
refreshAuth: () => {
|
|
256
|
+
client?.refreshAuth();
|
|
257
|
+
},
|
|
258
|
+
close: () => {
|
|
259
|
+
closed = true;
|
|
260
|
+
client?.close();
|
|
261
|
+
client = null;
|
|
262
|
+
}
|
|
263
|
+
};
|
|
264
|
+
}
|
|
218
265
|
function CapxulProvider({
|
|
219
266
|
config,
|
|
220
267
|
sessionStore,
|
|
@@ -244,12 +291,12 @@ function CapxulProvider({
|
|
|
244
291
|
function buildWiring(config, sessionStore) {
|
|
245
292
|
const validated = createCapxulConfig(config);
|
|
246
293
|
const transport = makeHttpTransport(validated);
|
|
247
|
-
const dataClient = validated.mode === "build-time-urls" ? createReactDataClient(validated.convexUrl, sessionStore) :
|
|
294
|
+
const dataClient = validated.mode === "build-time-urls" ? createReactDataClient(validated.convexUrl, sessionStore) : createLazyReactDataClient(transport, sessionStore);
|
|
248
295
|
const sdkConfig = {
|
|
249
296
|
_transport: transport,
|
|
250
297
|
publishableKey: validated.mode === "publishable-key" ? validated.publishableKey : void 0,
|
|
251
298
|
data: dataClient ?? void 0,
|
|
252
|
-
auth:
|
|
299
|
+
auth: validated.mode === "build-time-urls" || validated.mode === "publishable-key" ? {
|
|
253
300
|
// The auth client builds the BetterAuth root URL from this
|
|
254
301
|
// value. Convex's `.cloud` URL is the wrong host (BetterAuth
|
|
255
302
|
// is mounted on the `.site` URL), but the build-time-urls
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@capxul/sdk-react",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.8",
|
|
4
4
|
"description": "React provider + hooks for the @capxul/sdk headless client.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"private": false,
|
|
@@ -46,13 +46,13 @@
|
|
|
46
46
|
"access": "public"
|
|
47
47
|
},
|
|
48
48
|
"dependencies": {
|
|
49
|
-
"@capxul/sdk": "0.1.0-alpha.
|
|
49
|
+
"@capxul/sdk": "0.1.0-alpha.8"
|
|
50
50
|
},
|
|
51
51
|
"peerDependencies": {
|
|
52
52
|
"@tanstack/react-query": "^5",
|
|
53
53
|
"@xstate/react": "^5",
|
|
54
54
|
"convex": ">=1.0.0",
|
|
55
|
-
"react": ">=
|
|
55
|
+
"react": ">=19.0.0",
|
|
56
56
|
"viem": ">=2.0.0"
|
|
57
57
|
},
|
|
58
58
|
"devDependencies": {
|