@usesidekick/react 0.1.0 → 0.1.2
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 +190 -147
- package/dist/server/index.d.mts +3 -1
- package/dist/server/index.d.ts +3 -1
- package/dist/server/index.js +77 -0
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +76 -0
- package/dist/server/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/server/index.ts +1 -0
- package/src/server/json-storage.ts +88 -0
package/README.md
CHANGED
|
@@ -1,40 +1,55 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @usesidekick/react
|
|
2
2
|
|
|
3
|
-
Zero-change
|
|
3
|
+
Zero-change runtime for extensible React applications. Override modules can wrap, replace, or enhance any component by name without modifying the host app's source code.
|
|
4
4
|
|
|
5
|
-
##
|
|
6
|
-
|
|
7
|
-
### 1. Install
|
|
5
|
+
## Installation
|
|
8
6
|
|
|
9
7
|
```bash
|
|
10
8
|
npm install @usesidekick/react
|
|
11
9
|
```
|
|
12
10
|
|
|
13
|
-
|
|
11
|
+
For the full automated setup (installs deps, configures build, creates API routes):
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npx @usesidekick/cli init
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Quick Start
|
|
18
|
+
|
|
19
|
+
### 1. Wrap Your App
|
|
14
20
|
|
|
15
21
|
```tsx
|
|
16
22
|
import { SidekickProvider } from '@usesidekick/react';
|
|
17
23
|
|
|
18
24
|
export default function App() {
|
|
19
25
|
return (
|
|
20
|
-
<SidekickProvider>
|
|
26
|
+
<SidekickProvider overridesEndpoint="/api/sidekick/overrides">
|
|
21
27
|
<YourApp />
|
|
22
28
|
</SidekickProvider>
|
|
23
29
|
);
|
|
24
30
|
}
|
|
25
31
|
```
|
|
26
32
|
|
|
27
|
-
###
|
|
33
|
+
### 2. Add the Build Plugin
|
|
34
|
+
|
|
35
|
+
The `babel-plugin-add-react-displayname` plugin preserves component names through minification so overrides can target them in production.
|
|
28
36
|
|
|
29
|
-
|
|
37
|
+
```bash
|
|
38
|
+
npm install -D babel-plugin-add-react-displayname
|
|
39
|
+
```
|
|
30
40
|
|
|
31
|
-
**Next.js** (`
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
41
|
+
**Next.js** (`.babelrc`):
|
|
42
|
+
```json
|
|
43
|
+
{
|
|
44
|
+
"presets": [
|
|
45
|
+
["next/babel", {
|
|
46
|
+
"preset-react": {
|
|
47
|
+
"runtime": "automatic",
|
|
48
|
+
"importSource": "@usesidekick/react"
|
|
49
|
+
}
|
|
50
|
+
}]
|
|
51
|
+
],
|
|
52
|
+
"plugins": ["add-react-displayname"]
|
|
38
53
|
}
|
|
39
54
|
```
|
|
40
55
|
|
|
@@ -45,41 +60,25 @@ import react from '@vitejs/plugin-react';
|
|
|
45
60
|
export default {
|
|
46
61
|
plugins: [
|
|
47
62
|
react({
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
}
|
|
63
|
+
jsxImportSource: '@usesidekick/react',
|
|
64
|
+
babel: { plugins: ['add-react-displayname'] }
|
|
51
65
|
})
|
|
52
66
|
]
|
|
53
67
|
}
|
|
54
68
|
```
|
|
55
69
|
|
|
56
|
-
|
|
57
|
-
```json
|
|
58
|
-
{
|
|
59
|
-
"plugins": ["add-react-displayname"]
|
|
60
|
-
}
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
That's it! Override modules can now customize any component in your app.
|
|
64
|
-
|
|
65
|
-
## How Override Modules Work
|
|
66
|
-
|
|
67
|
-
Override modules use the SDK to wrap or replace components by name:
|
|
68
|
-
|
|
69
|
-
### Wrapping Components
|
|
70
|
-
|
|
71
|
-
Add behavior around any component without modifying it:
|
|
70
|
+
### 3. Write an Override
|
|
72
71
|
|
|
73
72
|
```tsx
|
|
74
73
|
import { createOverride } from '@usesidekick/react';
|
|
75
74
|
|
|
76
75
|
export default createOverride({
|
|
77
|
-
name: '
|
|
76
|
+
name: 'Beta Banner',
|
|
78
77
|
primitives: ['ui.wrap'],
|
|
79
78
|
activate: (sdk) => {
|
|
80
|
-
sdk.ui.wrap('
|
|
81
|
-
<div
|
|
82
|
-
<
|
|
79
|
+
sdk.ui.wrap('TaskBoard', (Original) => (props) => (
|
|
80
|
+
<div>
|
|
81
|
+
<div style={{ background: 'purple', color: 'white', padding: 8 }}>Beta</div>
|
|
83
82
|
<Original {...props} />
|
|
84
83
|
</div>
|
|
85
84
|
));
|
|
@@ -87,159 +86,203 @@ export default createOverride({
|
|
|
87
86
|
});
|
|
88
87
|
```
|
|
89
88
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
Completely swap out a component:
|
|
93
|
-
|
|
94
|
-
```tsx
|
|
95
|
-
import { createOverride } from '@usesidekick/react';
|
|
96
|
-
import { MyCustomModal } from './MyCustomModal';
|
|
97
|
-
|
|
98
|
-
export default createOverride({
|
|
99
|
-
name: 'Custom Modal',
|
|
100
|
-
primitives: ['ui.replace'],
|
|
101
|
-
activate: (sdk) => {
|
|
102
|
-
sdk.ui.replace('TaskModal', MyCustomModal);
|
|
103
|
-
},
|
|
104
|
-
});
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
### Injecting Styles
|
|
108
|
-
|
|
109
|
-
Add CSS without touching any files:
|
|
110
|
-
|
|
111
|
-
```tsx
|
|
112
|
-
sdk.ui.addStyles(`
|
|
113
|
-
.task-card {
|
|
114
|
-
border-radius: 12px;
|
|
115
|
-
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
|
116
|
-
}
|
|
117
|
-
`);
|
|
118
|
-
```
|
|
119
|
-
|
|
120
|
-
## Component Name Resolution
|
|
121
|
-
|
|
122
|
-
The SDK resolves component names in this order:
|
|
123
|
-
|
|
124
|
-
1. **displayName** - Explicit name, survives minification
|
|
125
|
-
2. **function name** - Works in development
|
|
126
|
-
3. **Inner component** - For memo/forwardRef wrapped components
|
|
127
|
-
|
|
128
|
-
| Environment | Name Source | Works? |
|
|
129
|
-
|------------|-------------|--------|
|
|
130
|
-
| Development | function name | Always |
|
|
131
|
-
| Production (with build plugin) | auto-added displayName | Always |
|
|
132
|
-
| Production (without plugin) | minified name | Breaks |
|
|
133
|
-
|
|
134
|
-
For best results, either:
|
|
135
|
-
- Use the babel plugin (recommended, zero per-component changes)
|
|
136
|
-
- Or manually add `displayName` to components you want to target
|
|
137
|
-
|
|
138
|
-
## API Reference
|
|
139
|
-
|
|
140
|
-
### SidekickProvider
|
|
141
|
-
|
|
142
|
-
```tsx
|
|
143
|
-
<SidekickProvider
|
|
144
|
-
overridesEndpoint="/api/overrides" // Optional: API endpoint for remote overrides
|
|
145
|
-
>
|
|
146
|
-
{children}
|
|
147
|
-
</SidekickProvider>
|
|
148
|
-
```
|
|
149
|
-
|
|
150
|
-
### SDK Primitives
|
|
89
|
+
## Override Primitives
|
|
151
90
|
|
|
152
|
-
|
|
91
|
+
### UI
|
|
153
92
|
|
|
154
93
|
| Method | Description |
|
|
155
94
|
|--------|-------------|
|
|
156
|
-
| `sdk.ui.wrap(name, wrapper)` | Wrap a component
|
|
157
|
-
| `sdk.ui.replace(name, component)` | Replace a component
|
|
158
|
-
| `sdk.ui.inject(extensionPointId, component)` | Inject into an ExtensionPoint |
|
|
95
|
+
| `sdk.ui.wrap(name, wrapper)` | Wrap a component with additional markup/logic |
|
|
96
|
+
| `sdk.ui.replace(name, component)` | Replace a component entirely |
|
|
97
|
+
| `sdk.ui.inject(extensionPointId, component)` | Inject into an `<ExtensionPoint>` slot |
|
|
159
98
|
| `sdk.ui.addStyles(css)` | Inject global CSS |
|
|
160
99
|
| `sdk.ui.addColumn(tableId, config)` | Add a column to a table |
|
|
161
100
|
| `sdk.ui.addMenuItem(menuId, config)` | Add a menu item |
|
|
162
101
|
| `sdk.ui.addTab(tabGroupId, config)` | Add a tab |
|
|
163
102
|
| `sdk.ui.addAction(actionBarId, config)` | Add an action button |
|
|
164
|
-
| `sdk.ui.modifyProps(componentId, modifier)` | Modify component props |
|
|
103
|
+
| `sdk.ui.modifyProps(componentId, modifier)` | Modify a component's props at render time |
|
|
165
104
|
|
|
166
|
-
|
|
105
|
+
### Data
|
|
167
106
|
|
|
168
107
|
| Method | Description |
|
|
169
108
|
|--------|-------------|
|
|
170
|
-
| `sdk.data.computed(fieldName, compute)` | Add a computed field |
|
|
109
|
+
| `sdk.data.computed(fieldName, compute)` | Add a computed/derived field |
|
|
171
110
|
| `sdk.data.addFilter(name, filter)` | Add a data filter |
|
|
172
|
-
| `sdk.data.transform(dataKey, transform)` | Transform data |
|
|
111
|
+
| `sdk.data.transform(dataKey, transform)` | Transform data before render |
|
|
173
112
|
| `sdk.data.intercept(pathPattern, handler)` | Intercept API responses |
|
|
174
113
|
| `sdk.data.addSortOption(tableId, config)` | Add a sort option |
|
|
175
114
|
| `sdk.data.addGroupBy(tableId, config)` | Add a group-by option |
|
|
176
115
|
|
|
177
|
-
|
|
116
|
+
### Behavior
|
|
178
117
|
|
|
179
118
|
| Method | Description |
|
|
180
119
|
|--------|-------------|
|
|
181
|
-
| `sdk.behavior.onEvent(name, handler)` |
|
|
182
|
-
| `sdk.behavior.addKeyboardShortcut(keys, action)` |
|
|
120
|
+
| `sdk.behavior.onEvent(name, handler)` | Listen for custom events |
|
|
121
|
+
| `sdk.behavior.addKeyboardShortcut(keys, action)` | Register keyboard shortcuts |
|
|
183
122
|
| `sdk.behavior.modifyRoute(pattern, handler)` | Modify routing behavior |
|
|
184
123
|
|
|
185
|
-
##
|
|
124
|
+
## React Hooks
|
|
186
125
|
|
|
187
|
-
|
|
126
|
+
The SDK provides hooks for host apps that want to read override state:
|
|
188
127
|
|
|
189
128
|
```tsx
|
|
190
|
-
import {
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
129
|
+
import {
|
|
130
|
+
useAddedColumns,
|
|
131
|
+
useColumnRenames,
|
|
132
|
+
useHiddenColumns,
|
|
133
|
+
useColumnOrder,
|
|
134
|
+
useMenuItems,
|
|
135
|
+
useTabs,
|
|
136
|
+
useActions,
|
|
137
|
+
useValidations,
|
|
138
|
+
usePropsModifier,
|
|
139
|
+
useComputedField,
|
|
140
|
+
useFilter,
|
|
141
|
+
useSortOptions,
|
|
142
|
+
useGroupByOptions,
|
|
143
|
+
useKeyboardShortcuts,
|
|
144
|
+
useEventEmitter,
|
|
145
|
+
} from '@usesidekick/react';
|
|
200
146
|
```
|
|
201
147
|
|
|
202
|
-
|
|
148
|
+
## SidekickPanel
|
|
149
|
+
|
|
150
|
+
A built-in admin panel for managing overrides at runtime. Supports AI-powered generation, toggling, and deletion.
|
|
203
151
|
|
|
204
152
|
```tsx
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
153
|
+
import { SidekickPanel } from '@usesidekick/react';
|
|
154
|
+
|
|
155
|
+
<SidekickPanel
|
|
156
|
+
apiEndpoint="/api/sidekick/generate"
|
|
157
|
+
toggleEndpoint="/api/sidekick/toggle"
|
|
158
|
+
deleteEndpoint="/api/sidekick/delete"
|
|
159
|
+
/>
|
|
208
160
|
```
|
|
209
161
|
|
|
210
|
-
|
|
162
|
+
| Prop | Type | Description |
|
|
163
|
+
|------|------|-------------|
|
|
164
|
+
| `apiEndpoint` | `string?` | Endpoint for AI override generation |
|
|
165
|
+
| `toggleEndpoint` | `string?` | Endpoint for enable/disable |
|
|
166
|
+
| `deleteEndpoint` | `string?` | Endpoint for deletion |
|
|
167
|
+
| `onGenerate` | `function?` | Custom generate handler (overrides `apiEndpoint`) |
|
|
168
|
+
| `onToggle` | `function?` | Custom toggle handler (overrides `toggleEndpoint`) |
|
|
169
|
+
| `onDelete` | `function?` | Custom delete handler (overrides `deleteEndpoint`) |
|
|
170
|
+
|
|
171
|
+
## Server (`@usesidekick/react/server`)
|
|
172
|
+
|
|
173
|
+
Server-side utilities for building the Sidekick API backend. Handles override CRUD, AI generation, and validation.
|
|
211
174
|
|
|
212
|
-
###
|
|
175
|
+
### Setup with Drizzle + Neon
|
|
213
176
|
|
|
214
|
-
|
|
177
|
+
```ts
|
|
178
|
+
// app/api/sidekick/[...action]/route.ts
|
|
179
|
+
import { createSidekickHandler, createDrizzleStorage } from '@usesidekick/react/server';
|
|
180
|
+
import { db } from '@/lib/db';
|
|
181
|
+
import { overrides } from '@/lib/db/schema';
|
|
182
|
+
|
|
183
|
+
const handler = createSidekickHandler({
|
|
184
|
+
storage: createDrizzleStorage(db, overrides),
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
export const GET = handler.GET;
|
|
188
|
+
export const POST = handler.POST;
|
|
189
|
+
```
|
|
215
190
|
|
|
216
|
-
|
|
217
|
-
|
|
191
|
+
This single catch-all route handles four actions (dispatched by the last URL path segment):
|
|
192
|
+
|
|
193
|
+
| Method | Path | Action |
|
|
194
|
+
|--------|------|--------|
|
|
195
|
+
| GET | `/api/sidekick/overrides` | List all overrides |
|
|
196
|
+
| POST | `/api/sidekick/generate` | AI-generate an override |
|
|
197
|
+
| POST | `/api/sidekick/toggle` | Enable/disable an override |
|
|
198
|
+
| POST | `/api/sidekick/delete` | Delete an override |
|
|
199
|
+
|
|
200
|
+
### Server Exports
|
|
201
|
+
|
|
202
|
+
```ts
|
|
203
|
+
import {
|
|
204
|
+
// Handler factory
|
|
205
|
+
createSidekickHandler,
|
|
206
|
+
|
|
207
|
+
// Storage
|
|
208
|
+
createDrizzleStorage, // Drizzle ORM adapter
|
|
209
|
+
sidekickOverrides, // pgTable definition (for your schema)
|
|
210
|
+
|
|
211
|
+
// AI generation (for custom integrations)
|
|
212
|
+
buildSystemPrompt,
|
|
213
|
+
buildUserPrompt,
|
|
214
|
+
callAI,
|
|
215
|
+
parseAIResponse,
|
|
216
|
+
validateCode,
|
|
217
|
+
formatDesignSystem,
|
|
218
|
+
} from '@usesidekick/react/server';
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
### Custom Storage Adapter
|
|
222
|
+
|
|
223
|
+
Implement `SidekickStorage` to use any database:
|
|
224
|
+
|
|
225
|
+
```ts
|
|
226
|
+
import type { SidekickStorage } from '@usesidekick/react/server';
|
|
227
|
+
|
|
228
|
+
const myStorage: SidekickStorage = {
|
|
229
|
+
listOverrides: async () => { /* ... */ },
|
|
230
|
+
getOverride: async (id) => { /* ... */ },
|
|
231
|
+
createOverride: async (data) => { /* ... */ },
|
|
232
|
+
updateOverride: async (id, data) => { /* ... */ },
|
|
233
|
+
deleteOverride: async (id) => { /* ... */ },
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
const handler = createSidekickHandler({ storage: myStorage });
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
## How It Works
|
|
240
|
+
|
|
241
|
+
The SDK overrides `React.createElement` via a custom JSX runtime to intercept every component render. When a component renders, it checks:
|
|
242
|
+
|
|
243
|
+
1. Is there a **replacement** registered for this component? Use it.
|
|
244
|
+
2. Is there a **wrapper** registered? Wrap the original.
|
|
218
245
|
3. Otherwise, render normally.
|
|
219
246
|
|
|
220
|
-
This
|
|
247
|
+
This requires **zero changes** to existing components.
|
|
248
|
+
|
|
249
|
+
### Component Name Resolution
|
|
250
|
+
|
|
251
|
+
Names are resolved in order: `displayName` > `function.name` > inner component name (for memo/forwardRef).
|
|
252
|
+
|
|
253
|
+
| Environment | Name Source | Reliable? |
|
|
254
|
+
|-------------|-------------|-----------|
|
|
255
|
+
| Development | function name | Yes |
|
|
256
|
+
| Production + build plugin | auto-added displayName | Yes |
|
|
257
|
+
| Production without plugin | minified name | No |
|
|
221
258
|
|
|
222
259
|
### Performance
|
|
223
260
|
|
|
224
|
-
- One Map
|
|
225
|
-
-
|
|
226
|
-
- No impact when no overrides are registered
|
|
261
|
+
- One `Map.get()` per `createElement` call
|
|
262
|
+
- No overhead when no overrides are registered
|
|
227
263
|
|
|
228
264
|
### Compatibility
|
|
229
265
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
266
|
+
Works with: functional components, class components, `React.memo`, `React.forwardRef`, Suspense, Portals.
|
|
267
|
+
|
|
268
|
+
**Not supported:** React Server Components (client-side only).
|
|
269
|
+
|
|
270
|
+
## Package Exports
|
|
271
|
+
|
|
272
|
+
| Import Path | Description |
|
|
273
|
+
|-------------|-------------|
|
|
274
|
+
| `@usesidekick/react` | Provider, hooks, panel, override API, types |
|
|
275
|
+
| `@usesidekick/react/jsx-runtime` | Custom JSX runtime (configured via `jsxImportSource`) |
|
|
276
|
+
| `@usesidekick/react/jsx-dev-runtime` | Development JSX runtime |
|
|
277
|
+
| `@usesidekick/react/server` | Server handler, storage adapters, AI generation |
|
|
237
278
|
|
|
238
|
-
|
|
279
|
+
## Peer Dependencies
|
|
239
280
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
281
|
+
| Package | Version | Required? |
|
|
282
|
+
|---------|---------|-----------|
|
|
283
|
+
| `react` | ^18.2.0 | Yes |
|
|
284
|
+
| `drizzle-orm` | >=0.29.0 | Only if using `createDrizzleStorage` |
|
|
285
|
+
| `next` | >=14.0.0 | Only if using `createSidekickHandler` |
|
|
243
286
|
|
|
244
287
|
## License
|
|
245
288
|
|
package/dist/server/index.d.mts
CHANGED
|
@@ -222,6 +222,8 @@ type DrizzleDb = {
|
|
|
222
222
|
};
|
|
223
223
|
declare function createDrizzleStorage(db: DrizzleDb, overridesTable: typeof sidekickOverrides): SidekickStorage;
|
|
224
224
|
|
|
225
|
+
declare function createJsonFileStorage(filePath?: string): SidekickStorage;
|
|
226
|
+
|
|
225
227
|
declare function formatDesignSystem(schema: Record<string, unknown>): string;
|
|
226
228
|
declare function buildSystemPrompt(schema: Record<string, unknown>): string;
|
|
227
229
|
declare function buildUserPrompt(request: string, previousErrors?: string[], existingCode?: string): string;
|
|
@@ -232,4 +234,4 @@ declare function validateCode(code: string): {
|
|
|
232
234
|
errors: string[];
|
|
233
235
|
};
|
|
234
236
|
|
|
235
|
-
export { type GeneratedOverride, type NewOverrideRecord, type NewSidekickOverride, type OverrideManifest, type OverrideRecord, type SidekickHandlerOptions, type SidekickOverride, type SidekickStorage, buildSystemPrompt, buildUserPrompt, callAI, createDrizzleStorage, createSidekickHandler, formatDesignSystem, parseAIResponse, sidekickOverrides, validateCode };
|
|
237
|
+
export { type GeneratedOverride, type NewOverrideRecord, type NewSidekickOverride, type OverrideManifest, type OverrideRecord, type SidekickHandlerOptions, type SidekickOverride, type SidekickStorage, buildSystemPrompt, buildUserPrompt, callAI, createDrizzleStorage, createJsonFileStorage, createSidekickHandler, formatDesignSystem, parseAIResponse, sidekickOverrides, validateCode };
|
package/dist/server/index.d.ts
CHANGED
|
@@ -222,6 +222,8 @@ type DrizzleDb = {
|
|
|
222
222
|
};
|
|
223
223
|
declare function createDrizzleStorage(db: DrizzleDb, overridesTable: typeof sidekickOverrides): SidekickStorage;
|
|
224
224
|
|
|
225
|
+
declare function createJsonFileStorage(filePath?: string): SidekickStorage;
|
|
226
|
+
|
|
225
227
|
declare function formatDesignSystem(schema: Record<string, unknown>): string;
|
|
226
228
|
declare function buildSystemPrompt(schema: Record<string, unknown>): string;
|
|
227
229
|
declare function buildUserPrompt(request: string, previousErrors?: string[], existingCode?: string): string;
|
|
@@ -232,4 +234,4 @@ declare function validateCode(code: string): {
|
|
|
232
234
|
errors: string[];
|
|
233
235
|
};
|
|
234
236
|
|
|
235
|
-
export { type GeneratedOverride, type NewOverrideRecord, type NewSidekickOverride, type OverrideManifest, type OverrideRecord, type SidekickHandlerOptions, type SidekickOverride, type SidekickStorage, buildSystemPrompt, buildUserPrompt, callAI, createDrizzleStorage, createSidekickHandler, formatDesignSystem, parseAIResponse, sidekickOverrides, validateCode };
|
|
237
|
+
export { type GeneratedOverride, type NewOverrideRecord, type NewSidekickOverride, type OverrideManifest, type OverrideRecord, type SidekickHandlerOptions, type SidekickOverride, type SidekickStorage, buildSystemPrompt, buildUserPrompt, callAI, createDrizzleStorage, createJsonFileStorage, createSidekickHandler, formatDesignSystem, parseAIResponse, sidekickOverrides, validateCode };
|
package/dist/server/index.js
CHANGED
|
@@ -34,6 +34,7 @@ __export(server_exports, {
|
|
|
34
34
|
buildUserPrompt: () => buildUserPrompt,
|
|
35
35
|
callAI: () => callAI,
|
|
36
36
|
createDrizzleStorage: () => createDrizzleStorage,
|
|
37
|
+
createJsonFileStorage: () => createJsonFileStorage,
|
|
37
38
|
createSidekickHandler: () => createSidekickHandler,
|
|
38
39
|
formatDesignSystem: () => formatDesignSystem,
|
|
39
40
|
parseAIResponse: () => parseAIResponse,
|
|
@@ -613,6 +614,81 @@ function createDrizzleStorage(db, overridesTable) {
|
|
|
613
614
|
};
|
|
614
615
|
}
|
|
615
616
|
|
|
617
|
+
// src/server/json-storage.ts
|
|
618
|
+
var fs2 = __toESM(require("fs/promises"));
|
|
619
|
+
var path2 = __toESM(require("path"));
|
|
620
|
+
function deserializeDates(record) {
|
|
621
|
+
return {
|
|
622
|
+
...record,
|
|
623
|
+
createdAt: new Date(record.createdAt),
|
|
624
|
+
updatedAt: new Date(record.updatedAt)
|
|
625
|
+
};
|
|
626
|
+
}
|
|
627
|
+
async function readData(filePath) {
|
|
628
|
+
try {
|
|
629
|
+
const raw = await fs2.readFile(filePath, "utf-8");
|
|
630
|
+
const parsed = JSON.parse(raw);
|
|
631
|
+
return {
|
|
632
|
+
overrides: (parsed.overrides || []).map(deserializeDates)
|
|
633
|
+
};
|
|
634
|
+
} catch (err) {
|
|
635
|
+
if (err.code === "ENOENT") {
|
|
636
|
+
const empty = { overrides: [] };
|
|
637
|
+
await fs2.mkdir(path2.dirname(filePath), { recursive: true });
|
|
638
|
+
await fs2.writeFile(filePath, JSON.stringify(empty, null, 2) + "\n");
|
|
639
|
+
return empty;
|
|
640
|
+
}
|
|
641
|
+
throw err;
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
async function writeData(filePath, data) {
|
|
645
|
+
const tmpPath = filePath + ".tmp";
|
|
646
|
+
await fs2.mkdir(path2.dirname(filePath), { recursive: true });
|
|
647
|
+
await fs2.writeFile(tmpPath, JSON.stringify(data, null, 2) + "\n");
|
|
648
|
+
await fs2.rename(tmpPath, filePath);
|
|
649
|
+
}
|
|
650
|
+
function createJsonFileStorage(filePath) {
|
|
651
|
+
const resolvedPath = filePath || path2.join(process.cwd(), ".sidekick", "overrides.json");
|
|
652
|
+
return {
|
|
653
|
+
async listOverrides() {
|
|
654
|
+
const data = await readData(resolvedPath);
|
|
655
|
+
return data.overrides;
|
|
656
|
+
},
|
|
657
|
+
async getOverride(id) {
|
|
658
|
+
const data = await readData(resolvedPath);
|
|
659
|
+
return data.overrides.find((o) => o.id === id) ?? null;
|
|
660
|
+
},
|
|
661
|
+
async createOverride(record) {
|
|
662
|
+
const data = await readData(resolvedPath);
|
|
663
|
+
data.overrides.push({
|
|
664
|
+
id: record.id,
|
|
665
|
+
name: record.name,
|
|
666
|
+
description: record.description,
|
|
667
|
+
version: record.version,
|
|
668
|
+
primitives: record.primitives,
|
|
669
|
+
code: record.code,
|
|
670
|
+
enabled: record.enabled ?? true,
|
|
671
|
+
createdAt: record.createdAt ?? /* @__PURE__ */ new Date(),
|
|
672
|
+
updatedAt: record.updatedAt ?? /* @__PURE__ */ new Date()
|
|
673
|
+
});
|
|
674
|
+
await writeData(resolvedPath, data);
|
|
675
|
+
},
|
|
676
|
+
async updateOverride(id, updates) {
|
|
677
|
+
const data = await readData(resolvedPath);
|
|
678
|
+
const idx = data.overrides.findIndex((o) => o.id === id);
|
|
679
|
+
if (idx === -1) return;
|
|
680
|
+
const { id: _id, createdAt: _ca, ...rest } = updates;
|
|
681
|
+
data.overrides[idx] = { ...data.overrides[idx], ...rest, updatedAt: /* @__PURE__ */ new Date() };
|
|
682
|
+
await writeData(resolvedPath, data);
|
|
683
|
+
},
|
|
684
|
+
async deleteOverride(id) {
|
|
685
|
+
const data = await readData(resolvedPath);
|
|
686
|
+
data.overrides = data.overrides.filter((o) => o.id !== id);
|
|
687
|
+
await writeData(resolvedPath, data);
|
|
688
|
+
}
|
|
689
|
+
};
|
|
690
|
+
}
|
|
691
|
+
|
|
616
692
|
// src/server/drizzle-schema.ts
|
|
617
693
|
var import_pg_core = require("drizzle-orm/pg-core");
|
|
618
694
|
var sidekickOverrides = (0, import_pg_core.pgTable)("overrides", {
|
|
@@ -633,6 +709,7 @@ var sidekickOverrides = (0, import_pg_core.pgTable)("overrides", {
|
|
|
633
709
|
buildUserPrompt,
|
|
634
710
|
callAI,
|
|
635
711
|
createDrizzleStorage,
|
|
712
|
+
createJsonFileStorage,
|
|
636
713
|
createSidekickHandler,
|
|
637
714
|
formatDesignSystem,
|
|
638
715
|
parseAIResponse,
|