@danieljvdm/dev-kit 0.5.0 → 0.7.0

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 (56) hide show
  1. package/README.md +161 -68
  2. package/dev-kit.example.jsonc +8 -3
  3. package/package.json +19 -15
  4. package/schema/dev-kit.schema.json +52 -0
  5. package/skill-sources.jsonc +8 -12
  6. package/skill-sources.lock.json +3 -9
  7. package/skills/dev-kit/SKILL.md +74 -24
  8. package/skills/effect-atom-data-fetching/SKILL.md +40 -0
  9. package/skills/effect-atom-data-fetching/agents/openai.yaml +4 -0
  10. package/skills/effect-atom-data-fetching/references/cache-lifecycle.md +72 -0
  11. package/skills/effect-atom-data-fetching/references/http-and-invalidation.md +93 -0
  12. package/skills/effect-atom-data-fetching/references/tanstack-start.md +69 -0
  13. package/skills/effect-atom-data-fetching/references/testing.md +63 -0
  14. package/skills/effect-ts/agents/openai.yaml +0 -1
  15. package/skills/effect-ts/references/audit-services.md +11 -11
  16. package/skills/effect-ts/references/guide-effect.md +56 -69
  17. package/skills/effect-ts/references/guide-error-handling.md +64 -73
  18. package/skills/effect-ts/references/guide-layers.md +187 -215
  19. package/skills/effect-ts/references/guide-observability.md +91 -116
  20. package/skills/effect-ts/references/guide-retries.md +32 -44
  21. package/skills/effect-ts/references/guide-schedule.md +26 -40
  22. package/skills/effect-ts/references/guide-schema.md +50 -57
  23. package/skills/effect-ts/references/guide-sql.md +47 -50
  24. package/skills/effect-ts/references/guide-testing.md +96 -98
  25. package/skills/effect-ts/references/guide-type-safety-and-boundaries.md +7 -7
  26. package/skills/effect-ts/references/version-and-source.md +0 -1
  27. package/src/bin/dev-kit.ts +61 -28
  28. package/src/catalog-manager.ts +86 -34
  29. package/src/catalog.ts +72 -34
  30. package/src/cli-ui.ts +20 -16
  31. package/src/effect-source.ts +49 -19
  32. package/src/effect-tsgo.ts +66 -35
  33. package/src/gitignore.ts +19 -6
  34. package/src/index.ts +12 -0
  35. package/src/manifest.ts +51 -3
  36. package/src/node-symbolic-link.ts +3 -0
  37. package/src/oxlint-plugin-effect.js +3 -0
  38. package/src/oxlint-plugin-style.d.ts +8 -0
  39. package/src/oxlint-plugin-style.js +8 -0
  40. package/src/oxlint.js +14 -0
  41. package/src/oxlint.ts +14 -0
  42. package/src/package-skill-source.ts +190 -75
  43. package/src/path-digest.ts +37 -10
  44. package/src/project-package.ts +59 -0
  45. package/src/project-process-lock.ts +19 -12
  46. package/src/project-state.ts +29 -2
  47. package/src/skill-manager.ts +134 -55
  48. package/src/skill-selector.ts +8 -2
  49. package/src/source-manifest.ts +2 -6
  50. package/src/sync.ts +491 -121
  51. package/src/vendor.ts +112 -42
  52. package/src/vite-plus-hooks.ts +174 -0
  53. package/src/vite-plus-quality.ts +49 -0
  54. package/templates/AGENTS.md +9 -0
  55. package/templates/vite-plus/github-actions-check.yml +44 -0
  56. package/templates/vite-plus/vite.config.ts +22 -0
@@ -49,9 +49,9 @@ attempt limits, and backoff in the schedule.
49
49
  Use the operator that matches the control flow:
50
50
 
51
51
  ```ts
52
- const retried = Effect.retry(loadRemote, retryPolicy)
53
- const repeated = Effect.repeat(refreshCache, refreshPolicy)
54
- const scheduled = Effect.schedule(runJob, nightly)
52
+ const retried = Effect.retry(loadRemote, retryPolicy);
53
+ const repeated = Effect.repeat(refreshCache, refreshPolicy);
54
+ const scheduled = Effect.schedule(runJob, nightly);
55
55
  ```
56
56
 
57
57
  - `retry` steps the schedule when the effect fails; the schedule input is the
@@ -69,7 +69,7 @@ before the schedule is stepped, so `recurs(3)` permits one initial attempt and
69
69
  up to three retries.
70
70
 
71
71
  ```ts
72
- const retryThreeTimes = Schedule.recurs(3)
72
+ const retryThreeTimes = Schedule.recurs(3);
73
73
  ```
74
74
 
75
75
  ### `Schedule.forever`
@@ -78,7 +78,7 @@ const retryThreeTimes = Schedule.recurs(3)
78
78
  combinators unless a tight loop is intentional.
79
79
 
80
80
  ```ts
81
- const unbounded = Schedule.forever
81
+ const unbounded = Schedule.forever;
82
82
  ```
83
83
 
84
84
  ### `Schedule.spaced`
@@ -86,7 +86,7 @@ const unbounded = Schedule.forever
86
86
  Use `spaced` when each delay starts after the preceding action completes.
87
87
 
88
88
  ```ts
89
- const pollEverySecond = Schedule.spaced("1 second")
89
+ const pollEverySecond = Schedule.spaced("1 second");
90
90
  ```
91
91
 
92
92
  ### `Schedule.fixed`
@@ -95,7 +95,7 @@ Use `fixed` for a regular cadence that accounts for the time spent running the
95
95
  action. This differs from naïve spacing when the action itself is slow.
96
96
 
97
97
  ```ts
98
- const everyMinute = Schedule.fixed("1 minute")
98
+ const everyMinute = Schedule.fixed("1 minute");
99
99
  ```
100
100
 
101
101
  ### `Schedule.windowed`
@@ -103,7 +103,7 @@ const everyMinute = Schedule.fixed("1 minute")
103
103
  Use `windowed` to align work to the nearest interval boundary.
104
104
 
105
105
  ```ts
106
- const flushOnTenSecondWindows = Schedule.windowed("10 seconds")
106
+ const flushOnTenSecondWindows = Schedule.windowed("10 seconds");
107
107
  ```
108
108
 
109
109
  ### `Schedule.duration`
@@ -111,7 +111,7 @@ const flushOnTenSecondWindows = Schedule.windowed("10 seconds")
111
111
  `duration` recurs once after the given delay, then completes.
112
112
 
113
113
  ```ts
114
- const onceAfterOneSecond = Schedule.duration("1 second")
114
+ const onceAfterOneSecond = Schedule.duration("1 second");
115
115
  ```
116
116
 
117
117
  ### `Schedule.during`
@@ -119,7 +119,7 @@ const onceAfterOneSecond = Schedule.duration("1 second")
119
119
  `during` recurs only within an elapsed-time window.
120
120
 
121
121
  ```ts
122
- const forThirtySeconds = Schedule.during("30 seconds")
122
+ const forThirtySeconds = Schedule.during("30 seconds");
123
123
  ```
124
124
 
125
125
  ### `Schedule.cron`
@@ -129,7 +129,7 @@ with `CronParseError`, so keep that failure visible where the expression is not
129
129
  a trusted constant.
130
130
 
131
131
  ```ts
132
- const nightly = Schedule.cron("0 0 * * *")
132
+ const nightly = Schedule.cron("0 0 * * *");
133
133
  ```
134
134
 
135
135
  ## Backoff
@@ -139,7 +139,7 @@ const nightly = Schedule.cron("0 0 * * *")
139
139
  Use exponential backoff for transient external failures.
140
140
 
141
141
  ```ts
142
- const backoff = Schedule.exponential("100 millis", 2)
142
+ const backoff = Schedule.exponential("100 millis", 2);
143
143
  ```
144
144
 
145
145
  Bound the policy explicitly:
@@ -148,7 +148,7 @@ Bound the policy explicitly:
148
148
  const boundedBackoff = Schedule.exponential("100 millis").pipe(
149
149
  Schedule.upTo({ duration: "30 seconds", times: 6 }),
150
150
  Schedule.jittered,
151
- )
151
+ );
152
152
  ```
153
153
 
154
154
  ### `Schedule.fibonacci`
@@ -156,9 +156,7 @@ const boundedBackoff = Schedule.exponential("100 millis").pipe(
156
156
  Use Fibonacci backoff when growth should be gentler than exponential.
157
157
 
158
158
  ```ts
159
- const fibonacciBackoff = Schedule.fibonacci("100 millis").pipe(
160
- Schedule.upTo({ times: 6 }),
161
- )
159
+ const fibonacciBackoff = Schedule.fibonacci("100 millis").pipe(Schedule.upTo({ times: 6 }));
162
160
  ```
163
161
 
164
162
  ### `Schedule.jittered`
@@ -167,9 +165,7 @@ Use jitter for distributed clients, workers, or polling loops that might
167
165
  otherwise synchronize their retries.
168
166
 
169
167
  ```ts
170
- const jittered = Schedule.exponential("200 millis").pipe(
171
- Schedule.jittered,
172
- )
168
+ const jittered = Schedule.exponential("200 millis").pipe(Schedule.jittered);
173
169
  ```
174
170
 
175
171
  ## Bounding Policies
@@ -184,7 +180,7 @@ const bounded = Schedule.spaced("1 second").pipe(
184
180
  duration: "20 seconds",
185
181
  times: 5,
186
182
  }),
187
- )
183
+ );
188
184
  ```
189
185
 
190
186
  Prefer `upTo` over rebuilding count and elapsed-time checks with mutable state.
@@ -198,10 +194,8 @@ Use `andThen` when one policy should complete before another begins.
198
194
  ```ts
199
195
  const quickThenSlow = Schedule.exponential("100 millis").pipe(
200
196
  Schedule.upTo({ times: 3 }),
201
- Schedule.andThen(
202
- Schedule.spaced("5 seconds").pipe(Schedule.upTo({ times: 5 })),
203
- ),
204
- )
197
+ Schedule.andThen(Schedule.spaced("5 seconds").pipe(Schedule.upTo({ times: 5 }))),
198
+ );
205
199
  ```
206
200
 
207
201
  This is the v4 replacement for older examples that used `Schedule.either` to
@@ -221,10 +215,7 @@ largest delay. Use it to enforce several stop conditions while retaining the
221
215
  slowest applicable cadence.
222
216
 
223
217
  ```ts
224
- const countedBackoff = Schedule.max([
225
- Schedule.exponential("100 millis"),
226
- Schedule.recurs(5),
227
- ])
218
+ const countedBackoff = Schedule.max([Schedule.exponential("100 millis"), Schedule.recurs(5)]);
228
219
  ```
229
220
 
230
221
  ### `Schedule.min`
@@ -234,10 +225,7 @@ smallest available delay. Use it only when that "any policy may continue"
234
225
  behavior is intended.
235
226
 
236
227
  ```ts
237
- const fastestAvailable = Schedule.min([
238
- Schedule.spaced("1 second"),
239
- Schedule.spaced("5 seconds"),
240
- ])
228
+ const fastestAvailable = Schedule.min([Schedule.spaced("1 second"), Schedule.spaced("5 seconds")]);
241
229
  ```
242
230
 
243
231
  Do not treat `max` and `min` as ordinary numeric delay combinators without
@@ -252,9 +240,9 @@ Use `modifyDelay` to replace the computed delay from schedule metadata.
252
240
  ```ts
253
241
  const cappedDelay = Schedule.exponential("100 millis").pipe(
254
242
  Schedule.modifyDelay(({ duration }) =>
255
- Effect.succeed(Duration.min(duration, Duration.seconds(5)))
243
+ Effect.succeed(Duration.min(duration, Duration.seconds(5))),
256
244
  ),
257
- )
245
+ );
258
246
  ```
259
247
 
260
248
  ### `Schedule.addDelay`
@@ -266,11 +254,9 @@ For retries, inspect the typed error through `metadata.input`.
266
254
  const serverAware = Schedule.spaced("1 second").pipe(
267
255
  Schedule.setInputType<RateLimitedError>(),
268
256
  Schedule.addDelay(({ input: error }) =>
269
- error._tag === "RateLimited"
270
- ? Effect.succeed(error.retryAfter)
271
- : Effect.succeed(Duration.zero)
257
+ error._tag === "RateLimited" ? Effect.succeed(error.retryAfter) : Effect.succeed(Duration.zero),
272
258
  ),
273
- )
259
+ );
274
260
  ```
275
261
 
276
262
  ### `Schedule.map`
@@ -299,9 +285,9 @@ const observed = Schedule.exponential("100 millis").pipe(
299
285
  delay: String(duration),
300
286
  errorTag: input._tag,
301
287
  }),
302
- )
288
+ ),
303
289
  ),
304
- )
290
+ );
305
291
  ```
306
292
 
307
293
  ## Advanced Construction And Inspection
@@ -57,16 +57,14 @@ Make Schema the source of truth for application data. Export the schema value
57
57
  and derive its decoded TypeScript type from `.Type` under the same name.
58
58
 
59
59
  ```ts
60
- export const ArtifactId = Schema.NonEmptyString.pipe(
61
- Schema.brand("@acme/ArtifactId")
62
- )
63
- export type ArtifactId = typeof ArtifactId.Type
60
+ export const ArtifactId = Schema.NonEmptyString.pipe(Schema.brand("@acme/ArtifactId"));
61
+ export type ArtifactId = typeof ArtifactId.Type;
64
62
 
65
63
  export const GenerateInput = Schema.Struct({
66
64
  artifactId: ArtifactId,
67
- prompt: Schema.String
68
- })
69
- export type GenerateInput = typeof GenerateInput.Type
65
+ prompt: Schema.String,
66
+ });
67
+ export type GenerateInput = typeof GenerateInput.Type;
70
68
  ```
71
69
 
72
70
  Use schema classes for named reusable models when their validated construction,
@@ -127,14 +125,14 @@ Bad pattern:
127
125
  const Todo = Schema.Struct({
128
126
  id: Schema.Number,
129
127
  title: Schema.String,
130
- completed: Schema.Boolean
131
- })
128
+ completed: Schema.Boolean,
129
+ });
132
130
 
133
131
  const TodoSql = Schema.Struct({
134
132
  id: Schema.Number,
135
133
  title: Schema.String,
136
- completed: Schema.BooleanFromBit
137
- })
134
+ completed: Schema.BooleanFromBit,
135
+ });
138
136
  ```
139
137
 
140
138
  This is usually a sign that transformations are not being used properly.
@@ -165,23 +163,23 @@ When a schema represents a named domain model, reusable payload, or long-lived A
165
163
  Prefer:
166
164
 
167
165
  ```ts
168
- import { Schema } from "effect"
166
+ import { Schema } from "effect";
169
167
 
170
168
  export class User extends Schema.Class<User>("User")({
171
169
  id: Schema.String,
172
- name: Schema.String
170
+ name: Schema.String,
173
171
  }) {}
174
172
  ```
175
173
 
176
174
  Over:
177
175
 
178
176
  ```ts
179
- import { Schema } from "effect"
177
+ import { Schema } from "effect";
180
178
 
181
179
  export const User = Schema.Struct({
182
180
  id: Schema.String,
183
- name: Schema.String
184
- })
181
+ name: Schema.String,
182
+ });
185
183
  ```
186
184
 
187
185
  Why `Class` variants are usually better:
@@ -248,8 +246,8 @@ Example:
248
246
  const Todo = Schema.Struct({
249
247
  id: Schema.Number,
250
248
  title: Schema.String,
251
- completed: Schema.Boolean
252
- })
249
+ completed: Schema.Boolean,
250
+ });
253
251
  ```
254
252
 
255
253
  ## `Class`, `TaggedClass`, and `TaggedErrorClass`
@@ -261,7 +259,7 @@ Use for named reusable schema-backed models.
261
259
  ```ts
262
260
  class Product extends Schema.Class<Product>("Product")({
263
261
  id: Schema.String,
264
- price: Schema.Number
262
+ price: Schema.Number,
265
263
  }) {}
266
264
  ```
267
265
 
@@ -275,8 +273,8 @@ Prefer:
275
273
  const todo = Todo.make({
276
274
  id: 1,
277
275
  title: "write docs",
278
- completed: false
279
- })
276
+ completed: false,
277
+ });
280
278
  ```
281
279
 
282
280
  Over:
@@ -285,8 +283,8 @@ Over:
285
283
  const todo = new Todo({
286
284
  id: 1,
287
285
  title: "write docs",
288
- completed: false
289
- })
286
+ completed: false,
287
+ });
290
288
  ```
291
289
 
292
290
  Why:
@@ -308,12 +306,12 @@ Use for members of tagged unions.
308
306
 
309
307
  ```ts
310
308
  class Circle extends Schema.TaggedClass<Circle>()("Circle", {
311
- radius: Schema.Number
309
+ radius: Schema.Number,
312
310
  }) {}
313
311
 
314
312
  class Rectangle extends Schema.TaggedClass<Rectangle>()("Rectangle", {
315
313
  width: Schema.Number,
316
- height: Schema.Number
314
+ height: Schema.Number,
317
315
  }) {}
318
316
  ```
319
317
 
@@ -323,7 +321,7 @@ Use for schema-backed typed errors.
323
321
 
324
322
  ```ts
325
323
  class NotFound extends Schema.TaggedErrorClass<NotFound>()("NotFound", {
326
- id: Schema.String
324
+ id: Schema.String,
327
325
  }) {}
328
326
  ```
329
327
 
@@ -342,8 +340,8 @@ Prefer:
342
340
 
343
341
  ```ts
344
342
  const Query = Schema.Struct({
345
- search: Schema.optionalKey(Schema.String)
346
- })
343
+ search: Schema.optionalKey(Schema.String),
344
+ });
347
345
  ```
348
346
 
349
347
  Use `optional` when the value itself should be `A | undefined`, not just an omitted field.
@@ -353,24 +351,21 @@ Use `optional` when the value itself should be `A | undefined`, not just an omit
353
351
  Use `Schema.Union([...])` for ordinary unions.
354
352
 
355
353
  ```ts
356
- const Id = Schema.Union([
357
- Schema.String,
358
- Schema.Number
359
- ])
354
+ const Id = Schema.Union([Schema.String, Schema.Number]);
360
355
  ```
361
356
 
362
357
  Prefer tagged unions for domain variants.
363
358
 
364
359
  ```ts
365
360
  class Created extends Schema.TaggedClass<Created>()("Created", {
366
- id: Schema.String
361
+ id: Schema.String,
367
362
  }) {}
368
363
 
369
364
  class Deleted extends Schema.TaggedClass<Deleted>()("Deleted", {
370
- id: Schema.String
365
+ id: Schema.String,
371
366
  }) {}
372
367
 
373
- const TodoEvent = Schema.Union([Created, Deleted])
368
+ const TodoEvent = Schema.Union([Created, Deleted]);
374
369
  ```
375
370
 
376
371
  Why:
@@ -384,14 +379,14 @@ Use `Schema.suspend` for recursive schemas.
384
379
 
385
380
  ```ts
386
381
  type Tree = {
387
- readonly name: string
388
- readonly children: ReadonlyArray<Tree>
389
- }
382
+ readonly name: string;
383
+ readonly children: ReadonlyArray<Tree>;
384
+ };
390
385
 
391
386
  const Tree: Schema.Schema<Tree> = Schema.Struct({
392
387
  name: Schema.String,
393
- children: Schema.Array(Schema.suspend((): Schema.Schema<Tree> => Tree))
394
- })
388
+ children: Schema.Array(Schema.suspend((): Schema.Schema<Tree> => Tree)),
389
+ });
395
390
  ```
396
391
 
397
392
  Use it whenever a schema refers to itself, directly or indirectly.
@@ -416,9 +411,9 @@ Use `decodeTo` when you want one schema to decode into another schema's type.
416
411
  const TrimmedString = Schema.String.pipe(
417
412
  Schema.decodeTo(Schema.String, {
418
413
  decode: (value) => value.trim(),
419
- encode: (value) => value
420
- })
421
- )
414
+ encode: (value) => value,
415
+ }),
416
+ );
422
417
  ```
423
418
 
424
419
  The canonical docs explicitly note that `decodeTo` is curried and should be used with `pipe`.
@@ -432,19 +427,19 @@ Use `encodeTo` when the reverse direction reads more clearly.
432
427
  Use `transformOrFail` when the transformation itself is effectful or may fail.
433
428
 
434
429
  ```ts
435
- import * as Effect from "effect/Effect"
436
- import * as Schema from "effect/Schema"
437
- import * as SchemaTransformation from "effect/SchemaTransformation"
430
+ import * as Effect from "effect/Effect";
431
+ import * as Schema from "effect/Schema";
432
+ import * as SchemaTransformation from "effect/SchemaTransformation";
438
433
 
439
434
  const VerifiedString = Schema.String.pipe(
440
435
  Schema.decodeTo(
441
436
  Schema.String,
442
437
  SchemaTransformation.transformOrFail({
443
438
  decode: (value) => Effect.succeed(value.trim()),
444
- encode: (value) => Effect.succeed(value)
445
- })
446
- )
447
- )
439
+ encode: (value) => Effect.succeed(value),
440
+ }),
441
+ ),
442
+ );
448
443
  ```
449
444
 
450
445
  Use this when:
@@ -460,13 +455,13 @@ Very often, the right answer is not a second object schema but a transformed fie
460
455
  Example shape:
461
456
 
462
457
  ```ts
463
- const Completed = Schema.BooleanFromBit
458
+ const Completed = Schema.BooleanFromBit;
464
459
 
465
460
  const Todo = Schema.Struct({
466
461
  id: Schema.Number,
467
462
  title: Schema.String,
468
- completed: Completed
469
- })
463
+ completed: Completed,
464
+ });
470
465
  ```
471
466
 
472
467
  In this pattern:
@@ -519,9 +514,7 @@ Use opaque or branded schemas when a value should stay distinct from its structu
519
514
  Use `brand` for refined nominal distinctions.
520
515
 
521
516
  ```ts
522
- const UserId = Schema.String.pipe(
523
- Schema.brand("UserId")
524
- )
517
+ const UserId = Schema.String.pipe(Schema.brand("UserId"));
525
518
  ```
526
519
 
527
520
  This is useful for:
@@ -598,7 +591,7 @@ Preferred rule:
598
591
  Good pattern:
599
592
 
600
593
  ```ts
601
- const decodeUser = Schema.decodeUnknownEffect(User)
594
+ const decodeUser = Schema.decodeUnknownEffect(User);
602
595
  ```
603
596
 
604
597
  ## Schema Metadata And Derived Tooling
@@ -79,7 +79,7 @@ Prefer typed SQL queries instead of leaving row shapes implicit.
79
79
  The repo uses typed query literals like:
80
80
 
81
81
  ```ts
82
- const rows = yield* sql<{ id: number; name: string }>`SELECT * FROM test`
82
+ const rows = yield * sql<{ id: number; name: string }>`SELECT * FROM test`;
83
83
  ```
84
84
 
85
85
  This is the first level of typed SQL usage and is already better than untyped row access.
@@ -111,8 +111,8 @@ Why:
111
111
  Avoid this pattern:
112
112
 
113
113
  ```ts
114
- const row = yield* sql`SELECT id, title FROM todos WHERE id = ${id}`
115
- const todo = row[0] as TodoRow
114
+ const row = yield * sql`SELECT id, title FROM todos WHERE id = ${id}`;
115
+ const todo = row[0] as TodoRow;
116
116
  ```
117
117
 
118
118
  Prefer:
@@ -126,10 +126,10 @@ Example boundary decode:
126
126
  const TodoRow = Schema.Struct({
127
127
  id: Schema.Number,
128
128
  title: Schema.String,
129
- completed: Schema.Boolean
130
- })
129
+ completed: Schema.Boolean,
130
+ });
131
131
 
132
- const decodeTodoRows = Schema.decodeUnknownEffect(Schema.Array(TodoRow))
132
+ const decodeTodoRows = Schema.decodeUnknownEffect(Schema.Array(TodoRow));
133
133
  ```
134
134
 
135
135
  Then keep the query and decoding together in one SQL-aware operation.
@@ -150,11 +150,11 @@ const resolver = SqlResolver.findById({
150
150
  Id: Schema.Number,
151
151
  Result: Schema.Struct({
152
152
  id: Schema.Number,
153
- name: Schema.String
153
+ name: Schema.String,
154
154
  }),
155
155
  ResultId: (row) => row.id,
156
- execute: (ids) => sql`SELECT * FROM test WHERE id IN ${sql.in(ids)}`
157
- })
156
+ execute: (ids) => sql`SELECT * FROM test WHERE id IN ${sql.in(ids)}`,
157
+ });
158
158
  ```
159
159
 
160
160
  This is a preferred pattern when:
@@ -201,17 +201,17 @@ Prefer a layer that provides `SqlClient`, and let domain services depend on that
201
201
  Good pattern:
202
202
 
203
203
  ```ts
204
- import * as Context from "effect/Context"
205
- import * as Effect from "effect/Effect"
206
- import * as SqlClient from "effect/unstable/sql/SqlClient"
204
+ import * as Context from "effect/Context";
205
+ import * as Effect from "effect/Effect";
206
+ import * as SqlClient from "effect/unstable/sql/SqlClient";
207
207
 
208
208
  class TodoRepo extends Context.Service<TodoRepo>()("TodoRepo", {
209
209
  make: Effect.succeed({
210
- getById: Effect.fn("TodoRepo.getById")(function*(id: number) {
211
- const sql = yield* SqlClient.SqlClient
212
- return yield* sql`SELECT id, title, completed FROM todos WHERE id = ${id}`
213
- })
214
- })
210
+ getById: Effect.fn("TodoRepo.getById")(function* (id: number) {
211
+ const sql = yield* SqlClient.SqlClient;
212
+ return yield* sql`SELECT id, title, completed FROM todos WHERE id = ${id}`;
213
+ }),
214
+ }),
215
215
  }) {}
216
216
  ```
217
217
 
@@ -233,16 +233,16 @@ Repo reference:
233
233
  Prefer:
234
234
 
235
235
  ```ts
236
- const createAndAudit = Effect.fn("TodoRepo.createAndAudit")(function*(title: string) {
237
- const sql = yield* SqlClient.SqlClient
236
+ const createAndAudit = Effect.fn("TodoRepo.createAndAudit")(function* (title: string) {
237
+ const sql = yield* SqlClient.SqlClient;
238
238
 
239
239
  return yield* sql.withTransaction(
240
- Effect.gen(function*() {
241
- yield* sql`INSERT INTO todos ${sql.insert({ title, completed: false })}`
242
- yield* sql`INSERT INTO audit_log ${sql.insert({ event: "todo_created" })}`
243
- })
244
- )
245
- })
240
+ Effect.gen(function* () {
241
+ yield* sql`INSERT INTO todos ${sql.insert({ title, completed: false })}`;
242
+ yield* sql`INSERT INTO audit_log ${sql.insert({ event: "todo_created" })}`;
243
+ }),
244
+ );
245
+ });
246
246
  ```
247
247
 
248
248
  Avoid:
@@ -265,10 +265,10 @@ Avoid exposing one exported accessor function per SQL service method if it only
265
265
  Bad:
266
266
 
267
267
  ```ts
268
- export const createTodo = Effect.fn(function*(title: string) {
269
- const todos = yield* TodoRepo
270
- return yield* todos.create(title)
271
- })
268
+ export const createTodo = Effect.fn(function* (title: string) {
269
+ const todos = yield* TodoRepo;
270
+ return yield* todos.create(title);
271
+ });
272
272
  ```
273
273
 
274
274
  Prefer:
@@ -352,25 +352,25 @@ The runtime-specific SQL migrator packages expose `fromRecord(...)` to define mi
352
352
  Example shape:
353
353
 
354
354
  ```ts
355
- import * as SqliteMigrator from "@effect/sql-sqlite-bun/SqliteMigrator"
356
- import * as Effect from "effect/Effect"
355
+ import * as SqliteMigrator from "@effect/sql-sqlite-bun/SqliteMigrator";
356
+ import * as Effect from "effect/Effect";
357
357
 
358
358
  const migrations = SqliteMigrator.fromRecord({
359
- "1_create_todos": Effect.gen(function*() {
359
+ "1_create_todos": Effect.gen(function* () {
360
360
  yield* sql`
361
361
  CREATE TABLE todos (
362
362
  id INTEGER PRIMARY KEY NOT NULL,
363
363
  title TEXT NOT NULL,
364
364
  completed INTEGER NOT NULL DEFAULT 0
365
365
  )
366
- `.withoutTransform
366
+ `.withoutTransform;
367
367
  }),
368
- "2_add_todo_index": Effect.gen(function*() {
368
+ "2_add_todo_index": Effect.gen(function* () {
369
369
  yield* sql`
370
370
  CREATE INDEX todos_completed_idx ON todos (completed)
371
- `.withoutTransform
372
- })
373
- })
371
+ `.withoutTransform;
372
+ }),
373
+ });
374
374
  ```
375
375
 
376
376
  This matches the model used by the canonical migrator implementation:
@@ -386,11 +386,11 @@ Use the runtime-specific `run(...)` helper when you want a startup effect that r
386
386
  Example shape:
387
387
 
388
388
  ```ts
389
- import * as SqliteMigrator from "@effect/sql-sqlite-bun/SqliteMigrator"
389
+ import * as SqliteMigrator from "@effect/sql-sqlite-bun/SqliteMigrator";
390
390
 
391
391
  const runMigrations = SqliteMigrator.run({
392
- loader: migrations
393
- })
392
+ loader: migrations,
393
+ });
394
394
  ```
395
395
 
396
396
  This is a good fit when:
@@ -408,11 +408,11 @@ Use the runtime-specific `layer(...)` helper when migrations should run as part
408
408
  Example shape:
409
409
 
410
410
  ```ts
411
- import * as SqliteMigrator from "@effect/sql-sqlite-bun/SqliteMigrator"
411
+ import * as SqliteMigrator from "@effect/sql-sqlite-bun/SqliteMigrator";
412
412
 
413
413
  const MigrationLayer = SqliteMigrator.layer({
414
- loader: migrations
415
- })
414
+ loader: migrations,
415
+ });
416
416
  ```
417
417
 
418
418
  From the canonical packages, this is implemented as `Layer.effectDiscard(run(options))`.
@@ -428,16 +428,13 @@ That means:
428
428
  Preferred shape:
429
429
 
430
430
  ```ts
431
- const SqlLayer = SqliteClient.layer({ filename: "todos.sqlite" })
431
+ const SqlLayer = SqliteClient.layer({ filename: "todos.sqlite" });
432
432
 
433
433
  const MigrationLayer = SqliteMigrator.layer({
434
- loader: migrations
435
- })
434
+ loader: migrations,
435
+ });
436
436
 
437
- const MigratedSqlLayer = Layer.merge(
438
- SqlLayer,
439
- MigrationLayer.pipe(Layer.provide(SqlLayer))
440
- )
437
+ const MigratedSqlLayer = Layer.merge(SqlLayer, MigrationLayer.pipe(Layer.provide(SqlLayer)));
441
438
  ```
442
439
 
443
440
  This keeps the structure explicit: