@vobs/cli 0.3.0 → 1.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 (143) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +116 -0
  3. package/bin/vobs.js +12 -0
  4. package/dist/banner.cjs +37 -0
  5. package/dist/banner.cjs.map +1 -0
  6. package/dist/banner.d.cts +18 -0
  7. package/dist/banner.d.ts +18 -0
  8. package/dist/banner.js +33 -0
  9. package/dist/banner.js.map +1 -0
  10. package/dist/cli.cjs +416 -0
  11. package/dist/cli.cjs.map +1 -0
  12. package/dist/cli.d.cts +5 -0
  13. package/dist/cli.d.ts +5 -0
  14. package/dist/cli.js +389 -0
  15. package/dist/cli.js.map +1 -0
  16. package/dist/commands/add.cjs +113 -0
  17. package/dist/commands/add.cjs.map +1 -0
  18. package/dist/commands/add.d.cts +5 -0
  19. package/dist/commands/add.d.ts +5 -0
  20. package/dist/commands/add.js +88 -0
  21. package/dist/commands/add.js.map +1 -0
  22. package/dist/commands/build.cjs +55 -0
  23. package/dist/commands/build.cjs.map +1 -0
  24. package/dist/commands/build.d.cts +5 -0
  25. package/dist/commands/build.d.ts +5 -0
  26. package/dist/commands/build.js +49 -0
  27. package/dist/commands/build.js.map +1 -0
  28. package/dist/commands/dev.cjs +57 -0
  29. package/dist/commands/dev.cjs.map +1 -0
  30. package/dist/commands/dev.d.cts +5 -0
  31. package/dist/commands/dev.d.ts +5 -0
  32. package/dist/commands/dev.js +51 -0
  33. package/dist/commands/dev.js.map +1 -0
  34. package/dist/commands/generate.cjs +153 -0
  35. package/dist/commands/generate.cjs.map +1 -0
  36. package/dist/commands/generate.d.cts +5 -0
  37. package/dist/commands/generate.d.ts +5 -0
  38. package/dist/commands/generate.js +126 -0
  39. package/dist/commands/generate.js.map +1 -0
  40. package/dist/commands/index.cjs +331 -0
  41. package/dist/commands/index.cjs.map +1 -0
  42. package/dist/commands/index.d.cts +6 -0
  43. package/dist/commands/index.d.ts +6 -0
  44. package/dist/commands/index.js +300 -0
  45. package/dist/commands/index.js.map +1 -0
  46. package/dist/commands/init.cjs +187 -0
  47. package/dist/commands/init.cjs.map +1 -0
  48. package/dist/commands/init.d.cts +5 -0
  49. package/dist/commands/init.d.ts +5 -0
  50. package/dist/commands/init.js +160 -0
  51. package/dist/commands/init.js.map +1 -0
  52. package/dist/index.cjs +561 -0
  53. package/dist/index.cjs.map +1 -0
  54. package/dist/index.d.cts +14 -0
  55. package/dist/index.d.ts +14 -18
  56. package/dist/index.js +489 -486
  57. package/dist/index.js.map +1 -0
  58. package/dist/repl.cjs +436 -0
  59. package/dist/repl.cjs.map +1 -0
  60. package/dist/repl.d.cts +8 -0
  61. package/dist/repl.d.ts +8 -0
  62. package/dist/repl.js +409 -0
  63. package/dist/repl.js.map +1 -0
  64. package/dist/start.cjs +543 -0
  65. package/dist/start.cjs.map +1 -0
  66. package/dist/start.d.cts +4 -0
  67. package/dist/start.d.ts +4 -0
  68. package/dist/start.js +516 -0
  69. package/dist/start.js.map +1 -0
  70. package/dist/templates/basic/.gitignore.hbs +4 -0
  71. package/dist/templates/basic/index.html.hbs +12 -0
  72. package/dist/templates/basic/package.json.hbs +25 -0
  73. package/dist/templates/basic/src/App.tsx.hbs +8 -0
  74. package/dist/templates/basic/src/app.css.hbs +32 -0
  75. package/dist/templates/basic/src/main.ts.hbs +20 -0
  76. package/dist/templates/basic/tsconfig.json.hbs +19 -0
  77. package/dist/templates/basic/vite.config.ts.hbs +10 -0
  78. package/dist/templates/component.hbs +7 -0
  79. package/dist/templates/page.hbs +7 -0
  80. package/dist/types.cjs +4 -0
  81. package/dist/types.cjs.map +1 -0
  82. package/dist/types.d.cts +71 -0
  83. package/dist/types.d.ts +71 -0
  84. package/dist/types.js +3 -0
  85. package/dist/types.js.map +1 -0
  86. package/dist/utils/file.cjs +79 -0
  87. package/dist/utils/file.cjs.map +1 -0
  88. package/dist/utils/file.d.cts +14 -0
  89. package/dist/utils/file.d.ts +14 -0
  90. package/dist/utils/file.js +67 -0
  91. package/dist/utils/file.js.map +1 -0
  92. package/dist/utils/logger.cjs +45 -0
  93. package/dist/utils/logger.cjs.map +1 -0
  94. package/dist/utils/logger.d.cts +14 -0
  95. package/dist/utils/logger.d.ts +14 -0
  96. package/dist/utils/logger.js +34 -0
  97. package/dist/utils/logger.js.map +1 -0
  98. package/dist/utils/pm.cjs +38 -0
  99. package/dist/utils/pm.cjs.map +1 -0
  100. package/dist/utils/pm.d.cts +9 -0
  101. package/dist/utils/pm.d.ts +9 -0
  102. package/dist/utils/pm.js +34 -0
  103. package/dist/utils/pm.js.map +1 -0
  104. package/package.json +34 -40
  105. package/src/banner.ts +41 -0
  106. package/src/cli.ts +108 -0
  107. package/src/commands/add.ts +37 -0
  108. package/src/commands/build.ts +17 -0
  109. package/src/commands/dev.ts +19 -0
  110. package/src/commands/generate.ts +87 -0
  111. package/src/commands/index.ts +5 -0
  112. package/src/commands/init.ts +84 -0
  113. package/src/index.ts +13 -0
  114. package/src/repl.ts +140 -0
  115. package/src/start.ts +20 -0
  116. package/src/templates/basic/.gitignore.hbs +4 -0
  117. package/src/templates/basic/index.html.hbs +12 -0
  118. package/src/templates/basic/package.json.hbs +25 -0
  119. package/src/templates/basic/src/App.tsx.hbs +8 -0
  120. package/src/templates/basic/src/app.css.hbs +32 -0
  121. package/src/templates/basic/src/main.ts.hbs +20 -0
  122. package/src/templates/basic/tsconfig.json.hbs +19 -0
  123. package/src/templates/basic/vite.config.ts.hbs +10 -0
  124. package/src/templates/component.hbs +7 -0
  125. package/src/templates/page.hbs +7 -0
  126. package/src/types.ts +78 -0
  127. package/src/utils/file.ts +77 -0
  128. package/src/utils/logger.ts +27 -0
  129. package/src/utils/pm.ts +42 -0
  130. package/dist/ai-server.d.ts +0 -11
  131. package/dist/ai-server.js +0 -212
  132. package/dist/context.d.ts +0 -12
  133. package/dist/context.js +0 -301
  134. package/dist/diagnose.d.ts +0 -12
  135. package/dist/diagnose.js +0 -122
  136. package/dist/enterprise-template.d.ts +0 -83
  137. package/dist/enterprise-template.js +0 -638
  138. package/dist/inspect.d.ts +0 -11
  139. package/dist/inspect.js +0 -576
  140. package/dist/logo/cli-logo.d.ts +0 -5
  141. package/dist/logo/cli-logo.js +0 -16
  142. package/dist/scaffold.d.ts +0 -23
  143. package/dist/scaffold.js +0 -448
@@ -1,638 +0,0 @@
1
- /** @license MIT
2
- * Copyright (c) 2026 vobsjs
3
- * @vobs/cli
4
- */
5
- const packageJson = `{
6
- "name": "{{packageName}}",
7
- "version": "0.1.0",
8
- "private": true,
9
- "type": "module",
10
- "engines": {
11
- "node": ">=22.12.0"
12
- },
13
- "scripts": {
14
- "dev": "vite",
15
- "build": "tsc --noEmit && vite build",
16
- "preview": "vite preview",
17
- "typecheck": "tsc --noEmit"
18
- },
19
- "dependencies": {
20
- "@vobs/di": "0.1.0",
21
- "@vobs/authorization": "0.1.0",
22
- "@vobs/forms": "0.1.0",
23
- "@vobs/i18n": "0.1.0",
24
- "@vobs/reactivity": "0.1.0",
25
- "@vobs/router": "0.1.0",
26
- "@vobs/runtime-dom": "0.1.0",
27
- "@vobs/server-renderer": "0.1.0",
28
- "@vobs/ui": "0.2.0"
29
- },
30
- "devDependencies": {
31
- "@vobs/vite-plugin": "0.1.0",
32
- "typescript": "^5.7.0",
33
- "vite": "^8.0.0"
34
- }
35
- }
36
- `;
37
- const tsconfig = `{
38
- "compilerOptions": {
39
- "target": "ES2022",
40
- "module": "ESNext",
41
- "moduleResolution": "Bundler",
42
- "lib": ["ES2022", "DOM", "DOM.Iterable"],
43
- "strict": true,
44
- "skipLibCheck": true,
45
- "isolatedModules": true,
46
- "verbatimModuleSyntax": true,
47
- "types": ["@vobs/vite-plugin/client"]
48
- },
49
- "include": ["src/**/*.ts", "vite.config.ts"]
50
- }
51
- `;
52
- const viteConfig = `import { defineConfig, type PluginOption } from 'vite';
53
- import { vobs } from '@vobs/vite-plugin';
54
-
55
- export default defineConfig({
56
- plugins: [vobs() as PluginOption],
57
- });
58
- `;
59
- const indexHtml = `<!doctype html>
60
- <html lang="en">
61
- <head>
62
- <meta charset="UTF-8" />
63
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
64
- <title>{{projectName}}</title>
65
- </head>
66
- <body>
67
- <div id="app"></div>
68
- <script type="module" src="/src/main.ts"></script>
69
- </body>
70
- </html>
71
- `;
72
- const envDts = `/// <reference types="@vobs/vite-plugin/client" />
73
-
74
- declare module '*.css';
75
- `;
76
- const mainTs = `import { app } from './app.js';
77
- import '@vobs/ui/tokens.css';
78
- import '@vobs/ui/base.css';
79
- import '@vobs/ui/components.css';
80
- import './styles/global.css';
81
-
82
- await app.mount('#app');
83
- `;
84
- const appTs = `import { createInjectionScope } from '@vobs/di';
85
- import { provideI18n } from '@vobs/i18n';
86
- import { createVobsApp } from '@vobs/runtime-dom';
87
- import { setupUi } from '@vobs/ui';
88
- import router from 'vobs:routes';
89
- import appShells from './app-shell.js';
90
- import { createEnterpriseI18n } from './app/i18n.js';
91
- import { registerEnterpriseServices } from './app/services.js';
92
-
93
- const ui = setupUi({ appShells });
94
- const injections = ui.injections ?? createInjectionScope();
95
- registerEnterpriseServices(injections);
96
- provideI18n(injections, createEnterpriseI18n());
97
-
98
- const app = createVobsApp({
99
- router,
100
- ui: { ...ui, injections },
101
- routePending: true,
102
- onAppError(error) {
103
- queueMicrotask(() => {
104
- throw error;
105
- });
106
- },
107
- });
108
-
109
- export { app, injections };
110
- `;
111
- const i18nTs = `import { createI18n, defineMessages } from '@vobs/i18n';
112
-
113
- const en = defineMessages({
114
- navigation: {
115
- dashboard: 'Dashboard',
116
- users: 'Users',
117
- },
118
- dashboard: {
119
- title: 'Operations dashboard',
120
- },
121
- users: {
122
- new: 'Create user',
123
- },
124
- forms: {
125
- required: '{label} is required',
126
- },
127
- });
128
-
129
- export function createEnterpriseI18n() {
130
- return createI18n({
131
- locale: 'en-US',
132
- fallbackLocale: 'en-US',
133
- messages: { 'en-US': en },
134
- });
135
- }
136
- `;
137
- const servicesTs = `import { createInjectionKey, type InjectionScope } from '@vobs/di';
138
- import { AuthorizationPortKey, authorizer } from '../access/authorization.js';
139
-
140
- export interface AuditService {
141
- record(event: string, details: Readonly<Record<string, unknown>>): void;
142
- }
143
-
144
- export const AuditServiceKey = createInjectionKey<AuditService>('enterprise.audit');
145
-
146
- export function registerEnterpriseServices(scope: InjectionScope): void {
147
- scope.provide(AuthorizationPortKey, authorizer);
148
- scope.provide(AuditServiceKey, {
149
- record(event, details) {
150
- console.info('[audit]', event, details);
151
- },
152
- });
153
- }
154
- `;
155
- const authorizationTs = `import {
156
- AuthorizationPortKey,
157
- createAuthorizer,
158
- type AuthorizationSubject,
159
- } from '@vobs/authorization';
160
- import type { RouteGuardContext, RouteGuardResult } from '@vobs/router';
161
-
162
- export interface AuthorizationRequestContext {
163
- readonly authorizationSubject?: AuthorizationSubject | null;
164
- }
165
-
166
- export const authorizer = createAuthorizer({
167
- roles: [{ name: 'local-admin', permissions: ['dashboard:view', 'users:write'] }],
168
- });
169
-
170
- const developmentSubject: AuthorizationSubject = {
171
- id: 'local-admin',
172
- roles: ['local-admin'],
173
- };
174
-
175
- export function requireCapabilities(
176
- context: RouteGuardContext,
177
- requiredCapabilities: readonly string[],
178
- ): RouteGuardResult {
179
- const subject = readAuthorizationSubject(context.request);
180
- if (subject === null) return '/login';
181
- const allowed = requiredCapabilities.every((capability) =>
182
- authorizer.can(subject, capability, { type: 'route', attributes: { path: context.route.path } }),
183
- );
184
- return allowed ? true : '/403';
185
- }
186
-
187
- function readAuthorizationSubject(request: unknown): AuthorizationSubject | null {
188
- if (typeof request !== 'object' || request === null || !('authorizationSubject' in request)) {
189
- return developmentSubject;
190
- }
191
- return (request as AuthorizationRequestContext).authorizationSubject ?? null;
192
- }
193
- `;
194
- const appShellTs = `import { defineAppShell } from '@vobs/ui';
195
-
196
- export default defineAppShell({
197
- id: 'enterprise',
198
- title: '{{projectName}}',
199
- brand: {
200
- label: '{{projectName}}',
201
- href: '/dashboard',
202
- mark: 'K',
203
- },
204
- navigation: {
205
- primary: [
206
- { id: 'dashboard', label: 'Dashboard', route: '/dashboard' },
207
- { id: 'new-user', label: 'Create user', route: '/dashboard/users/new' },
208
- ],
209
- },
210
- routes: [
211
- {
212
- route: '/dashboard',
213
- title: 'Operations dashboard',
214
- description: 'A quiet starting point for enterprise workflows.',
215
- activeNav: 'dashboard',
216
- status: 'Ready',
217
- },
218
- {
219
- route: '/dashboard/users/new',
220
- title: 'Create user',
221
- description: 'Schema-driven form with DI, i18n, and validation.',
222
- activeNav: 'new-user',
223
- status: 'Form',
224
- },
225
- ],
226
- pageHeader: {
227
- kicker: 'Workspace',
228
- titleFallback: '{{projectName}}',
229
- descriptionFallback: 'Enterprise administration starter.',
230
- },
231
- topbar: {
232
- account: {
233
- label: 'Local Admin',
234
- initials: 'LA',
235
- menu: [{ id: 'sign-out', label: 'Sign out', tone: 'danger' }],
236
- },
237
- },
238
- statusbar: {
239
- text: 'Ready',
240
- version: '{{projectName}} v0.1.0',
241
- },
242
- theme: {
243
- mode: 'light',
244
- brand: 'green',
245
- },
246
- });
247
- `;
248
- const homePageTs = `import { definePage } from '@vobs/runtime-dom';
249
- import template from './index.html';
250
-
251
- export default definePage({
252
- template,
253
- setup() {
254
- return { projectName: '{{projectName}}' };
255
- },
256
- });
257
- `;
258
- const homePageHtml = `<main class="entry-page">
259
- <p class="eyebrow">vobs enterprise starter</p>
260
- <h1>{{ projectName }}</h1>
261
- <p>Start with the dashboard shell, authorization boundary, forms, i18n, and SSR adapter.</p>
262
- <a class="primary-link" href="/dashboard">Open dashboard</a>
263
- </main>
264
- `;
265
- const loginPageTs = `import { definePage } from '@vobs/runtime-dom';
266
- import template from './login.html';
267
-
268
- export default definePage({ template, setup: () => ({}) });
269
- `;
270
- const loginPageHtml = `<main class="status-page">
271
- <h1>Sign in required</h1>
272
- <p>Replace this page with your identity provider redirect or sign-in flow.</p>
273
- <a href="/dashboard">Use local development subject</a>
274
- </main>
275
- `;
276
- const forbiddenPageTs = `import { definePage } from '@vobs/runtime-dom';
277
- import template from './403.html';
278
-
279
- export default definePage({ template, setup: () => ({}) });
280
- `;
281
- const forbiddenPageHtml = `<main class="status-page">
282
- <h1>Access denied</h1>
283
- <p>Your current subject does not have the required capability.</p>
284
- <a href="/dashboard">Return to dashboard</a>
285
- </main>
286
- `;
287
- const adminLayoutTs = `import { definePage } from '@vobs/runtime-dom';
288
- import template from './_layout.html';
289
-
290
- export default definePage({ template, setup: () => ({}) });
291
- `;
292
- const adminLayoutHtml = `<k-app-shell shell="enterprise">
293
- <slot></slot>
294
- </k-app-shell>
295
- `;
296
- const dashboardPageTs = `import type { RouteGuardContext, RouteGuardResult } from '@vobs/router';
297
- import { definePage } from '@vobs/runtime-dom';
298
- import { requireCapabilities } from '../../../access/authorization.js';
299
- import template from './index.html';
300
-
301
- export const meta = {
302
- requiresAuth: true,
303
- capabilities: ['dashboard:view'],
304
- } as const;
305
-
306
- export function guard(context: RouteGuardContext): RouteGuardResult {
307
- return requireCapabilities(context, meta.capabilities);
308
- }
309
-
310
- export default definePage({
311
- template,
312
- setup() {
313
- return {
314
- stats: [
315
- { id: 'open', label: 'Open work', value: 18 },
316
- { id: 'review', label: 'Awaiting review', value: 7 },
317
- { id: 'resolved', label: 'Resolved today', value: 42 },
318
- ],
319
- };
320
- },
321
- });
322
- `;
323
- const dashboardPageHtml = `<main class="workspace-page">
324
- <h1>{{@dashboard.title}}</h1>
325
- <section class="stat-grid" aria-label="Operational summary">
326
- <article #for="stat in stats" #key="stat.id" class="stat-item">
327
- <span>{{ stat.label }}</span>
328
- <strong>{{ stat.value }}</strong>
329
- </article>
330
- </section>
331
- <section class="work-list">
332
- <h2>Next actions</h2>
333
- <a href="/dashboard/users/new">Create a user</a>
334
- </section>
335
- </main>
336
- `;
337
- const userFormPageTs = `import { defineForm, useForm, type FormView } from '@vobs/forms';
338
- import { signal } from '@vobs/reactivity';
339
- import type { RouteGuardContext, RouteGuardResult } from '@vobs/router';
340
- import { definePage } from '@vobs/runtime-dom';
341
- import { requireCapabilities } from '../../../../access/authorization.js';
342
- import { AuditServiceKey } from '../../../../app/services.js';
343
- import template from './new.html';
344
-
345
- const userFormSchema = defineForm({
346
- fields: {
347
- name: { label: 'Name', defaultValue: '', required: true },
348
- email: { label: 'Email', defaultValue: '', required: true },
349
- role: {
350
- label: 'Role',
351
- defaultValue: 'operator',
352
- type: 'select',
353
- options: [
354
- { label: 'Operator', value: 'operator' },
355
- { label: 'Administrator', value: 'administrator' },
356
- ],
357
- },
358
- active: { label: 'Active', defaultValue: true, type: 'checkbox' },
359
- },
360
- });
361
-
362
- type UserFormView = FormView<typeof userFormSchema.fields>;
363
-
364
- export const meta = {
365
- requiresAuth: true,
366
- capabilities: ['users:write'],
367
- } as const;
368
-
369
- export function guard(context: RouteGuardContext): RouteGuardResult {
370
- return requireCapabilities(context, meta.capabilities);
371
- }
372
-
373
- export default definePage<{
374
- readonly view: UserFormView;
375
- readonly saved: ReturnType<typeof signal<string>>;
376
- readonly save: () => void;
377
- }>({
378
- template,
379
- setup(context) {
380
- const { view } = useForm(context, userFormSchema, {
381
- viewId: 'user-form',
382
- validateOn: 'blur',
383
- });
384
- const saved = signal('');
385
-
386
- function save() {
387
- void view.submit((values) => {
388
- context.inject(AuditServiceKey).record('user.created', values);
389
- saved.value = 'Saved ' + values.name;
390
- });
391
- }
392
-
393
- return { view, saved, save };
394
- },
395
- });
396
- `;
397
- const userFormPageHtml = `<main class="workspace-page">
398
- <h1>{{@users.new}}</h1>
399
- <form :id="view.id" :class="view.className" novalidate @submit.prevent="save">
400
- <section #if="view.errorSummary.value.length > 0" class="error-summary" role="alert">
401
- <h2>Check the form</h2>
402
- <ul>
403
- <li #for="error in view.errorSummary.value" #key="error.id">
404
- <a :href="error.href">{{ error.message }}</a>
405
- </li>
406
- </ul>
407
- </section>
408
- <section #for="item in view.items" #key="item.name" :class="item.className">
409
- <span :id="item.labelId">{{ item.labelText }}</span>
410
- <input
411
- #if="item.control === 'input'"
412
- :id="item.controlId"
413
- :name="item.name"
414
- :type="item.inputType"
415
- :required="item.required"
416
- :disabled="item.disabled"
417
- :aria-labelledby="item.labelId"
418
- :aria-describedby="item.ariaDescribedBy"
419
- :aria-invalid="item.ariaInvalid"
420
- #model="item.model"
421
- />
422
- <select
423
- #if="item.control === 'select'"
424
- :id="item.controlId"
425
- :name="item.name"
426
- :required="item.required"
427
- :disabled="item.disabled"
428
- :aria-labelledby="item.labelId"
429
- :aria-describedby="item.ariaDescribedBy"
430
- :aria-invalid="item.ariaInvalid"
431
- #model="item.model"
432
- >
433
- <option #for="option in item.options" #key="option.value" :value="option.value">
434
- {{ option.label }}
435
- </option>
436
- </select>
437
- <input
438
- #if="item.control === 'checkbox'"
439
- :id="item.controlId"
440
- :name="item.name"
441
- type="checkbox"
442
- :disabled="item.disabled"
443
- :aria-labelledby="item.labelId"
444
- #model="item.model"
445
- />
446
- <p #if="item.errorText.value.length > 0" :id="item.errorId" class="field-error">
447
- {{ item.errorText }}
448
- </p>
449
- </section>
450
- <button type="submit" :disabled="view.submitting">Save user</button>
451
- </form>
452
- <output aria-live="polite">{{ saved }}</output>
453
- </main>
454
- `;
455
- const renderRequestTs = `import { createRouteResolver } from '@vobs/router';
456
- import {
457
- renderRoute,
458
- type RenderRouteOptions,
459
- type RenderRouteResult,
460
- } from '@vobs/server-renderer';
461
-
462
- export interface EnterpriseSsrRequestOptions
463
- extends Omit<RenderRouteOptions, 'path' | 'request' | 'resolver'> {
464
- readonly url: string;
465
- readonly request?: unknown;
466
- }
467
-
468
- export async function renderEnterpriseRequest(
469
- options: EnterpriseSsrRequestOptions,
470
- ): Promise<RenderRouteResult> {
471
- const { url, request, ...renderOptions } = options;
472
- const location = new URL(url, 'http://localhost');
473
- return renderRoute({
474
- ...renderOptions,
475
- path: location.pathname,
476
- resolver: createRouteResolver(),
477
- ...(request === undefined ? {} : { request }),
478
- });
479
- }
480
-
481
- export function createHtmlDocument(result: RenderRouteResult): string {
482
- return (
483
- '<!doctype html><html lang="en"><head><meta charset="UTF-8">' +
484
- '<meta name="viewport" content="width=device-width, initial-scale=1.0">' +
485
- '<title>{{projectName}}</title></head><body><div id="app">' +
486
- result.html +
487
- (result.initialStateScript ?? '') +
488
- '</div><script type="module" src="/src/main.ts"></script></body></html>'
489
- );
490
- }
491
- `;
492
- const globalCss = `:root {
493
- color-scheme: light;
494
- font-family: Inter, ui-sans-serif, system-ui, sans-serif;
495
- color: #18211d;
496
- background: #f5f7f6;
497
- }
498
-
499
- body {
500
- margin: 0;
501
- }
502
-
503
- a {
504
- color: #176a46;
505
- }
506
-
507
- .entry-page,
508
- .status-page,
509
- .workspace-page {
510
- width: min(100% - 32px, 960px);
511
- margin: 0 auto;
512
- padding: 40px 0;
513
- }
514
-
515
- .eyebrow {
516
- color: #527064;
517
- font-size: 0.8rem;
518
- font-weight: 700;
519
- text-transform: uppercase;
520
- }
521
-
522
- .primary-link,
523
- button {
524
- display: inline-flex;
525
- min-height: 40px;
526
- align-items: center;
527
- border: 0;
528
- border-radius: 4px;
529
- padding: 0 16px;
530
- color: white;
531
- background: #176a46;
532
- font: inherit;
533
- text-decoration: none;
534
- }
535
-
536
- .stat-grid {
537
- display: grid;
538
- grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
539
- gap: 12px;
540
- }
541
-
542
- .stat-item {
543
- border: 1px solid #d7dfdb;
544
- border-radius: 6px;
545
- padding: 16px;
546
- background: white;
547
- }
548
-
549
- .stat-item strong {
550
- display: block;
551
- margin-top: 8px;
552
- font-size: 1.8rem;
553
- }
554
-
555
- .work-list,
556
- form {
557
- margin-top: 24px;
558
- border-top: 1px solid #d7dfdb;
559
- padding-top: 24px;
560
- }
561
-
562
- .vobs-field {
563
- display: grid;
564
- gap: 6px;
565
- max-width: 520px;
566
- margin-bottom: 16px;
567
- }
568
-
569
- input,
570
- select {
571
- min-height: 40px;
572
- box-sizing: border-box;
573
- border: 1px solid #aab8b1;
574
- border-radius: 4px;
575
- padding: 8px 10px;
576
- font: inherit;
577
- }
578
-
579
- .field-error,
580
- .error-summary {
581
- color: #a22020;
582
- }
583
- `;
584
- const readme = `# {{projectName}}
585
-
586
- {{description}}
587
-
588
- ## Run
589
-
590
- ~~~bash
591
- pnpm install
592
- pnpm run dev
593
- ~~~
594
-
595
- Open /dashboard for the application shell and /dashboard/users/new for the schema-driven form.
596
-
597
- ## Boundaries
598
-
599
- | Area | Starter responsibility | Production responsibility |
600
- | --- | --- | --- |
601
- | DI | One root InjectionScope wires authorization, audit, UI, and i18n | Replace service implementations at composition time |
602
- | Authorization | Route guards consume an AuthorizationSubject and capability list | Authenticate the request and re-authorize every server mutation |
603
- | UI | setupUi registers AppShell and shared providers | Extend navigation and components without putting policy decisions in UI Plans |
604
- | Forms | useForm owns validation and accessible view state | Call an API and apply server errors before showing success |
605
- | SSR | render-request.ts adapts URL/request data to renderRoute | Supply compiled routes/templates per request and attach platform HTTP headers |
606
-
607
- The built-in local subject exists only so the generated client demo is navigable. Treat client capability checks as presentation logic, never as a security boundary. On SSR, pass authorizationSubject in the request context. Your API must independently authenticate and authorize writes.
608
-
609
- The SSR adapter is host-independent. A Node, Hono, Express, or edge entry point can call renderEnterpriseRequest with its route array, server template registry, per-request environment, and request context, then map RenderRouteResult.status to an HTTP status. Keep secrets and non-serializable session objects out of initialState.
610
- `;
611
- export const enterpriseFiles = [
612
- { path: 'package.json', content: packageJson },
613
- { path: 'tsconfig.json', content: tsconfig },
614
- { path: 'vite.config.ts', content: viteConfig },
615
- { path: 'index.html', content: indexHtml },
616
- { path: 'README.md', content: readme },
617
- { path: 'src/env.d.ts', content: envDts },
618
- { path: 'src/main.ts', content: mainTs },
619
- { path: 'src/app.ts', content: appTs },
620
- { path: 'src/app/i18n.ts', content: i18nTs },
621
- { path: 'src/app/services.ts', content: servicesTs },
622
- { path: 'src/app-shell.ts', content: appShellTs },
623
- { path: 'src/access/authorization.ts', content: authorizationTs },
624
- { path: 'src/server/render-request.ts', content: renderRequestTs },
625
- { path: 'src/pages/index.ts', content: homePageTs },
626
- { path: 'src/pages/index.html', content: homePageHtml },
627
- { path: 'src/pages/login.ts', content: loginPageTs },
628
- { path: 'src/pages/login.html', content: loginPageHtml },
629
- { path: 'src/pages/403.ts', content: forbiddenPageTs },
630
- { path: 'src/pages/403.html', content: forbiddenPageHtml },
631
- { path: 'src/pages/(admin)/_layout.ts', content: adminLayoutTs },
632
- { path: 'src/pages/(admin)/_layout.html', content: adminLayoutHtml },
633
- { path: 'src/pages/(admin)/dashboard/index.ts', content: dashboardPageTs },
634
- { path: 'src/pages/(admin)/dashboard/index.html', content: dashboardPageHtml },
635
- { path: 'src/pages/(admin)/dashboard/users/new.ts', content: userFormPageTs },
636
- { path: 'src/pages/(admin)/dashboard/users/new.html', content: userFormPageHtml },
637
- { path: 'src/styles/global.css', content: globalCss },
638
- ];
package/dist/inspect.d.ts DELETED
@@ -1,11 +0,0 @@
1
- /** @license MIT
2
- * Copyright (c) 2026 vobsjs
3
- * @vobs/cli
4
- */
5
- import type { VobsProjectManifest } from '@vobs/ai-contracts';
6
- export interface InspectOptions {
7
- readonly tsconfigPath: string;
8
- readonly out?: string;
9
- }
10
- export declare function inspectVobsProject(options: InspectOptions): VobsProjectManifest;
11
- export declare function writeInspectOutput(manifest: VobsProjectManifest, outputPath: string): void;