@webjskit/cli 0.4.1 → 0.4.4

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/lib/create.js CHANGED
@@ -87,9 +87,9 @@ export async function scaffoldApp(name, cwd, opts = {}) {
87
87
  '@web/test-runner': '^0.20.0',
88
88
  '@web/test-runner-playwright': '^0.11.0',
89
89
  'playwright': '^1.59.0',
90
- // tsserver plugins for editor intelligence inside html`` templates.
91
- // Order in tsconfig matters see below.
92
- 'ts-lit-plugin': '^2.0.0',
90
+ // tsserver plugin for editor intelligence inside html`` templates.
91
+ // @webjskit/ts-plugin bundles ts-lit-plugin internally, so just one
92
+ // plugin entry is needed in tsconfig (see below).
93
93
  '@webjskit/ts-plugin': 'latest',
94
94
  },
95
95
  }, null, 2) + '\n');
@@ -104,14 +104,16 @@ export async function scaffoldApp(name, cwd, opts = {}) {
104
104
  noEmit: true,
105
105
  allowImportingTsExtensions: true,
106
106
  skipLibCheck: true,
107
- // ts-lit-plugin: type-check + diagnostics inside html`` templates.
108
- // @webjskit/ts-plugin: webjs-aware go-to-definition, "Unknown tag/attr"
109
- // suppression for elements registered via Class.register('tag'), and
110
- // attribute auto-complete sourced from `static properties`.
111
- // Order matters list ts-lit-plugin first; @webjskit/ts-plugin wraps
112
- // it. Remove either entry if you don't want that capability.
107
+ // @webjskit/ts-plugin gives the editor:
108
+ // type-check + diagnostics inside html`` templates (via the
109
+ // ts-lit-plugin it bundles internally)
110
+ // webjs-aware go-to-definition on custom-element tags
111
+ // "Unknown tag/attribute" suppression for elements registered
112
+ // via Class.register('tag-name')
113
+ // • attribute auto-complete sourced from `static properties`
114
+ // • attribute-value type-check against `declare` annotations
115
+ // Editor-only — the framework runs without it.
113
116
  plugins: [
114
- { name: 'ts-lit-plugin', strict: true },
115
117
  { name: '@webjskit/ts-plugin' },
116
118
  ],
117
119
  },
@@ -266,6 +268,27 @@ export async function POST(req: Request) {
266
268
  const body = await req.json();
267
269
  return Response.json(await createUser(body));
268
270
  }
271
+ `);
272
+ // Minimal test stub so the scaffold passes `webjs check` (tests-exist)
273
+ // and `webjs test` runs cleanly. Replace these with real assertions
274
+ // once you wire the action/query to a real data source.
275
+ await writeFile(join(appDir, 'test', 'unit', 'users.test.ts'), `import { test } from 'node:test';
276
+ import assert from 'node:assert/strict';
277
+
278
+ import { listUsers } from '../../modules/users/queries/list-users.server.ts';
279
+ import { createUser } from '../../modules/users/actions/create-user.server.ts';
280
+
281
+ test('listUsers returns an array', async () => {
282
+ const users = await listUsers();
283
+ assert.ok(Array.isArray(users));
284
+ });
285
+
286
+ test('createUser returns a success envelope with the input echoed back', async () => {
287
+ const result = await createUser({ name: 'Test', email: 'test@example.com' });
288
+ assert.equal(result.success, true);
289
+ assert.equal(result.data.name, 'Test');
290
+ assert.equal(result.data.email, 'test@example.com');
291
+ });
269
292
  `);
270
293
  await writeFile(join(appDir, 'modules', 'users', 'types.ts'), `export interface User {
271
294
  id: string;
@@ -133,6 +133,54 @@ export async function writeSaasFiles(appDir) {
133
133
  "",
134
134
  ].join('\n'));
135
135
 
136
+ // test/unit/auth.test.ts — minimal stub so the scaffold passes
137
+ // `webjs check` (tests-exist) and `webjs test` runs cleanly out of the
138
+ // box. The signup/current-user functions import from lib/prisma.ts and
139
+ // lib/auth.ts, both of which need `prisma generate` to have run before
140
+ // they can be imported — so we deliberately test only the runtime-
141
+ // dependency-free types.ts here. Replace with real tests once Prisma
142
+ // is set up (run `npm install && npx prisma migrate dev --name init`).
143
+ await writeFile(join(appDir, 'test', 'unit', 'auth.test.ts'), [
144
+ "import { test } from 'node:test';",
145
+ "import assert from 'node:assert/strict';",
146
+ "",
147
+ "import type { User, ActionResult } from '../../modules/auth/types.ts';",
148
+ "",
149
+ "test('User shape: id is numeric, email is required', () => {",
150
+ " const u: User = { id: 1, name: 'Test', email: 'test@example.com' };",
151
+ " assert.equal(typeof u.id, 'number');",
152
+ " assert.equal(typeof u.email, 'string');",
153
+ "});",
154
+ "",
155
+ "test('ActionResult: success envelope carries data', () => {",
156
+ " const r: ActionResult<User> = {",
157
+ " success: true,",
158
+ " data: { id: 1, name: 'Test', email: 'test@example.com' },",
159
+ " };",
160
+ " assert.equal(r.success, true);",
161
+ " if (r.success) assert.equal(r.data.email, 'test@example.com');",
162
+ "});",
163
+ "",
164
+ "test('ActionResult: failure envelope carries error + status', () => {",
165
+ " const r: ActionResult<User> = {",
166
+ " success: false,",
167
+ " error: 'Email already registered',",
168
+ " status: 409,",
169
+ " };",
170
+ " assert.equal(r.success, false);",
171
+ " if (!r.success) {",
172
+ " assert.equal(r.status, 409);",
173
+ " assert.ok(r.error.length > 0);",
174
+ " }",
175
+ "});",
176
+ "",
177
+ "// TODO: once you've run `npm install && npx prisma migrate dev` you can",
178
+ "// import { signup } from '../../modules/auth/actions/signup.server.ts'",
179
+ "// and { currentUser } from '../../modules/auth/queries/current-user.server.ts'",
180
+ "// and write real integration tests against a test SQLite DB.",
181
+ "",
182
+ ].join('\n'));
183
+
136
184
  // app/api/auth/[...path]/route.ts
137
185
  await mkdir(join(appDir, 'app', 'api', 'auth', '[...path]'), { recursive: true });
138
186
  await writeFile(join(appDir, 'app', 'api', 'auth', '[...path]', 'route.ts'), [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webjskit/cli",
3
- "version": "0.4.1",
3
+ "version": "0.4.4",
4
4
  "type": "module",
5
5
  "description": "webjs CLI — dev, start, create, db",
6
6
  "bin": {
@@ -13,7 +13,7 @@
13
13
  "README.md"
14
14
  ],
15
15
  "dependencies": {
16
- "@webjskit/server": "0.4.1"
16
+ "@webjskit/server": "0.4.2"
17
17
  },
18
18
  "publishConfig": {
19
19
  "access": "public"
@@ -80,5 +80,5 @@ Quality bar stays the same — just no blocking on questions.
80
80
  - One function per server action file (*.server.ts)
81
81
  - Components must call customElements.define('tag', Class)
82
82
  - Never import @prisma/client or node:* from client components
83
- - Use directives (classMap, styleMap, ref, etc.) from '@webjskit/core/directives'
83
+ - Directives are deliberately minimal: only `unsafeHTML`, `live`, and `repeat` ship. Lit's `classMap` / `styleMap` / `ref` / `when` / `choose` / `guard` are NOT exported — use plain template-literal expressions (`class=${cond ? 'a' : 'b'}`, `${cond ? a : b}`) and lifecycle hooks (`this.query('#el')` in `firstUpdated`) instead.
84
84
  - See AGENTS.md for the complete directive decision guide
@@ -64,9 +64,9 @@ Every code change must include:
64
64
  ## Code patterns
65
65
 
66
66
  - Tagged template: html`<div>${value}</div>` with css`...` for styles
67
- - Components: extend WebComponent, use static tag/styles/properties, call Class.register('tag')
67
+ - Components: extend WebComponent, declare `static properties` (and `static styles` for shadow-DOM components), call `Class.register('tag-name')` at the bottom of the file. The tag name is the argument to `.register()`, not a static field.
68
68
  - Server actions: *.server.ts files with one exported async function each
69
- - Directives: import { classMap, styleMap, ref, when, ... } from '@webjskit/core/directives'
69
+ - Directives: webjs ships only `unsafeHTML`, `live`, and `repeat`. Lit's `classMap` / `styleMap` / `ref` / `when` / `choose` / `guard` are NOT exported — use plain template-literal expressions and lifecycle hooks instead.
70
70
  - Context: import { createContext, ContextProvider, ContextConsumer } from '@webjskit/core/context'
71
71
  - Task: import { Task, TaskStatus } from '@webjskit/core/task'
72
72
  - Routing: file-based under app/ (page.ts, layout.ts, route.ts, middleware.ts)
@@ -67,8 +67,9 @@ The user should never have to ask for tests or documentation.
67
67
  ## Framework specifics
68
68
 
69
69
  - No build step: ES modules served directly
70
- - Web components with shadow DOM by default
70
+ - Web components render into light DOM by default (so Tailwind / global CSS apply directly). Opt in to shadow DOM per component with `static shadow = true` when you need scoped styles, slot projection, or third-party-embed isolation.
71
+ - Custom-element tag names are passed to `.register('tag-name')` — they are NOT a static field on the class.
71
72
  - One function per server action file (*.server.ts)
72
- - Use webjs directives: classMap, styleMap, ref, when, choose, guard, etc.
73
+ - Directives are deliberately minimal: only `unsafeHTML`, `live`, and `repeat` ship. Use plain template-literal expressions (`class=${active ? 'btn active' : 'btn'}`, `style=${'color:' + color}`, `${cond ? a : b}`) and lifecycle hooks (`this.query('#el')` in `firstUpdated`) instead of Lit's `classMap` / `styleMap` / `ref` / `when` / `choose` / `guard`.
73
74
  - Use Context for cross-component data, Task for async data in components
74
75
  - Full API reference in AGENTS.md
@@ -84,6 +84,34 @@ node_modules/@webjskit/
84
84
  Reaching straight for the source is the fastest way to resolve "why
85
85
  doesn't X work?" — no documentation guesswork, no stale blog posts.
86
86
 
87
+ ## Editor TS plugin — `@webjskit/ts-plugin`
88
+
89
+ This scaffold's `tsconfig.json` lists a single tsserver plugin. It is
90
+ editor-only — not required for the framework to run.
91
+
92
+ ```jsonc
93
+ // tsconfig.json (already wired by the scaffold)
94
+ "plugins": [
95
+ { "name": "@webjskit/ts-plugin" }
96
+ ]
97
+ ```
98
+
99
+ `@webjskit/ts-plugin` bundles `ts-lit-plugin` internally (it's a runtime
100
+ dependency of the plugin) and loads it programmatically — so users
101
+ list one entry, not two. You get the full stack of template-literal
102
+ intelligence (type-checking, diagnostics, go-to-def inside
103
+ `` html`…` `` and `` css`…` `` templates) **plus** webjs-aware behaviour
104
+ layered on top:
105
+
106
+ - "Unknown tag/attribute" diagnostics are silenced for elements
107
+ registered via `Class.register('tag-name')`.
108
+ - Attribute auto-complete sourced from each component's
109
+ `static properties`.
110
+ - Attribute-value type-check against `declare propName: T` annotations.
111
+
112
+ See [docs.webjs.com → Editor setup](https://docs.webjs.com/docs/editor-setup)
113
+ for the full walkthrough.
114
+
87
115
  ## File conventions
88
116
 
89
117
  ```
@@ -172,9 +200,8 @@ import { rateLimit, cache, createAuth, Credentials, Session } from '@webjskit/se
172
200
  import { WebComponent, html, css } from '@webjskit/core';
173
201
 
174
202
  export class Counter extends WebComponent {
175
- static tag = 'my-counter'; // required, must contain a hyphen
176
203
  static properties = { count: { type: Number } };
177
- static styles = css`button { padding: 8px 12px; }`;
204
+ static styles = css`button { padding: 8px 12px; }`; // shadow-DOM only
178
205
  // static shadow = true; // opt into shadow DOM (default: light DOM)
179
206
  // static lazy = true; // download JS only when scrolled into view
180
207
 
@@ -223,7 +250,7 @@ absolute URLs from `ctx.url`).
223
250
 
224
251
  ## Invariants (do not violate)
225
252
 
226
- 1. Custom element tags must contain a hyphen. Set `static tag`, call `.register()`.
253
+ 1. Custom element tags must contain a hyphen. Pass the tag to `.register('tag-name')` at the bottom of the file. The tag is not a static field.
227
254
  2. Never import `@prisma/client` or `node:*` from client-reachable files —
228
255
  only from `.server.ts` modules or `lib/*.ts`.
229
256
  3. Event / property / boolean holes in `` html`` `` are unquoted: