@fluxy-chat/create-fluxy-chat 0.5.13 → 0.5.19
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 +39 -0
- package/dist/index.js +9 -4
- package/package.json +1 -1
- package/readme.md +2 -1
- package/templates/basic/package.json +1 -1
- package/templates/comments-board/package.json +1 -1
- package/templates/deal-room/package.json +1 -1
- package/templates/deal-room/src/App.tsx +17 -1
- package/templates/discord/package.json +1 -1
- package/templates/draw/package.json +1 -1
- package/templates/fleet-panel/package.json +1 -1
- package/templates/full/README.md +14 -4
- package/templates/full/fluxy.hosted.json +15 -0
- package/templates/full/package.json +4 -3
- package/templates/full/scripts/fluxy-deploy.mjs +53 -0
- package/templates/full/scripts/fluxy-setup.mjs +31 -7
- package/templates/full/src/App.tsx +14 -0
- package/templates/full/src/session.ts +7 -2
- package/templates/full/src/vite-env.d.ts +2 -1
- package/templates/game-tick/package.json +1 -1
- package/templates/iot-panel/package.json +1 -1
- package/templates/javascript-live-cursors/package.json +1 -1
- package/templates/live-cursors/.env.example +8 -5
- package/templates/live-cursors/package.json +2 -2
- package/templates/live-cursors/src/App.tsx +19 -2
- package/templates/live-cursors/src/vite-env.d.ts +1 -0
- package/templates/live-cursors-chat/package.json +1 -1
- package/templates/minimal/.env.example +2 -1
- package/templates/minimal/package.json +2 -2
- package/templates/minimal/src/App.tsx +1 -0
- package/templates/polls/.env.example +13 -0
- package/templates/polls/README.md +13 -0
- package/templates/polls/index.html +12 -0
- package/templates/polls/package.json +24 -0
- package/templates/polls/src/App.tsx +135 -0
- package/templates/polls/src/index.css +85 -0
- package/templates/polls/src/main.tsx +10 -0
- package/templates/polls/src/session.ts +73 -0
- package/templates/polls/src/vite-env.d.ts +13 -0
- package/templates/polls/tsconfig.json +21 -0
- package/templates/polls/vite.config.ts +7 -0
- package/templates/react/.env.example +9 -5
- package/templates/react/README.md +7 -32
- package/templates/react/package.json +2 -2
- package/templates/react/src/App.tsx +31 -23
- package/templates/react/src/vite-env.d.ts +1 -0
- package/templates/slack/package.json +1 -1
- package/templates/telegram/package.json +1 -1
- package/templates/tiptap-room/package.json +1 -1
- package/templates/voice-stage/package.json +1 -1
- package/templates/war-room/package.json +1 -1
- package/templates/whiteboard/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,44 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.5.19] - 2026-09-02
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- Full template `fluxy.hosted.json` deploys `rooms` templates and extension slots with `pnpm fluxy:deploy`.
|
|
8
|
+
- Pin `@fluxy-chat/sdk@^0.6.8` (`connectInbox`, room extensions).
|
|
9
|
+
|
|
10
|
+
## [0.5.18] - 2026-09-01
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- Hosted `setup:hosted` reads `GET /public/demo-credentials` and writes `VITE_FLUXYCHAT_PUBLISHABLE_KEY`.
|
|
15
|
+
- `pnpm fluxy:deploy` on the full template: `fluxy.hosted.json` → `PUT /admin/projects/:id/publish-config`.
|
|
16
|
+
- React and live-cursors templates prefer `publishableKey` (pin sdk `^0.6.7` / react `^0.1.6`).
|
|
17
|
+
|
|
18
|
+
## [0.5.17] - 2026-09-01
|
|
19
|
+
|
|
20
|
+
### Added
|
|
21
|
+
|
|
22
|
+
- Gallery `--example polls`: `createPoll` / `votePoll`. Prefers `VITE_FLUXYCHAT_PUBLISHABLE_KEY`. Documents `POST /polls` `isAnonymous`.
|
|
23
|
+
|
|
24
|
+
## [0.5.16] - 2026-08-31
|
|
25
|
+
|
|
26
|
+
### Added
|
|
27
|
+
|
|
28
|
+
- `deal-room` template: Ask agent when `VITE_FLUXYCHAT_AGENT_ID` is set (`invokeAgent`).
|
|
29
|
+
|
|
30
|
+
## [0.5.15] - 2026-08-31
|
|
31
|
+
|
|
32
|
+
### Changed
|
|
33
|
+
|
|
34
|
+
- Help text states the scoped package: `npx @fluxy-chat/create-fluxy-chat@latest`. Unscoped `create-fluxy-chat` is not ours.
|
|
35
|
+
|
|
36
|
+
## [0.5.14] - 2026-08-27
|
|
37
|
+
|
|
38
|
+
### Changed
|
|
39
|
+
|
|
40
|
+
- Templates pin `@fluxy-chat/sdk@^0.6.5`. Minimal template pins `@fluxy-chat/ui-kit@^0.1.3` and uses guest mode when no member JWT is set. Publish protocol `0.1.5`, sdk `0.6.5`, and ui-kit `0.1.3` **before** this CLI.
|
|
41
|
+
|
|
3
42
|
## [0.5.13] - 2026-08-27
|
|
4
43
|
|
|
5
44
|
### Changed
|
package/dist/index.js
CHANGED
|
@@ -888,6 +888,7 @@ var GALLERY_EXAMPLES = [
|
|
|
888
888
|
"game-tick",
|
|
889
889
|
"voice-stage",
|
|
890
890
|
"comments-board",
|
|
891
|
+
"polls",
|
|
891
892
|
"whiteboard"
|
|
892
893
|
];
|
|
893
894
|
function parseArgs(argv) {
|
|
@@ -983,6 +984,9 @@ function parseArgs(argv) {
|
|
|
983
984
|
var HELP_TEXT = `
|
|
984
985
|
${pc.bold("create-fluxy-chat")} \u2014 Scaffold a FluxyChat app or bot worker
|
|
985
986
|
|
|
987
|
+
${pc.yellow("Use the scoped package:")} npx @fluxy-chat/create-fluxy-chat@latest
|
|
988
|
+
Unscoped ${pc.bold("npx create-fluxy-chat")} is not ours and will 404.
|
|
989
|
+
|
|
986
990
|
${pc.bold("Usage:")}
|
|
987
991
|
npx @fluxy-chat/create-fluxy-chat [project-name] [options]
|
|
988
992
|
|
|
@@ -1008,7 +1012,7 @@ ${pc.bold("Examples:")}
|
|
|
1008
1012
|
${pc.cyan("npx @fluxy-chat/create-fluxy-chat@latest my-cursors --example live-cursors")}
|
|
1009
1013
|
${pc.cyan("npx @fluxy-chat/create-fluxy-chat@latest my-doc --example tiptap-room")}
|
|
1010
1014
|
${pc.cyan("npx @fluxy-chat/create-fluxy-chat@latest my-war --example war-room")}
|
|
1011
|
-
${pc.cyan("npx @fluxy-chat/create-fluxy-chat@latest my-
|
|
1015
|
+
${pc.cyan("npx @fluxy-chat/create-fluxy-chat@latest my-polls --example polls")}
|
|
1012
1016
|
${pc.cyan("npx @fluxy-chat/create-fluxy-chat@latest my-chat --minimal")}
|
|
1013
1017
|
${pc.cyan("npx @fluxy-chat/create-fluxy-chat@latest my-bot --adapter slack")}
|
|
1014
1018
|
`;
|
|
@@ -1084,6 +1088,7 @@ async function main() {
|
|
|
1084
1088
|
"game-tick": "# Matchmake + start, then Submit input (not netcode)",
|
|
1085
1089
|
"voice-stage": "# Open two tabs \u2014 join speaker/listener (signaling, not WebRTC)",
|
|
1086
1090
|
"comments-board": "# Click the canvas to pin a thread",
|
|
1091
|
+
polls: "# Create a poll, open a second tab, vote",
|
|
1087
1092
|
"live-cursors-chat": "# Open two tabs \u2014 move and chat",
|
|
1088
1093
|
whiteboard: "# Open two tabs \u2014 draw strokes (Yjs, not a second CRDT)"
|
|
1089
1094
|
};
|
|
@@ -1092,7 +1097,7 @@ async function main() {
|
|
|
1092
1097
|
[
|
|
1093
1098
|
`cd ${projectName}`,
|
|
1094
1099
|
"cp .env.example .env",
|
|
1095
|
-
"# Set VITE_FLUXYCHAT_WORKER_URL + public room ID
|
|
1100
|
+
"# Set VITE_FLUXYCHAT_WORKER_URL + pk_ (or public room ID / member JWT)",
|
|
1096
1101
|
`${devCmd2} dev`,
|
|
1097
1102
|
tryHint
|
|
1098
1103
|
].join("\n"),
|
|
@@ -1253,7 +1258,7 @@ async function main() {
|
|
|
1253
1258
|
const devCmd = config.packageManager === "npm" ? "npm run" : config.packageManager;
|
|
1254
1259
|
const nextSteps = config.full || config.adapter === "full" ? config.mode === "hosted" ? [
|
|
1255
1260
|
`cd ${config.name}`,
|
|
1256
|
-
`${devCmd} setup:hosted #
|
|
1261
|
+
`${devCmd} setup:hosted # writes pk_ when /public/demo-credentials is on`,
|
|
1257
1262
|
`${devCmd} dev # http://localhost:5173`,
|
|
1258
1263
|
`# Keep this project: https://fluxychat.com/onboarding?from=cli`
|
|
1259
1264
|
].join("\n") : [
|
|
@@ -1266,7 +1271,7 @@ async function main() {
|
|
|
1266
1271
|
].join("\n") : config.adapter === "react" || config.minimal ? [
|
|
1267
1272
|
`cd ${config.name}`,
|
|
1268
1273
|
"cp .env.example .env",
|
|
1269
|
-
"# Set VITE_FLUXYCHAT_WORKER_URL +
|
|
1274
|
+
"# Set VITE_FLUXYCHAT_WORKER_URL + VITE_FLUXYCHAT_PUBLISHABLE_KEY",
|
|
1270
1275
|
`${devCmd} dev`,
|
|
1271
1276
|
"# In the room, send: @assistant hello"
|
|
1272
1277
|
].join("\n") : [
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -36,6 +36,7 @@ npx @fluxy-chat/create-fluxy-chat@latest my-fleet --example fleet-panel
|
|
|
36
36
|
npx @fluxy-chat/create-fluxy-chat@latest my-game --example game-tick
|
|
37
37
|
npx @fluxy-chat/create-fluxy-chat@latest my-stage --example voice-stage
|
|
38
38
|
npx @fluxy-chat/create-fluxy-chat@latest my-comments --example comments-board
|
|
39
|
+
npx @fluxy-chat/create-fluxy-chat@latest my-polls --example polls
|
|
39
40
|
npx @fluxy-chat/create-fluxy-chat@latest my-chat --template react -y
|
|
40
41
|
npx @fluxy-chat/create-fluxy-chat@latest my-bot --adapter slack --pm pnpm
|
|
41
42
|
```
|
|
@@ -51,7 +52,7 @@ npx @fluxy-chat/create-fluxy-chat@latest my-bot --adapter slack --pm pnpm
|
|
|
51
52
|
| `--yes` | `-y` | Skip prompts and accept defaults |
|
|
52
53
|
| `--full` | | Full stack template: chat + `@assistant` + `pnpm setup` / `pnpm dev` |
|
|
53
54
|
| `--minimal` | | Chat-only widget (`@fluxy-chat/ui-kit`), no platform modules |
|
|
54
|
-
| `--example <name>` | | Gallery: `live-cursors`, `live-cursors-chat`, `javascript-live-cursors`, `tiptap-room`, `war-room`, `iot-panel`, `draw`, `deal-room`, `fleet-panel`, `game-tick`, `voice-stage`, `comments-board`, `whiteboard` |
|
|
55
|
+
| `--example <name>` | | Gallery: `live-cursors`, `live-cursors-chat`, `javascript-live-cursors`, `tiptap-room`, `war-room`, `iot-panel`, `draw`, `deal-room`, `fleet-panel`, `game-tick`, `voice-stage`, `comments-board`, `polls`, `whiteboard` |
|
|
55
56
|
| `--skip-install` | | Skip dependency installation |
|
|
56
57
|
| `--no-git` | | Skip git repository initialization |
|
|
57
58
|
| `--help` | `-h` | Show help |
|
|
@@ -4,9 +4,10 @@ import { useFluxySession, workerUrl } from "./session";
|
|
|
4
4
|
|
|
5
5
|
function DealBoard({ roomId }: { roomId: string }) {
|
|
6
6
|
const { client } = useFluxyChat();
|
|
7
|
-
const { messages, sendMessage, connected } = useChat({ roomId, replay: "request" });
|
|
7
|
+
const { messages, sendMessage, connected, invokeAgent } = useChat({ roomId, replay: "request" });
|
|
8
8
|
const [draft, setDraft] = useState("Approve term sheet?");
|
|
9
9
|
const [busy, setBusy] = useState(false);
|
|
10
|
+
const agentId = import.meta.env.VITE_FLUXYCHAT_AGENT_ID?.trim();
|
|
10
11
|
|
|
11
12
|
async function propose() {
|
|
12
13
|
const content = draft.trim();
|
|
@@ -45,6 +46,16 @@ function DealBoard({ roomId }: { roomId: string }) {
|
|
|
45
46
|
URL.revokeObjectURL(url);
|
|
46
47
|
}
|
|
47
48
|
|
|
49
|
+
async function askAgent() {
|
|
50
|
+
if (!agentId) return;
|
|
51
|
+
setBusy(true);
|
|
52
|
+
try {
|
|
53
|
+
await invokeAgent(agentId, "Summarize this deal thread and list open decisions.");
|
|
54
|
+
} finally {
|
|
55
|
+
setBusy(false);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
48
59
|
return (
|
|
49
60
|
<section className="panel">
|
|
50
61
|
<header className="chat-header">
|
|
@@ -87,6 +98,11 @@ function DealBoard({ roomId }: { roomId: string }) {
|
|
|
87
98
|
<button type="button" className="primary" onClick={() => void exportMarkdown()}>
|
|
88
99
|
Export .md
|
|
89
100
|
</button>
|
|
101
|
+
{agentId ? (
|
|
102
|
+
<button type="button" disabled={busy} onClick={() => void askAgent()}>
|
|
103
|
+
Ask agent
|
|
104
|
+
</button>
|
|
105
|
+
) : null}
|
|
90
106
|
</form>
|
|
91
107
|
</section>
|
|
92
108
|
);
|
package/templates/full/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# FluxyChat full stack starter
|
|
2
2
|
|
|
3
|
-
Chat + AI agent in a Vite app. Hosted
|
|
3
|
+
Chat + AI agent in a Vite app. Hosted: `pnpm setup:hosted` writes a public `pk_` when the Worker exposes `GET /public/demo-credentials`. Otherwise copy a `pk_` from the console, or sign in for a private assistant room.
|
|
4
4
|
|
|
5
5
|
## Quick start
|
|
6
6
|
|
|
@@ -14,7 +14,16 @@ pnpm setup:hosted
|
|
|
14
14
|
pnpm dev
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
If demo credentials are configured on the Worker, chat starts with `publishableKey` (no Clerk). Sign in later for a private assistant room.
|
|
18
|
+
|
|
19
|
+
**Hosted overlay (one file deploy for deny / rooms / extension slots):**
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
# fluxy.hosted.json → PUT /admin/projects/:id/publish-config
|
|
23
|
+
FLUXY_WORKER_URL=https://api.fluxychat.com FLUXY_ADMIN_JWT=eyJ... FLUXY_PROJECT_ID=prj_... pnpm fluxy:deploy
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
This is not Worker-bundled `onPublish` callbacks. Those run in `fluxy.config.ts` on self-host. Hosted extension slots are declared `kv` / `counter` on the room Durable Object (`GET /rooms/:id/extensions`).
|
|
18
27
|
|
|
19
28
|
**Self-host (your Worker):**
|
|
20
29
|
|
|
@@ -37,14 +46,15 @@ If the Worker is down, `setup:local` asks for the URL. Merge `.fluxy/worker.dev.
|
|
|
37
46
|
|
|
38
47
|
| Command | Description |
|
|
39
48
|
|---------|-------------|
|
|
40
|
-
| `pnpm setup:hosted` |
|
|
49
|
+
| `pnpm setup:hosted` | Worker URL + public `pk_` when `/public/demo-credentials` is configured |
|
|
50
|
+
| `pnpm fluxy:deploy` | PUT hosted publish-config from `fluxy.hosted.json` |
|
|
41
51
|
| `pnpm setup:local` / `pnpm setup:self-host` | `POST /dev/provision` on your Worker |
|
|
42
52
|
| `pnpm doctor` | Health check |
|
|
43
53
|
| `pnpm dev` | Start Vite |
|
|
44
54
|
|
|
45
55
|
## Environment
|
|
46
56
|
|
|
47
|
-
`.env` from `pnpm setup:hosted`
|
|
57
|
+
`.env` from `pnpm setup:hosted` includes worker URL and, when configured, `VITE_FLUXYCHAT_PUBLISHABLE_KEY`. Clerk still creates a private assistant room.
|
|
48
58
|
|
|
49
59
|
Dashboard: [fluxychat.com/dashboard](https://fluxychat.com/dashboard)
|
|
50
60
|
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"denySubstrings": [],
|
|
3
|
+
"guestCanPublish": true,
|
|
4
|
+
"iotAutoAgentId": null,
|
|
5
|
+
"rooms": {
|
|
6
|
+
"support-*": {
|
|
7
|
+
"anonymous": false,
|
|
8
|
+
"guestCanPublish": false
|
|
9
|
+
},
|
|
10
|
+
"room-*": {
|
|
11
|
+
"anonymous": true,
|
|
12
|
+
"extensions": [{ "id": "state", "kind": "kv" }]
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
"setup:hosted": "node scripts/fluxy-setup.mjs --mode hosted",
|
|
9
9
|
"setup:local": "node scripts/fluxy-setup.mjs --mode local",
|
|
10
10
|
"setup:self-host": "node scripts/fluxy-setup.mjs --mode self-host",
|
|
11
|
+
"fluxy:deploy": "node scripts/fluxy-deploy.mjs",
|
|
11
12
|
"doctor": "node scripts/fluxy-doctor.mjs",
|
|
12
13
|
"dev": "node scripts/fluxy-dev.mjs",
|
|
13
14
|
"dev:app": "vite",
|
|
@@ -16,8 +17,8 @@
|
|
|
16
17
|
"postinstall": "node scripts/hoist-fluxy-sdk.mjs"
|
|
17
18
|
},
|
|
18
19
|
"dependencies": {
|
|
19
|
-
"@fluxy-chat/react": "^0.1.
|
|
20
|
-
"@fluxy-chat/sdk": "^0.6.
|
|
20
|
+
"@fluxy-chat/react": "^0.1.6",
|
|
21
|
+
"@fluxy-chat/sdk": "^0.6.8",
|
|
21
22
|
"@fluxy-chat/ui": "^0.1.4",
|
|
22
23
|
"class-variance-authority": "^0.7.1",
|
|
23
24
|
"clsx": "^2.1.1",
|
|
@@ -40,7 +41,7 @@
|
|
|
40
41
|
},
|
|
41
42
|
"pnpm": {
|
|
42
43
|
"overrides": {
|
|
43
|
-
"@fluxy-chat/sdk": "^0.6.
|
|
44
|
+
"@fluxy-chat/sdk": "^0.6.8"
|
|
44
45
|
}
|
|
45
46
|
}
|
|
46
47
|
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Hosted overlay: PUT /admin/projects/:id/publish-config
|
|
4
|
+
* Serializes one fluxy.hosted.json (deny, guest publish, iotAutoAgentId, rooms
|
|
5
|
+
* templates + extension slots). Does not upload Worker callbacks.
|
|
6
|
+
*
|
|
7
|
+
* FLUXY_WORKER_URL=https://api.fluxychat.com \
|
|
8
|
+
* FLUXY_ADMIN_JWT=eyJ... \
|
|
9
|
+
* FLUXY_PROJECT_ID=prj_... \
|
|
10
|
+
* pnpm fluxy:deploy
|
|
11
|
+
*/
|
|
12
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
13
|
+
import { dirname, join, resolve } from "node:path";
|
|
14
|
+
import { fileURLToPath } from "node:url";
|
|
15
|
+
|
|
16
|
+
const root = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
17
|
+
const configPath = join(root, "fluxy.hosted.json");
|
|
18
|
+
|
|
19
|
+
const workerUrl = (process.env.FLUXY_WORKER_URL || process.env.VITE_FLUXYCHAT_WORKER_URL || "").replace(/\/$/, "");
|
|
20
|
+
const adminJwt = process.env.FLUXY_ADMIN_JWT || "";
|
|
21
|
+
const projectId = process.env.FLUXY_PROJECT_ID || process.env.VITE_FLUXYCHAT_PROJECT_ID || "";
|
|
22
|
+
|
|
23
|
+
function fail(msg) {
|
|
24
|
+
console.error(`fluxy deploy: ${msg}`);
|
|
25
|
+
process.exit(1);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (!workerUrl) fail("set FLUXY_WORKER_URL");
|
|
29
|
+
if (!adminJwt) fail("set FLUXY_ADMIN_JWT (owner/admin JWT, not pk_)");
|
|
30
|
+
if (!projectId) fail("set FLUXY_PROJECT_ID");
|
|
31
|
+
if (!existsSync(configPath)) fail(`missing ${configPath}`);
|
|
32
|
+
|
|
33
|
+
const hosted = JSON.parse(readFileSync(configPath, "utf8"));
|
|
34
|
+
const body = {
|
|
35
|
+
denySubstrings: Array.isArray(hosted.denySubstrings) ? hosted.denySubstrings : [],
|
|
36
|
+
guestCanPublish: hosted.guestCanPublish !== false,
|
|
37
|
+
iotAutoAgentId: hosted.iotAutoAgentId ?? null,
|
|
38
|
+
rooms: hosted.rooms && typeof hosted.rooms === "object" ? hosted.rooms : {},
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const url = `${workerUrl}/admin/projects/${encodeURIComponent(projectId)}/publish-config`;
|
|
42
|
+
const res = await fetch(url, {
|
|
43
|
+
method: "PUT",
|
|
44
|
+
headers: {
|
|
45
|
+
Authorization: `Bearer ${adminJwt}`,
|
|
46
|
+
"Content-Type": "application/json",
|
|
47
|
+
},
|
|
48
|
+
body: JSON.stringify(body),
|
|
49
|
+
});
|
|
50
|
+
const text = await res.text();
|
|
51
|
+
if (!res.ok) fail(`${res.status} ${text}`);
|
|
52
|
+
console.log("publish-config updated");
|
|
53
|
+
console.log(text);
|
|
@@ -194,6 +194,7 @@ function writeEnv(vars) {
|
|
|
194
194
|
const lines = [
|
|
195
195
|
"# Auto-generated by pnpm setup — do not commit secrets",
|
|
196
196
|
`VITE_FLUXYCHAT_WORKER_URL=${vars.workerUrl}`,
|
|
197
|
+
`VITE_FLUXYCHAT_PUBLISHABLE_KEY=${vars.publishableKey || ""}`,
|
|
197
198
|
`VITE_FLUXYCHAT_MEMBER_JWT=${vars.token}`,
|
|
198
199
|
`VITE_FLUXYCHAT_ROOM_ID=${vars.roomId}`,
|
|
199
200
|
`VITE_FLUXYCHAT_AGENT_ID=${vars.agentId}`,
|
|
@@ -218,13 +219,30 @@ async function setupHosted() {
|
|
|
218
219
|
process.env.FLUXY_WORKER_URL ||
|
|
219
220
|
HOSTED_WORKER_DEFAULT;
|
|
220
221
|
const consoleUrl = process.env.FLUXY_CONSOLE_URL || HOSTED_CONSOLE_DEFAULT;
|
|
222
|
+
const fromEnvPk = (process.env.FLUXY_PUBLISHABLE_KEY || process.env.VITE_FLUXYCHAT_PUBLISHABLE_KEY || "").trim();
|
|
221
223
|
|
|
222
224
|
console.log(dim(` mode: hosted · worker: ${workerUrl}`));
|
|
223
225
|
|
|
226
|
+
let publishableKey = fromEnvPk.startsWith("pk_") ? fromEnvPk : "";
|
|
227
|
+
let roomId = process.env.VITE_FLUXYCHAT_ROOM_ID?.trim() || "";
|
|
228
|
+
if (!publishableKey) {
|
|
229
|
+
try {
|
|
230
|
+
const demo = await getJson(workerUrl, "/public/demo-credentials");
|
|
231
|
+
if (demo?.publishableKey?.startsWith("pk_")) {
|
|
232
|
+
publishableKey = demo.publishableKey;
|
|
233
|
+
roomId = demo.roomId || roomId || "general";
|
|
234
|
+
ok("wrote public demo pk_ (GET /public/demo-credentials)");
|
|
235
|
+
}
|
|
236
|
+
} catch {
|
|
237
|
+
/* demo not configured on this Worker */
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
224
241
|
writeEnv({
|
|
225
242
|
workerUrl,
|
|
243
|
+
publishableKey,
|
|
226
244
|
token: "",
|
|
227
|
-
roomId: "",
|
|
245
|
+
roomId: roomId || (publishableKey ? "general" : ""),
|
|
228
246
|
agentId: "",
|
|
229
247
|
agentHandle: "@assistant",
|
|
230
248
|
projectId: "",
|
|
@@ -236,17 +254,22 @@ async function setupHosted() {
|
|
|
236
254
|
mode: "hosted",
|
|
237
255
|
workerUrl,
|
|
238
256
|
projectId: null,
|
|
239
|
-
roomId: null,
|
|
257
|
+
roomId: roomId || null,
|
|
240
258
|
agentId: null,
|
|
241
259
|
agentHandle: "@assistant",
|
|
242
260
|
setupAt: new Date().toISOString(),
|
|
243
|
-
auth: "clerk",
|
|
261
|
+
auth: publishableKey ? "publishableKey" : "clerk",
|
|
244
262
|
});
|
|
245
263
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
264
|
+
if (publishableKey) {
|
|
265
|
+
ok("public room is ready. pnpm dev — no Clerk required");
|
|
266
|
+
console.log(dim(" Sign in later for a private assistant room: Open dashboard"));
|
|
267
|
+
} else {
|
|
268
|
+
ok("wrote hosted endpoints (copy a pk_ from the console, or sign in on pnpm dev)");
|
|
269
|
+
console.log(dim(" Run: pnpm dev"));
|
|
270
|
+
console.log(dim(` Console: ${consoleUrl}/onboarding`));
|
|
271
|
+
console.log(dim(" Hosted ops: set PUBLIC_DEMO_PUBLISHABLE_KEY on the Worker for a no-account path"));
|
|
272
|
+
}
|
|
250
273
|
}
|
|
251
274
|
|
|
252
275
|
async function setupLocal() {
|
|
@@ -323,6 +346,7 @@ async function setupLocal() {
|
|
|
323
346
|
|
|
324
347
|
writeEnv({
|
|
325
348
|
workerUrl,
|
|
349
|
+
publishableKey: provision.publishableKey || "",
|
|
326
350
|
token: auth.token,
|
|
327
351
|
roomId,
|
|
328
352
|
agentId: agent.id,
|
|
@@ -4,6 +4,7 @@ import { ChatWindow } from "@fluxy-chat/ui";
|
|
|
4
4
|
import { loadCliSession, type CliSession } from "./session";
|
|
5
5
|
|
|
6
6
|
const envWorkerUrl = import.meta.env.VITE_FLUXYCHAT_WORKER_URL?.trim() ?? "";
|
|
7
|
+
const envPublishableKey = import.meta.env.VITE_FLUXYCHAT_PUBLISHABLE_KEY?.trim() ?? "";
|
|
7
8
|
const envJwt = import.meta.env.VITE_FLUXYCHAT_MEMBER_JWT?.trim() ?? "";
|
|
8
9
|
const envRoomId = import.meta.env.VITE_FLUXYCHAT_ROOM_ID?.trim() ?? "";
|
|
9
10
|
const envAgentId = import.meta.env.VITE_FLUXYCHAT_AGENT_ID?.trim() ?? "";
|
|
@@ -31,6 +32,18 @@ function dashboardHref(): string {
|
|
|
31
32
|
}
|
|
32
33
|
|
|
33
34
|
function sessionFromEnv(): CliSession | null {
|
|
35
|
+
if (envWorkerUrl && envPublishableKey.startsWith("pk_") && envRoomId) {
|
|
36
|
+
return {
|
|
37
|
+
workerUrl: envWorkerUrl,
|
|
38
|
+
publishableKey: envPublishableKey,
|
|
39
|
+
memberJwt: envJwt || undefined,
|
|
40
|
+
roomId: envRoomId,
|
|
41
|
+
agentId: envAgentId,
|
|
42
|
+
agentHandle: envAgentHandle,
|
|
43
|
+
projectId: envProjectId,
|
|
44
|
+
userId: envUserId || "guest",
|
|
45
|
+
};
|
|
46
|
+
}
|
|
34
47
|
if (!envWorkerUrl || !envJwt || !envRoomId) return null;
|
|
35
48
|
return {
|
|
36
49
|
workerUrl: envWorkerUrl,
|
|
@@ -226,6 +239,7 @@ export function App() {
|
|
|
226
239
|
<div className="page">
|
|
227
240
|
<FluxyRealtimeProvider
|
|
228
241
|
workerUrl={session.workerUrl}
|
|
242
|
+
publishableKey={session.memberJwt ? undefined : session.publishableKey}
|
|
229
243
|
authTokenProvider={session.memberJwt}
|
|
230
244
|
userId={session.userId}
|
|
231
245
|
>
|
|
@@ -2,7 +2,8 @@ const STORAGE_KEY = "fluxy-cli-session";
|
|
|
2
2
|
|
|
3
3
|
export interface CliSession {
|
|
4
4
|
workerUrl: string;
|
|
5
|
-
memberJwt
|
|
5
|
+
memberJwt?: string;
|
|
6
|
+
publishableKey?: string;
|
|
6
7
|
roomId: string;
|
|
7
8
|
agentId: string;
|
|
8
9
|
agentHandle: string;
|
|
@@ -15,7 +16,11 @@ export interface CliSession {
|
|
|
15
16
|
function isCliSession(value: unknown): value is CliSession {
|
|
16
17
|
if (!value || typeof value !== "object") return false;
|
|
17
18
|
const v = value as Record<string, unknown>;
|
|
18
|
-
|
|
19
|
+
if (typeof v.workerUrl !== "string" || v.workerUrl.length === 0) return false;
|
|
20
|
+
if (typeof v.roomId !== "string" || v.roomId.length === 0) return false;
|
|
21
|
+
const hasMember = typeof v.memberJwt === "string" && v.memberJwt.length > 0;
|
|
22
|
+
const hasPk = typeof v.publishableKey === "string" && v.publishableKey.startsWith("pk_");
|
|
23
|
+
return hasMember || hasPk;
|
|
19
24
|
}
|
|
20
25
|
|
|
21
26
|
export function readCliSessionFromHash(): CliSession | null {
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
interface ImportMetaEnv {
|
|
4
4
|
readonly VITE_FLUXYCHAT_WORKER_URL: string;
|
|
5
|
-
readonly
|
|
5
|
+
readonly VITE_FLUXYCHAT_PUBLISHABLE_KEY?: string;
|
|
6
|
+
readonly VITE_FLUXYCHAT_MEMBER_JWT?: string;
|
|
6
7
|
readonly VITE_FLUXYCHAT_ROOM_ID: string;
|
|
7
8
|
readonly VITE_FLUXYCHAT_AGENT_ID: string;
|
|
8
9
|
readonly VITE_FLUXYCHAT_AGENT_HANDLE: string;
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
# FluxyChat worker URL (hosted or self-hosted)
|
|
2
|
-
VITE_FLUXYCHAT_WORKER_URL=https://
|
|
2
|
+
VITE_FLUXYCHAT_WORKER_URL=https://api.fluxychat.com
|
|
3
3
|
|
|
4
|
-
# Option A —
|
|
5
|
-
|
|
6
|
-
VITE_FLUXYCHAT_ROOM_ID=
|
|
4
|
+
# Option A — public room (pin sdk 0.6.7+)
|
|
5
|
+
VITE_FLUXYCHAT_PUBLISHABLE_KEY=pk_...
|
|
6
|
+
VITE_FLUXYCHAT_ROOM_ID=general
|
|
7
7
|
|
|
8
|
-
# Option B —
|
|
8
|
+
# Option B — member JWT
|
|
9
|
+
# VITE_FLUXYCHAT_MEMBER_JWT=eyJ...
|
|
10
|
+
|
|
11
|
+
# Option C — guest session without pk_
|
|
9
12
|
# VITE_FLUXYCHAT_PUBLIC_ROOM_ID=your-public-room-id
|
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
"preview": "vite preview"
|
|
10
10
|
},
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"@fluxy-chat/react": "^0.1.
|
|
13
|
-
"@fluxy-chat/sdk": "^0.6.
|
|
12
|
+
"@fluxy-chat/react": "^0.1.6",
|
|
13
|
+
"@fluxy-chat/sdk": "^0.6.7",
|
|
14
14
|
"react": "^19.0.0",
|
|
15
15
|
"react-dom": "^19.0.0",
|
|
16
16
|
"zustand": "^5.0.0"
|
|
@@ -3,6 +3,7 @@ import { FluxyChatClient } from "@fluxy-chat/sdk";
|
|
|
3
3
|
import { FluxyRealtimeProvider, useChat } from "@fluxy-chat/react";
|
|
4
4
|
|
|
5
5
|
const workerUrl = import.meta.env.VITE_FLUXYCHAT_WORKER_URL?.trim();
|
|
6
|
+
const publishableKey = import.meta.env.VITE_FLUXYCHAT_PUBLISHABLE_KEY?.trim();
|
|
6
7
|
const memberJwt = import.meta.env.VITE_FLUXYCHAT_MEMBER_JWT?.trim();
|
|
7
8
|
const publicRoomId = import.meta.env.VITE_FLUXYCHAT_PUBLIC_ROOM_ID?.trim();
|
|
8
9
|
const configuredRoomId = import.meta.env.VITE_FLUXYCHAT_ROOM_ID?.trim() || "demo";
|
|
@@ -149,6 +150,23 @@ function hashCode(value: string): number {
|
|
|
149
150
|
}
|
|
150
151
|
|
|
151
152
|
export function App() {
|
|
153
|
+
const pkRoomId = publicRoomId || configuredRoomId;
|
|
154
|
+
if (workerUrl && publishableKey) {
|
|
155
|
+
return (
|
|
156
|
+
<main className="shell">
|
|
157
|
+
<h1>Live cursors</h1>
|
|
158
|
+
<p className="mode-badge">publishableKey · two tabs, same room</p>
|
|
159
|
+
<FluxyRealtimeProvider workerUrl={workerUrl} publishableKey={publishableKey}>
|
|
160
|
+
<CursorCanvas roomId={pkRoomId} selfUserId="guest" />
|
|
161
|
+
</FluxyRealtimeProvider>
|
|
162
|
+
</main>
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return <MemberOrGuestCursors />;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function MemberOrGuestCursors() {
|
|
152
170
|
const { session, loading, error } = useFluxySession();
|
|
153
171
|
const [roomId, setRoomId] = useState(configuredRoomId);
|
|
154
172
|
|
|
@@ -166,8 +184,7 @@ export function App() {
|
|
|
166
184
|
<code>VITE_FLUXYCHAT_WORKER_URL</code>.
|
|
167
185
|
</p>
|
|
168
186
|
<p>
|
|
169
|
-
Then
|
|
170
|
-
<code>VITE_FLUXYCHAT_PUBLIC_ROOM_ID</code>.
|
|
187
|
+
Then <code>VITE_FLUXYCHAT_PUBLISHABLE_KEY</code>, a member JWT, or a public room id.
|
|
171
188
|
</p>
|
|
172
189
|
</main>
|
|
173
190
|
);
|