resultar 3.8.0 → 3.9.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.
package/README.md CHANGED
@@ -494,13 +494,12 @@ The callback runs only when the task executes. Use `tryPromise({ try, catch })`
494
494
  specific error type; both forms receive the runtime signal and preserve interruption semantics.
495
495
 
496
496
  Workflows can request typed services with `yield*` and receive them at the boundary. Pass the service
497
- type and its literal identifier so the named environment remains checked:
497
+ type first, then let the second call infer its literal identifier:
498
498
 
499
499
  ```ts
500
500
  const Database = ResultTask.service<
501
- { findUser: (id: string) => Promise<string> },
502
- 'Database'
503
- >('Database')
501
+ { findUser: (id: string) => Promise<string> }
502
+ >()('Database')
504
503
 
505
504
  const taskWithDatabase = ResultTask.gen(function* () {
506
505
  const database = yield* Database
@@ -529,6 +528,16 @@ await ResultTask.runResult(readyWithOne)
529
528
  await ResultTask.runResult(readyWithAll)
530
529
  ```
531
530
 
531
+ The direct form `ResultTask.service<DatabaseContract, 'Database'>('Database')` remains supported.
532
+ The curried form can also be yielded inline: `yield* ResultTask.service<DatabaseContract>()('Database')`.
533
+ Requirements belong to `R` in `ResultTask<T, E, R>`; `Result` has no service lookup API.
534
+
535
+ Every tag creation has its own symbol identity. Inline tags resolve through named environments
536
+ (`provideServices` or the DI module). `provideService(token, value)` supplies both an exact token binding and a named fallback.
537
+ Reuse the same token to select its exact binding when identifiers collide; a separately created
538
+ same-name tag can resolve the named fallback. Exact token bindings take precedence. For class services and explicit dependency maps, see
539
+ [`Service.require` and `requires` in resultar-di](../di/README.md#class-services-and-explicit-requirements).
540
+
532
541
  Infrastructure such as a dependency-injection adapter can resolve service tags lazily with
533
542
  `provideServiceResolver(task, { Logger: () => loggerTask })`. Each required identifier has a
534
543
  typed lazy provider. Provider errors and external requirements remain in the resulting task type;
@@ -42,7 +42,10 @@ work, typed service requirements, or owned resource lifetimes. Preserve existing
42
42
  contracts; converting an already-started Promise or ResultAsync cannot undo its execution.
43
43
  `ResultTask.runResult` can reject on defects, interruption, and composite causes. Use `runExit`
44
44
  when the boundary must inspect every exit without rejection. See [API details](references/api.md).
45
- For DI, Hono and Fastify, read [services and HTTP scopes](references/services.md).
45
+ For DI, Hono and Fastify, read [services and HTTP scopes](references/services.md). Use
46
+ `ResultTask.service<T>()(name)` or DI `Service.require<T>()(name)` for inferred identifiers. Class
47
+ services support optional `requires` with a factory returning ResultTask; generator-only `make`
48
+ remains available. Check installed versions before using these overloads.
46
49
 
47
50
  ## Apply Opinionated Defaults
48
51
 
@@ -1,9 +1,22 @@
1
1
  # Typed services and HTTP scopes
2
2
 
3
3
  Read the installed `resultar-di/README.md`, `resultar-hono/README.md` and `resultar-fastify/README.md` for the exact companion
4
- versions. The primary DI exports are `createModule`, `service`, and `resource`; class tokens and
5
- named factory overloads belong to `resultar-di/advanced`.
4
+ versions. The application DI helpers are `createModule`, `service`, `Service`, and `resource`.
5
+ Named factory overloads and low-level adapter access use the same `resultar-di` entry point.
6
+ The former `/advanced` subpath has been removed; migrate existing imports to `resultar-di`.
6
7
 
8
+ - Use `ResultTask.service<Contract>()('name')` in core or `Service.require<Contract>()('name')`
9
+ in DI to infer the literal identifier. The direct core overload remains supported; do not invent
10
+ `Result.service`. Service requirements are represented by `R` in `ResultTask<T, E, R>`.
11
+ - Declare class services with `Service('name', { requires: { alias: Token }, make: ({ alias }) =>
12
+ ResultTask.sync(...) })`. The readonly dependency object is inferred; `make` must return a
13
+ ResultTask, never a plain object or Promise. Use `ResultTask.gen` for initialization with more
14
+ steps. Without `requires`, pass a task directly as `make` and yield requirements inline or by token.
15
+ Both forms support `Service<Contract>()('name', definition)`.
16
+ - Keep provider registration explicit. `requires` does not acquire or register dependencies.
17
+ Inline tokens resolve by name in DI or `provideServices`; core `provideService` supplies an exact
18
+ token binding plus a named fallback. Reuse the same token for exact identity when identifiers
19
+ collide; separately created tags can resolve the named fallback.
7
20
  - Register a service token with `.singleton(Token)`, `.scoped(Token)`, or `.transient(Token)`.
8
21
  Dependency objects are inferred from tokens. Use `service(name, task)` for asynchronous
9
22
  initialization; an async function passed as an ordinary factory is a defect in the contract.
@@ -11,10 +24,26 @@ named factory overloads belong to `resultar-di/advanced`.
11
24
  live resource from a completed scope returns a resource whose finalizer has already run.
12
25
  - Use `createHonoApp` for Hono routes. Ordinary `await` and `result.match` inside a route are valid;
13
26
  generator-specific restrictions do not apply to a route body.
27
+ Export `type AppHono = Hono<{ Bindings: InferRequestServices<typeof createApplication> }>`
28
+ from `main.ts`, using `InferRequestServices` from `resultar-hono`. Separate route files import
29
+ `AppHono` with `import type` and receive `(app: AppHono)`. Bindings follow the application
30
+ selection without repeating service tokens.
31
+ - `bindings` is optional in `createHonoApp`, `createFastifyApp` and `createFastifyPlugin`.
32
+ Omission selects all registrations; an explicit list restricts the view and `[]` selects none.
33
+ Selected services resolve before the handler, preserving each lifetime and resource ownership.
34
+ Unused default-selected services can still fail acquisition and prevent the handler.
35
+ Fastify `appBindings` continues to default to `[]`; locals satisfy requirements without being
36
+ automatically exposed as registrations. The Hono middleware API still takes explicit keys.
14
37
  - Use `createHonoServices(module).middleware(keys, { locals })` to add services to an existing Hono
15
38
  router. Inline route middleware infers `c.var.services` while preserving `c.env` and native RPC
16
39
  responses. Install one services middleware per request; consume/cancel responses before `close()`.
17
- - Use `createFastifyPlugin({ services, bindings, appBindings?, locals? })` for native Fastify routes.
40
+ - Use `createFastifyApp({ services, bindings? }, configure)` for a new native Fastify application,
41
+ or `createFastifyPlugin({ services, bindings?, appBindings?, locals? })` for an existing server.
42
+ Derive `FastifyRequest.services` once with
43
+ `InferRequestServices<typeof createApplication>` directly in `main.ts` or in a declaration
44
+ file included by TypeScript. `InferAppServices` also accepts the application return type. Both follow the
45
+ selected bindings or custom exposed views; no global types or runtime metadata are installed
46
+ by the adapter. Native routes and autoload do not need wrappers.
18
47
  `app.services` contains the selected startup singletons; `request.services` is available from
19
48
  `preHandler` through response completion. Register authentication providing locals earlier.
20
49
  Infer decorators with `InferAppServices` / `InferRequestServices`; augment Fastify in the application
@@ -37,3 +66,23 @@ named factory overloads belong to `resultar-di/advanced`.
37
66
  For a complete runnable pattern, see the workspace `examples/hono/` and `examples/resultar/`
38
67
  application lifecycle examples. The distributed guide includes the checked core recipe at
39
68
  `examples/workflow.mjs`; use the published declarations to adapt companion integrations.
69
+
70
+ ## Framework DI exports
71
+
72
+ `resultar-fastify` and `resultar-hono` reexport the application DI helpers: `createModule`, `Service`,
73
+ `service`, `resource`, plus `HttpApplication`, `ServiceClass`, `ServiceLifetime`, `ServiceModule`
74
+ and `ServiceScope` types. In framework-specific code, import these from the adapter together
75
+ with its integration helpers. Core APIs such as `ResultTask` still come from `resultar`.
76
+ Keep direct `resultar-di` imports and dependencies in framework-independent shared code and
77
+ for framework adapter helpers such as `withProvider` and `useServiceAccess`. Check the installed adapter exports before using this convenience
78
+ with older versions.
79
+
80
+ ## Runnable HTTP examples
81
+
82
+ The maintained Fastify and Hono examples each contain their own `services.ts`, `routes.ts`
83
+ and `main.ts`. `services.ts` declares `Cache`, `UsersRepository` and `Users` classes,
84
+ function-based `Health`, and the `createServices` module factory. `main.ts` omits
85
+ `bindings` and owns framework typing and startup. The default request view includes all
86
+ registered services, including the cache and repository. Do not introduce
87
+ a shared package, separate `users.ts` or an extra `app.ts` for these small examples.
88
+ Start either example with `pnpm dev` from its directory; `PORT` defaults to 3000.
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "resultar-check": "3.2.0",
3
- "resultar-di": "0.2.0",
4
- "resultar-fastify": "0.2.0",
5
- "resultar-hono": "0.2.0",
3
+ "resultar-di": "0.3.0",
4
+ "resultar-fastify": "0.3.0",
5
+ "resultar-hono": "0.3.0",
6
6
  "resultar-request": "0.1.2",
7
7
  "resultar-request-typebox": "0.1.2",
8
8
  "resultar-request-zod": "0.1.2",
9
- "resultar": "3.8.0"
9
+ "resultar": "3.9.0"
10
10
  }
package/dist/index.d.ts CHANGED
@@ -898,6 +898,8 @@ export declare class ResultTask<out A, out E = never, out R = never> extends Pip
898
898
  static scoped<A, E, R>(task: ResultTask<A, E, R>): ResultTask<A, E | ScopeError<R>, WithoutScope<R>>;
899
899
  /** Creates a service tag that can be requested with `yield*` inside `ResultTask.gen`. */
900
900
  static service<Service, const Identifier extends string>(identifier: Identifier): ServiceTag<Identifier, Service>;
901
+ /** Infers the literal identifier after specifying the service contract. */
902
+ static service<Service>(): <const Identifier extends string>(identifier: Identifier) => ServiceTag<Identifier, Service>;
901
903
  /** Builds a task from a generator and short-circuits on the first failed task. */
902
904
  static gen<Yield, Return, Next>(body: () => Generator<Yield, Return, Next>): ResultTask<Return, GeneratorError<Yield>, GeneratorRequirements<Yield>>;
903
905
  /** Maps the success value without executing the task. */
package/dist/index.js CHANGED
@@ -1222,8 +1222,8 @@ var ResultTask = class ResultTask extends Pipeable {
1222
1222
  return interruptSuccess(await scope.close(interruptSuccess(exit, context.signal)), context.signal);
1223
1223
  });
1224
1224
  }
1225
- /** Creates a service tag that can be requested with `yield*` inside `ResultTask.gen`. */
1226
1225
  static service(identifier) {
1226
+ if (identifier === void 0) return (name) => new ServiceTagValue(name);
1227
1227
  return new ServiceTagValue(identifier);
1228
1228
  }
1229
1229
  /** Builds a task from a generator and short-circuits on the first failed task. */
package/dist/llms.txt CHANGED
@@ -1,4 +1,4 @@
1
- # Resultar 3.8.0
1
+ # Resultar 3.9.0
2
2
 
3
3
  Documentation bundled with this package version. Installed declarations remain authoritative.
4
4
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "resultar",
3
- "version": "3.8.0",
3
+ "version": "3.9.0",
4
4
  "description": "Result pattern for TypeScript",
5
5
  "keywords": [
6
6
  "error-handling",
@@ -49,7 +49,7 @@
49
49
  "fallow": "3.25.0",
50
50
  "tsx": "4.23.13",
51
51
  "typescript": "7.0.2",
52
- "vite-plus": "0.3.1",
52
+ "vite-plus": "0.3.2",
53
53
  "vitest": "4.1.11"
54
54
  },
55
55
  "peerDependencies": {