@webjsdev/cli 0.10.18 → 0.10.19

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
@@ -85,11 +85,10 @@ const UI_REGISTRY_ROOT = resolveUiRegistryRoot();
85
85
 
86
86
  /**
87
87
  * Read a single @webjsdev/ui registry component, rewrite its relative import
88
- * of `../lib/utils.ts` so it resolves correctly when written to
89
- * `components/ui/<name>.ts` in the scaffolded app. The scaffold puts cn()
90
- * at `lib/utils/cn.ts` (folder-grouped with other browser-safe helpers).
91
- * From `components/ui/<x>.ts`, the equivalent path is two-up plus into the
92
- * utils/ folder: `../../lib/utils/cn.ts`.
88
+ * of `../lib/utils.ts` to the scaffolded app's aliased path so it resolves
89
+ * when written to `components/ui/<name>.ts`. The scaffold puts cn() at
90
+ * `lib/utils/cn.ts` (folder-grouped with other browser-safe helpers), so the
91
+ * alias form is `#lib/utils/cn.ts` (#555/#556).
93
92
  *
94
93
  * @param {string} name component name without `.ts` (e.g. 'button')
95
94
  * @returns {Promise<string>} source with import rewritten
@@ -97,9 +96,11 @@ const UI_REGISTRY_ROOT = resolveUiRegistryRoot();
97
96
  async function readUiComponent(name) {
98
97
  const src = join(UI_REGISTRY_ROOT, 'components', `${name}.ts`);
99
98
  const raw = await readFile(src, 'utf8');
99
+ // The registry component imports cn() via a relative `../lib/utils.ts`; rewrite
100
+ // it to the scaffolded app's aliased path (cn lives at lib/utils/cn.ts).
100
101
  return raw
101
- .replaceAll("'../lib/utils.ts'", "'../../lib/utils/cn.ts'")
102
- .replaceAll('"../lib/utils.ts"', '"../../lib/utils/cn.ts"');
102
+ .replaceAll("'../lib/utils.ts'", "'#lib/utils/cn.ts'")
103
+ .replaceAll('"../lib/utils.ts"', '"#lib/utils/cn.ts"');
103
104
  }
104
105
 
105
106
  /**
@@ -286,6 +287,17 @@ export async function scaffoldApp(name, cwd, opts = {}) {
286
287
  version: '0.1.0',
287
288
  type: 'module',
288
289
  private: true,
290
+ // Native package.json subpath aliases (#555): write app-internal imports as
291
+ // `#lib/...`, `#components/...`, `#db/...`, `#<any-dir>/...` instead of deep
292
+ // `../../../` relatives. ONE catch-all key, so a new top-level folder is
293
+ // aliased with no config change. Node 24+ and Bun both resolve `#*` natively
294
+ // (a `#/`-prefixed key is rejected by Bun, so this slash-free form is the
295
+ // cross-runtime-safe shape; no build step, no tsconfig paths). The webjs
296
+ // server expands the same map for the import graph + browser importmap. Opt
297
+ // out by using a plain relative import.
298
+ imports: {
299
+ '#*': './*',
300
+ },
289
301
  scripts: {
290
302
  // No `predev` / `prestart` hooks (#550): the `webjs` block below holds
291
303
  // the start orchestration (`webjs db migrate`), run INSIDE `webjs start`,
@@ -724,8 +736,8 @@ export async function createUser(input: { name: string; email: string }) {
724
736
  * /api/users: thin route wrapper over typed server actions.
725
737
  * Business logic lives in modules/users/, not here.
726
738
  */
727
- import { listUsers } from '../../../modules/users/queries/list-users.server.ts';
728
- import { createUser } from '../../../modules/users/actions/create-user.server.ts';
739
+ import { listUsers } from '#modules/users/queries/list-users.server.ts';
740
+ import { createUser } from '#modules/users/actions/create-user.server.ts';
729
741
 
730
742
  export async function GET() {
731
743
  return Response.json(await listUsers());
@@ -742,8 +754,8 @@ export async function POST(req: Request) {
742
754
  await writeFile(join(appDir, 'test', 'unit', 'users.test.ts'), `import { test } from 'node:test';
743
755
  import assert from 'node:assert/strict';
744
756
 
745
- import { listUsers } from '../../modules/users/queries/list-users.server.ts';
746
- import { createUser } from '../../modules/users/actions/create-user.server.ts';
757
+ import { listUsers } from '#modules/users/queries/list-users.server.ts';
758
+ import { createUser } from '#modules/users/actions/create-user.server.ts';
747
759
 
748
760
  test('listUsers returns an array', async () => {
749
761
  const users = await listUsers();
@@ -833,16 +845,16 @@ export type ActionResult<T> =
833
845
  await writeFile(join(appDir, 'app', 'layout.ts'), `// webjs-scaffold-placeholder. This is the example app chrome (brand, nav, content-width container). Adapt it to your app, then delete this line. webjs check fails while the marker remains.
834
846
  import { html, cspNonce } from '@webjsdev/core';
835
847
  import '@webjsdev/core/client-router';
836
- import '../components/theme-toggle.ts';
848
+ import '#components/theme-toggle.ts';
837
849
  // Webjs UI components are tiered:
838
850
  // - Tier 1 (button, card, input, label, alert, badge, separator, etc.) are
839
851
  // class-helper FUNCTIONS, with no custom element to register. Each page
840
852
  // imports the specific helpers it needs (e.g.
841
- // \`import { buttonClass } from '../components/ui/button.ts'\`).
853
+ // \`import { buttonClass } from '#components/ui/button.ts'\`).
842
854
  // - Tier 2 (dialog, popover, tooltip, tabs, accordion, etc.) ARE custom
843
855
  // elements. Register them by side-effect-importing here once so they
844
856
  // work transitively across every page:
845
- // import '../components/ui/dialog.ts';
857
+ // import '#components/ui/dialog.ts';
846
858
  // The example app/page.ts below uses only Tier-1 helpers, so nothing
847
859
  // extra needs to be registered. Add Tier-2 imports as you 'webjs ui add'.
848
860
 
@@ -1014,18 +1026,18 @@ ${SHADCN_THEME}
1014
1026
 
1015
1027
  await writeFile(join(appDir, 'app', 'page.ts'), `// webjs-scaffold-placeholder. This is the example homepage. Replace it with your app's real page, then delete this line. webjs check fails while the marker remains.
1016
1028
  import { html } from '@webjsdev/core';
1017
- import { rubric, displayH1, accentLink } from '../lib/utils/ui.ts';
1018
- import { buttonClass } from '../components/ui/button.ts';
1019
- import { badgeClass } from '../components/ui/badge.ts';
1029
+ import { rubric, displayH1, accentLink } from '#lib/utils/ui.ts';
1030
+ import { buttonClass } from '#components/ui/button.ts';
1031
+ import { badgeClass } from '#components/ui/badge.ts';
1020
1032
  import {
1021
1033
  cardClass,
1022
1034
  cardHeaderClass,
1023
1035
  cardTitleClass,
1024
1036
  cardDescriptionClass,
1025
1037
  cardContentClass,
1026
- } from '../components/ui/card.ts';
1027
- import { alertClass, alertTitleClass, alertDescriptionClass } from '../components/ui/alert.ts';
1028
- import { separatorClass } from '../components/ui/separator.ts';
1038
+ } from '#components/ui/card.ts';
1039
+ import { alertClass, alertTitleClass, alertDescriptionClass } from '#components/ui/alert.ts';
1040
+ import { separatorClass } from '#components/ui/separator.ts';
1029
1041
 
1030
1042
  export const metadata = {
1031
1043
  title: '${name}: built with webjs',
@@ -14,17 +14,19 @@ const UI_REGISTRY_ROOT = resolve(
14
14
  );
15
15
 
16
16
  /**
17
- * Read a registry component and rewrite its `'../lib/utils.ts'` import for
18
- * the scaffolded app's `components/ui/<name>.ts` layout (two-up to lib/).
19
- * Mirrors the helper in `create.js`, kept private here to avoid coupling.
17
+ * Read a registry component and rewrite its `'#lib/utils.ts'` import for
18
+ * the scaffolded app's `components/ui/<name>.ts` layout (the `#lib/utils/cn.ts`
19
+ * alias). Mirrors the helper in `create.js`, kept private here to avoid coupling.
20
20
  */
21
21
  async function readUiComponent(name) {
22
22
  const src = join(UI_REGISTRY_ROOT, 'components', `${name}.ts`);
23
23
  if (!existsSync(src)) return null;
24
24
  const raw = await readFile(src, 'utf8');
25
+ // The registry component imports cn() via a relative `../lib/utils.ts`; rewrite
26
+ // it to the scaffolded app's aliased path (cn lives at lib/utils/cn.ts).
25
27
  return raw
26
- .replaceAll("'../lib/utils.ts'", "'../../lib/utils.ts'")
27
- .replaceAll('"../lib/utils.ts"', '"../../lib/utils.ts"');
28
+ .replaceAll("'../lib/utils.ts'", "'#lib/utils/cn.ts'")
29
+ .replaceAll('"../lib/utils.ts"', '"#lib/utils/cn.ts"');
28
30
  }
29
31
 
30
32
  /** Copy named registry components into `<appDir>/components/ui/`. */
@@ -79,7 +81,7 @@ export async function writeSaasFiles(appDir) {
79
81
  // lib/auth.server.ts
80
82
  await writeFile(join(appDir, 'lib', 'auth.server.ts'), [
81
83
  "import { createAuth, Credentials } from '@webjsdev/server';",
82
- "import { db } from '../db/connection.server.ts';",
84
+ "import { db } from '#db/connection.server.ts';",
83
85
  "import { compare } from './password.server.ts';",
84
86
  "",
85
87
  "export const { auth, signIn, signOut, handlers } = createAuth({",
@@ -124,9 +126,9 @@ export async function writeSaasFiles(appDir) {
124
126
  await writeFile(join(appDir, 'modules', 'auth', 'actions', 'signup.server.ts'), [
125
127
  "'use server';",
126
128
  "",
127
- "import { db } from '../../../db/connection.server.ts';",
128
- "import { users } from '../../../db/schema.server.ts';",
129
- "import { hash } from '../../../lib/password.server.ts';",
129
+ "import { db } from '#db/connection.server.ts';",
130
+ "import { users } from '#db/schema.server.ts';",
131
+ "import { hash } from '#lib/password.server.ts';",
130
132
  "",
131
133
  "export async function signup(input: { name: string; email: string; password: string }) {",
132
134
  " const exists = await db.query.users.findFirst({ where: { email: input.email }, columns: { id: true } });",
@@ -141,7 +143,7 @@ export async function writeSaasFiles(appDir) {
141
143
  await writeFile(join(appDir, 'modules', 'auth', 'queries', 'current-user.server.ts'), [
142
144
  "'use server';",
143
145
  "",
144
- "import { auth } from '../../../lib/auth.server.ts';",
146
+ "import { auth } from '#lib/auth.server.ts';",
145
147
  "",
146
148
  "export async function currentUser() {",
147
149
  " const session = await auth();",
@@ -263,7 +265,7 @@ export async function writeSaasFiles(appDir) {
263
265
  // app/api/auth/[...path]/route.ts
264
266
  await mkdir(join(appDir, 'app', 'api', 'auth', '[...path]'), { recursive: true });
265
267
  await writeFile(join(appDir, 'app', 'api', 'auth', '[...path]', 'route.ts'), [
266
- "import { handlers } from '../../../../lib/auth.server.ts';",
268
+ "import { handlers } from '#lib/auth.server.ts';",
267
269
  "export const GET = handlers.GET;",
268
270
  "export const POST = handlers.POST;",
269
271
  "",
@@ -273,10 +275,10 @@ export async function writeSaasFiles(appDir) {
273
275
  await mkdir(join(appDir, 'app', 'login'), { recursive: true });
274
276
  await writeFile(join(appDir, 'app', 'login', 'page.ts'), [
275
277
  "import { html } from '@webjsdev/core';",
276
- "import { cardClass, cardHeaderClass, cardTitleClass, cardDescriptionClass, cardContentClass, cardFooterClass } from '../../components/ui/card.ts';",
277
- "import { buttonClass } from '../../components/ui/button.ts';",
278
- "import { inputClass } from '../../components/ui/input.ts';",
279
- "import { labelClass } from '../../components/ui/label.ts';",
278
+ "import { cardClass, cardHeaderClass, cardTitleClass, cardDescriptionClass, cardContentClass, cardFooterClass } from '#components/ui/card.ts';",
279
+ "import { buttonClass } from '#components/ui/button.ts';",
280
+ "import { inputClass } from '#components/ui/input.ts';",
281
+ "import { labelClass } from '#components/ui/label.ts';",
280
282
  "",
281
283
  "export const metadata = { title: 'Login' };",
282
284
  "",
@@ -315,11 +317,11 @@ export async function writeSaasFiles(appDir) {
315
317
  await mkdir(join(appDir, 'app', 'signup'), { recursive: true });
316
318
  await writeFile(join(appDir, 'app', 'signup', 'page.ts'), [
317
319
  "import { html } from '@webjsdev/core';",
318
- "import { signup } from '../../modules/auth/actions/signup.server.ts';",
319
- "import { cardClass, cardHeaderClass, cardTitleClass, cardDescriptionClass, cardContentClass, cardFooterClass } from '../../components/ui/card.ts';",
320
- "import { buttonClass } from '../../components/ui/button.ts';",
321
- "import { inputClass } from '../../components/ui/input.ts';",
322
- "import { labelClass } from '../../components/ui/label.ts';",
320
+ "import { signup } from '#modules/auth/actions/signup.server.ts';",
321
+ "import { cardClass, cardHeaderClass, cardTitleClass, cardDescriptionClass, cardContentClass, cardFooterClass } from '#components/ui/card.ts';",
322
+ "import { buttonClass } from '#components/ui/button.ts';",
323
+ "import { inputClass } from '#components/ui/input.ts';",
324
+ "import { labelClass } from '#components/ui/label.ts';",
323
325
  "",
324
326
  "export const metadata = { title: 'Sign up' };",
325
327
  "",
@@ -387,7 +389,7 @@ export async function writeSaasFiles(appDir) {
387
389
  // app/dashboard/middleware.ts
388
390
  await mkdir(join(appDir, 'app', 'dashboard', 'settings'), { recursive: true });
389
391
  await writeFile(join(appDir, 'app', 'dashboard', 'middleware.ts'), [
390
- "import { auth } from '../../lib/auth.server.ts';",
392
+ "import { auth } from '#lib/auth.server.ts';",
391
393
  "",
392
394
  "export default async function requireAuth(req: Request, next: () => Promise<Response>) {",
393
395
  " const session = await auth();",
@@ -402,10 +404,10 @@ export async function writeSaasFiles(appDir) {
402
404
  // app/dashboard/page.ts
403
405
  await writeFile(join(appDir, 'app', 'dashboard', 'page.ts'), [
404
406
  "import { html } from '@webjsdev/core';",
405
- "import { currentUser } from '../../modules/auth/queries/current-user.server.ts';",
406
- "import { cardClass, cardHeaderClass, cardTitleClass, cardDescriptionClass, cardContentClass } from '../../components/ui/card.ts';",
407
- "import { buttonClass } from '../../components/ui/button.ts';",
408
- "import { badgeClass } from '../../components/ui/badge.ts';",
407
+ "import { currentUser } from '#modules/auth/queries/current-user.server.ts';",
408
+ "import { cardClass, cardHeaderClass, cardTitleClass, cardDescriptionClass, cardContentClass } from '#components/ui/card.ts';",
409
+ "import { buttonClass } from '#components/ui/button.ts';",
410
+ "import { badgeClass } from '#components/ui/badge.ts';",
409
411
  "",
410
412
  "export const metadata = { title: 'Dashboard' };",
411
413
  "",
@@ -433,8 +435,8 @@ export async function writeSaasFiles(appDir) {
433
435
  // app/dashboard/settings/page.ts
434
436
  await writeFile(join(appDir, 'app', 'dashboard', 'settings', 'page.ts'), [
435
437
  "import { html } from '@webjsdev/core';",
436
- "import { currentUser } from '../../../modules/auth/queries/current-user.server.ts';",
437
- "import { cardClass, cardHeaderClass, cardTitleClass, cardDescriptionClass, cardContentClass } from '../../../components/ui/card.ts';",
438
+ "import { currentUser } from '#modules/auth/queries/current-user.server.ts';",
439
+ "import { cardClass, cardHeaderClass, cardTitleClass, cardDescriptionClass, cardContentClass } from '#components/ui/card.ts';",
438
440
  "",
439
441
  "export const metadata = { title: 'Settings' };",
440
442
  "",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webjsdev/cli",
3
- "version": "0.10.18",
3
+ "version": "0.10.19",
4
4
  "type": "module",
5
5
  "description": "webjs CLI - dev, start, create, db",
6
6
  "bin": {
@@ -202,10 +202,10 @@ Pure functions that return Tailwind class strings. You apply them to
202
202
  import {
203
203
  cardClass, cardHeaderClass, cardTitleClass,
204
204
  cardContentClass, cardFooterClass,
205
- } from '../../components/ui/card.ts';
206
- import { inputClass } from '../../components/ui/input.ts';
207
- import { labelClass } from '../../components/ui/label.ts';
208
- import { buttonClass } from '../../components/ui/button.ts';
205
+ } from '#components/ui/card.ts';
206
+ import { inputClass } from '#components/ui/input.ts';
207
+ import { labelClass } from '#components/ui/label.ts';
208
+ import { buttonClass } from '#components/ui/button.ts';
209
209
 
210
210
  return html`
211
211
  <div class=${cardClass()}>
@@ -237,13 +237,13 @@ elements. Import them once (typically in `app/layout.ts`) and use
237
237
 
238
238
  ```ts
239
239
  // app/layout.ts (registers the custom elements for every page)
240
- import '../components/ui/dialog.ts';
241
- import '../components/ui/tabs.ts';
240
+ import '#components/ui/dialog.ts';
241
+ import '#components/ui/tabs.ts';
242
242
  ```
243
243
 
244
244
  ```ts
245
245
  // app/some-page/page.ts (uses the registered elements)
246
- import { buttonClass } from '../../components/ui/button.ts';
246
+ import { buttonClass } from '#components/ui/button.ts';
247
247
 
248
248
  return html`
249
249
  <ui-dialog>
@@ -463,7 +463,7 @@ singleton avoids opening a new connection on every dev-server reload), and
463
463
  the tables from `db/schema.server.ts`:
464
464
 
465
465
  ```ts
466
- import { db } from '../../../db/connection.server.ts';
466
+ import { db } from '#db/connection.server.ts';
467
467
  const users = await db.query.users.findMany();
468
468
  ```
469
469
 
@@ -754,8 +754,8 @@ legitimately use `static styles = css\`\`` for scoped CSS.
754
754
  ```ts
755
755
  // modules/posts/actions/create-post.server.ts
756
756
  'use server';
757
- import { db } from '../../../db/connection.server.ts';
758
- import { posts } from '../../../db/schema.server.ts';
757
+ import { db } from '#db/connection.server.ts';
758
+ import { posts } from '#db/schema.server.ts';
759
759
 
760
760
  export async function createPost(input: { title: string; body: string }) {
761
761
  if (!input.title) return { success: false, error: 'title required', status: 400 };
@@ -806,7 +806,7 @@ with a `route.ts` POST handler:
806
806
  ```ts
807
807
  // app/posts/route.ts
808
808
  import { redirect, html } from '@webjsdev/core';
809
- import { createPost } from '../../modules/posts/actions/create-post.server.ts';
809
+ import { createPost } from '#modules/posts/actions/create-post.server.ts';
810
810
 
811
811
  export async function POST(req: Request) {
812
812
  const form = await req.formData();
@@ -281,7 +281,7 @@ codegen, so there is no dev `before` step.
281
281
  preferences (theme, sidebar collapsed, etc.).
282
282
  5. To add a model: edit `db/schema.server.ts`, then `npm run db:generate`
283
283
  and `npm run db:migrate`. Access via `import { db } from
284
- '../../../db/connection.server.ts'` (and the tables from
284
+ '#db/connection.server.ts'` (and the tables from
285
285
  `db/schema.server.ts`) **only inside `.server.{js,ts}` files,
286
286
  `route.ts` handlers, or `middleware.ts`**. Components, pages, and
287
287
  layouts call into the wrapped server query instead; the framework
@@ -388,6 +388,7 @@ modules/
388
388
  ```
389
389
 
390
390
  **Rules:**
391
+ - **Prefer the `#` root alias over deep relatives.** Write `import { db } from '#db/connection.server.ts'`, `import { Button } from '#components/ui/button.ts'`, `#lib/...`, `#modules/...` instead of `../../../`. It is native `package.json "imports"` (the single `"#*": "./*"` key covers every top-level folder, so a new folder needs no config), resolved by Node and Bun with no build step. There is no slash after the `#` (`#lib/...`, not `#/lib/...`). A same-directory import stays relative (`./sibling.ts`).
391
392
  - One exported function per server action/query file
392
393
  - Server actions need BOTH the `.server.{js,ts}` extension AND a `'use server'` directive at the top. Extension alone marks a server-only utility (source-protected, not RPC-callable). Directive alone is a lint violation (`use-server-needs-extension`).
393
394
  - Components must call `Class.register('tag')`
@@ -588,8 +589,8 @@ the module once (typically in `app/layout.ts`) and use the tag.
588
589
  ```ts
589
590
  // Tier 1: class helpers on native elements (use this for forms,
590
591
  // dashboards, cards, layouts, anywhere the value is purely visual)
591
- import { buttonClass } from '../components/ui/button.ts';
592
- import { inputClass } from '../components/ui/input.ts';
592
+ import { buttonClass } from '#components/ui/button.ts';
593
+ import { inputClass } from '#components/ui/input.ts';
593
594
  return html`
594
595
  <button class=${buttonClass({ size: 'lg' })}>Save</button>
595
596
  <input class=${inputClass()} placeholder="Email">
@@ -773,7 +774,7 @@ Consume:
773
774
 
774
775
  ```ts
775
776
  // app/page.ts
776
- import { rubric } from '../lib/utils/ui.ts';
777
+ import { rubric } from '#lib/utils/ui.ts';
777
778
 
778
779
  export default function Home() {
779
780
  return html`
@@ -925,8 +926,8 @@ route imports and calls it.
925
926
  ```ts
926
927
  // modules/posts/actions/create-post.server.ts
927
928
  'use server';
928
- import { db } from '../../../db/connection.server.ts';
929
- import { posts } from '../../../db/schema.server.ts';
929
+ import { db } from '#db/connection.server.ts';
930
+ import { posts } from '#db/schema.server.ts';
930
931
  export async function createPost({ title, body }) {
931
932
  const [post] = await db.insert(posts).values({ title, body }).returning();
932
933
  return post;
@@ -936,7 +937,7 @@ export async function createPost({ title, body }) {
936
937
  ```ts
937
938
  // app/api/posts/route.ts
938
939
  import { route } from '@webjsdev/server';
939
- import { createPost } from '../../../modules/posts/actions/create-post.server.ts';
940
+ import { createPost } from '#modules/posts/actions/create-post.server.ts';
940
941
  // The route() adapter merges query + route params + JSON body into one input
941
942
  // object and JSON-responds the result. Pass { validate } to guard the input.
942
943
  export const POST = route(createPost);
@@ -1039,8 +1040,8 @@ Where the data lives, where to read it:
1039
1040
  ```ts
1040
1041
  // modules/posts/actions/create-post.server.ts
1041
1042
  'use server';
1042
- import { db } from '../../../db/connection.server.ts';
1043
- import { posts } from '../../../db/schema.server.ts';
1043
+ import { db } from '#db/connection.server.ts';
1044
+ import { posts } from '#db/schema.server.ts';
1044
1045
  import type { ActionResult } from '../types.ts';
1045
1046
 
1046
1047
  export async function createPost(input: {
@@ -1167,8 +1168,8 @@ Routes are thin wrappers over typed server actions. Business logic lives in
1167
1168
 
1168
1169
  ```ts
1169
1170
  // app/api/users/route.ts: thin wrapper
1170
- import { listUsers } from '../../../modules/users/queries/list-users.server.ts';
1171
- import { createUser } from '../../../modules/users/actions/create-user.server.ts';
1171
+ import { listUsers } from '#modules/users/queries/list-users.server.ts';
1172
+ import { createUser } from '#modules/users/actions/create-user.server.ts';
1172
1173
 
1173
1174
  export async function GET() { return Response.json(await listUsers()); }
1174
1175
  export async function POST(req: Request) {
@@ -16,7 +16,7 @@ test('html template renders correctly', async () => {
16
16
 
17
17
  test('example: your first server action test', async () => {
18
18
  // Import your server action:
19
- // import { createPost } from '../../modules/posts/actions/create-post.server.ts';
19
+ // import { createPost } from '#modules/posts/actions/create-post.server.ts';
20
20
  //
21
21
  // const result = await createPost({ title: 'Test', body: 'Content' });
22
22
  // assert.equal(result.success, true);