@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.
- package/README.md +127 -23
- package/dist/adapters.d.ts +25 -0
- package/dist/adapters.js +56 -0
- package/dist/core/application/exceptions.d.ts +17 -0
- package/dist/core/application/migrate.d.ts +19 -0
- package/dist/core/application/schema.d.ts +30 -0
- package/dist/core/application/types/application.interface.d.ts +37 -0
- package/dist/core/auth/jwt.d.ts +30 -0
- package/dist/core/auth/types/jwt.interface.d.ts +66 -0
- package/dist/core/blueprint/exceptions.d.ts +5 -0
- package/dist/core/blueprint/optional.d.ts +3 -1
- package/dist/core/blueprint/types/blueprint.interface.d.ts +79 -5
- package/dist/core/blueprint/variant.d.ts +32 -0
- package/dist/core/entity/abstract-entity.d.ts +5 -0
- package/dist/core/entity/entity.d.ts +1 -1
- package/dist/core/entity/exceptions.d.ts +9 -0
- package/dist/core/entity/trust.d.ts +24 -0
- package/dist/core/entity/types/entity.interface.d.ts +30 -0
- package/dist/core/output/access.d.ts +16 -0
- package/dist/core/output/exceptions.d.ts +16 -0
- package/dist/core/output/http.d.ts +36 -0
- package/dist/core/output/openapi-sink.d.ts +23 -2
- package/dist/core/output/stage.d.ts +7 -2
- package/dist/core/output/status.d.ts +1 -1
- package/dist/core/output/types/http.interface.d.ts +130 -0
- package/dist/core/output/types/output.interface.d.ts +25 -5
- package/dist/core/parse/issue.d.ts +28 -3
- package/dist/core/parse/parse.d.ts +9 -0
- package/dist/core/property/abstract-property.d.ts +9 -0
- package/dist/core/property/define-property.d.ts +34 -6
- package/dist/core/property/types/property-options.interface.d.ts +10 -0
- package/dist/core/property/types/property-type.interface.d.ts +4 -0
- package/dist/core/record/abstract-record.d.ts +7 -0
- package/dist/core/record/types/record.interface.d.ts +12 -1
- package/dist/core/repository/exceptions.d.ts +13 -0
- package/dist/core/repository/in-memory.d.ts +2 -2
- package/dist/core/repository/migrate.d.ts +20 -0
- package/dist/core/repository/state.d.ts +2 -0
- package/dist/core/repository/types/repository.interface.d.ts +33 -0
- package/dist/core/repository/types/schema.interface.d.ts +126 -0
- package/dist/core/repository/upcast.d.ts +64 -0
- package/dist/core/schema/schema.d.ts +28 -0
- package/dist/core/symbols/kind.d.ts +1 -1
- package/dist/core/use-case/access.d.ts +12 -0
- package/dist/core/use-case/decorators.d.ts +40 -0
- package/dist/core/use-case/route.d.ts +18 -0
- package/dist/core/use-case/steps/types/check.interface.d.ts +214 -0
- package/dist/core/use-case/types/access.interface.d.ts +39 -0
- package/dist/core/use-case/types/route.interface.d.ts +66 -0
- package/dist/core/use-case/use-case.d.ts +52 -2
- package/dist/experimental.d.ts +13 -1
- package/dist/experimental.js +63 -25
- package/dist/index-3aae5jfq.js +2997 -0
- package/dist/index-hg1z2s2v.js +1055 -0
- package/dist/index-ny3as79r.js +4567 -0
- package/dist/index-xegv6a1p.js +4291 -0
- package/dist/index-y280ew0k.js +396 -0
- package/dist/index.d.ts +45 -49
- package/dist/index.js +110 -186
- package/dist/std/properties/password.d.ts +0 -2
- package/dist/std/record-plugins.d.ts +2 -2
- package/dist/std/resource.d.ts +31 -0
- package/dist/std/runtime.d.ts +6 -0
- package/dist/std/use-cases/auth.d.ts +5 -1
- package/dist/std/use-cases/index.d.ts +1 -1
- package/dist/std/use-cases/shared.d.ts +2 -2
- package/dist/std/use-cases/types.d.ts +97 -1
- package/dist/testing/http-provider-contract.d.ts +32 -0
- package/dist/testing/index.d.ts +2 -0
- package/dist/testing/index.js +495 -4
- package/dist/testing/provider-contract.d.ts +17 -1
- package/package.json +16 -3
- package/dist/index-qxfkyd6k.js +0 -1721
- 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;
|
package/dist/testing/index.d.ts
CHANGED
|
@@ -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";
|