@gp2f/client-sdk 1.0.0 → 1.0.3
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 +114 -0
- package/dist/index.js +10 -6
- package/package.json +8 -2
- package/src/index.ts +10 -6
package/README.md
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# @gp2f/client-sdk
|
|
2
|
+
|
|
3
|
+
GP2F client SDK – reconciliation UX components and WebSocket client.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
This SDK provides React components for opportunistic UI state reconciliation, along with a WebSocket client that directly interacts with the GP2F backend server using CRDTs. It is designed to create collaborative, real-time shared experiences seamlessly.
|
|
7
|
+
|
|
8
|
+
## Installation
|
|
9
|
+
```bash
|
|
10
|
+
npm install @gp2f/client-sdk
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
### 1. WebSocket Client (`Gp2fClient`)
|
|
16
|
+
The client provides robust sync over WebSockets with built-in Token Bucket rate-limiting and time-offset tracking.
|
|
17
|
+
|
|
18
|
+
```typescript
|
|
19
|
+
import { Gp2fClient } from '@gp2f/client-sdk';
|
|
20
|
+
|
|
21
|
+
const client = new Gp2fClient({
|
|
22
|
+
url: 'ws://localhost:3000/ws',
|
|
23
|
+
onMessage: (msg) => {
|
|
24
|
+
console.log('Received from server:', msg);
|
|
25
|
+
},
|
|
26
|
+
onToken: (token, done) => {
|
|
27
|
+
// Helpful for streaming AI responses ("Time to First Token")
|
|
28
|
+
console.log(`Token: ${token}, Done: ${done}`);
|
|
29
|
+
},
|
|
30
|
+
onReloadRequired: (version, reason) => {
|
|
31
|
+
console.warn(`Incompatible AST schema (${version}): ${reason}`);
|
|
32
|
+
window.location.reload();
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
client.connect();
|
|
37
|
+
|
|
38
|
+
// Send messages (automatically rate-limited)
|
|
39
|
+
client.send({
|
|
40
|
+
type: 'SYNC',
|
|
41
|
+
payload: { /* ... */ }
|
|
42
|
+
});
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### 2. Optimistic Updates
|
|
46
|
+
Visual indication for optimistic updates or LLM loading limits.
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
import { applyOptimisticUpdate } from '@gp2f/client-sdk';
|
|
50
|
+
|
|
51
|
+
const container = document.getElementById('my-loader-div');
|
|
52
|
+
|
|
53
|
+
// Shows a shimmering skeleton loader
|
|
54
|
+
const cleanup = applyOptimisticUpdate({
|
|
55
|
+
container,
|
|
56
|
+
confidence: 0.8, // >= 0.7 triggers high-confidence skeleton loader
|
|
57
|
+
thinkingText: "Vibe checking..."
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
// Later, when the update completes:
|
|
61
|
+
cleanup();
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### 3. React Components
|
|
65
|
+
The SDK ships with React components to handle state conflicts and reconciliation UX:
|
|
66
|
+
|
|
67
|
+
```tsx
|
|
68
|
+
import React from 'react';
|
|
69
|
+
import { ReconciliationBanner, UndoButton, MergeModal } from '@gp2f/client-sdk';
|
|
70
|
+
|
|
71
|
+
export function EditorHeader() {
|
|
72
|
+
return (
|
|
73
|
+
<header>
|
|
74
|
+
{/* Banner handles showing connection states and sync issues */}
|
|
75
|
+
<ReconciliationBanner
|
|
76
|
+
status="conflict"
|
|
77
|
+
onResolve={() => console.log('Resolve clicked')}
|
|
78
|
+
/>
|
|
79
|
+
|
|
80
|
+
{/* Undo integration */}
|
|
81
|
+
<UndoButton
|
|
82
|
+
canUndo={true}
|
|
83
|
+
onUndo={() => console.log('Undo triggered!')}
|
|
84
|
+
/>
|
|
85
|
+
</header>
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### 4. Lazy Policy Evaluation (WASM Engine)
|
|
91
|
+
Load the fast WASM policy engine dynamically when needed without blocking the main thread.
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
import { loadPolicyEngine } from '@gp2f/client-sdk';
|
|
95
|
+
|
|
96
|
+
async function checkPolicy(state: any, ast: any) {
|
|
97
|
+
const engine = await loadPolicyEngine();
|
|
98
|
+
const { result } = engine.evaluate(
|
|
99
|
+
JSON.stringify(state),
|
|
100
|
+
JSON.stringify(ast)
|
|
101
|
+
);
|
|
102
|
+
return result;
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Peer Dependencies
|
|
107
|
+
Please note that you'll need `react` and `react-dom` version `>=18.0.0` installed in your host project.
|
|
108
|
+
|
|
109
|
+
## Scripts
|
|
110
|
+
- **Build**: `npm run build`
|
|
111
|
+
- **Test**: `npm run test`
|
|
112
|
+
|
|
113
|
+
## License
|
|
114
|
+
MIT
|
package/dist/index.js
CHANGED
|
@@ -32,13 +32,17 @@ let _policyEngineCache = null;
|
|
|
32
32
|
* to emit this as a separate chunk so it is only downloaded on demand.
|
|
33
33
|
*/
|
|
34
34
|
async function _importPolicyEngine() {
|
|
35
|
-
//
|
|
36
|
-
//
|
|
37
|
-
//
|
|
35
|
+
// We intentionally defeat static import analysis by building the specifier
|
|
36
|
+
// at runtime. Vite / Rollup / webpack resolve bare string literals in
|
|
37
|
+
// dynamic imports at *build time*, before any try/catch can help. A computed
|
|
38
|
+
// expression is invisible to those static passes, so the try/catch below
|
|
39
|
+
// actually runs at runtime when the package is absent.
|
|
40
|
+
//
|
|
41
|
+
// If @gp2f/policy-core-wasm IS installed, this resolves normally.
|
|
42
|
+
// If it is NOT installed, the runtime import() throws and we return the stub.
|
|
43
|
+
const specifier = /* @vite-ignore */ "@gp2f/" + "policy-core-wasm";
|
|
38
44
|
try {
|
|
39
|
-
|
|
40
|
-
// that may not be installed. The try/catch below handles the absence case.
|
|
41
|
-
const mod = await import(/* webpackChunkName: "policy-engine" */ "@gp2f/policy-core-wasm");
|
|
45
|
+
const mod = await import(/* @vite-ignore */ specifier);
|
|
42
46
|
return mod;
|
|
43
47
|
}
|
|
44
48
|
catch {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gp2f/client-sdk",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"description": "GP2F client SDK – reconciliation UX components and WebSocket client",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -28,7 +28,13 @@
|
|
|
28
28
|
"license": "MIT",
|
|
29
29
|
"peerDependencies": {
|
|
30
30
|
"react": ">=18.0.0",
|
|
31
|
-
"react-dom": ">=18.0.0"
|
|
31
|
+
"react-dom": ">=18.0.0",
|
|
32
|
+
"@gp2f/policy-core-wasm": "*"
|
|
33
|
+
},
|
|
34
|
+
"peerDependenciesMeta": {
|
|
35
|
+
"@gp2f/policy-core-wasm": {
|
|
36
|
+
"optional": true
|
|
37
|
+
}
|
|
32
38
|
},
|
|
33
39
|
"devDependencies": {
|
|
34
40
|
"@types/react": "^18.0.0",
|
package/src/index.ts
CHANGED
|
@@ -69,13 +69,17 @@ let _policyEngineCache: PolicyEngineModule | null = null;
|
|
|
69
69
|
* to emit this as a separate chunk so it is only downloaded on demand.
|
|
70
70
|
*/
|
|
71
71
|
async function _importPolicyEngine(): Promise<PolicyEngineModule> {
|
|
72
|
-
//
|
|
73
|
-
//
|
|
74
|
-
//
|
|
72
|
+
// We intentionally defeat static import analysis by building the specifier
|
|
73
|
+
// at runtime. Vite / Rollup / webpack resolve bare string literals in
|
|
74
|
+
// dynamic imports at *build time*, before any try/catch can help. A computed
|
|
75
|
+
// expression is invisible to those static passes, so the try/catch below
|
|
76
|
+
// actually runs at runtime when the package is absent.
|
|
77
|
+
//
|
|
78
|
+
// If @gp2f/policy-core-wasm IS installed, this resolves normally.
|
|
79
|
+
// If it is NOT installed, the runtime import() throws and we return the stub.
|
|
80
|
+
const specifier = /* @vite-ignore */ "@gp2f/" + "policy-core-wasm";
|
|
75
81
|
try {
|
|
76
|
-
|
|
77
|
-
// that may not be installed. The try/catch below handles the absence case.
|
|
78
|
-
const mod = await import(/* webpackChunkName: "policy-engine" */ "@gp2f/policy-core-wasm");
|
|
82
|
+
const mod = await import(/* @vite-ignore */ specifier);
|
|
79
83
|
return mod as PolicyEngineModule;
|
|
80
84
|
} catch {
|
|
81
85
|
// WASM package not installed – return a stub that always delegates to the
|