hotpipe 0.1.0 → 0.10.0

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.
@@ -1,103 +1,243 @@
1
1
  import { SignJWT } from 'jose';
2
- const DEFAULT_BROKER_URL = 'https://api.hotpipe.dev';
2
+ import { DEFAULT_TOKEN_EXPIRY_SECONDS } from '../constants';
3
+ import { SDK_VERSION } from '../version';
4
+ import { parseSecret } from './parse-secret';
5
+ const DEFAULT_API_URL = 'https://api.hotpipe.dev';
3
6
  /**
4
- * Creates a typed server-side publisher for emitting events to the broker
7
+ * Derives a publish-specific auth token from the shared secret via HMAC.
8
+ * This ensures the raw secret is never sent over the wire as a Bearer token.
9
+ */
10
+ async function derivePublishToken(apiKey) {
11
+ const encoder = new TextEncoder();
12
+ const key = await crypto.subtle.importKey('raw', encoder.encode(apiKey), { name: 'HMAC', hash: 'SHA-256' }, false, ['sign']);
13
+ const signature = await crypto.subtle.sign('HMAC', key, encoder.encode('hotpipe-publish-v1'));
14
+ return Array.from(new Uint8Array(signature))
15
+ .map((b) => b.toString(16).padStart(2, '0'))
16
+ .join('');
17
+ }
18
+ /**
19
+ * Creates a typed server-side publisher for emitting events to the hotpipe API
5
20
  * from API routes, server actions, webhooks, cron jobs, etc.
6
21
  *
7
22
  * ```ts
8
- * const realtime = createRealtimePublisher({
9
- * apiKey: process.env.HOTPIPE_API_KEY!,
23
+ * const realtime = createPipePublisher({
24
+ * secret: process.env.HOTPIPE_SECRET!,
10
25
  * events: realtimeEvents,
11
26
  * });
12
27
  *
13
- * await realtime.publish('general', 'message.created', { ... });
28
+ * const teamChat = realtime.pipe('team-chat');
29
+ * await teamChat.publish('message.created', { ... });
14
30
  * ```
15
31
  */
16
- export function createRealtimePublisher(config) {
17
- const brokerUrl = config.brokerUrl ?? DEFAULT_BROKER_URL;
18
- const headers = {
19
- 'Content-Type': 'application/json',
20
- Authorization: `Bearer ${config.apiKey}`,
21
- };
32
+ export function createPipePublisher(config) {
33
+ const { projectId, apiKey } = parseSecret(config.secret);
34
+ const apiUrl = config.apiUrl ?? DEFAULT_API_URL;
35
+ let cachedHeaders = null;
36
+ async function getHeaders() {
37
+ if (!cachedHeaders) {
38
+ const publishToken = await derivePublishToken(apiKey);
39
+ cachedHeaders = {
40
+ 'Content-Type': 'application/json',
41
+ Authorization: `Bearer ${publishToken}`,
42
+ 'X-Hotpipe-SDK': SDK_VERSION,
43
+ };
44
+ }
45
+ return cachedHeaders;
46
+ }
47
+ async function publishToApi(pipe, event, data, options) {
48
+ const schema = config.events[event];
49
+ if (schema) {
50
+ schema.parse(data);
51
+ }
52
+ const body = { projectId, pipe, event, data };
53
+ if (options?.sender) {
54
+ body.sender = options.sender;
55
+ }
56
+ const res = await fetch(`${apiUrl}/publish`, {
57
+ method: 'POST',
58
+ headers: await getHeaders(),
59
+ body: JSON.stringify(body),
60
+ });
61
+ if (!res.ok) {
62
+ throw new Error(`hotpipe publish failed: ${res.status} ${await res.text()}`);
63
+ }
64
+ }
22
65
  return {
23
66
  /**
24
- * Publish a single event to a channel.
25
- */
26
- async publish(channel, event, data) {
27
- const schema = config.events[event];
28
- if (schema) {
29
- schema.parse(data);
30
- }
31
- const res = await fetch(`${brokerUrl}/publish`, {
32
- method: 'POST',
33
- headers,
34
- body: JSON.stringify({ channel, event, data }),
35
- });
36
- if (!res.ok) {
37
- throw new Error(`hotpipe publish failed: ${res.status} ${await res.text()}`);
38
- }
39
- },
40
- /**
41
- * Publish multiple events in a single HTTP request.
67
+ * Get a reference to a pipe. Returns a `{ publish }` object with
68
+ * the same signature as the client-side `usePipe` publish function.
69
+ *
70
+ * ```ts
71
+ * const teamChat = realtime.pipe('team-chat');
72
+ * await teamChat.publish('message.created', { ... });
73
+ * ```
42
74
  */
43
- async publishBatch(events) {
44
- const res = await fetch(`${brokerUrl}/publish/batch`, {
45
- method: 'POST',
46
- headers,
47
- body: JSON.stringify({ events }),
48
- });
49
- if (!res.ok) {
50
- throw new Error(`hotpipe batch publish failed: ${res.status} ${await res.text()}`);
51
- }
75
+ pipe(pipe) {
76
+ return {
77
+ async publish(event, data, options) {
78
+ return publishToApi(pipe, event, data, options);
79
+ },
80
+ };
52
81
  },
53
82
  };
54
83
  }
55
84
  /**
56
- * Creates a Next.js-compatible route handler for client auth.
57
- * The client SDK calls this endpoint to get a signed token before
58
- * opening the WebSocket connection to the broker.
85
+ * Creates a Next.js-compatible catch-all route handler for hotpipe.
86
+ * Mount this at `app/api/realtime/[...all]/route.ts` and the SDK
87
+ * handles the rest.
59
88
  *
60
89
  * ```ts
61
- * // app/api/realtime/auth/route.ts
62
- * export const POST = createAuthHandler({
63
- * secret: process.env.BROKER_SIGNING_SECRET!,
90
+ * // app/api/realtime/[...all]/route.ts
91
+ * export const { POST } = createPipeHandler({
92
+ * secret: process.env.HOTPIPE_SECRET!,
64
93
  * authorize: async (req) => {
65
- * const session = await getServerSession();
94
+ * const { session } = await getAuth(req);
66
95
  * if (!session) return null;
67
96
  * return {
68
- * userId: session.user.id,
69
- * channels: {
70
- * general: ['subscribe', 'publish'],
71
- * [`user-${session.user.id}`]: ['subscribe'],
97
+ * userId: session.userId,
98
+ * pipes: {
99
+ * global: { subscribe: true, publish: true },
100
+ * [`user-${session.userId}`]: { subscribe: true },
72
101
  * },
73
102
  * };
74
103
  * },
75
104
  * });
76
105
  * ```
77
106
  */
78
- export function createAuthHandler(handlerConfig) {
79
- const encodedSecret = new TextEncoder().encode(handlerConfig.secret);
80
- const expiry = handlerConfig.tokenExpiry || 3600;
81
- return async (req) => {
107
+ export function createPipeHandler(handlerConfig) {
108
+ const { projectId, apiKey } = parseSecret(handlerConfig.secret);
109
+ const encodedApiKey = new TextEncoder().encode(apiKey);
110
+ const expiry = handlerConfig.tokenExpiry || DEFAULT_TOKEN_EXPIRY_SECONDS;
111
+ async function handleAuth(req) {
82
112
  try {
83
113
  const result = await handlerConfig.authorize(req);
84
114
  if (!result) {
85
115
  return Response.json({ error: 'Unauthorized' }, { status: 401 });
86
116
  }
117
+ // Transform { subscribe?: boolean, publish?: boolean } to string arrays
118
+ // for the API wire format
119
+ const permissions = {};
120
+ for (const [pipe, perms] of Object.entries(result.pipes)) {
121
+ const arr = [];
122
+ if (perms.subscribe)
123
+ arr.push('subscribe');
124
+ if (perms.publish)
125
+ arr.push('publish');
126
+ permissions[pipe] = arr;
127
+ }
87
128
  const token = await new SignJWT({
88
- channels: Object.keys(result.channels),
89
- permissions: result.channels,
129
+ projectId,
130
+ pipes: Object.keys(result.pipes),
131
+ permissions,
90
132
  })
91
133
  .setSubject(result.userId)
92
134
  .setIssuedAt()
93
135
  .setExpirationTime(`${expiry}s`)
94
136
  .setProtectedHeader({ alg: 'HS256' })
95
- .sign(encodedSecret);
137
+ .sign(encodedApiKey);
96
138
  return Response.json({ token });
97
139
  }
98
140
  catch {
99
141
  return Response.json({ error: 'Internal error' }, { status: 500 });
100
142
  }
143
+ }
144
+ async function handler(req) {
145
+ const url = new URL(req.url);
146
+ if (url.pathname.endsWith('/auth')) {
147
+ return handleAuth(req);
148
+ }
149
+ return Response.json({ error: 'Not found' }, { status: 404 });
150
+ }
151
+ return { POST: handler };
152
+ }
153
+ /**
154
+ * Creates a server-side admin client for revoking pipe access.
155
+ *
156
+ * ```ts
157
+ * const pipeAdmin = createPipeAdmin({
158
+ * secret: process.env.HOTPIPE_SECRET!,
159
+ * });
160
+ *
161
+ * await pipeAdmin.revoke('user-123', 'room-xyz');
162
+ * await pipeAdmin.revokeAll('user-123');
163
+ * ```
164
+ */
165
+ export function createPipeAdmin(config) {
166
+ const { projectId, apiKey } = parseSecret(config.secret);
167
+ const apiUrl = config.apiUrl ?? DEFAULT_API_URL;
168
+ let cachedHeaders = null;
169
+ async function getHeaders() {
170
+ if (!cachedHeaders) {
171
+ const publishToken = await derivePublishToken(apiKey);
172
+ cachedHeaders = {
173
+ 'Content-Type': 'application/json',
174
+ Authorization: `Bearer ${publishToken}`,
175
+ 'X-Hotpipe-SDK': SDK_VERSION,
176
+ };
177
+ }
178
+ return cachedHeaders;
179
+ }
180
+ async function postRevoke(body) {
181
+ const res = await fetch(`${apiUrl}/revoke`, {
182
+ method: 'POST',
183
+ headers: await getHeaders(),
184
+ body: JSON.stringify({ projectId, ...body }),
185
+ });
186
+ if (!res.ok) {
187
+ throw new Error(`hotpipe revoke failed: ${res.status} ${await res.text()}`);
188
+ }
189
+ }
190
+ async function postBatchRevoke(body) {
191
+ const res = await fetch(`${apiUrl}/revoke/batch`, {
192
+ method: 'POST',
193
+ headers: await getHeaders(),
194
+ body: JSON.stringify({ projectId, ...body }),
195
+ });
196
+ if (!res.ok) {
197
+ throw new Error(`hotpipe batch revoke failed: ${res.status} ${await res.text()}`);
198
+ }
199
+ }
200
+ return {
201
+ /**
202
+ * Revoke access to one or more pipes for a user.
203
+ *
204
+ * ```ts
205
+ * await pipeAdmin.revoke('user-123', 'room-xyz');
206
+ * await pipeAdmin.revoke('user-123', ['room-xyz', 'room-abc']);
207
+ * ```
208
+ */
209
+ async revoke(userId, pipe, options) {
210
+ if (Array.isArray(pipe)) {
211
+ const revocations = pipe.map((p) => ({ userId, pipe: p }));
212
+ await postBatchRevoke({ revocations, ttl: options?.ttl });
213
+ }
214
+ else {
215
+ await postRevoke({ userId, pipe, ttl: options?.ttl });
216
+ }
217
+ },
218
+ /**
219
+ * Revoke all pipe access for a user (e.g., account suspension).
220
+ *
221
+ * ```ts
222
+ * await pipeAdmin.revokeAll('user-123');
223
+ * ```
224
+ */
225
+ async revokeAll(userId, options) {
226
+ await postRevoke({ userId, allPipes: true, ttl: options?.ttl });
227
+ },
228
+ /**
229
+ * Batch-revoke access for multiple user/pipe combinations.
230
+ *
231
+ * ```ts
232
+ * await pipeAdmin.revokeBatch([
233
+ * { userId: 'user-123', pipe: 'room-xyz' },
234
+ * { userId: 'user-456', pipe: 'room-xyz' },
235
+ * ]);
236
+ * ```
237
+ */
238
+ async revokeBatch(revocations, options) {
239
+ await postBatchRevoke({ revocations, ttl: options?.ttl });
240
+ },
101
241
  };
102
242
  }
103
243
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export declare function parseSecret(secret: string): {
2
+ projectId: string;
3
+ apiKey: string;
4
+ };
5
+ //# sourceMappingURL=parse-secret.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse-secret.d.ts","sourceRoot":"","sources":["../../src/server/parse-secret.ts"],"names":[],"mappings":"AAAA,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAMjF"}
@@ -0,0 +1,8 @@
1
+ export function parseSecret(secret) {
2
+ const match = secret.match(/^hp_([a-zA-Z0-9]{8})_([a-zA-Z0-9]{32})$/);
3
+ if (!match || !match[1]) {
4
+ throw new Error('Invalid hotpipe secret format. Expected: hp_<id>_<key>');
5
+ }
6
+ return { projectId: match[1], apiKey: secret };
7
+ }
8
+ //# sourceMappingURL=parse-secret.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse-secret.js","sourceRoot":"","sources":["../../src/server/parse-secret.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,WAAW,CAAC,MAAc;IACxC,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,yCAAyC,CAAC,CAAC;IACtE,IAAI,CAAC,KAAK,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,wDAAwD,CAAC,CAAC;IAC5E,CAAC;IACD,OAAO,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;AACjD,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare const SDK_VERSION = "0.10.0";
2
+ //# sourceMappingURL=version.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,WAAW,WAAW,CAAC"}
@@ -0,0 +1,2 @@
1
+ export const SDK_VERSION = '0.10.0';
2
+ //# sourceMappingURL=version.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,WAAW,GAAG,QAAQ,CAAC"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "hotpipe",
3
- "version": "0.1.0",
4
- "description": "Type-safe real-time event broker SDK for React and Next.js",
3
+ "version": "0.10.0",
4
+ "description": "Type-safe real-time events for React and Next.js",
5
5
  "license": "MIT",
6
6
  "type": "module",
7
7
  "keywords": [
@@ -10,7 +10,7 @@
10
10
  "react",
11
11
  "hooks",
12
12
  "pubsub",
13
- "event-broker",
13
+ "events",
14
14
  "nextjs",
15
15
  "type-safe",
16
16
  "zod"
@@ -40,7 +40,7 @@
40
40
  "reset": "npm run clean && rm -rf node_modules"
41
41
  },
42
42
  "dependencies": {
43
- "jose": "^5.0.0"
43
+ "jose": "^6.1.3"
44
44
  },
45
45
  "peerDependencies": {
46
46
  "react": ">=18",
@@ -48,7 +48,7 @@
48
48
  },
49
49
  "devDependencies": {
50
50
  "@pepper/tsconfig": "1.0.0",
51
- "@types/react": ">=18",
52
- "typescript": "^5.0.0"
51
+ "@types/react": ">=19",
52
+ "typescript": "^5.9.3"
53
53
  }
54
54
  }