@donotdev/cli 0.0.6 → 0.0.8
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 +3 -18
- package/dependencies-matrix.json +64 -121
- package/dist/bin/commands/build.js +173 -161
- package/dist/bin/commands/bump.js +181 -156
- package/dist/bin/commands/cacheout.js +188 -171
- package/dist/bin/commands/create-app.js +213 -156
- package/dist/bin/commands/create-project.js +183 -154
- package/dist/bin/commands/deploy.js +491 -477
- package/dist/bin/commands/dev.js +176 -160
- package/dist/bin/commands/emu.js +181 -165
- package/dist/bin/commands/format.js +191 -174
- package/dist/bin/commands/lint.js +191 -171
- package/dist/bin/commands/preview.js +177 -161
- package/dist/bin/commands/sync-secrets.js +172 -158
- package/dist/bin/commands/wai.d.ts +11 -0
- package/dist/bin/commands/wai.d.ts.map +1 -0
- package/dist/bin/commands/wai.js +12 -0
- package/dist/bin/commands/wai.js.map +1 -0
- package/dist/bin/dndev.js +24 -24
- package/dist/bin/donotdev.js +24 -24
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +661 -669
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/templates/app-demo/src/config/app.ts.example +12 -0
- package/templates/app-next/src/config/app.ts.example +75 -48
- package/templates/app-vite/index.html.example +71 -37
- package/templates/app-vite/src/config/app.ts.example +75 -47
- package/templates/app-vite/src/pages/FormPageExample.tsx.example +152 -0
- package/templates/app-vite/src/pages/HomePage.tsx.example +81 -134
- package/templates/app-vite/src/pages/ListPageExample.tsx.example +88 -0
- package/templates/functions-firebase/build.mjs.example +8 -1
- package/templates/functions-firebase/functions-firebase/build.mjs.example +8 -1
- package/templates/functions-firebase/functions-firebase/src/index.ts.example +19 -25
- package/templates/functions-firebase/functions.config.js.example +35 -0
- package/templates/root-consumer/entities/ExampleEntity.ts.example +223 -0
- package/templates/root-consumer/entities/demo.ts.example +576 -0
- package/templates/root-consumer/entities/index.ts.example +15 -0
- package/templates/root-consumer/eslint.config.js.example +2 -80
- package/templates/root-consumer/guides/{AGENT_START_HERE.md.example → dndev/AGENT_START_HERE.md.example} +22 -0
- package/templates/root-consumer/guides/dndev/COMPONENTS_CRUD.md.example +231 -0
- package/templates/root-consumer/guides/{SETUP_AUTH.md.example → dndev/SETUP_AUTH.md.example} +30 -0
- package/templates/root-consumer/guides/dndev/SETUP_CRUD.md.example +539 -0
- package/templates/root-consumer/guides/dndev/SETUP_FUNCTIONS.md.example +116 -0
- package/templates/root-consumer/guides/{SETUP_I18N.md.example → dndev/SETUP_I18N.md.example} +46 -0
- package/templates/root-consumer/guides/wai-way/WAI_WAY_CLI.md.example +404 -0
- package/templates/root-consumer/guides/wai-way/agents/architect.md.example +78 -0
- package/templates/root-consumer/guides/wai-way/agents/builder.md.example +87 -0
- package/templates/root-consumer/guides/wai-way/agents/extractor.md.example +325 -0
- package/templates/root-consumer/guides/wai-way/agents/polisher.md.example +100 -0
- package/templates/root-consumer/guides/wai-way/blueprints/0_brainstorm.md.example +281 -0
- package/templates/root-consumer/guides/wai-way/blueprints/1_scaffold.md.example +77 -0
- package/templates/root-consumer/guides/wai-way/blueprints/2_entities.md.example +104 -0
- package/templates/root-consumer/guides/wai-way/blueprints/3_compose.md.example +124 -0
- package/templates/root-consumer/guides/wai-way/blueprints/4_configure.md.example +165 -0
- package/templates/root-consumer/guides/wai-way/context_map.json.example +95 -0
- package/templates/root-consumer/guides/wai-way/entity_patterns.md.example +840 -0
- package/templates/root-consumer/guides/wai-way/page_patterns.md.example +686 -0
- package/templates/root-consumer/guides/wai-way/presets_guide.md.example +217 -0
- package/templates/root-consumer/guides/wai-way/spec_template.md.example +312 -0
- package/templates/functions-firebase/functions-firebase/src/crud/createEntity.ts.example +0 -19
- package/templates/functions-firebase/functions-firebase/src/crud/deleteEntity.ts.example +0 -14
- package/templates/functions-firebase/functions-firebase/src/crud/getEntity.ts.example +0 -14
- package/templates/functions-firebase/functions-firebase/src/crud/index.ts.example +0 -12
- package/templates/functions-firebase/functions-firebase/src/crud/listEntities.ts.example +0 -14
- package/templates/functions-firebase/functions-firebase/src/crud/updateEntity.ts.example +0 -14
- package/templates/root-consumer/guides/COMPONENTS_CRUD.md.example +0 -70
- package/templates/root-consumer/guides/SETUP_CRUD.md.example +0 -1244
- package/templates/root-consumer/guides/SETUP_FUNCTIONS.md.example +0 -114
- /package/templates/root-consumer/guides/{COMPONENTS_ADV.md.example → dndev/COMPONENTS_ADV.md.example} +0 -0
- /package/templates/root-consumer/guides/{COMPONENTS_ATOMIC.md.example → dndev/COMPONENTS_ATOMIC.md.example} +0 -0
- /package/templates/root-consumer/guides/{COMPONENTS_UI.md.example → dndev/COMPONENTS_UI.md.example} +0 -0
- /package/templates/root-consumer/guides/{ENV_SETUP.md.example → dndev/ENV_SETUP.md.example} +0 -0
- /package/templates/root-consumer/guides/{INDEX.md.example → dndev/INDEX.md.example} +0 -0
- /package/templates/root-consumer/guides/{SETUP_APP_CONFIG.md.example → dndev/SETUP_APP_CONFIG.md.example} +0 -0
- /package/templates/root-consumer/guides/{SETUP_BILLING.md.example → dndev/SETUP_BILLING.md.example} +0 -0
- /package/templates/root-consumer/guides/{SETUP_LAYOUTS.md.example → dndev/SETUP_LAYOUTS.md.example} +0 -0
- /package/templates/root-consumer/guides/{SETUP_OAUTH.md.example → dndev/SETUP_OAUTH.md.example} +0 -0
- /package/templates/root-consumer/guides/{SETUP_PAGES.md.example → dndev/SETUP_PAGES.md.example} +0 -0
- /package/templates/root-consumer/guides/{SETUP_PWA.md.example → dndev/SETUP_PWA.md.example} +0 -0
- /package/templates/root-consumer/guides/{SETUP_THEMES.md.example → dndev/SETUP_THEMES.md.example} +0 -0
- /package/templates/root-consumer/guides/{USE_ROUTING.md.example → dndev/USE_ROUTING.md.example} +0 -0
- /package/templates/root-consumer/guides/{advanced → dndev/advanced}/APP_CHECK.md.example +0 -0
- /package/templates/root-consumer/guides/{advanced → dndev/advanced}/COOKIE_REFERENCE.md.example +0 -0
- /package/templates/root-consumer/guides/{advanced → dndev/advanced}/EMULATORS.md.example +0 -0
- /package/templates/root-consumer/guides/{advanced → dndev/advanced}/VERSION_CONTROL.md.example +0 -0
|
@@ -229,6 +229,28 @@ bun run dev
|
|
|
229
229
|
|
|
230
230
|
---
|
|
231
231
|
|
|
232
|
+
## 🤖 WAI-WAY: The "With AI Way" Protocol (Recommended)
|
|
233
|
+
|
|
234
|
+
**WAI-WAY** (based on the **BMAD Method**) is a rigorous, agent-driven protocol designed to build mistake-free apps by separating concerns into 4 distinct phases.
|
|
235
|
+
|
|
236
|
+
**How to Use:**
|
|
237
|
+
1. Navigate to `guides/wai-way/`.
|
|
238
|
+
2. Open `WAI_WAY_CLI.md` to see the activation instructions.
|
|
239
|
+
3. Paste the **Activation Prompt** into your AI Agent (Cursor, Claude, etc.) to start a phase.
|
|
240
|
+
|
|
241
|
+
**The 4 Phases:**
|
|
242
|
+
1. **Brainstorm (Extractor):** Define WHAT to build -> `step_1_prd.md`
|
|
243
|
+
2. **Review (Architect):** Define HOW to build (Component mapping) -> `step_2_spec.md`
|
|
244
|
+
3. **Build (Builder):** Implement code based on spec -> Working App
|
|
245
|
+
4. **Polish (Polisher):** Refine UX and content -> Production App
|
|
246
|
+
|
|
247
|
+
**Why use it?**
|
|
248
|
+
WAI-WAY forces your AI to "Think before it Codes". By separating the Architecture phase from the Build phase, we ensure that **only valid DoNotDev primitives are used**, preventing custom CSS bloat and "hallucinated" patterns.
|
|
249
|
+
|
|
250
|
+
**See [WAI_WAY_CLI.md](../wai-way/WAI_WAY_CLI.md) for full instructions.**
|
|
251
|
+
|
|
252
|
+
---
|
|
253
|
+
|
|
232
254
|
## Landing Page Example
|
|
233
255
|
|
|
234
256
|
```tsx
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
# CRUD Package Reference
|
|
2
|
+
|
|
3
|
+
**Import:** `@donotdev/crud`
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Hooks
|
|
8
|
+
|
|
9
|
+
### useCrud
|
|
10
|
+
Single document CRUD actions (add, update, delete, get, subscribe).
|
|
11
|
+
|
|
12
|
+
```tsx
|
|
13
|
+
const { add, update, delete: remove, get, data, loading, error } = useCrud(carEntity);
|
|
14
|
+
await add({ name: 'Tesla', year: 2024 });
|
|
15
|
+
await remove('doc-id');
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
### useCrudList
|
|
19
|
+
Paginated list with automatic loading. For data tables.
|
|
20
|
+
|
|
21
|
+
```tsx
|
|
22
|
+
const { items, loading, hasMore, loadMore } = useCrudList(productEntity);
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### useCrudCardList
|
|
26
|
+
Card-based list with infinite scroll.
|
|
27
|
+
|
|
28
|
+
```tsx
|
|
29
|
+
const { items, loading, hasMore, loadMore, refresh } = useCrudCardList(articleEntity);
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## Form Components
|
|
35
|
+
|
|
36
|
+
### EntityFormRenderer
|
|
37
|
+
Auto-render full entity form from definition.
|
|
38
|
+
|
|
39
|
+
```tsx
|
|
40
|
+
<EntityFormRenderer
|
|
41
|
+
entity={productEntity}
|
|
42
|
+
operation="create"
|
|
43
|
+
onSubmit={handleSubmit}
|
|
44
|
+
/>
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### FormFieldRenderer
|
|
48
|
+
Render single field. Used inside custom forms.
|
|
49
|
+
|
|
50
|
+
```tsx
|
|
51
|
+
<FormFieldRenderer field={field} control={form.control} />
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### EntityList
|
|
55
|
+
Data table for entity collection.
|
|
56
|
+
|
|
57
|
+
```tsx
|
|
58
|
+
<EntityList entity={userEntity} onRowClick={(user) => edit(user.id)} />
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### EntityCardList
|
|
62
|
+
Card grid for entity collection.
|
|
63
|
+
|
|
64
|
+
```tsx
|
|
65
|
+
<EntityCardList entity={productEntity} renderCard={(item) => <ProductCard {...item} />} />
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## Form Building Blocks
|
|
71
|
+
|
|
72
|
+
For custom forms, use these low-level utilities:
|
|
73
|
+
|
|
74
|
+
```tsx
|
|
75
|
+
import { useEntityForm, getFieldsForOperation, validateEntity } from '@donotdev/crud';
|
|
76
|
+
|
|
77
|
+
const { register, handleSubmit, fields, formState } = useEntityForm(productEntity, {
|
|
78
|
+
operation: 'create'
|
|
79
|
+
});
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
| Export | Purpose |
|
|
83
|
+
|--------|---------|
|
|
84
|
+
| `useEntityForm` | React Hook Form wrapper for entities |
|
|
85
|
+
| `useEntityField` | Single field hook |
|
|
86
|
+
| `getFieldsForOperation` | Get editable fields for create/edit |
|
|
87
|
+
| `validateEntity` | Validate data against entity schema |
|
|
88
|
+
| `isFieldEditable` | Check if field is editable |
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## Field Types (Built-in)
|
|
93
|
+
|
|
94
|
+
Field components are auto-rendered by `FormFieldRenderer`. You don't import them directly.
|
|
95
|
+
|
|
96
|
+
### Text Inputs
|
|
97
|
+
- `text` - Single-line text input
|
|
98
|
+
- `email` - Email input with validation
|
|
99
|
+
- `tel` - Phone number input
|
|
100
|
+
- `url` - URL input
|
|
101
|
+
- `color` - Color picker
|
|
102
|
+
- `password` - Password input (masked)
|
|
103
|
+
- `textarea` - Multi-line text input
|
|
104
|
+
- `richtext` - Rich text editor
|
|
105
|
+
|
|
106
|
+
### Numbers
|
|
107
|
+
- `number` - Numeric input
|
|
108
|
+
- `range` - Slider input
|
|
109
|
+
|
|
110
|
+
### Boolean
|
|
111
|
+
- `checkbox` - Checkbox input
|
|
112
|
+
- `boolean` - Alias for checkbox
|
|
113
|
+
- `switch` - Toggle switch
|
|
114
|
+
|
|
115
|
+
### Dates & Time
|
|
116
|
+
- `date` - Date picker
|
|
117
|
+
- `datetime-local` - Date and time picker
|
|
118
|
+
- `time` - Time picker
|
|
119
|
+
- `week` - Week picker
|
|
120
|
+
- `month` - Month picker
|
|
121
|
+
- `timestamp` - Timestamp (Firestore Timestamp)
|
|
122
|
+
|
|
123
|
+
### Selection
|
|
124
|
+
- `select` - Dropdown select
|
|
125
|
+
- `combobox` - Searchable dropdown
|
|
126
|
+
- `multiselect` - Multiple selection dropdown
|
|
127
|
+
- `radio` - Radio button group
|
|
128
|
+
|
|
129
|
+
### Files & Media
|
|
130
|
+
- `file` - Single file upload
|
|
131
|
+
- `files` - Multiple file uploads
|
|
132
|
+
- `document` - Document upload (PDF, etc.)
|
|
133
|
+
- `documents` - Multiple document uploads
|
|
134
|
+
- `image` - Single image upload
|
|
135
|
+
- `images` - Multiple image uploads
|
|
136
|
+
|
|
137
|
+
### Complex Types
|
|
138
|
+
- `geopoint` - Geographic coordinates (lat/lng)
|
|
139
|
+
- `address` - Address input with autocomplete
|
|
140
|
+
- `map` - Map picker
|
|
141
|
+
- `array` - Array of text inputs
|
|
142
|
+
|
|
143
|
+
### Special
|
|
144
|
+
- `avatar` - Avatar image upload
|
|
145
|
+
- `badge` - Badge display
|
|
146
|
+
- `hidden` - Hidden field (not displayed)
|
|
147
|
+
- `submit` - Submit button (uncontrolled)
|
|
148
|
+
- `reset` - Reset button (uncontrolled)
|
|
149
|
+
|
|
150
|
+
To add custom field types:
|
|
151
|
+
```tsx
|
|
152
|
+
import { useController, registerFieldType } from '@donotdev/crud';
|
|
153
|
+
import type { ControlledFieldProps } from '@donotdev/crud';
|
|
154
|
+
|
|
155
|
+
// Custom controlled component MUST use framework's useController (not react-hook-form's)
|
|
156
|
+
function RatingField({
|
|
157
|
+
fieldConfig,
|
|
158
|
+
control,
|
|
159
|
+
errors,
|
|
160
|
+
t,
|
|
161
|
+
onChange
|
|
162
|
+
}: ControlledFieldProps) {
|
|
163
|
+
// REQUIRED: Use framework's useController - ensures type compatibility
|
|
164
|
+
const { field, fieldState } = useController({
|
|
165
|
+
name: fieldConfig.name,
|
|
166
|
+
control: control,
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
return (
|
|
170
|
+
<div>
|
|
171
|
+
<label>{t(fieldConfig.label)}</label>
|
|
172
|
+
{/* Use field.value and field.onChange */}
|
|
173
|
+
<input
|
|
174
|
+
type="number"
|
|
175
|
+
value={field.value ?? 0}
|
|
176
|
+
onChange={(e) => {
|
|
177
|
+
const value = Number(e.target.value);
|
|
178
|
+
field.onChange(value);
|
|
179
|
+
onChange?.(value);
|
|
180
|
+
}}
|
|
181
|
+
min={0}
|
|
182
|
+
max={5}
|
|
183
|
+
/>
|
|
184
|
+
{fieldState?.error && (
|
|
185
|
+
<span className="error">{fieldState.error.message}</span>
|
|
186
|
+
)}
|
|
187
|
+
</div>
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
registerFieldType({
|
|
192
|
+
type: 'rating',
|
|
193
|
+
controlledComponent: RatingField,
|
|
194
|
+
});
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
**Important:**
|
|
198
|
+
- Custom controlled components receive `control` prop, NOT `field` prop
|
|
199
|
+
- You must use **framework's `useController`** (from `@donotdev/crud`), NOT `react-hook-form`'s useController
|
|
200
|
+
- This ensures type compatibility - no type assertions needed
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
## Service & Store
|
|
205
|
+
|
|
206
|
+
Direct access (rarely needed):
|
|
207
|
+
|
|
208
|
+
```tsx
|
|
209
|
+
import { getCrudService, useCrudStore } from '@donotdev/crud';
|
|
210
|
+
|
|
211
|
+
const service = getCrudService();
|
|
212
|
+
await service.query('products', { where: [['active', '==', true]] });
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
## Collection Utilities
|
|
218
|
+
|
|
219
|
+
```tsx
|
|
220
|
+
import { loadDeterministicRange, upsertDeterministic, appendToCollection } from '@donotdev/crud';
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
| Utility | Purpose |
|
|
224
|
+
|---------|---------|
|
|
225
|
+
| `loadDeterministicRange` | Paginated loading with deterministic IDs |
|
|
226
|
+
| `upsertDeterministic` | Insert or update with deterministic ID |
|
|
227
|
+
| `appendToCollection` | Add to collection end |
|
|
228
|
+
|
|
229
|
+
---
|
|
230
|
+
|
|
231
|
+
**JSDoc in IDE** - Hover over any import for full props and examples.
|
package/templates/root-consumer/guides/{SETUP_AUTH.md.example → dndev/SETUP_AUTH.md.example}
RENAMED
|
@@ -74,4 +74,34 @@ const signOut = useAuth('signOut');
|
|
|
74
74
|
|
|
75
75
|
---
|
|
76
76
|
|
|
77
|
+
## User Roles
|
|
78
|
+
|
|
79
|
+
**Role hierarchy:** `guest (0) < user (1) < admin (2) < super (3)`
|
|
80
|
+
|
|
81
|
+
**Default:** All authenticated users are `'user'` role.
|
|
82
|
+
|
|
83
|
+
**Setting admin/super roles:** Set Firebase Auth customClaims:
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
// Using Firebase Admin SDK
|
|
87
|
+
import { getFirebaseAdminAuth } from '@donotdev/firebase/server';
|
|
88
|
+
|
|
89
|
+
const auth = getFirebaseAdminAuth();
|
|
90
|
+
await auth.setCustomUserClaims(userId, {
|
|
91
|
+
role: 'admin', // or 'super'
|
|
92
|
+
isAdmin: true // legacy support
|
|
93
|
+
});
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
**Using CLI:**
|
|
97
|
+
```bash
|
|
98
|
+
dndev make-admin <userId>
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
**Note:** User must sign out and sign in again for role changes to take effect (customClaims are in the ID token).
|
|
102
|
+
|
|
103
|
+
**Used by:** CRUD access control, protected routes, field visibility filtering.
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
77
107
|
**Add env vars, get auth. Framework handles the rest.**
|