@afora/core 0.0.8 → 0.0.9

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 (74) hide show
  1. package/README.md +127 -23
  2. package/dist/adapters.d.ts +25 -0
  3. package/dist/adapters.js +56 -0
  4. package/dist/core/application/exceptions.d.ts +17 -0
  5. package/dist/core/application/migrate.d.ts +19 -0
  6. package/dist/core/application/schema.d.ts +30 -0
  7. package/dist/core/application/types/application.interface.d.ts +37 -0
  8. package/dist/core/auth/jwt.d.ts +30 -0
  9. package/dist/core/auth/types/jwt.interface.d.ts +66 -0
  10. package/dist/core/blueprint/exceptions.d.ts +5 -0
  11. package/dist/core/blueprint/optional.d.ts +3 -1
  12. package/dist/core/blueprint/types/blueprint.interface.d.ts +79 -5
  13. package/dist/core/blueprint/variant.d.ts +32 -0
  14. package/dist/core/entity/abstract-entity.d.ts +5 -0
  15. package/dist/core/entity/entity.d.ts +1 -1
  16. package/dist/core/entity/exceptions.d.ts +9 -0
  17. package/dist/core/entity/trust.d.ts +24 -0
  18. package/dist/core/entity/types/entity.interface.d.ts +30 -0
  19. package/dist/core/output/access.d.ts +16 -0
  20. package/dist/core/output/exceptions.d.ts +16 -0
  21. package/dist/core/output/http.d.ts +36 -0
  22. package/dist/core/output/openapi-sink.d.ts +23 -2
  23. package/dist/core/output/stage.d.ts +7 -2
  24. package/dist/core/output/status.d.ts +1 -1
  25. package/dist/core/output/types/http.interface.d.ts +130 -0
  26. package/dist/core/output/types/output.interface.d.ts +25 -5
  27. package/dist/core/parse/issue.d.ts +28 -3
  28. package/dist/core/parse/parse.d.ts +9 -0
  29. package/dist/core/property/abstract-property.d.ts +9 -0
  30. package/dist/core/property/define-property.d.ts +34 -6
  31. package/dist/core/property/types/property-options.interface.d.ts +10 -0
  32. package/dist/core/property/types/property-type.interface.d.ts +4 -0
  33. package/dist/core/record/abstract-record.d.ts +7 -0
  34. package/dist/core/record/types/record.interface.d.ts +12 -1
  35. package/dist/core/repository/exceptions.d.ts +13 -0
  36. package/dist/core/repository/in-memory.d.ts +2 -2
  37. package/dist/core/repository/migrate.d.ts +20 -0
  38. package/dist/core/repository/state.d.ts +2 -0
  39. package/dist/core/repository/types/repository.interface.d.ts +33 -0
  40. package/dist/core/repository/types/schema.interface.d.ts +126 -0
  41. package/dist/core/repository/upcast.d.ts +64 -0
  42. package/dist/core/schema/schema.d.ts +28 -0
  43. package/dist/core/symbols/kind.d.ts +1 -1
  44. package/dist/core/use-case/access.d.ts +12 -0
  45. package/dist/core/use-case/decorators.d.ts +40 -0
  46. package/dist/core/use-case/route.d.ts +18 -0
  47. package/dist/core/use-case/steps/types/check.interface.d.ts +214 -0
  48. package/dist/core/use-case/types/access.interface.d.ts +39 -0
  49. package/dist/core/use-case/types/route.interface.d.ts +66 -0
  50. package/dist/core/use-case/use-case.d.ts +52 -2
  51. package/dist/experimental.d.ts +13 -1
  52. package/dist/experimental.js +63 -25
  53. package/dist/index-3aae5jfq.js +2997 -0
  54. package/dist/index-hg1z2s2v.js +1055 -0
  55. package/dist/index-ny3as79r.js +4567 -0
  56. package/dist/index-xegv6a1p.js +4291 -0
  57. package/dist/index-y280ew0k.js +396 -0
  58. package/dist/index.d.ts +45 -49
  59. package/dist/index.js +110 -186
  60. package/dist/std/properties/password.d.ts +0 -2
  61. package/dist/std/record-plugins.d.ts +2 -2
  62. package/dist/std/resource.d.ts +31 -0
  63. package/dist/std/runtime.d.ts +6 -0
  64. package/dist/std/use-cases/auth.d.ts +5 -1
  65. package/dist/std/use-cases/index.d.ts +1 -1
  66. package/dist/std/use-cases/shared.d.ts +2 -2
  67. package/dist/std/use-cases/types.d.ts +97 -1
  68. package/dist/testing/http-provider-contract.d.ts +32 -0
  69. package/dist/testing/index.d.ts +2 -0
  70. package/dist/testing/index.js +495 -4
  71. package/dist/testing/provider-contract.d.ts +17 -1
  72. package/package.json +16 -3
  73. package/dist/index-qxfkyd6k.js +0 -1721
  74. package/dist/index-t5qwtyj5.js +0 -8194
@@ -1,10 +1,13 @@
1
+ import type { DescribedJwtOptions } from "../../core/auth/types/jwt.interface.js";
1
2
  import type { AnyBlueprint, AnyBlueprintList, AnyRecordClass, BlueprintField, BlueprintValue, IBlueprint, IBlueprintCollection, IBlueprintList, OptionalBlueprint, OptionalBlueprintList, OptionalRecord } from "../../core/blueprint/types/blueprint.interface.js";
2
3
  import type { EntityIdentityKey } from "../../core/entity/types/entity.interface.js";
3
4
  import type { EntityVersion } from "../../core/entity/version.js";
4
5
  import type { OptionalProperty } from "../../core/property/types/optional-property.type.js";
5
6
  import type { AnyPropertyConstructor } from "../../core/property/types/property-collection.type.js";
6
7
  import type { AnyRepository, AnyRepositoryEntity, EntityInstanceOf } from "../../core/repository/types/repository.interface.js";
8
+ import type { AccessDeclaration } from "../../core/use-case/types/access.interface.js";
7
9
  import type { IUseCasePlugin, UseCaseTarget } from "../../core/use-case/types/plugin.interface.js";
10
+ import type { RouteSettings } from "../../core/use-case/types/route.interface.js";
8
11
  import type { AnyExceptionClass, DependencyFunctions, StepsUseCaseConstructor, UseCaseCollection } from "../../core/use-case/use-case.js";
9
12
  import type { Integer, StringProperty } from "../properties/primitives.js";
10
13
  type EntityOf<Repository> = Repository extends {
@@ -44,7 +47,41 @@ export interface StdUseCaseOptions {
44
47
  readonly tags?: readonly string[];
45
48
  readonly deprecated?: boolean;
46
49
  readonly errors?: StdUseCaseErrors;
50
+ /** Where the use case is served over HTTP: the `route` of `useCaseOf`. */
51
+ readonly route?: RouteSettings;
52
+ /** Who may call it: the `access` of `useCaseOf`. */
53
+ readonly access?: AccessDeclaration;
47
54
  }
55
+ /**
56
+ * The tokens `login` and `refresh` issue: the options of `jwtOf`, plus what
57
+ * a token says of the entity. JSON, so it lives in an `afora.json`: the
58
+ * secret is named by its environment variable (`{ env: "JWT_SECRET" }`).
59
+ * Experimental: it may change in any release.
60
+ */
61
+ export interface StdTokenOptions extends DescribedJwtOptions {
62
+ /** Also issues a refresh token, which `refresh` exchanges; `expiresIn` is its life in seconds. */
63
+ readonly refresh?: {
64
+ readonly expiresIn: number;
65
+ };
66
+ /** Scopes every token gets. */
67
+ readonly scopes?: readonly string[];
68
+ /** A key of the entity that holds a list of scopes, added to `scopes`. */
69
+ readonly scopesFrom?: string;
70
+ /** Claims of the token, each from a key of the entity: `{ tenant: "tenantId" }`. */
71
+ readonly claims?: {
72
+ readonly [claim: string]: string;
73
+ };
74
+ }
75
+ /** The response keys the `token` option adds. */
76
+ type TokenResponse<Options> = Options extends {
77
+ readonly token: infer Token;
78
+ } ? {
79
+ readonly token: typeof StringProperty;
80
+ } & (Token extends {
81
+ readonly refresh: object;
82
+ } ? {
83
+ readonly refreshToken: typeof StringProperty;
84
+ } : unknown) : unknown;
48
85
  /** Who owns the entities: the caller, whose id the context gives. */
49
86
  export interface StdOwnerOption<Repository> {
50
87
  /**
@@ -258,12 +295,34 @@ export type RegisterMaker = <Repository extends AnyRepository, const Options ext
258
295
  /** `login`: for an authenticatable entity, with `findByEmail`. */
259
296
  export type LoginMaker = <Repository extends AnyRepository, const Options extends StdUseCaseOptions & {
260
297
  readonly as?: string;
298
+ /** Issues a token for the entity (and a refresh token, with `refresh`), in the response. */
299
+ readonly token?: StdTokenOptions;
261
300
  } & StdNoHookOptions = None>(repository: Repository & UseCaseTarget<Repository, "findByEmail", Authenticatable, "authenticatable">, options?: Options) => StepsUseCaseConstructor<{
262
301
  readonly email: FieldAt<Props<Repository>, "email">;
263
302
  readonly password: typeof StringProperty;
264
- }, EntityResponse<Repository, Options>, {
303
+ }, EntityResponse<Repository, Options> & TokenResponse<Options>, {
265
304
  readonly repository: Repository;
266
305
  }>;
306
+ /** `refresh`: exchanges a refresh token of `login` for new tokens; needs `findById`. */
307
+ export type RefreshMaker = <Repository extends AnyRepository>(repository: Repository & UseCaseTarget<Repository, "findById">, options: StdUseCaseOptions & {
308
+ readonly token: StdTokenOptions & {
309
+ readonly refresh: {
310
+ readonly expiresIn: number;
311
+ };
312
+ };
313
+ } & StdNoHookOptions) => StepsUseCaseConstructor<{
314
+ readonly refreshToken: typeof StringProperty;
315
+ }, {
316
+ readonly token: typeof StringProperty;
317
+ readonly refreshToken: typeof StringProperty;
318
+ }, {
319
+ readonly repository: Repository;
320
+ }>;
321
+ /** `logout`: gives empty tokens, which a route with `setCookie` turns into removed cookies. */
322
+ export type LogoutMaker = <Repository extends AnyRepository>(repository: Repository, options?: StdUseCaseOptions & StdNoHookOptions) => StepsUseCaseConstructor<Record<never, never>, {
323
+ readonly token: typeof StringProperty;
324
+ readonly refreshToken: typeof StringProperty;
325
+ }, Record<never, never>>;
267
326
  /**
268
327
  * The standard use cases, by name: what the `useCases` of `commandOf` gets
269
328
  * to pick from, each called with a repository and its options.
@@ -283,9 +342,46 @@ export interface StdUseCaseContext {
283
342
  readonly untag: TagMaker;
284
343
  readonly register: RegisterMaker;
285
344
  readonly login: LoginMaker;
345
+ readonly refresh: RefreshMaker;
346
+ readonly logout: LogoutMaker;
286
347
  }
287
348
  /** The plugins of `StdUseCases`, by name. */
288
349
  export type StdUseCasePlugins = {
289
350
  readonly [Name in keyof StdUseCaseContext]: IUseCasePlugin<Name, StdUseCaseContext[Name]>;
290
351
  };
352
+ /** The operations `resourceOf` can give. */
353
+ export type ResourceAction = "create" | "get" | "list" | "update" | "delete";
354
+ /** The use cases of `resourceOf`, by operation: the standard ones, with no option but their route and access. */
355
+ export interface ResourceUseCases<Repository extends AnyRepository> {
356
+ readonly create: EntityUseCase<Repository, None, CreateInput<Repository, None>>;
357
+ readonly get: EntityUseCase<Repository, None, ById<Repository>>;
358
+ readonly list: StepsUseCaseConstructor<{
359
+ readonly limit: OptionalProperty<typeof Integer>;
360
+ readonly offset: OptionalProperty<typeof Integer>;
361
+ }, {
362
+ readonly items: IBlueprintList<EntityOf<Repository>>;
363
+ readonly total: typeof Integer;
364
+ readonly limit: typeof Integer;
365
+ readonly offset: typeof Integer;
366
+ }, {
367
+ readonly repository: Repository;
368
+ }>;
369
+ readonly update: EntityUseCase<Repository, None, UpdateInput<Repository>>;
370
+ readonly delete: EntityUseCase<Repository, None, ById<Repository>>;
371
+ }
372
+ /** The options of `resourceOf`. */
373
+ export interface ResourceOptions<Actions extends readonly ResourceAction[] = readonly ResourceAction[]> {
374
+ /** The path of the collection, e.g. `"/posts"`; one entity is at `{path}/{id}`. */
375
+ readonly path: string;
376
+ /** The operations to give; all five by default. Each needs its repository action. */
377
+ readonly actions?: Actions;
378
+ /**
379
+ * Who may call: one declaration for every operation, or one per operation
380
+ * (`{ create: { scopes: ["posts:write"] }, get: { public: true } }`; an
381
+ * operation left out declares none).
382
+ */
383
+ readonly access?: AccessDeclaration | {
384
+ readonly [Action in ResourceAction]?: AccessDeclaration;
385
+ };
386
+ }
291
387
  export {};
@@ -0,0 +1,32 @@
1
+ import type { Authenticator, HttpOptions, SinkStage } from "../adapters.js";
2
+ import type { ContractRunner } from "./provider-contract.js";
3
+ /** What the kit needs of a sink that serves HTTP. */
4
+ export interface HttpProviderContractSettings<Server> {
5
+ /** The sink under test, made with these options and this authenticator. */
6
+ sink(options: HttpOptions, hooks: {
7
+ readonly authenticator?: Authenticator;
8
+ }): SinkStage<Server, HttpOptions>;
9
+ /** Sends a request to the server the sink built, and gives its response. */
10
+ fetch(server: Server, request: Request): Response | Promise<Response>;
11
+ /** Releases the server (a listening socket), after each case. */
12
+ close?(server: Server): void | Promise<void>;
13
+ }
14
+ /**
15
+ * The cases every sink that serves HTTP must pass, whatever its server: the
16
+ * routes use cases declare, where each input key is read from, the context,
17
+ * access, statuses, problems, cookies, the request id and the document. A
18
+ * sink built on `compileRoutes` passes when it routes each method and path
19
+ * to `handle` and sends the result as is.
20
+ *
21
+ * ```ts
22
+ * import { describe, expect, it } from "bun:test";
23
+ * import { httpProviderContract } from "@afora/core/testing";
24
+ *
25
+ * httpProviderContract(
26
+ * "hono",
27
+ * { sink: (options, hooks) => hono(options, hooks), fetch: (app, request) => app.fetch(request) },
28
+ * { describe, it, expect },
29
+ * );
30
+ * ```
31
+ */
32
+ export declare function httpProviderContract<Server>(name: string, settings: HttpProviderContractSettings<Server>, runner: ContractRunner): void;
@@ -1,3 +1,5 @@
1
+ export type { HttpProviderContractSettings } from "./http-provider-contract.js";
2
+ export { httpProviderContract } from "./http-provider-contract.js";
1
3
  export type { MemoryPublisher } from "./memory-publisher.js";
2
4
  export { memoryPublisher } from "./memory-publisher.js";
3
5
  export type { ContractRunner, ProviderContractOptions, } from "./provider-contract.js";