@shivaedev/build 0.1.0 → 0.1.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.1 - 2026-11-11
4
+
5
+ ### Changed
6
+
7
+ - The README's examples name a module file after its export, as in `src/modules/notes/Notes.ts` and `#generated/modules/notes/Notes.ts`, and import operations from the module's `server/` folder, as applications write them.
8
+
9
+ ### Fixed
10
+
11
+ - Generating no longer leaves an empty `.<file>.XXXXXX` folder beside every file it writes, under `src/generated` and in `node_modules/.cache/@shivaedev/build`. Each write still replaces the file in one rename, and its temporary folder is removed when the write ends, also when it fails or is interrupted. Folders left by earlier versions stay until you delete them.
12
+
3
13
  ## 0.1.0 - 2026-11-11
4
14
 
5
15
  ### Added
package/README.md CHANGED
@@ -8,10 +8,10 @@ An operation written as `payload` and `*run` has its success and rejections only
8
8
 
9
9
  ```ts
10
10
  import { defineModule } from "@shivaedev/contract/defineModule.ts";
11
- import { notesWire } from "#generated/modules/notes/notes.ts";
12
- import { Create } from "#modules/notes/create.ts";
13
- import { List } from "#modules/notes/list.ts";
14
- import { NotesStore } from "#modules/notes/store.ts";
11
+ import { notesWire } from "#generated/modules/notes/Notes.ts";
12
+ import { Create } from "#modules/notes/server/Create.ts";
13
+ import { List } from "#modules/notes/server/List.ts";
14
+ import { NotesStore } from "#modules/notes/server/Store.ts";
15
15
 
16
16
  export const Notes = defineModule({ name: "notes", operations: [List, Create], requires: [NotesStore], wire: notesWire });
17
17
  ```
@@ -21,7 +21,7 @@ shivaedev-build generate
21
21
  ```
22
22
 
23
23
  ```text
24
- src/generated/modules/notes/notes.ts: written
24
+ src/generated/modules/notes/Notes.ts: written
25
25
  ```
26
26
 
27
27
  ## Using it
@@ -68,7 +68,7 @@ The application's `package.json` runs the generator before anything that reads t
68
68
  }
69
69
  ```
70
70
 
71
- pnpm does not run `prepare` on a production install (`pnpm install --prod`), so a production install without development dependencies succeeds without the generator; the files must already be written, as `pnpm build` writes them through the Vite plugin. The folder's contents stay out of Git except a README that names the command, and once the application imports from the folder, Quality's `imports/resolvable` lists it as `generated`:
71
+ pnpm does not run `prepare` on a production install (`pnpm install --prod`), so a production install without development dependencies succeeds without the generator; the files must already be written, as `pnpm build` writes them through the Vite plugin. The folder's contents stay out of Git except a README that names the command, and `quality lint` runs the `generate` script before it reads the sources, so no configuration names the folder:
72
72
 
73
73
  ```gitignore
74
74
  src/generated/*
@@ -123,19 +123,19 @@ With a generated client the browser never needs a module or its operations, so t
123
123
  The build fails with the import chain from the client entry to that module:
124
124
 
125
125
  ```text
126
- Server code reached the browser bundle: src/modules/notes/notes.ts is a module file: it calls defineModule. The import chain from the client entry:
126
+ Server code reached the browser bundle: src/modules/notes/Notes.ts is a module file: it calls defineModule. The import chain from the client entry:
127
127
  index.html
128
128
  → src/client.ts
129
129
  → src/screens/notes.ts
130
- → src/modules/notes/notes.ts
130
+ → src/modules/notes/Notes.ts
131
131
  The browser reaches a defined module through its generated client in src/generated and imports no server code.
132
132
  ```
133
133
 
134
- The browser imports `Notes` from `#generated/modules/notes/notes.ts` instead.
134
+ The browser imports `Notes` from `#generated/modules/notes/Notes.ts` instead.
135
135
 
136
136
  ### The generated file
137
137
 
138
- For the module above, the file starts with a line saying it is generated from `src/modules/notes/notes.ts`, must not be edited and is not committed. It exports the module's wire, named after the module's `name`, the browser's contract under the module's own export name, built by `clientContract`, and a closing `ClientMatchesModule` assertion:
138
+ For the module above, the file starts with a line saying it is generated from `src/modules/notes/Notes.ts`, must not be edited and is not committed. It exports the module's wire, named after the module's `name`, the browser's contract under the module's own export name, built by `clientContract`, and a closing `ClientMatchesModule` assertion:
139
139
 
140
140
  ```ts
141
141
  export const notesWire = {
@@ -1 +1 @@
1
- {"version":3,"file":"files.d.ts","sourceRoot":"","sources":["../src/files.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAE1D,eAAO,MAAM,aAAa,6HAMxB,CAAC;AAGH,eAAO,MAAM,eAAe,sIAO1B,CAAC"}
1
+ {"version":3,"file":"files.d.ts","sourceRoot":"","sources":["../src/files.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAE1D,eAAO,MAAM,aAAa,6HAMxB,CAAC;AAIH,eAAO,MAAM,eAAe,sIAW1B,CAAC"}
package/dist/files.js CHANGED
@@ -3,13 +3,16 @@ export const readIfPresent = Effect.fn("Build.readIfPresent")(function* (file) {
3
3
  const fs = yield* FileSystem.FileSystem;
4
4
  return yield* fs.readFileString(file).pipe(Effect.map(Option.some), Effect.catchReason("PlatformError", "NotFound", () => Effect.succeed(Option.none())));
5
5
  });
6
- // A reader never sees half a file: the text goes to a fresh file beside the target, which then replaces it in one rename.
6
+ // A reader never sees half a file: the text goes to a fresh file beside the target, which then replaces it in one rename. The
7
+ // draft lives in a temporary folder of its own, removed when the write ends however it ends.
7
8
  export const writeAtomically = Effect.fn("Build.writeAtomically")(function* (file, text) {
8
9
  const fs = yield* FileSystem.FileSystem;
9
10
  const path = yield* Path.Path;
10
11
  yield* fs.makeDirectory(path.dirname(file), { recursive: true });
11
- const draft = yield* fs.makeTempFile({ directory: path.dirname(file), prefix: `.${path.basename(file)}.` });
12
- yield* fs.writeFileString(draft, text);
13
- yield* fs.rename(draft, file);
12
+ yield* Effect.scoped(Effect.gen(function* () {
13
+ const draft = yield* fs.makeTempFileScoped({ directory: path.dirname(file), prefix: `.${path.basename(file)}.` });
14
+ yield* fs.writeFileString(draft, text);
15
+ yield* fs.rename(draft, file);
16
+ }));
14
17
  });
15
18
  //# sourceMappingURL=files.js.map
package/dist/files.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"files.js","sourceRoot":"","sources":["../src/files.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAE1D,MAAM,CAAC,MAAM,aAAa,GAAG,MAAM,CAAC,EAAE,CAAC,qBAAqB,CAAC,CAAC,QAAQ,CAAC,EAAE,IAAY;IACpF,MAAM,EAAE,GAAG,KAAK,CAAC,CAAC,UAAU,CAAC,UAAU,CAAC;IACxC,OAAO,KAAK,CAAC,CAAC,EAAE,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,IAAI,CACzC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,EACvB,MAAM,CAAC,WAAW,CAAC,eAAe,EAAE,UAAU,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,EAAU,CAAC,CAAC,CAC5F,CAAC;AACH,CAAC,CAAC,CAAC;AAEH,0HAA0H;AAC1H,MAAM,CAAC,MAAM,eAAe,GAAG,MAAM,CAAC,EAAE,CAAC,uBAAuB,CAAC,CAAC,QAAQ,CAAC,EAAE,IAAY,EAAE,IAAY;IACtG,MAAM,EAAE,GAAG,KAAK,CAAC,CAAC,UAAU,CAAC,UAAU,CAAC;IACxC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;IAC9B,KAAK,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACjE,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;IAC5G,KAAK,CAAC,CAAC,EAAE,CAAC,eAAe,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IACvC,KAAK,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;AAC/B,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"files.js","sourceRoot":"","sources":["../src/files.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAE1D,MAAM,CAAC,MAAM,aAAa,GAAG,MAAM,CAAC,EAAE,CAAC,qBAAqB,CAAC,CAAC,QAAQ,CAAC,EAAE,IAAY;IACpF,MAAM,EAAE,GAAG,KAAK,CAAC,CAAC,UAAU,CAAC,UAAU,CAAC;IACxC,OAAO,KAAK,CAAC,CAAC,EAAE,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,IAAI,CACzC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,EACvB,MAAM,CAAC,WAAW,CAAC,eAAe,EAAE,UAAU,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,EAAU,CAAC,CAAC,CAC5F,CAAC;AACH,CAAC,CAAC,CAAC;AAEH,8HAA8H;AAC9H,6FAA6F;AAC7F,MAAM,CAAC,MAAM,eAAe,GAAG,MAAM,CAAC,EAAE,CAAC,uBAAuB,CAAC,CAAC,QAAQ,CAAC,EAAE,IAAY,EAAE,IAAY;IACtG,MAAM,EAAE,GAAG,KAAK,CAAC,CAAC,UAAU,CAAC,UAAU,CAAC;IACxC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;IAC9B,KAAK,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACjE,KAAK,CAAC,CAAC,MAAM,CAAC,MAAM,CACnB,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QACnB,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,EAAE,CAAC,kBAAkB,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;QAClH,KAAK,CAAC,CAAC,EAAE,CAAC,eAAe,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;QACvC,KAAK,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IAC/B,CAAC,CAAC,CACF,CAAC;AACH,CAAC,CAAC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shivaedev/build",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "An application's build setup: its Vite and Vitest configuration, and the generated wire and browser contract of each defined module",
5
5
  "homepage": "https://github.com/ShivaeDev/platform/tree/main/packages/build#readme",
6
6
  "bugs": {
@@ -45,7 +45,7 @@
45
45
  ],
46
46
  "dependencies": {
47
47
  "@shivaedev/heavy-lock": "0.11.2",
48
- "@shivaedev/quality": "0.77.0",
48
+ "@shivaedev/quality": "0.78.0",
49
49
  "typescript": "npm:@typescript/typescript6@6.0.2"
50
50
  },
51
51
  "devDependencies": {
@@ -54,7 +54,7 @@
54
54
  "@shivaedev/changes": "0.12.0",
55
55
  "@shivaedev/contract": "0.44.0",
56
56
  "@shivaedev/errors": "0.12.0",
57
- "@shivaedev/test-story": "0.47.0",
57
+ "@shivaedev/test-story": "0.47.1",
58
58
  "@types/node": "24.19.2",
59
59
  "@typescript/native": "npm:typescript@7.0.2",
60
60
  "effect": "4.1.2",
package/src/files.ts CHANGED
@@ -8,12 +8,17 @@ export const readIfPresent = Effect.fn("Build.readIfPresent")(function* (file: s
8
8
  );
9
9
  });
10
10
 
11
- // A reader never sees half a file: the text goes to a fresh file beside the target, which then replaces it in one rename.
11
+ // A reader never sees half a file: the text goes to a fresh file beside the target, which then replaces it in one rename. The
12
+ // draft lives in a temporary folder of its own, removed when the write ends however it ends.
12
13
  export const writeAtomically = Effect.fn("Build.writeAtomically")(function* (file: string, text: string) {
13
14
  const fs = yield* FileSystem.FileSystem;
14
15
  const path = yield* Path.Path;
15
16
  yield* fs.makeDirectory(path.dirname(file), { recursive: true });
16
- const draft = yield* fs.makeTempFile({ directory: path.dirname(file), prefix: `.${path.basename(file)}.` });
17
- yield* fs.writeFileString(draft, text);
18
- yield* fs.rename(draft, file);
17
+ yield* Effect.scoped(
18
+ Effect.gen(function* () {
19
+ const draft = yield* fs.makeTempFileScoped({ directory: path.dirname(file), prefix: `.${path.basename(file)}.` });
20
+ yield* fs.writeFileString(draft, text);
21
+ yield* fs.rename(draft, file);
22
+ }),
23
+ );
19
24
  });