@vibecodeapp/sdk 0.1.0 → 0.2.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.
Files changed (44) hide show
  1. package/LICENSE +25 -11
  2. package/dist/dev/VibeDevWrapper.d.ts +9 -0
  3. package/dist/dev/VibeDevWrapper.d.ts.map +1 -0
  4. package/dist/dev/VibeDevWrapper.js +6 -0
  5. package/dist/dev/VibeDevWrapper.js.map +1 -0
  6. package/dist/dev/safe-insets.d.ts +9 -0
  7. package/dist/dev/safe-insets.d.ts.map +1 -0
  8. package/dist/dev/safe-insets.js +5 -0
  9. package/dist/dev/safe-insets.js.map +1 -0
  10. package/dist/dev/safe-insets.web.d.ts +9 -0
  11. package/dist/dev/safe-insets.web.d.ts.map +1 -0
  12. package/dist/dev/safe-insets.web.js +40 -0
  13. package/dist/dev/safe-insets.web.js.map +1 -0
  14. package/dist/index.d.ts +3 -1
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +5 -1
  17. package/dist/index.js.map +1 -1
  18. package/dist/polyfills/alert.web.d.ts +1 -1
  19. package/dist/polyfills/alert.web.d.ts.map +1 -1
  20. package/dist/polyfills/alert.web.js +1 -1
  21. package/dist/polyfills/alert.web.js.map +1 -1
  22. package/dist/polyfills/fetch.web.d.ts +14 -0
  23. package/dist/polyfills/fetch.web.d.ts.map +1 -0
  24. package/dist/polyfills/fetch.web.js +160 -0
  25. package/dist/polyfills/fetch.web.js.map +1 -0
  26. package/dist/polyfills/haptics.web.d.ts.map +1 -1
  27. package/dist/polyfills/haptics.web.js +3 -3
  28. package/dist/polyfills/haptics.web.js.map +1 -1
  29. package/dist/polyfills/maps.web.d.ts +1 -1
  30. package/dist/polyfills/maps.web.d.ts.map +1 -1
  31. package/dist/polyfills/maps.web.js +4 -4
  32. package/dist/polyfills/maps.web.js.map +1 -1
  33. package/dist/polyfills/refresh-control-component.d.ts +1 -1
  34. package/dist/polyfills/refresh-control-component.d.ts.map +1 -1
  35. package/dist/polyfills/refresh-control-component.js +13 -9
  36. package/dist/polyfills/refresh-control-component.js.map +1 -1
  37. package/dist/polyfills/secure-store.web.d.ts.map +1 -1
  38. package/dist/polyfills/secure-store.web.js +6 -6
  39. package/dist/polyfills/secure-store.web.js.map +1 -1
  40. package/metro/index.cjs +121 -108
  41. package/metro/index.d.ts +18 -18
  42. package/metro/metro-http-store.cjs +254 -254
  43. package/metro/transformer.cjs +69 -0
  44. package/package.json +59 -57
@@ -11,264 +11,264 @@
11
11
  * Requires an HTTP/2 server - will fail on HTTP/1.1.
12
12
  */
13
13
 
14
- const http2 = require("node:http2");
15
- const zlib = require("node:zlib");
16
- const { Buffer } = require("node:buffer");
17
- const pLimit = require("p-limit");
14
+ const http2 = require('node:http2')
15
+ const zlib = require('node:zlib')
16
+ const { Buffer } = require('node:buffer')
17
+ const pLimit = require('p-limit')
18
18
 
19
- const NULL_BYTE = 0x00;
20
- const NULL_BYTE_BUFFER = Buffer.from([NULL_BYTE]);
19
+ const NULL_BYTE = 0x00
20
+ const NULL_BYTE_BUFFER = Buffer.from([NULL_BYTE])
21
21
 
22
22
  const ZLIB_OPTIONS = {
23
- level: 9,
24
- };
23
+ level: 9,
24
+ }
25
25
 
26
26
  class HttpStore {
27
- #origin;
28
- #path;
29
- #timeout;
30
- #sessions = [];
31
- #maxConnections;
32
- #nextSession = 0;
33
- #limit;
34
-
35
- /**
36
- * @param {Object} options
37
- * @param {string} options.endpoint - Full URL to the cache server (e.g., "https://cache.example.com/metro")
38
- * @param {number} [options.timeout=10000] - Request timeout in milliseconds
39
- * @param {number} [options.maxConnections=8] - Number of HTTP/2 connections in pool
40
- * @param {number} [options.maxConcurrent=64] - Max concurrent requests in flight
41
- */
42
- constructor(options) {
43
- const url = new URL(options.endpoint);
44
- this.#origin = url.origin;
45
- this.#path = url.pathname.replace(/\/$/, ""); // Remove trailing slash
46
- this.#timeout = options.timeout ?? 10000;
47
- this.#maxConnections = options.maxConnections ?? 8;
48
- this.#limit = pLimit(options.maxConcurrent ?? 64);
49
- }
50
-
51
- /**
52
- * Get an HTTP/2 session from the pool using round-robin.
53
- * Lazily creates connections on first use.
54
- * Never throws - returns null if connection fails.
55
- */
56
- #getSession() {
57
- // Round-robin through connections
58
- const index = this.#nextSession++ % this.#maxConnections;
59
-
60
- // Check if we have a valid session at this index
61
- const existing = this.#sessions[index];
62
- if (existing && !existing.closed && !existing.destroyed) {
63
- return existing;
64
- }
65
-
66
- // Create new session for this slot
67
- try {
68
- const session = http2.connect(this.#origin);
69
-
70
- session.on("error", (err) => {
71
- console.warn("[HttpStore] Session error:", err.message);
72
- if (this.#sessions[index] === session) {
73
- this.#sessions[index] = null;
74
- }
75
- });
76
-
77
- session.on("close", () => {
78
- if (this.#sessions[index] === session) {
79
- this.#sessions[index] = null;
80
- }
81
- });
82
-
83
- this.#sessions[index] = session;
84
- return session;
85
- } catch (err) {
86
- console.warn("[HttpStore] Failed to connect:", err.message);
87
- return null;
88
- }
89
- }
90
-
91
- /**
92
- * GET - Blocking read from cache.
93
- * Returns null on any error (network, timeout, parse) - never throws.
94
- * @param {Buffer} key
95
- * @returns {Promise<any|null>}
96
- */
97
- async get(key) {
98
- try {
99
- return await this.#limit(() => this.#doGet(key));
100
- } catch (err) {
101
- console.warn("[HttpStore] Get failed:", err.message);
102
- return null; // Fall back to next cache store (FileStore)
103
- }
104
- }
105
-
106
- #doGet(key) {
107
- return new Promise((resolve, reject) => {
108
- const session = this.#getSession();
109
- if (!session) {
110
- reject(new Error("No session available"));
111
- return;
112
- }
113
-
114
- const path = `${this.#path}/${key.toString("hex")}`;
115
- const req = session.request({
116
- ":method": "GET",
117
- ":path": path,
118
- });
119
-
120
- const timeoutId = setTimeout(() => {
121
- req.close(http2.constants.NGHTTP2_CANCEL);
122
- reject(new Error("Request timed out"));
123
- }, this.#timeout);
124
-
125
- const chunks = [];
126
-
127
- req.on("response", (headers) => {
128
- const status = headers[":status"];
129
-
130
- // 404 = cache miss
131
- if (status === 404) {
132
- clearTimeout(timeoutId);
133
- req.close();
134
- resolve(null);
135
- return;
136
- }
137
-
138
- // Non-2xx = error
139
- if (status < 200 || status >= 300) {
140
- clearTimeout(timeoutId);
141
- req.close();
142
- reject(new Error(`HTTP error: ${status}`));
143
- return;
144
- }
145
- });
146
-
147
- req.on("data", (chunk) => {
148
- chunks.push(chunk);
149
- });
150
-
151
- req.on("end", () => {
152
- clearTimeout(timeoutId);
153
-
154
- const compressed = Buffer.concat(chunks);
155
- if (compressed.length === 0) {
156
- resolve(null);
157
- return;
158
- }
159
-
160
- // Decompress the response
161
- zlib.gunzip(compressed, (err, buffer) => {
162
- if (err) {
163
- reject(err);
164
- return;
165
- }
166
-
167
- try {
168
- // If first byte is NULL_BYTE, it's a raw Buffer
169
- if (buffer.length > 0 && buffer[0] === NULL_BYTE) {
170
- resolve(buffer.subarray(1));
171
- } else {
172
- resolve(JSON.parse(buffer.toString("utf8")));
173
- }
174
- } catch (parseErr) {
175
- reject(parseErr);
176
- }
177
- });
178
- });
179
-
180
- req.on("error", (err) => {
181
- clearTimeout(timeoutId);
182
- reject(err);
183
- });
184
-
185
- req.end();
186
- });
187
- }
188
-
189
- /**
190
- * SET - Non-blocking write to cache.
191
- * Returns immediately, HTTP request happens in background.
192
- * @param {Buffer} key
193
- * @param {any} value
194
- * @returns {Promise<void>}
195
- */
196
- set(key, value) {
197
- // Fire and forget - queue the work but return immediately
198
- this.#limit(() => this.#doSet(key, value)).catch((err) => {
199
- console.warn("[HttpStore] Background write failed:", err.message);
200
- });
201
-
202
- return Promise.resolve();
203
- }
204
-
205
- #doSet(key, value) {
206
- return new Promise((resolve, reject) => {
207
- const session = this.#getSession();
208
- if (!session) {
209
- reject(new Error("No session available"));
210
- return;
211
- }
212
-
213
- const path = `${this.#path}/${key.toString("hex")}`;
214
-
215
- // Prepare data to compress
216
- let data;
217
- if (Buffer.isBuffer(value)) {
218
- // Prepend NULL_BYTE marker for Buffer values
219
- data = Buffer.concat([NULL_BYTE_BUFFER, value]);
220
- } else {
221
- data = Buffer.from(JSON.stringify(value) ?? "null", "utf8");
222
- }
223
-
224
- // Compress the data
225
- zlib.gzip(data, ZLIB_OPTIONS, (err, compressed) => {
226
- if (err) {
227
- reject(err);
228
- return;
229
- }
230
-
231
- const req = session.request({
232
- ":method": "PUT",
233
- ":path": path,
234
- "content-type": "application/octet-stream",
235
- "content-length": compressed.length,
236
- });
237
-
238
- const timeoutId = setTimeout(() => {
239
- req.close(http2.constants.NGHTTP2_CANCEL);
240
- reject(new Error("Request timed out"));
241
- }, this.#timeout);
242
-
243
- req.on("response", (headers) => {
244
- const status = headers[":status"];
245
-
246
- clearTimeout(timeoutId);
247
-
248
- if (status >= 200 && status < 300) {
249
- resolve();
250
- } else {
251
- reject(new Error(`HTTP error: ${status}`));
252
- }
253
- });
254
-
255
- req.on("error", (err) => {
256
- clearTimeout(timeoutId);
257
- reject(err);
258
- });
259
-
260
- req.write(compressed);
261
- req.end();
262
- });
263
- });
264
- }
265
-
266
- /**
267
- * CLEAR - Not implemented.
268
- */
269
- clear() {
270
- // No-op - Metro's HTTP cache protocol doesn't define a clear operation
271
- }
27
+ #origin
28
+ #path
29
+ #timeout
30
+ #sessions = []
31
+ #maxConnections
32
+ #nextSession = 0
33
+ #limit
34
+
35
+ /**
36
+ * @param {Object} options
37
+ * @param {string} options.endpoint - Full URL to the cache server (e.g., "https://cache.example.com/metro")
38
+ * @param {number} [options.timeout=10000] - Request timeout in milliseconds
39
+ * @param {number} [options.maxConnections=8] - Number of HTTP/2 connections in pool
40
+ * @param {number} [options.maxConcurrent=64] - Max concurrent requests in flight
41
+ */
42
+ constructor(options) {
43
+ const url = new URL(options.endpoint)
44
+ this.#origin = url.origin
45
+ this.#path = url.pathname.replace(/\/$/, '') // Remove trailing slash
46
+ this.#timeout = options.timeout ?? 10000
47
+ this.#maxConnections = options.maxConnections ?? 8
48
+ this.#limit = pLimit(options.maxConcurrent ?? 64)
49
+ }
50
+
51
+ /**
52
+ * Get an HTTP/2 session from the pool using round-robin.
53
+ * Lazily creates connections on first use.
54
+ * Never throws - returns null if connection fails.
55
+ */
56
+ #getSession() {
57
+ // Round-robin through connections
58
+ const index = this.#nextSession++ % this.#maxConnections
59
+
60
+ // Check if we have a valid session at this index
61
+ const existing = this.#sessions[index]
62
+ if (existing && !existing.closed && !existing.destroyed) {
63
+ return existing
64
+ }
65
+
66
+ // Create new session for this slot
67
+ try {
68
+ const session = http2.connect(this.#origin)
69
+
70
+ session.on('error', (err) => {
71
+ console.warn('[HttpStore] Session error:', err.message)
72
+ if (this.#sessions[index] === session) {
73
+ this.#sessions[index] = null
74
+ }
75
+ })
76
+
77
+ session.on('close', () => {
78
+ if (this.#sessions[index] === session) {
79
+ this.#sessions[index] = null
80
+ }
81
+ })
82
+
83
+ this.#sessions[index] = session
84
+ return session
85
+ } catch (err) {
86
+ console.warn('[HttpStore] Failed to connect:', err.message)
87
+ return null
88
+ }
89
+ }
90
+
91
+ /**
92
+ * GET - Blocking read from cache.
93
+ * Returns null on any error (network, timeout, parse) - never throws.
94
+ * @param {Buffer} key
95
+ * @returns {Promise<any|null>}
96
+ */
97
+ async get(key) {
98
+ try {
99
+ return await this.#limit(() => this.#doGet(key))
100
+ } catch (err) {
101
+ console.warn('[HttpStore] Get failed:', err.message)
102
+ return null // Fall back to next cache store (FileStore)
103
+ }
104
+ }
105
+
106
+ #doGet(key) {
107
+ return new Promise((resolve, reject) => {
108
+ const session = this.#getSession()
109
+ if (!session) {
110
+ reject(new Error('No session available'))
111
+ return
112
+ }
113
+
114
+ const path = `${this.#path}/${key.toString('hex')}`
115
+ const req = session.request({
116
+ ':method': 'GET',
117
+ ':path': path,
118
+ })
119
+
120
+ const timeoutId = setTimeout(() => {
121
+ req.close(http2.constants.NGHTTP2_CANCEL)
122
+ reject(new Error('Request timed out'))
123
+ }, this.#timeout)
124
+
125
+ const chunks = []
126
+
127
+ req.on('response', (headers) => {
128
+ const status = headers[':status']
129
+
130
+ // 404 = cache miss
131
+ if (status === 404) {
132
+ clearTimeout(timeoutId)
133
+ req.close()
134
+ resolve(null)
135
+ return
136
+ }
137
+
138
+ // Non-2xx = error
139
+ if (status < 200 || status >= 300) {
140
+ clearTimeout(timeoutId)
141
+ req.close()
142
+ reject(new Error(`HTTP error: ${status}`))
143
+ return
144
+ }
145
+ })
146
+
147
+ req.on('data', (chunk) => {
148
+ chunks.push(chunk)
149
+ })
150
+
151
+ req.on('end', () => {
152
+ clearTimeout(timeoutId)
153
+
154
+ const compressed = Buffer.concat(chunks)
155
+ if (compressed.length === 0) {
156
+ resolve(null)
157
+ return
158
+ }
159
+
160
+ // Decompress the response
161
+ zlib.gunzip(compressed, (err, buffer) => {
162
+ if (err) {
163
+ reject(err)
164
+ return
165
+ }
166
+
167
+ try {
168
+ // If first byte is NULL_BYTE, it's a raw Buffer
169
+ if (buffer.length > 0 && buffer[0] === NULL_BYTE) {
170
+ resolve(buffer.subarray(1))
171
+ } else {
172
+ resolve(JSON.parse(buffer.toString('utf8')))
173
+ }
174
+ } catch (parseErr) {
175
+ reject(parseErr)
176
+ }
177
+ })
178
+ })
179
+
180
+ req.on('error', (err) => {
181
+ clearTimeout(timeoutId)
182
+ reject(err)
183
+ })
184
+
185
+ req.end()
186
+ })
187
+ }
188
+
189
+ /**
190
+ * SET - Non-blocking write to cache.
191
+ * Returns immediately, HTTP request happens in background.
192
+ * @param {Buffer} key
193
+ * @param {any} value
194
+ * @returns {Promise<void>}
195
+ */
196
+ set(key, value) {
197
+ // Fire and forget - queue the work but return immediately
198
+ this.#limit(() => this.#doSet(key, value)).catch((err) => {
199
+ console.warn('[HttpStore] Background write failed:', err.message)
200
+ })
201
+
202
+ return Promise.resolve()
203
+ }
204
+
205
+ #doSet(key, value) {
206
+ return new Promise((resolve, reject) => {
207
+ const session = this.#getSession()
208
+ if (!session) {
209
+ reject(new Error('No session available'))
210
+ return
211
+ }
212
+
213
+ const path = `${this.#path}/${key.toString('hex')}`
214
+
215
+ // Prepare data to compress
216
+ let data
217
+ if (Buffer.isBuffer(value)) {
218
+ // Prepend NULL_BYTE marker for Buffer values
219
+ data = Buffer.concat([NULL_BYTE_BUFFER, value])
220
+ } else {
221
+ data = Buffer.from(JSON.stringify(value) ?? 'null', 'utf8')
222
+ }
223
+
224
+ // Compress the data
225
+ zlib.gzip(data, ZLIB_OPTIONS, (err, compressed) => {
226
+ if (err) {
227
+ reject(err)
228
+ return
229
+ }
230
+
231
+ const req = session.request({
232
+ ':method': 'PUT',
233
+ ':path': path,
234
+ 'content-type': 'application/octet-stream',
235
+ 'content-length': compressed.length,
236
+ })
237
+
238
+ const timeoutId = setTimeout(() => {
239
+ req.close(http2.constants.NGHTTP2_CANCEL)
240
+ reject(new Error('Request timed out'))
241
+ }, this.#timeout)
242
+
243
+ req.on('response', (headers) => {
244
+ const status = headers[':status']
245
+
246
+ clearTimeout(timeoutId)
247
+
248
+ if (status >= 200 && status < 300) {
249
+ resolve()
250
+ } else {
251
+ reject(new Error(`HTTP error: ${status}`))
252
+ }
253
+ })
254
+
255
+ req.on('error', (err) => {
256
+ clearTimeout(timeoutId)
257
+ reject(err)
258
+ })
259
+
260
+ req.write(compressed)
261
+ req.end()
262
+ })
263
+ })
264
+ }
265
+
266
+ /**
267
+ * CLEAR - Not implemented.
268
+ */
269
+ clear() {
270
+ // No-op - Metro's HTTP cache protocol doesn't define a clear operation
271
+ }
272
272
  }
273
273
 
274
- module.exports = { HttpStore };
274
+ module.exports = { HttpStore }
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Metro transformer that automatically wraps _layout.tsx with Vibecode providers
3
+ * Uses simple string transformations to inject wrappers
4
+ */
5
+
6
+ // Chain to SVG transformer, which then chains to the default babel transformer
7
+ // Cant use @expo/metro-config/babel-transformer because it doesnt chain to the SVG transformer.
8
+ const upstreamTransformer = require('react-native-svg-transformer/expo')
9
+
10
+ /**
11
+ * Checks if the file is the root _layout.tsx
12
+ */
13
+ function isRootLayout(filename) {
14
+ return (
15
+ (filename.includes('app/_layout.tsx') ||
16
+ filename.includes('app/_layout.js')) &&
17
+ !filename.includes('app/(') // Exclude grouped layouts
18
+ )
19
+ }
20
+
21
+ /**
22
+ * Wraps the layout component with Vibecode providers
23
+ */
24
+ function wrapLayoutWithProviders(src) {
25
+ // Find the default export function
26
+ const defaultExportPattern = /export\s+default\s+function\s+(\w+)/
27
+ const match = src.match(defaultExportPattern)
28
+
29
+ if (!match) {
30
+ return src // Can't transform, return as-is
31
+ }
32
+
33
+ const originalFunctionName = match[1]
34
+
35
+ // Remove the default keyword from the original function
36
+ let transformed = src.replace(
37
+ defaultExportPattern,
38
+ `function ${originalFunctionName}`,
39
+ )
40
+
41
+ // Add wrapper import at the top
42
+ transformed = `import { VibeDevWrapper } from '@vibecodeapp/sdk';\n${transformed}`
43
+
44
+ // Add new default export that wraps the original function
45
+ const newDefaultExport = `
46
+ export default function VibeRootLayoutWrapper() {
47
+ return (
48
+ <VibeDevWrapper>
49
+ <${originalFunctionName} />
50
+ </VibeDevWrapper>
51
+ );
52
+ }
53
+ `
54
+
55
+ transformed = transformed + '\n' + newDefaultExport
56
+
57
+ return transformed
58
+ }
59
+
60
+ async function transform(props) {
61
+ if (isRootLayout(props.filename)) {
62
+ const transformedSrc = wrapLayoutWithProviders(props.src)
63
+ return upstreamTransformer.transform({ ...props, src: transformedSrc })
64
+ }
65
+
66
+ return upstreamTransformer.transform(props)
67
+ }
68
+
69
+ module.exports = { transform }