@nmtjs/contract 0.14.5 → 0.15.0-beta.10

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/LICENSE.md CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2024 Denis Ilchyshyn
1
+ Copyright (c) 2025 Denys Ilchyshyn
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
4
 
package/README.md CHANGED
@@ -6,4 +6,4 @@
6
6
  - binary data streaming and event subscriptions
7
7
  - contract-based API
8
8
  - end-to-end type safety
9
- - CPU-intensive task execution on separate workers
9
+ - CPU-intensive task execution on separate workers
package/dist/constants.js CHANGED
@@ -1 +1,2 @@
1
1
  export const Kind = Symbol.for('neemata:kind');
2
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,cAAc,CAAC,CAAA"}
package/dist/index.d.ts CHANGED
@@ -1,4 +1,3 @@
1
- export * from './schemas/api.ts';
2
1
  export * from './schemas/event.ts';
3
2
  export * from './schemas/procedure.ts';
4
3
  export * from './schemas/router.ts';
@@ -7,11 +6,11 @@ export declare namespace contract {
7
6
  const procedure: <const Options extends {
8
7
  input?: import("@nmtjs/type").BaseType;
9
8
  output?: import("@nmtjs/type").BaseType;
10
- stream?: import("@nmtjs/type").BaseType | undefined;
9
+ stream?: true | undefined;
11
10
  timeout?: number;
12
11
  schemaOptions?: import("./utils.ts").ContractSchemaOptions;
13
12
  name?: string;
14
- }>(options: Options) => import("./schemas/procedure.ts").TProcedureContract<Options["input"] extends import("@nmtjs/type").BaseType ? Options["input"] : import("@nmtjs/type/never").NeverType, Options["output"] extends import("@nmtjs/type").BaseType ? Options["output"] : import("@nmtjs/type/never").NeverType, Options["stream"] extends import("@nmtjs/type").BaseType ? Options["stream"] : undefined, Options["name"] extends string ? Options["name"] : undefined>;
13
+ }>(options: Options) => import("./schemas/procedure.ts").TProcedureContract<Options["input"] extends import("@nmtjs/type").BaseType ? Options["input"] : import("@nmtjs/type/never").NeverType, Options["output"] extends import("@nmtjs/type").BaseType ? Options["output"] : import("@nmtjs/type/never").NeverType, Options["stream"] extends true ? true : undefined, Options["name"] extends string ? Options["name"] : undefined>;
15
14
  const event: <Payload extends import("@nmtjs/type").BaseType, Name extends string | undefined = undefined, Options extends import("./schemas/subscription.ts").SubcriptionOptions | undefined = undefined>(options?: {
16
15
  payload?: Payload;
17
16
  schemaOptions?: import("./utils.ts").ContractSchemaOptions;
@@ -34,11 +33,6 @@ export declare namespace contract {
34
33
  timeout?: number;
35
34
  schemaOptions?: import("./utils.ts").ContractSchemaOptions;
36
35
  }>(options: Options) => import("./schemas/router.ts").TRouterContract<Options["routes"], Options["name"] extends string ? Options["name"] : undefined>;
37
- const api: <const Options extends {
38
- router: import("./schemas/router.ts").TAnyRouterContract;
39
- timeout?: number;
40
- schemaOptions?: import("./utils.ts").ContractSchemaOptions;
41
- }>(options: Options) => import("./schemas/api.ts").TAPIContract<Options["router"]>;
42
36
  const blob: (options?: import("./types/blob.ts").BlobOptions) => import("@nmtjs/type/custom").CustomType<import("@nmtjs/protocol").ProtocolBlobInterface>;
43
37
  }
44
38
  export { contract as c };
package/dist/index.js CHANGED
@@ -1,10 +1,8 @@
1
- import { APIContract } from "./schemas/api.js";
2
1
  import { EventContract } from "./schemas/event.js";
3
2
  import { ProcedureContract } from "./schemas/procedure.js";
4
3
  import { RouterContract } from "./schemas/router.js";
5
4
  import { SubscriptionContract } from "./schemas/subscription.js";
6
5
  import { BlobType } from "./types/blob.js";
7
- export * from "./schemas/api.js";
8
6
  export * from "./schemas/event.js";
9
7
  export * from "./schemas/procedure.js";
10
8
  export * from "./schemas/router.js";
@@ -15,8 +13,8 @@ export var contract;
15
13
  contract.event = EventContract;
16
14
  contract.subscription = SubscriptionContract;
17
15
  contract.router = RouterContract;
18
- contract.api = APIContract;
19
16
  contract.blob = BlobType;
20
17
  })(contract || (contract = {}));
21
18
  export { contract as c };
22
19
  export default contract;
20
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAClD,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AACpD,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAA;AAChE,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAA;AAE1C,cAAc,oBAAoB,CAAA;AAClC,cAAc,wBAAwB,CAAA;AACtC,cAAc,qBAAqB,CAAA;AACnC,cAAc,2BAA2B,CAAA;AAEzC,MAAM,KAAW,QAAQ,CAMxB;AAND,WAAiB,QAAQ;IACV,kBAAS,GAAG,iBAAiB,CAAA;IAC7B,cAAK,GAAG,aAAa,CAAA;IACrB,qBAAY,GAAG,oBAAoB,CAAA;IACnC,eAAM,GAAG,cAAc,CAAA;IACvB,aAAI,GAAG,QAAQ,CAAA;AAC9B,CAAC,EANgB,QAAQ,KAAR,QAAQ,QAMxB;AAED,OAAO,EAAE,QAAQ,IAAI,CAAC,EAAE,CAAA;AAExB,eAAe,QAAQ,CAAA"}
@@ -16,3 +16,4 @@ export const EventContract = (options) => {
16
16
  export function IsEventContract(value) {
17
17
  return Kind in value && value[Kind] === EventKind;
18
18
  }
19
+ //# sourceMappingURL=event.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event.js","sourceRoot":"","sources":["../../src/schemas/event.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,aAAa,CAAA;AAI/B,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAA;AACtC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAE1C,MAAM,CAAC,MAAM,SAAS,GAAG,MAAM,CAAC,cAAc,CAAC,CAAA;AAoB/C,MAAM,CAAC,MAAM,aAAa,GAAG,CAI3B,OAID,EAAE,EAAE;IACH,MAAM,EACJ,OAAO,GAAG,CAAC,CAAC,KAAK,EAAwB,EACzC,aAAa,GAAG,EAAE,EAClB,IAAI,GAAG,SAAgB,GACxB,GAAG,OAAO,IAAI,EAAE,CAAA;IACjB,OAAO,YAAY,CAAyC;QAC1D,GAAG,aAAa;QAChB,CAAC,IAAI,CAAC,EAAE,SAAS;QACjB,IAAI,EAAE,eAAe;QACrB,OAAO;QACP,IAAI;QACJ,OAAO,EAAE,SAAoB;KAC9B,CAAC,CAAA;AACJ,CAAC,CAAA;AAED,MAAM,UAAU,eAAe,CAAC,KAAU;IACxC,OAAO,IAAI,IAAI,KAAK,IAAI,KAAK,CAAC,IAAI,CAAC,KAAK,SAAS,CAAA;AACnD,CAAC"}
@@ -2,9 +2,9 @@ import type { BaseType } from '@nmtjs/type';
2
2
  import type { NeverType } from '@nmtjs/type/never';
3
3
  import type { ContractSchemaOptions } from '../utils.ts';
4
4
  import { Kind } from '../constants.ts';
5
- export type TAnyProcedureContract = TProcedureContract<BaseType, BaseType, BaseType | undefined, string | undefined>;
5
+ export type TAnyProcedureContract = TProcedureContract<BaseType, BaseType, true | undefined, string | undefined>;
6
6
  export declare const ProcedureKind: unique symbol;
7
- export interface TProcedureContract<Input extends BaseType, Output extends BaseType, Stream extends BaseType | undefined, Name extends string | undefined = undefined> {
7
+ export interface TProcedureContract<Input extends BaseType, Output extends BaseType, Stream extends true | undefined = undefined, Name extends string | undefined = undefined> {
8
8
  readonly [Kind]: typeof ProcedureKind;
9
9
  readonly type: 'neemata:procedure';
10
10
  readonly name: Name;
@@ -16,10 +16,10 @@ export interface TProcedureContract<Input extends BaseType, Output extends BaseT
16
16
  export declare const ProcedureContract: <const Options extends {
17
17
  input?: BaseType;
18
18
  output?: BaseType;
19
- stream?: BaseType | undefined;
19
+ stream?: true | undefined;
20
20
  timeout?: number;
21
21
  schemaOptions?: ContractSchemaOptions;
22
22
  name?: string;
23
- }>(options: Options) => TProcedureContract<Options["input"] extends BaseType ? Options["input"] : NeverType, Options["output"] extends BaseType ? Options["output"] : NeverType, Options["stream"] extends BaseType ? Options["stream"] : undefined, Options["name"] extends string ? Options["name"] : undefined>;
23
+ }>(options: Options) => TProcedureContract<Options["input"] extends BaseType ? Options["input"] : NeverType, Options["output"] extends BaseType ? Options["output"] : NeverType, Options["stream"] extends true ? true : undefined, Options["name"] extends string ? Options["name"] : undefined>;
24
24
  export declare function IsProcedureContract(contract: any): contract is TAnyProcedureContract;
25
25
  export declare function IsStreamProcedureContract(contract: any): contract is TAnyProcedureContract;
@@ -21,3 +21,4 @@ export function IsProcedureContract(contract) {
21
21
  export function IsStreamProcedureContract(contract) {
22
22
  return IsProcedureContract(contract) && typeof contract.stream !== 'undefined';
23
23
  }
24
+ //# sourceMappingURL=procedure.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"procedure.js","sourceRoot":"","sources":["../../src/schemas/procedure.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,aAAa,CAAA;AAG/B,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAA;AACtC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAS1C,MAAM,CAAC,MAAM,aAAa,GAAG,MAAM,CAAC,kBAAkB,CAAC,CAAA;AAiBvD,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAU/B,OAAgB,EAMhB,EAAE;IACF,MAAM,EACJ,KAAK,GAAG,CAAC,CAAC,KAAK,EAAS,EACxB,MAAM,GAAG,CAAC,CAAC,KAAK,EAAS,EACzB,MAAM,GAAG,SAAgB,EACzB,IAAI,GAAG,SAAgB,EACvB,OAAO,EACP,aAAa,GAAG,EAAE,GACnB,GAAG,OAAO,CAAA;IACX,OAAO,YAAY,CAAC;QAClB,GAAG,aAAa;QAChB,CAAC,IAAI,CAAC,EAAE,aAAa;QACrB,IAAI,EAAE,mBAAmB;QACzB,KAAK;QACL,MAAM;QACN,MAAM;QACN,IAAI;QACJ,OAAO;KACR,CAAC,CAAA;AACJ,CAAC,CAAA;AAED,MAAM,UAAU,mBAAmB,CACjC,QAAa;IAEb,OAAO,IAAI,IAAI,QAAQ,IAAI,QAAQ,CAAC,IAAI,CAAC,KAAK,aAAa,CAAA;AAC7D,CAAC;AAED,MAAM,UAAU,yBAAyB,CACvC,QAAa;IAEb,OAAO,mBAAmB,CAAC,QAAQ,CAAC,IAAI,OAAO,QAAQ,CAAC,MAAM,KAAK,WAAW,CAAA;AAChF,CAAC"}
@@ -2,7 +2,7 @@ import type { ContractSchemaOptions } from '../utils.ts';
2
2
  import type { TAnyProcedureContract, TProcedureContract } from './procedure.ts';
3
3
  import { Kind } from '../constants.ts';
4
4
  export declare const RouterKind: unique symbol;
5
- export type TAnyRouterContract<RouteContracts extends Record<string, TRouteContract> = Record<string, TRouteContract>> = TRouterContract<RouteContracts, string | undefined>;
5
+ export type TAnyRouterContract<RouteContracts extends Record<string, TRouteContract> = Record<string, TRouteContract>, RouterName extends string | undefined = string | undefined> = TRouterContract<RouteContracts, RouterName>;
6
6
  export type TRouteContract = TAnyProcedureContract | TRouterContract<Record<string, TRouteContract>, string | undefined>;
7
7
  export interface TRouterContract<Routes extends Record<string, TRouteContract> = {}, Name extends string | undefined = undefined> {
8
8
  readonly [Kind]: typeof RouterKind;
@@ -39,3 +39,4 @@ function processNestedRoutes(routes, parentName) {
39
39
  export function IsRouterContract(value) {
40
40
  return Kind in value && value[Kind] === RouterKind;
41
41
  }
42
+ //# sourceMappingURL=router.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"router.js","sourceRoot":"","sources":["../../src/schemas/router.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAA;AACtC,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC1D,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAA;AAEpD,MAAM,CAAC,MAAM,UAAU,GAAG,MAAM,CAAC,eAAe,CAAC,CAAA;AA2CjD,MAAM,CAAC,MAAM,cAAc,GAAG,CAQ5B,OAAgB,EAChB,EAAE;IACF,MAAM,EACJ,IAAI,GAAG,SAAgB,EACvB,OAAO,EACP,aAAa,GAAG,EAA2B,GAC5C,GAAG,OAAO,CAAA;IAEX,MAAM,MAAM,GAAQ,mBAAmB,CAAC,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,CAAA;IAE7D,OAAO,YAAY,CAKjB;QACA,GAAG,aAAa;QAChB,CAAC,IAAI,CAAC,EAAE,UAAU;QAClB,IAAI,EAAE,gBAAgB;QACtB,IAAI;QACJ,MAAM;QACN,OAAO;KACR,CAAC,CAAA;AACJ,CAAC,CAAA;AAED,SAAS,mBAAmB,CAC1B,MAAkE,EAClE,UAA8B;IAE9B,MAAM,SAAS,GAAwB,EAAE,CAAA;IAEzC,KAAK,MAAM,SAAS,IAAI,MAAM,EAAE,CAAC;QAC/B,MAAM,KAAK,GAAG,MAAM,CAAC,SAAS,CAAC,CAAA;QAE/B,IAAI,gBAAgB,CAAC,KAAK,CAAC,EAAE,CAAC;YAC5B,MAAM,UAAU,GAAG,cAAc,CAAC,UAAU,EAAE,SAAS,CAAC,CAAA;YACxD,SAAS,CAAC,SAAS,CAAC,GAAG,YAAY,CAAC;gBAClC,GAAG,KAAK;gBACR,IAAI,EAAE,UAAU;gBAChB,MAAM,EAAE,mBAAmB,CAAC,KAAK,CAAC,MAAM,EAAE,UAAU,CAAC;aACtD,CAAC,CAAA;QACJ,CAAC;aAAM,IAAI,mBAAmB,CAAC,KAAK,CAAC,EAAE,CAAC;YACtC,MAAM,QAAQ,GAAG,cAAc,CAAC,UAAU,EAAE,SAAS,CAAC,CAAA;YACtD,SAAS,CAAC,SAAS,CAAC,GAAG,YAAY,CAAC,EAAE,GAAG,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAA;QACnE,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,KAAK,CAAC,0BAA0B,SAAS,EAAE,CAAC,CAAA;QACxD,CAAC;IACH,CAAC;IAED,OAAO,SAAS,CAAA;AAClB,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,KAAU;IACzC,OAAO,IAAI,IAAI,KAAK,IAAI,KAAK,CAAC,IAAI,CAAC,KAAK,UAAU,CAAA;AACpD,CAAC"}
@@ -26,3 +26,4 @@ export const SubscriptionContract = Object.assign(_SubscriptionContract, {
26
26
  export function IsSubscriptionContract(contract) {
27
27
  return Kind in contract && contract[Kind] === SubscriptionKind;
28
28
  }
29
+ //# sourceMappingURL=subscription.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subscription.js","sourceRoot":"","sources":["../../src/schemas/subscription.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAA;AACtC,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAE1D,MAAM,CAAC,MAAM,gBAAgB,GAAG,MAAM,CAAC,qBAAqB,CAAC,CAAA;AAmC7D,MAAM,qBAAqB,GAAG,CAQ5B,OAAgB,EAChB,EAAE;IACF,MAAM,EAAE,aAAa,GAAG,EAAE,EAAE,IAAI,EAAE,GAAG,OAAO,CAAA;IAC5C,MAAM,OAAO,GAAG,EAAS,CAAA;IACzB,KAAK,MAAM,GAAG,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;QACjC,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;QACjC,MAAM,QAAQ,GAAG,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,CAAA;QAC1C,OAAO,CAAC,GAAG,CAAC,GAAG,YAAY,CAAC,EAAE,GAAG,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAA;IAC3D,CAAC;IACD,OAAO,YAAY,CAEjB;QACA,GAAG,aAAa;QAChB,CAAC,IAAI,CAAC,EAAE,gBAAgB;QACxB,IAAI,EAAE,sBAAsB;QAC5B,MAAM,EAAE,OAAO;QACf,IAAI,EAAE,IAAI;QACV,OAAO,EAAE,SAA8B;KACxC,CAAC,CAAA;AACJ,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,oBAAoB,GAAG,MAAM,CAAC,MAAM,CAAC,qBAAqB,EAAE;IACvE,WAAW,EAAE,GAAuC,EAAE;QACpD,OAAO,CAOL,OAAU,EACV,EAAE,CAAC,qBAAqB,CAAa,OAAO,CAAC,CAAA;IACjD,CAAC;CACF,CAAC,CAAA;AAEF,MAAM,UAAU,sBAAsB,CACpC,QAAa;IAEb,OAAO,IAAI,IAAI,QAAQ,IAAI,QAAQ,CAAC,IAAI,CAAC,KAAK,gBAAgB,CAAA;AAChE,CAAC"}
@@ -1,7 +1,7 @@
1
1
  import type { ProtocolBlobInterface } from '@nmtjs/protocol';
2
- import { t } from '@nmtjs/type';
2
+ import { CustomType } from '@nmtjs/type/custom';
3
3
  export interface BlobOptions {
4
4
  maxSize?: number;
5
5
  contentType?: string;
6
6
  }
7
- export declare const BlobType: (options?: BlobOptions) => t.CustomType<ProtocolBlobInterface>;
7
+ export declare const BlobType: (options?: BlobOptions) => CustomType<ProtocolBlobInterface>;
@@ -1,16 +1,36 @@
1
- import { t } from '@nmtjs/type';
2
- export const BlobType = (options = {}) => t.custom({
3
- decode: (value) => {
4
- // TODO: here should be some validation logic to check if the value is an actual blob
5
- if ('metadata' in value) {
6
- if (options.maxSize) {
7
- const size = value.metadata.size;
8
- if (typeof size !== 'undefined' && size > options.maxSize) {
9
- throw new Error('Blob size unknown or exceeds maximum allowed size');
1
+ import { isBlobInterface } from '@nmtjs/protocol';
2
+ import { CustomType } from '@nmtjs/type/custom';
3
+ export const BlobType = (options = {}) => CustomType.factory({
4
+ decode: (value) => value,
5
+ encode: (value) => value,
6
+ validation: {
7
+ decode(value, { addIssue }) {
8
+ if (isBlobInterface(value)) {
9
+ if (options.maxSize) {
10
+ const size = value.metadata.size;
11
+ if (typeof size !== 'undefined' && size > options.maxSize) {
12
+ addIssue({
13
+ code: 'custom',
14
+ message: `Blob size unknown or exceeds maximum allowed size of ${options.maxSize} bytes`,
15
+ });
16
+ }
10
17
  }
11
18
  }
12
- }
13
- return value;
19
+ else {
20
+ addIssue({
21
+ code: 'custom',
22
+ message: 'Value is not a Neemata Blob. Make sure to use transport that supports encoded streams.',
23
+ });
24
+ }
25
+ },
26
+ encode(value, { addIssue }) {
27
+ if (!isBlobInterface(value)) {
28
+ addIssue({
29
+ code: 'custom',
30
+ message: 'Value is not a Neemata Blob. Make sure to use transport that supports encoded streams.',
31
+ });
32
+ }
33
+ },
14
34
  },
15
- encode: (value) => value,
16
35
  });
36
+ //# sourceMappingURL=blob.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"blob.js","sourceRoot":"","sources":["../../src/types/blob.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AAO/C,MAAM,CAAC,MAAM,QAAQ,GAAG,CACtB,UAAuB,EAAE,EACU,EAAE,CACrC,UAAU,CAAC,OAAO,CAAC;IACjB,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK;IACxB,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK;IACxB,UAAU,EAAE;QACV,MAAM,CAAC,KAAK,EAAE,EAAE,QAAQ,EAAE;YACxB,IAAI,eAAe,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC3B,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;oBACpB,MAAM,IAAI,GAAG,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAA;oBAChC,IAAI,OAAO,IAAI,KAAK,WAAW,IAAI,IAAI,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;wBAC1D,QAAQ,CAAC;4BACP,IAAI,EAAE,QAAQ;4BACd,OAAO,EAAE,wDAAwD,OAAO,CAAC,OAAO,QAAQ;yBACzF,CAAC,CAAA;oBACJ,CAAC;gBACH,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,QAAQ,CAAC;oBACP,IAAI,EAAE,QAAQ;oBACd,OAAO,EACL,wFAAwF;iBAC3F,CAAC,CAAA;YACJ,CAAC;QACH,CAAC;QACD,MAAM,CAAC,KAAK,EAAE,EAAE,QAAQ,EAAE;YACxB,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC5B,QAAQ,CAAC;oBACP,IAAI,EAAE,QAAQ;oBACd,OAAO,EACL,wFAAwF;iBAC3F,CAAC,CAAA;YACJ,CAAC;QACH,CAAC;KACF;CACF,CAAC,CAAA"}
package/dist/utils.js CHANGED
@@ -5,3 +5,4 @@ export const createSchema = (schema) => Object.freeze(schema);
5
5
  export const concatFullName = (parent, name) => {
6
6
  return parent ? `${parent}/${name}` : name;
7
7
  };
8
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,UAAU,GAAG,CACxB,MAAS,EACT,IAAyD,EACzD,EAAE;IACF,OAAO,MAAM,CAAC,WAAW,CACvB,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,GAAG,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,IAAI,EAAE,CAAC,CAAC,CACxE,CAAA;AACH,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,YAAY,GAAG,CAAI,MAAS,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAM,CAAA;AAExE,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,MAA0B,EAAE,IAAY,EAAE,EAAE;IACzE,OAAO,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAA;AAC5C,CAAC,CAAA"}
package/package.json CHANGED
@@ -2,24 +2,26 @@
2
2
  "name": "@nmtjs/contract",
3
3
  "type": "module",
4
4
  "exports": {
5
- ".": {
6
- "types": "./dist/index.d.ts",
7
- "import": "./dist/index.js",
8
- "module-sync": "./dist/index.js"
9
- }
5
+ ".": "./dist/index.js"
10
6
  },
11
7
  "dependencies": {
12
- "@nmtjs/protocol": "0.14.5",
13
- "@nmtjs/type": "0.14.5"
8
+ "@nmtjs/protocol": "0.15.0-beta.10",
9
+ "@nmtjs/type": "0.15.0-beta.10"
10
+ },
11
+ "devDependencies": {
12
+ "zod": "^4.1.0"
14
13
  },
15
14
  "files": [
16
15
  "dist",
16
+ "src",
17
17
  "LICENSE.md",
18
18
  "README.md"
19
19
  ],
20
- "version": "0.14.5",
20
+ "version": "0.15.0-beta.10",
21
21
  "scripts": {
22
- "build": "tsc",
22
+ "clean-build": "rm -rf ./dist",
23
+ "build": "tsc --declaration --sourcemap",
24
+ "dev": "tsc --watch",
23
25
  "type-check": "tsc --noEmit"
24
26
  }
25
27
  }
@@ -0,0 +1 @@
1
+ export const Kind = Symbol.for('neemata:kind')
package/src/index.ts ADDED
@@ -0,0 +1,22 @@
1
+ import { EventContract } from './schemas/event.ts'
2
+ import { ProcedureContract } from './schemas/procedure.ts'
3
+ import { RouterContract } from './schemas/router.ts'
4
+ import { SubscriptionContract } from './schemas/subscription.ts'
5
+ import { BlobType } from './types/blob.ts'
6
+
7
+ export * from './schemas/event.ts'
8
+ export * from './schemas/procedure.ts'
9
+ export * from './schemas/router.ts'
10
+ export * from './schemas/subscription.ts'
11
+
12
+ export namespace contract {
13
+ export const procedure = ProcedureContract
14
+ export const event = EventContract
15
+ export const subscription = SubscriptionContract
16
+ export const router = RouterContract
17
+ export const blob = BlobType
18
+ }
19
+
20
+ export { contract as c }
21
+
22
+ export default contract
@@ -0,0 +1,55 @@
1
+ import type { BaseType } from '@nmtjs/type'
2
+ import { t } from '@nmtjs/type'
3
+
4
+ import type { ContractSchemaOptions } from '../utils.ts'
5
+ import type { SubcriptionOptions } from './subscription.ts'
6
+ import { Kind } from '../constants.ts'
7
+ import { createSchema } from '../utils.ts'
8
+
9
+ export const EventKind = Symbol('NeemataEvent')
10
+
11
+ export type TAnyEventContract = TEventContract<
12
+ BaseType,
13
+ string | undefined,
14
+ SubcriptionOptions | undefined
15
+ >
16
+
17
+ export interface TEventContract<
18
+ Payload extends BaseType = t.NeverType,
19
+ Name extends string | undefined = undefined,
20
+ Options extends SubcriptionOptions | undefined = undefined,
21
+ > {
22
+ readonly [Kind]: typeof EventKind
23
+ readonly type: 'neemata:event'
24
+ readonly name: Name
25
+ readonly payload: Payload
26
+ readonly options: Options
27
+ }
28
+
29
+ export const EventContract = <
30
+ Payload extends BaseType,
31
+ Name extends string | undefined = undefined,
32
+ Options extends SubcriptionOptions | undefined = undefined,
33
+ >(options?: {
34
+ payload?: Payload
35
+ schemaOptions?: ContractSchemaOptions
36
+ name?: Name
37
+ }) => {
38
+ const {
39
+ payload = t.never() as unknown as Payload,
40
+ schemaOptions = {},
41
+ name = undefined as any,
42
+ } = options ?? {}
43
+ return createSchema<TEventContract<Payload, Name, Options>>({
44
+ ...schemaOptions,
45
+ [Kind]: EventKind,
46
+ type: 'neemata:event',
47
+ payload,
48
+ name,
49
+ options: undefined as Options,
50
+ })
51
+ }
52
+
53
+ export function IsEventContract(value: any): value is TAnyEventContract {
54
+ return Kind in value && value[Kind] === EventKind
55
+ }
@@ -0,0 +1,80 @@
1
+ import type { BaseType } from '@nmtjs/type'
2
+ import type { NeverType } from '@nmtjs/type/never'
3
+ import { t } from '@nmtjs/type'
4
+
5
+ import type { ContractSchemaOptions } from '../utils.ts'
6
+ import { Kind } from '../constants.ts'
7
+ import { createSchema } from '../utils.ts'
8
+
9
+ export type TAnyProcedureContract = TProcedureContract<
10
+ BaseType,
11
+ BaseType,
12
+ true | undefined,
13
+ string | undefined
14
+ >
15
+
16
+ export const ProcedureKind = Symbol('NeemataProcedure')
17
+
18
+ export interface TProcedureContract<
19
+ Input extends BaseType,
20
+ Output extends BaseType,
21
+ Stream extends true | undefined = undefined,
22
+ Name extends string | undefined = undefined,
23
+ > {
24
+ readonly [Kind]: typeof ProcedureKind
25
+ readonly type: 'neemata:procedure'
26
+ readonly name: Name
27
+ readonly input: Input
28
+ readonly output: Output
29
+ readonly stream: Stream
30
+ readonly timeout?: number
31
+ }
32
+
33
+ export const ProcedureContract = <
34
+ const Options extends {
35
+ input?: BaseType
36
+ output?: BaseType
37
+ stream?: true | undefined
38
+ timeout?: number
39
+ schemaOptions?: ContractSchemaOptions
40
+ name?: string
41
+ },
42
+ >(
43
+ options: Options,
44
+ ): TProcedureContract<
45
+ Options['input'] extends BaseType ? Options['input'] : NeverType,
46
+ Options['output'] extends BaseType ? Options['output'] : NeverType,
47
+ Options['stream'] extends true ? true : undefined,
48
+ Options['name'] extends string ? Options['name'] : undefined
49
+ > => {
50
+ const {
51
+ input = t.never() as any,
52
+ output = t.never() as any,
53
+ stream = undefined as any,
54
+ name = undefined as any,
55
+ timeout,
56
+ schemaOptions = {},
57
+ } = options
58
+ return createSchema({
59
+ ...schemaOptions,
60
+ [Kind]: ProcedureKind,
61
+ type: 'neemata:procedure',
62
+ input,
63
+ output,
64
+ stream,
65
+ name,
66
+ timeout,
67
+ })
68
+ }
69
+
70
+ export function IsProcedureContract(
71
+ contract: any,
72
+ ): contract is TAnyProcedureContract {
73
+ return Kind in contract && contract[Kind] === ProcedureKind
74
+ }
75
+
76
+ export function IsStreamProcedureContract(
77
+ contract: any,
78
+ ): contract is TAnyProcedureContract {
79
+ return IsProcedureContract(contract) && typeof contract.stream !== 'undefined'
80
+ }
@@ -0,0 +1,112 @@
1
+ import type { ContractSchemaOptions } from '../utils.ts'
2
+ import type { TAnyProcedureContract, TProcedureContract } from './procedure.ts'
3
+ import { Kind } from '../constants.ts'
4
+ import { concatFullName, createSchema } from '../utils.ts'
5
+ import { IsProcedureContract } from './procedure.ts'
6
+
7
+ export const RouterKind = Symbol('NeemataRouter')
8
+
9
+ export type TAnyRouterContract<
10
+ RouteContracts extends Record<string, TRouteContract> = Record<
11
+ string,
12
+ TRouteContract
13
+ >,
14
+ RouterName extends string | undefined = string | undefined,
15
+ > = TRouterContract<RouteContracts, RouterName>
16
+
17
+ export type TRouteContract =
18
+ | TAnyProcedureContract
19
+ | TRouterContract<Record<string, TRouteContract>, string | undefined>
20
+
21
+ export interface TRouterContract<
22
+ Routes extends Record<string, TRouteContract> = {},
23
+ Name extends string | undefined = undefined,
24
+ > {
25
+ readonly [Kind]: typeof RouterKind
26
+ readonly type: 'neemata:router'
27
+ readonly name: Name
28
+ readonly routes: {
29
+ [K in keyof Routes]: Routes[K] extends TAnyRouterContract
30
+ ? TRouterContract<
31
+ Routes[K]['routes'],
32
+ Name extends string
33
+ ? `${Name}/${Extract<K, string>}`
34
+ : Extract<K, string>
35
+ >
36
+ : Routes[K] extends TAnyProcedureContract
37
+ ? TProcedureContract<
38
+ Routes[K]['input'],
39
+ Routes[K]['output'],
40
+ Routes[K]['stream'],
41
+ Name extends string
42
+ ? `${Name}/${Extract<K, string>}`
43
+ : Extract<K, string>
44
+ >
45
+ : never
46
+ }
47
+ readonly timeout?: number
48
+ }
49
+
50
+ export const RouterContract = <
51
+ const Options extends {
52
+ routes: Record<string, TRouteContract>
53
+ name?: string
54
+ timeout?: number
55
+ schemaOptions?: ContractSchemaOptions
56
+ },
57
+ >(
58
+ options: Options,
59
+ ) => {
60
+ const {
61
+ name = undefined as any,
62
+ timeout,
63
+ schemaOptions = {} as ContractSchemaOptions,
64
+ } = options
65
+
66
+ const routes: any = processNestedRoutes(options.routes, name)
67
+
68
+ return createSchema<
69
+ TRouterContract<
70
+ Options['routes'],
71
+ Options['name'] extends string ? Options['name'] : undefined
72
+ >
73
+ >({
74
+ ...schemaOptions,
75
+ [Kind]: RouterKind,
76
+ type: 'neemata:router',
77
+ name,
78
+ routes,
79
+ timeout,
80
+ })
81
+ }
82
+
83
+ function processNestedRoutes(
84
+ routes: Record<string, TAnyRouterContract | TAnyProcedureContract>,
85
+ parentName: string | undefined,
86
+ ): Record<string, TAnyRouterContract | TAnyProcedureContract> {
87
+ const processed: Record<string, any> = {}
88
+
89
+ for (const routeName in routes) {
90
+ const route = routes[routeName]
91
+
92
+ if (IsRouterContract(route)) {
93
+ const nestedName = concatFullName(parentName, routeName)
94
+ processed[routeName] = createSchema({
95
+ ...route,
96
+ name: nestedName,
97
+ routes: processNestedRoutes(route.routes, nestedName),
98
+ })
99
+ } else if (IsProcedureContract(route)) {
100
+ const fullName = concatFullName(parentName, routeName)
101
+ processed[routeName] = createSchema({ ...route, name: fullName })
102
+ } else {
103
+ throw new Error(`Invalid route type for ${routeName}`)
104
+ }
105
+ }
106
+
107
+ return processed
108
+ }
109
+
110
+ export function IsRouterContract(value: any): value is TAnyRouterContract {
111
+ return Kind in value && value[Kind] === RouterKind
112
+ }
@@ -0,0 +1,88 @@
1
+ import type { ContractSchemaOptions } from '../utils.ts'
2
+ import type { TAnyEventContract, TEventContract } from './event.ts'
3
+ import { Kind } from '../constants.ts'
4
+ import { concatFullName, createSchema } from '../utils.ts'
5
+
6
+ export const SubscriptionKind = Symbol('NeemataSubscription')
7
+
8
+ export type SubcriptionOptions = Record<
9
+ string,
10
+ string | number | boolean
11
+ > | null
12
+
13
+ export type TAnySubscriptionContract = TSubscriptionContract<
14
+ SubcriptionOptions,
15
+ Record<string, TAnyEventContract>,
16
+ string | undefined
17
+ >
18
+
19
+ export interface TSubscriptionContract<
20
+ Options extends SubcriptionOptions = null,
21
+ Events extends Record<string, unknown> = {},
22
+ Name extends string | undefined = undefined,
23
+ > {
24
+ readonly [Kind]: typeof SubscriptionKind
25
+ readonly type: 'neemata:subscription'
26
+ readonly name: Name
27
+ readonly options: Options
28
+ readonly events: {
29
+ [K in keyof Events]: Events[K] extends TAnyEventContract
30
+ ? TEventContract<
31
+ Events[K]['payload'],
32
+ Name extends string
33
+ ? `${Name}/${Extract<K, string>}`
34
+ : Extract<K, string>,
35
+ Options
36
+ >
37
+ : never
38
+ }
39
+ }
40
+
41
+ const _SubscriptionContract = <
42
+ const Options extends {
43
+ events: Record<string, TAnyEventContract>
44
+ name?: string
45
+ schemaOptions?: ContractSchemaOptions
46
+ },
47
+ SubOpt extends SubcriptionOptions = null,
48
+ >(
49
+ options: Options,
50
+ ) => {
51
+ const { schemaOptions = {}, name } = options
52
+ const _events = {} as any
53
+ for (const key in options.events) {
54
+ const event = options.events[key]
55
+ const fullName = concatFullName(name, key)
56
+ _events[key] = createSchema({ ...event, name: fullName })
57
+ }
58
+ return createSchema<
59
+ TSubscriptionContract<SubOpt, Options['events'], Options['name']>
60
+ >({
61
+ ...schemaOptions,
62
+ [Kind]: SubscriptionKind,
63
+ type: 'neemata:subscription',
64
+ events: _events,
65
+ name: name,
66
+ options: undefined as unknown as SubOpt,
67
+ })
68
+ }
69
+
70
+ export const SubscriptionContract = Object.assign(_SubscriptionContract, {
71
+ withOptions: <Options extends SubcriptionOptions>() => {
72
+ return <
73
+ T extends {
74
+ events: Record<string, TAnyEventContract>
75
+ name?: string
76
+ schemaOptions?: ContractSchemaOptions
77
+ },
78
+ >(
79
+ options: T,
80
+ ) => _SubscriptionContract<T, Options>(options)
81
+ },
82
+ })
83
+
84
+ export function IsSubscriptionContract(
85
+ contract: any,
86
+ ): contract is TAnySubscriptionContract {
87
+ return Kind in contract && contract[Kind] === SubscriptionKind
88
+ }
@@ -0,0 +1,46 @@
1
+ import type { ProtocolBlobInterface } from '@nmtjs/protocol'
2
+ import { isBlobInterface } from '@nmtjs/protocol'
3
+ import { CustomType } from '@nmtjs/type/custom'
4
+
5
+ export interface BlobOptions {
6
+ maxSize?: number
7
+ contentType?: string
8
+ }
9
+
10
+ export const BlobType = (
11
+ options: BlobOptions = {},
12
+ ): CustomType<ProtocolBlobInterface> =>
13
+ CustomType.factory({
14
+ decode: (value) => value,
15
+ encode: (value) => value,
16
+ validation: {
17
+ decode(value, { addIssue }) {
18
+ if (isBlobInterface(value)) {
19
+ if (options.maxSize) {
20
+ const size = value.metadata.size
21
+ if (typeof size !== 'undefined' && size > options.maxSize) {
22
+ addIssue({
23
+ code: 'custom',
24
+ message: `Blob size unknown or exceeds maximum allowed size of ${options.maxSize} bytes`,
25
+ })
26
+ }
27
+ }
28
+ } else {
29
+ addIssue({
30
+ code: 'custom',
31
+ message:
32
+ 'Value is not a Neemata Blob. Make sure to use transport that supports encoded streams.',
33
+ })
34
+ }
35
+ },
36
+ encode(value, { addIssue }) {
37
+ if (!isBlobInterface(value)) {
38
+ addIssue({
39
+ code: 'custom',
40
+ message:
41
+ 'Value is not a Neemata Blob. Make sure to use transport that supports encoded streams.',
42
+ })
43
+ }
44
+ },
45
+ },
46
+ })
package/src/utils.ts ADDED
@@ -0,0 +1,16 @@
1
+ export type ContractSchemaOptions = { title?: string; description?: string }
2
+
3
+ export const applyNames = <T extends Record<string, { serviceName?: string }>>(
4
+ params: T,
5
+ opts: { serviceName?: string; subscriptionName?: string },
6
+ ) => {
7
+ return Object.fromEntries(
8
+ Object.entries(params).map(([k, v]) => [k, { ...v, name: k, ...opts }]),
9
+ )
10
+ }
11
+
12
+ export const createSchema = <T>(schema: T) => Object.freeze(schema) as T
13
+
14
+ export const concatFullName = (parent: string | undefined, name: string) => {
15
+ return parent ? `${parent}/${name}` : name
16
+ }
@@ -1,17 +0,0 @@
1
- import type { ContractSchemaOptions } from '../utils.ts';
2
- import type { TAnyRouterContract } from './router.ts';
3
- import { Kind } from '../constants.ts';
4
- export declare const APIKind: unique symbol;
5
- export type TAnyAPIContract = TAPIContract<TAnyRouterContract>;
6
- export interface TAPIContract<Router extends TAnyRouterContract = TAnyRouterContract> {
7
- readonly [Kind]: typeof APIKind;
8
- readonly type: 'neemata:api';
9
- readonly router: Router;
10
- readonly timeout?: number;
11
- }
12
- export declare const APIContract: <const Options extends {
13
- router: TAnyRouterContract;
14
- timeout?: number;
15
- schemaOptions?: ContractSchemaOptions;
16
- }>(options: Options) => TAPIContract<Options["router"]>;
17
- export declare function IsAPIContract(value: any): value is TAnyAPIContract;
@@ -1,16 +0,0 @@
1
- import { Kind } from "../constants.js";
2
- import { createSchema } from "../utils.js";
3
- export const APIKind = Symbol('NeemataAPI');
4
- export const APIContract = (options) => {
5
- const { router, timeout, schemaOptions } = options;
6
- return createSchema({
7
- ...schemaOptions,
8
- [Kind]: APIKind,
9
- type: 'neemata:api',
10
- router,
11
- timeout,
12
- });
13
- };
14
- export function IsAPIContract(value) {
15
- return Kind in value && value[Kind] === APIKind;
16
- }