@mayhem93/nexxus-core-lib 0.0.1 → 0.0.2

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 (77) hide show
  1. package/dist-cjs/common/BuiltinSchemas.js +24 -5
  2. package/dist-cjs/common/BuiltinSchemas.js.map +1 -1
  3. package/dist-cjs/common/FilterQuery.js +4 -15
  4. package/dist-cjs/common/FilterQuery.js.map +1 -1
  5. package/dist-cjs/common/InferModel.js +3 -0
  6. package/dist-cjs/common/InferModel.js.map +1 -0
  7. package/dist-cjs/common/JsonPatch.js +42 -225
  8. package/dist-cjs/common/JsonPatch.js.map +1 -1
  9. package/dist-cjs/common/SchemaValidator.js +100 -29
  10. package/dist-cjs/common/SchemaValidator.js.map +1 -1
  11. package/dist-cjs/index.js +3 -0
  12. package/dist-cjs/index.js.map +1 -1
  13. package/dist-cjs/lib/BaseService.js +6 -6
  14. package/dist-cjs/lib/BaseService.js.map +1 -1
  15. package/dist-cjs/lib/ConfigManager.js +18 -21
  16. package/dist-cjs/lib/ConfigManager.js.map +1 -1
  17. package/dist-cjs/lib/Exceptions.js +8 -1
  18. package/dist-cjs/lib/Exceptions.js.map +1 -1
  19. package/dist-cjs/lib/Logger.js +138 -65
  20. package/dist-cjs/lib/Logger.js.map +1 -1
  21. package/dist-cjs/models/AppModel.js +17 -3
  22. package/dist-cjs/models/AppModel.js.map +1 -1
  23. package/dist-cjs/models/Application.js +51 -12
  24. package/dist-cjs/models/Application.js.map +1 -1
  25. package/dist-cjs/models/BaseModel.js.map +1 -1
  26. package/dist-cjs/models/BuiltinModel.js +8 -0
  27. package/dist-cjs/models/BuiltinModel.js.map +1 -0
  28. package/dist-cjs/models/User.js +12 -3
  29. package/dist-cjs/models/User.js.map +1 -1
  30. package/dist-esm/common/BuiltinSchemas.js +23 -4
  31. package/dist-esm/common/BuiltinSchemas.js.map +1 -1
  32. package/dist-esm/common/FilterQuery.js +5 -16
  33. package/dist-esm/common/FilterQuery.js.map +1 -1
  34. package/dist-esm/common/InferModel.js +2 -0
  35. package/dist-esm/common/InferModel.js.map +1 -0
  36. package/dist-esm/common/JsonPatch.js +44 -227
  37. package/dist-esm/common/JsonPatch.js.map +1 -1
  38. package/dist-esm/common/SchemaValidator.js +100 -29
  39. package/dist-esm/common/SchemaValidator.js.map +1 -1
  40. package/dist-esm/index.js +3 -0
  41. package/dist-esm/index.js.map +1 -1
  42. package/dist-esm/lib/BaseService.js +8 -8
  43. package/dist-esm/lib/BaseService.js.map +1 -1
  44. package/dist-esm/lib/ConfigManager.js +18 -21
  45. package/dist-esm/lib/ConfigManager.js.map +1 -1
  46. package/dist-esm/lib/Exceptions.js +6 -0
  47. package/dist-esm/lib/Exceptions.js.map +1 -1
  48. package/dist-esm/lib/Logger.js +139 -66
  49. package/dist-esm/lib/Logger.js.map +1 -1
  50. package/dist-esm/models/AppModel.js +17 -3
  51. package/dist-esm/models/AppModel.js.map +1 -1
  52. package/dist-esm/models/Application.js +52 -13
  53. package/dist-esm/models/Application.js.map +1 -1
  54. package/dist-esm/models/BaseModel.js.map +1 -1
  55. package/dist-esm/models/BuiltinModel.js +4 -0
  56. package/dist-esm/models/BuiltinModel.js.map +1 -0
  57. package/dist-esm/models/User.js +11 -2
  58. package/dist-esm/models/User.js.map +1 -1
  59. package/dist-types/common/BuiltinSchemas.d.ts +59 -5
  60. package/dist-types/common/FilterQuery.d.ts +3 -11
  61. package/dist-types/common/InferModel.d.ts +29 -0
  62. package/dist-types/common/JsonPatch.d.ts +4 -45
  63. package/dist-types/common/ModelTypes.d.ts +1 -0
  64. package/dist-types/common/QueuePayloads.d.ts +48 -26
  65. package/dist-types/common/SchemaValidator.d.ts +42 -2
  66. package/dist-types/index.d.ts +3 -0
  67. package/dist-types/lib/BaseService.d.ts +8 -1
  68. package/dist-types/lib/ConfigManager.d.ts +6 -12
  69. package/dist-types/lib/Exceptions.d.ts +4 -0
  70. package/dist-types/lib/Logger.d.ts +84 -14
  71. package/dist-types/models/AppModel.d.ts +31 -5
  72. package/dist-types/models/Application.d.ts +36 -8
  73. package/dist-types/models/BaseModel.d.ts +14 -12
  74. package/dist-types/models/BuiltinModel.d.ts +3 -0
  75. package/dist-types/models/User.d.ts +15 -13
  76. package/package.json +4 -4
  77. package/src/schemas/winston-logger.schema.json +51 -6
@@ -1,6 +1,15 @@
1
- import { NexxusBaseModel, MODEL_REGISTRY } from "./BaseModel";
1
+ import { MODEL_REGISTRY } from "./BaseModel";
2
+ import { NexxusBuiltinModel } from "./BuiltinModel";
3
+ import { NEXXUS_BUILTIN_MODEL_SCHEMAS } from "../common/BuiltinSchemas";
2
4
  import { InvalidUserModelException } from "../lib/Exceptions";
3
- export class NexxusApplicationUser extends NexxusBaseModel {
5
+ export class NexxusUser extends NexxusBuiltinModel {
6
+ static getModelSchema(userDetails) {
7
+ const base = { ...NEXXUS_BUILTIN_MODEL_SCHEMAS.user };
8
+ if (userDetails) {
9
+ base.details = { type: 'object', required: false, properties: userDetails };
10
+ }
11
+ return base;
12
+ }
4
13
  constructor(data) {
5
14
  super({ ...data, type: MODEL_REGISTRY.user });
6
15
  if (this.data.appId === undefined || typeof this.data.appId !== 'string') {
@@ -1 +1 @@
1
- {"version":3,"file":"User.js","sourceRoot":"","sources":["../../src/models/User.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EAEf,cAAc,EACf,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AAgB9D,MAAM,OAAO,qBAAsB,SAAQ,eAAoC;IAC7E,YAAY,IAAyB;QACnC,KAAK,CAAC,EAAE,GAAG,IAAI,EAAE,IAAI,EAAE,cAAc,CAAC,IAAI,EAAE,CAAC,CAAC;QAE9C,IAAI,IAAI,CAAC,IAAI,CAAC,KAAK,KAAK,SAAS,IAAI,OAAO,IAAI,CAAC,IAAI,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;YACzE,MAAM,IAAI,yBAAyB,CAAC,+CAA+C,CAAC,CAAC;QACvF,CAAC;QAED,IAAI,IAAI,CAAC,IAAI,CAAC,QAAQ,KAAK,SAAS,IAAI,OAAO,IAAI,CAAC,IAAI,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;YAC/E,MAAM,IAAI,yBAAyB,CAAC,kDAAkD,CAAC,CAAC;QAC1F,CAAC;QAED,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,KAAK,SAAS,IAAI,IAAI,CAAC,IAAI,CAAC,QAAQ,KAAK,IAAI,CAAC,IAAI,OAAO,IAAI,CAAC,IAAI,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;YAChH,MAAM,IAAI,yBAAyB,CAAC,8CAA8C,CAAC,CAAC;QACtF,CAAC;QAED,IAAI,IAAI,CAAC,IAAI,CAAC,aAAa,KAAK,SAAS,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,EAAE,KAAK,QAAQ,CAAC,EAAE,CAAC;YACnJ,MAAM,IAAI,yBAAyB,CAAC,kEAAkE,CAAC,CAAC;QAC1G,CAAC;QAED,IAAI,IAAI,CAAC,IAAI,CAAC,OAAO,KAAK,SAAS,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;YACzE,MAAM,IAAI,yBAAyB,CAAC,4CAA4C,CAAC,CAAC;QACpF,CAAC;aAAM,CAAC;YACN,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,OAAO,QAAQ,KAAK,QAAQ,CAAC,CAAC;YAExF,IAAI,CAAC,aAAa,EAAE,CAAC;gBACnB,MAAM,IAAI,yBAAyB,CAAC,4CAA4C,CAAC,CAAC;YACpF,CAAC;QACH,CAAC;QAED,IAAI,OAAO,IAAI,CAAC,IAAI,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;YAC3C,MAAM,IAAI,yBAAyB,CAAC,kCAAkC,CAAC,CAAC;QAC1E,CAAC;QAED,IAAI,IAAI,CAAC,IAAI,CAAC,OAAO,KAAK,SAAS,IAAI,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;YAC7E,MAAM,IAAI,yBAAyB,CAAC,8CAA8C,CAAC,CAAC;QACtF,CAAC;IACH,CAAC;CACF"}
1
+ {"version":3,"file":"User.js","sourceRoot":"","sources":["../../src/models/User.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  /**
2
- * Universal fields present in all models
3
- * Note: 'type' and 'appId' are excluded as they are handled separately in queries
2
+ * Universal fields present in all models (auto-managed by NexxusBaseModel).
3
+ * 'type' and 'appId' are excluded as they are handled separately in queries.
4
4
  */
5
5
  export declare const NEXXUS_UNIVERSAL_FIELDS: {
6
6
  readonly id: {
@@ -17,13 +17,31 @@ export declare const NEXXUS_UNIVERSAL_FIELDS: {
17
17
  };
18
18
  };
19
19
  /**
20
- * Schema definitions for built-in (reserved) models. Only used for
20
+ * Field names reserved by Nexxus across ALL app models. App developers cannot
21
+ * declare a field of these names in their application schemas — the
22
+ * `NexxusApplication` constructor enforces this on schema registration.
23
+ *
24
+ * Most of these are caller-settable at model construction time (e.g. `appId`,
25
+ * `userId`, `type` — set by the API/Worker). `version` is the sole exception:
26
+ * it's set exclusively by the database adapter and rejected from user input
27
+ * (see the inline check in `NexxusSchemaValidator.validateAgainstSchema`).
28
+ */
29
+ export declare const NEXXUS_RESERVED_FIELD_NAMES: ReadonlySet<string>;
30
+ /**
31
+ * Schema definitions for built-in (reserved) models. These are the runtime
32
+ * source of truth for built-in model field shapes; the corresponding TS
33
+ * interfaces (INexxusUser, INexxusApplication) are derived from these.
21
34
  */
22
35
  export declare const NEXXUS_BUILTIN_MODEL_SCHEMAS: {
23
36
  readonly user: {
37
+ readonly appId: {
38
+ readonly type: "string";
39
+ readonly required: true;
40
+ readonly filterable: true;
41
+ };
24
42
  readonly userType: {
25
43
  readonly type: "string";
26
- readonly required: false;
44
+ readonly required: true;
27
45
  readonly filterable: true;
28
46
  };
29
47
  readonly username: {
@@ -33,7 +51,8 @@ export declare const NEXXUS_BUILTIN_MODEL_SCHEMAS: {
33
51
  };
34
52
  readonly password: {
35
53
  readonly type: "string";
36
- readonly required: false;
54
+ readonly required: true;
55
+ readonly nullable: true;
37
56
  };
38
57
  readonly authProviders: {
39
58
  readonly type: "array";
@@ -57,6 +76,41 @@ export declare const NEXXUS_BUILTIN_MODEL_SCHEMAS: {
57
76
  readonly required: true;
58
77
  readonly filterable: true;
59
78
  };
79
+ readonly description: {
80
+ readonly type: "string";
81
+ readonly required: false;
82
+ };
83
+ /**
84
+ * Per-application auth block. When `authEnabled` is true this must be
85
+ * present and contain a non-empty `strategies` map; when false it should
86
+ * be absent or have an empty `strategies`. The conditional rule isn't
87
+ * expressible in the static schema — it's enforced imperatively in the
88
+ * `NexxusApplication` constructor.
89
+ *
90
+ * `strategies` is a free-form map keyed by strategy name (e.g. 'local',
91
+ * 'google'). The shape of each value is validated by that strategy's
92
+ * own JSON Schema, loaded by the `NexxusAuthStrategy` base class.
93
+ */
94
+ readonly auth: {
95
+ readonly type: "object";
96
+ readonly required: false;
97
+ readonly nullable: true;
98
+ readonly properties: {
99
+ readonly jwtSecret: {
100
+ readonly type: "string";
101
+ readonly required: true;
102
+ };
103
+ readonly jwtExpiresIn: {
104
+ readonly type: "string";
105
+ readonly required: false;
106
+ };
107
+ readonly strategies: {
108
+ readonly type: "object";
109
+ readonly required: true;
110
+ readonly properties: {};
111
+ };
112
+ };
113
+ };
60
114
  };
61
115
  };
62
116
  /**
@@ -1,7 +1,5 @@
1
1
  import type { NexxusModelDef } from '../common/ModelTypes';
2
- import { type NexxusBuiltinModelType } from './BuiltinSchemas';
3
- import type { NexxusAppModelType } from '../models/AppModel';
4
- import type { NexxusUserDetailSchema } from '../models/User';
2
+ import type { INexxusAppModel } from '../models/AppModel';
5
3
  export type NexxusComparisonOperator = 'gte' | 'lte' | 'gt' | 'lt' | 'ne' | 'in';
6
4
  export type NexxusLogicalOperator = '$and' | '$or';
7
5
  export type NexxusFieldValue = string | number | boolean;
@@ -30,21 +28,15 @@ type FilterNodeWithContext = FilterNode & {
30
28
  depth: number;
31
29
  parentOperator?: NexxusLogicalOperator;
32
30
  };
33
- export type NexxusFilterQueryConfig = {
34
- appModelDef: NexxusModelDef;
35
- } | {
36
- modelType: NexxusBuiltinModelType;
37
- userDetailsSchema?: NexxusUserDetailSchema;
38
- };
39
31
  export declare class NexxusFilterQuery {
40
32
  private query;
41
33
  private nodes;
42
34
  private modelDef;
43
- constructor(query: NexxusFilterQueryType, config: NexxusFilterQueryConfig);
35
+ constructor(query: NexxusFilterQueryType, schema: NexxusModelDef);
44
36
  getNodes(): FilterNode[];
45
37
  getNormalizedQuery(): NexxusFilterQueryType;
46
38
  [Symbol.iterator](): Generator<FilterNodeWithContext>;
47
- test(object: Partial<NexxusAppModelType>): boolean;
39
+ test(object: Partial<INexxusAppModel>): boolean;
48
40
  private testNode;
49
41
  private validateAndParse;
50
42
  private parseQuery;
@@ -0,0 +1,29 @@
1
+ export type InferFieldDef<D> = D extends {
2
+ type: 'string';
3
+ } ? string : D extends {
4
+ type: 'number';
5
+ } ? number : D extends {
6
+ type: 'boolean';
7
+ } ? boolean : D extends {
8
+ type: 'date';
9
+ } ? number : D extends {
10
+ type: 'array';
11
+ arrayType: infer AT;
12
+ properties?: infer P;
13
+ } ? AT extends 'object' ? P extends Record<string, any> ? Array<InferModel<P>> : never : AT extends 'string' ? string[] : AT extends 'number' ? number[] : AT extends 'boolean' ? boolean[] : AT extends 'date' ? number[] : never : D extends {
14
+ type: 'object';
15
+ properties: infer P;
16
+ } ? P extends Record<string, any> ? InferModel<P> : never : never;
17
+ type ApplyNullable<D, T> = D extends {
18
+ nullable: true;
19
+ } ? T | null : T;
20
+ export type InferModel<S> = {
21
+ -readonly [K in keyof S as S[K] extends {
22
+ required: true;
23
+ } ? K : never]: ApplyNullable<S[K], InferFieldDef<S[K]>>;
24
+ } & {
25
+ -readonly [K in keyof S as S[K] extends {
26
+ required: true;
27
+ } ? never : K]?: ApplyNullable<S[K], InferFieldDef<S[K]>>;
28
+ };
29
+ export {};
@@ -1,8 +1,5 @@
1
- import { NexxusApplicationSchema } from '../models/Application';
2
- import type { NexxusModelFieldType } from '../common/ModelTypes';
3
- import { NexxusAppModelType } from '../models/AppModel';
4
- import { NexxusBuiltinModelType } from './BuiltinSchemas';
5
- import type { NexxusUserDetailSchema } from '../models/User';
1
+ import type { NexxusModelDef, NexxusModelFieldType } from '../common/ModelTypes';
2
+ import { INexxusAppModel } from '../models/AppModel';
6
3
  declare const JSON_OPS: readonly ["replace", "append", "prepend", "incr", "decr"];
7
4
  export type NexxusJsonPatchConstructor = {
8
5
  op: typeof JSON_OPS[number];
@@ -26,12 +23,6 @@ type NexxusJsonPatchMetadataInternal = NexxusJsonPatchMetadata & {
26
23
  pathFieldTypes?: NexxusModelFieldType[];
27
24
  };
28
25
  export type NexxusJsonPatchMetadataConstructor = Omit<NexxusJsonPatchMetadata, 'pathFieldTypes'>;
29
- export type NexxusJsonPatchValidationConfig = {
30
- appSchema: NexxusApplicationSchema;
31
- } | {
32
- modelType: NexxusBuiltinModelType;
33
- userDetailsSchema?: NexxusUserDetailSchema;
34
- };
35
26
  export declare class NexxusJsonPatch {
36
27
  private valid;
37
28
  private fullPatch;
@@ -39,40 +30,8 @@ export declare class NexxusJsonPatch {
39
30
  constructor(fullPatch: NexxusJsonPatchConstructor | NexxusJsonPatchInternal);
40
31
  get(): NexxusJsonPatchInternal;
41
32
  isValid(): boolean;
42
- getPartialModel(): Partial<NexxusAppModelType>;
43
- validate(config: NexxusJsonPatchValidationConfig): void;
44
- private static validateAgainstType;
33
+ getPartialModel(): Partial<INexxusAppModel>;
34
+ validate(schema: NexxusModelDef): void;
45
35
  private static traverseSchema;
46
- private static validateValueType;
47
- /**
48
- * Validate string type
49
- */
50
- private static validateString;
51
- /**
52
- * Validate number type
53
- */
54
- private static validateNumber;
55
- /**
56
- * Validate boolean type
57
- */
58
- private static validateBoolean;
59
- /**
60
- * Validate date type
61
- */
62
- private static validateDate;
63
- /**
64
- * Validate object type (recursively validates properties)
65
- */
66
- private static validateObject;
67
- /**
68
- * Validate array type (recursively validates elements)
69
- */
70
- private static validateArray;
71
- /**
72
- * Helper to validate primitive types (reusable for arrays)
73
- */
74
- private static validatePrimitiveType;
75
- private static isObjectFieldDef;
76
- private static isArrayFieldDef;
77
36
  }
78
37
  export {};
@@ -3,6 +3,7 @@ export type NexxusModelFieldType = NexxusModelPrimitiveType | 'array' | 'object'
3
3
  interface BaseFieldDef {
4
4
  type: NexxusModelFieldType;
5
5
  required?: boolean;
6
+ nullable?: boolean;
6
7
  }
7
8
  export interface PrimitiveFieldDef extends BaseFieldDef {
8
9
  type: NexxusModelPrimitiveType;
@@ -1,4 +1,4 @@
1
- import { NexxusAppModelType } from '../models/AppModel';
1
+ import { INexxusAppModel } from '../models/AppModel';
2
2
  import { NexxusJsonPatchInternal, NexxusJsonPatchMetadata } from '../common/JsonPatch';
3
3
  export interface NexxusBaseQueuePayload {
4
4
  event: string;
@@ -6,65 +6,87 @@ export interface NexxusBaseQueuePayload {
6
6
  }
7
7
  export type NexxusModelCreatedPayload = {
8
8
  event: 'model_created';
9
- data: NexxusAppModelType;
9
+ data: INexxusAppModel;
10
10
  };
11
11
  export type NexxusModelUpdatedPayload = {
12
12
  event: 'model_updated';
13
13
  data: Array<NexxusJsonPatchInternal>;
14
14
  };
15
- export type NexxusModelDeletedData = Pick<NexxusAppModelType, 'id' | 'type' | 'appId' | 'userId'>;
15
+ export type NexxusModelDeletedData = Pick<INexxusAppModel, 'id' | 'type' | 'appId' | 'userId'>;
16
16
  export type NexxusModelDeletedPayload = {
17
17
  event: 'model_deleted';
18
18
  data: NexxusModelDeletedData;
19
19
  };
20
20
  export type NexxusWriterPayload = NexxusModelCreatedPayload | NexxusModelUpdatedPayload | NexxusModelDeletedPayload;
21
- export type NexxusTransportManagetJsonPatch = Omit<NexxusJsonPatchInternal, 'metadata'> & {
21
+ export type NexxusTransportManagerJsonPatch = Omit<NexxusJsonPatchInternal, 'metadata'> & {
22
22
  metadata: NexxusJsonPatchMetadata & {
23
- partialModel: Partial<NexxusAppModelType>;
23
+ partialModel: Partial<INexxusAppModel>;
24
24
  };
25
25
  };
26
26
  export type NexxusTransportManagerModelUpdatedPayload = {
27
27
  event: 'model_updated';
28
- data: Array<NexxusTransportManagetJsonPatch>;
28
+ data: Array<NexxusTransportManagerJsonPatch>;
29
29
  };
30
30
  export type NexxusTransportManagerPayload = NexxusModelCreatedPayload | NexxusTransportManagerModelUpdatedPayload | NexxusModelDeletedPayload;
31
- export interface NexxusWebSocketJsonPatchMetadata {
32
- id: string;
31
+ /**
32
+ * Metadata for transport-bound model events (create/update/delete alike).
33
+ * Carries the channels that matched the subscription router for this device,
34
+ * so the client can correlate the event with its local subscription containers.
35
+ */
36
+ export interface NexxusTransportMetadata {
33
37
  channels: Array<string>;
34
38
  }
35
39
  /**
36
- * JsonPatch type for WebSocket transport workers
40
+ * Payload for any transport worker - model created
41
+ */
42
+ export type NexxusTransportModelCreatedPayload = {
43
+ event: 'model_created';
44
+ model: INexxusAppModel;
45
+ metadata: NexxusTransportMetadata;
46
+ };
47
+ /**
48
+ * Payload for any transport worker - model deleted
37
49
  */
38
- export type NexxusWebSocketJsonPatch = Omit<NexxusJsonPatchInternal, 'metadata'> & {
39
- metadata: NexxusWebSocketJsonPatchMetadata;
50
+ export type NexxusTransportModelDeletedPayload = {
51
+ event: 'model_deleted';
52
+ model: NexxusModelDeletedData;
53
+ metadata: NexxusTransportMetadata;
40
54
  };
41
55
  /**
42
- * Payload for WebSocket Transport - slim metadata with just channel
56
+ * Payload for any transport worker - model updated.
57
+ * All patches in a single event target the same model — its identity is hoisted
58
+ * into `model`, and the matched channels into top-level `metadata`. Per-patch
59
+ * metadata is intentionally absent (it was redundant across patches of the same
60
+ * update event under the previous shape).
43
61
  */
44
- export type NexxusWebSocketModelUpdatedPayload = {
62
+ export type NexxusTransportModelUpdatedPayload = {
45
63
  event: 'model_updated';
46
- data: Array<NexxusWebSocketJsonPatch>;
64
+ /**
65
+ * Includes `version` — the post-update version stamp assigned by the adapter.
66
+ * Clients use it for gap detection: apply if `model.version === local.version + 1`,
67
+ * request a fresh GET if there's a gap, ignore if it's already been applied.
68
+ */
69
+ model: Pick<INexxusAppModel, 'id' | 'type' | 'appId' | 'userId' | 'version'>;
70
+ patches: Array<Omit<NexxusJsonPatchInternal, 'metadata'>>;
71
+ metadata: NexxusTransportMetadata;
47
72
  };
48
- export type NexxusWebsocketPayload = {
73
+ /**
74
+ * Canonical payload consumed by ALL transport workers (volatile and persistent alike).
75
+ * The shape is identical across transports; each transport translates the inner `data`
76
+ * into its own wire format inside its `sendToDevice` implementation.
77
+ */
78
+ export type NexxusTransportWorkerPayload = {
49
79
  event: 'device_message';
50
80
  deviceIds: Array<string>;
51
- data: NexxusModelCreatedPayload | NexxusWebSocketModelUpdatedPayload | NexxusModelDeletedPayload;
52
- };
53
- export type NexxusMqttPayload = {
54
- event: 'mqtt_publish';
55
- topic: string;
56
- payload: Buffer;
57
- } | {
58
- event: 'mqtt_subscribe';
59
- topic: string;
81
+ data: NexxusTransportModelCreatedPayload | NexxusTransportModelUpdatedPayload | NexxusTransportModelDeletedPayload;
60
82
  };
61
83
  export interface NexxusBuiltInQueuePayloadMap {
62
84
  'writer': NexxusWriterPayload;
63
85
  'transport-manager': NexxusTransportManagerPayload;
64
86
  }
65
87
  export interface NexxusDynamicQueuePayloadMap {
66
- 'websockets-transport': NexxusWebsocketPayload;
67
- 'mqtt-transport': NexxusMqttPayload;
88
+ 'websockets-transport': NexxusTransportWorkerPayload;
89
+ 'mqtt-transport': NexxusTransportWorkerPayload;
68
90
  }
69
91
  export type NexxusBuiltInQueueName = keyof NexxusBuiltInQueuePayloadMap;
70
92
  export type NexxusDynamicQueueType = keyof NexxusDynamicQueuePayloadMap;
@@ -1,4 +1,44 @@
1
- import { NexxusUserDetailSchema } from "../models/User";
1
+ import type { NexxusFieldDef, NexxusModelDef } from './ModelTypes';
2
+ /**
3
+ * Pure schema-aware validation + normalization for a single value against a
4
+ * field definition, or for whole-model data against a model definition.
5
+ *
6
+ * Returns a normalized copy of the input value (e.g. date strings become
7
+ * integer timestamps). Throws InvalidSchemaDataException on the first violation.
8
+ *
9
+ * Used by:
10
+ * - NexxusJsonPatch (per-path validation on patch operations)
11
+ * - NexxusAppModel (whole-model validation on construction)
12
+ *
13
+ * Required-field checking is intentionally NOT performed here yet; only fields
14
+ * present in the input are validated.
15
+ */
2
16
  export declare class NexxusSchemaValidator {
3
- static validateUserDetails(partialDetails: Record<string, any>, userDetailSchema: NexxusUserDetailSchema): boolean;
17
+ /**
18
+ * Validate every present field of `data` against the model definition.
19
+ * Returns a shallow-merged copy of `data` with each value normalized.
20
+ * Unknown fields (present in data but not declared in modelDef) are passed
21
+ * through unchanged.
22
+ */
23
+ static validateAgainstSchema(data: Record<string, unknown>, modelDef: NexxusModelDef): Record<string, unknown>;
24
+ /**
25
+ * Validate a single value against a field definition. Returns the normalized
26
+ * value. Throws InvalidSchemaDataException on failure.
27
+ *
28
+ * `path` is used only for error messages.
29
+ */
30
+ static validateValue(value: unknown, fieldDef: NexxusFieldDef, path: string): unknown;
31
+ private static validateString;
32
+ private static validateNumber;
33
+ private static validateBoolean;
34
+ /**
35
+ * Accepts: number (ms timestamp), ISO date string, or numeric string.
36
+ * Returns: integer ms timestamp.
37
+ *
38
+ * This is the single canonical date parser for the system; the previous
39
+ * inconsistency between `Date.parse()` and `new Date(s).getTime()` is gone.
40
+ */
41
+ private static validateDate;
42
+ private static validateObject;
43
+ private static validateArray;
4
44
  }
@@ -6,7 +6,10 @@ export * from "./lib/Logger";
6
6
  export * from "./common/QueuePayloads";
7
7
  export * from "./common/JsonPatch";
8
8
  export * from "./common/FilterQuery";
9
+ export * from "./common/InferModel";
10
+ export * from "./common/SchemaValidator";
9
11
  export * from "./models/BaseModel";
12
+ export * from "./models/BuiltinModel";
10
13
  export * from './common/BuiltinSchemas';
11
14
  export * from "./models/AppModel";
12
15
  export * from "./models/Application";
@@ -1,5 +1,5 @@
1
1
  import type { ConfigEnvVars, ConfigCliArgs, AddJsonSchemaDefFuncArg, NexxusConfigManager } from './ConfigManager';
2
- import type { NexxusBaseLogger } from "./Logger";
2
+ import type { NexxusBaseLogger } from './Logger';
3
3
  import { NexxusConfig } from './ConfigProvider';
4
4
  export type EventMap = Record<string | symbol, any[]>;
5
5
  export interface INexxusBaseServices {
@@ -18,6 +18,13 @@ export declare abstract class NexxusBaseService<T extends NexxusConfig, Ev exten
18
18
  protected config: Readonly<T>;
19
19
  protected static envVars: ConfigEnvVars;
20
20
  protected static cliArgs: ConfigCliArgs;
21
+ /**
22
+ * The top-level key under which this service's configuration sits in the merged
23
+ * root config (e.g. "logger", "database", "redis", "app"). Required for every
24
+ * concrete service — ConfigManager uses it as the property name when grafting
25
+ * the service's schema definition into the root JSON Schema.
26
+ */
27
+ protected static configRootKey: string;
21
28
  protected static schemaPath: string;
22
29
  private static schemaContents;
23
30
  constructor(config: Readonly<T>);
@@ -9,21 +9,17 @@ export type AddJsonSchemaDefFuncArg = {
9
9
  };
10
10
  type EnvVarsSpec = {
11
11
  name: string;
12
+ /** Dot-notation path relative to the service's configRootKey (e.g. "host", "auth.jwtSecret"). */
12
13
  location: string;
13
14
  };
14
- export type ConfigEnvVars = {
15
- source: string;
16
- specs: Array<EnvVarsSpec>;
17
- };
15
+ export type ConfigEnvVars = Array<EnvVarsSpec>;
18
16
  type CliArgsSpec = {
19
17
  name: string;
18
+ /** Dot-notation path relative to the service's configRootKey. */
20
19
  location: string;
21
20
  type: CliArgType;
22
21
  };
23
- export type ConfigCliArgs = {
24
- source: string;
25
- specs: Array<CliArgsSpec>;
26
- };
22
+ export type ConfigCliArgs = Array<CliArgsSpec>;
27
23
  export declare class NexxusConfigManager {
28
24
  private static CONF_FILE_NAME;
29
25
  private jsonSchema;
@@ -32,12 +28,10 @@ export declare class NexxusConfigManager {
32
28
  private data;
33
29
  private configProviders;
34
30
  private customProviders;
35
- constructor(confFile?: string);
31
+ constructor(configFileName?: string);
36
32
  addCustomProvider(provider: INexxusConfigProvider): void;
37
33
  private addJsonSchemaDef;
38
- validateServices(svcs: Array<typeof NexxusBaseService>): void;
39
- private addCliArgsToSpec;
40
- private addEnvVarsToSpec;
34
+ validateServices(svcs: Array<typeof NexxusBaseService>): Promise<void>;
41
35
  private populateFromCliArgs;
42
36
  private populateFromEnvVars;
43
37
  private populateFromCustomProviders;
@@ -5,6 +5,7 @@ export declare enum NexxusExceptions {
5
5
  INVALID_CONFIG = "InvalidConfigException",
6
6
  INVALID_JSON_PATCH = "InvalidJsonPatchException",
7
7
  INVALID_QUERY_FILTER = "InvalidQueryFilterException",
8
+ INVALID_SCHEMA_DATA = "InvalidSchemaDataException",
8
9
  INVALID_USER_MODEL = "InvalidUserModelException"
9
10
  }
10
11
  export declare class NexxusException extends Error {
@@ -28,6 +29,9 @@ export declare class InvalidJsonPatchException extends NexxusException {
28
29
  export declare class InvalidQueryFilterException extends NexxusException {
29
30
  constructor(message: string);
30
31
  }
32
+ export declare class InvalidSchemaDataException extends NexxusException {
33
+ constructor(message: string);
34
+ }
31
35
  export declare class InvalidUserModelException extends NexxusException {
32
36
  constructor(message: string);
33
37
  }
@@ -1,7 +1,7 @@
1
1
  import { ConfigEnvVars, ConfigCliArgs } from './ConfigManager';
2
2
  import { NexxusBaseService, INexxusBaseServices } from './BaseService';
3
3
  import { NexxusConfig } from './ConfigProvider';
4
- type LoggableType = string | object | number | boolean | null | undefined;
4
+ export type LogAttributes = Record<string, unknown>;
5
5
  export declare const enum NexxusLoggerLevels {
6
6
  EMERGENCY = "emerg",
7
7
  ALERT = "alert",
@@ -12,37 +12,107 @@ export declare const enum NexxusLoggerLevels {
12
12
  INFO = "info",
13
13
  DEBUG = "debug"
14
14
  }
15
+ export type StdoutTransportConfig = {
16
+ type: 'stdout';
17
+ };
18
+ export type FileTransportConfig = {
19
+ type: 'file';
20
+ filename: string;
21
+ maxSize?: number;
22
+ maxFiles?: number;
23
+ };
24
+ /**
25
+ * Catch-all for transports loaded dynamically from npm packages. The `type`
26
+ * field is the package name (e.g. "winston-papertrail"); `export` optionally
27
+ * names the class export within the package; `options` is the passthrough
28
+ * config object handed to the transport's constructor.
29
+ *
30
+ * The schema's `oneOf` discriminator excludes built-in type strings from this
31
+ * variant, so the TS-side `type: string` doesn't cause ambiguity at runtime.
32
+ */
33
+ export type CustomTransportConfig = {
34
+ type: string;
35
+ export?: string;
36
+ options?: Record<string, unknown>;
37
+ };
38
+ export type WinstonNexxusTransportConfig = StdoutTransportConfig | FileTransportConfig | CustomTransportConfig;
15
39
  type WinstonNexxusLoggerConfig = {
16
40
  level: NexxusLoggerLevels;
17
41
  logType: "json" | "text";
18
42
  timestamps: boolean;
19
43
  colors: boolean;
44
+ transports?: Array<WinstonNexxusTransportConfig>;
20
45
  } & NexxusConfig;
21
46
  export interface INexxusLogger {
22
- log(level: NexxusLoggerLevels, message: LoggableType, label?: string): void;
47
+ log(level: NexxusLoggerLevels, message: string, attributes?: LogAttributes, label?: string): void;
23
48
  }
24
- export interface INexxusAsyncLogger extends INexxusLogger {
25
- log(level: NexxusLoggerLevels, message: LoggableType, label?: string): Promise<void>;
49
+ export interface INexxusAsyncLogger {
50
+ log(level: NexxusLoggerLevels, message: string, attributes?: LogAttributes, label?: string): Promise<void>;
26
51
  }
27
52
  interface NexxusLoggerServices extends Omit<INexxusBaseServices, 'logger'> {
28
53
  }
29
54
  export declare abstract class NexxusBaseLogger<T extends NexxusConfig> extends NexxusBaseService<T> implements INexxusLogger {
55
+ protected static configRootKey: string;
30
56
  constructor(services: NexxusLoggerServices);
31
- abstract log(level: NexxusLoggerLevels, message: LoggableType, label?: string): void;
32
- debug(message: LoggableType, label?: string): void;
33
- info(message: LoggableType, label?: string): void;
34
- warn(message: LoggableType, label?: string): void;
35
- error(message: LoggableType, label?: string): void;
36
- critical(message: LoggableType, label?: string): void;
37
- alert(message: LoggableType, label?: string): void;
38
- emerg(message: LoggableType, label?: string): void;
57
+ abstract log(level: NexxusLoggerLevels, message: string, attributes?: LogAttributes, label?: string): void;
58
+ protected static serializeError(err: Error): Record<string, unknown>;
59
+ protected static makeSafeReplacer(): (key: string, value: unknown) => unknown;
60
+ protected static safeStringify(value: unknown): string;
61
+ debug(message: string, label?: string): void;
62
+ debug(message: string, attributes: LogAttributes, label?: string): void;
63
+ info(message: string, label?: string): void;
64
+ info(message: string, attributes: LogAttributes, label?: string): void;
65
+ warn(message: string, label?: string): void;
66
+ warn(message: string, attributes: LogAttributes, label?: string): void;
67
+ error(message: string, label?: string): void;
68
+ error(message: string, attributes: LogAttributes, label?: string): void;
69
+ critical(message: string, label?: string): void;
70
+ critical(message: string, attributes: LogAttributes, label?: string): void;
71
+ alert(message: string, label?: string): void;
72
+ alert(message: string, attributes: LogAttributes, label?: string): void;
73
+ emerg(message: string, label?: string): void;
74
+ emerg(message: string, attributes: LogAttributes, label?: string): void;
75
+ private dispatch;
39
76
  }
40
77
  export declare class WinstonNexxusLogger extends NexxusBaseLogger<WinstonNexxusLoggerConfig> {
41
78
  private winston;
42
79
  protected static schemaPath: string;
43
80
  protected static envVars: ConfigEnvVars;
44
81
  protected static cliArgs: ConfigCliArgs;
45
- constructor(services: NexxusLoggerServices);
46
- log(level: NexxusLoggerLevels, message: LoggableType, label?: string): void;
82
+ /**
83
+ * Private use `WinstonNexxusLogger.create(...)` instead. Transport instances
84
+ * must be resolved (async, since custom ones are dynamically imported) before
85
+ * the Winston logger can be constructed; the factory owns that step.
86
+ */
87
+ private constructor();
88
+ /**
89
+ * Async factory. Custom transports are loaded via dynamic `import()` so
90
+ * initialization is unavoidably async. API/Worker bootstrap code should
91
+ * `await WinstonNexxusLogger.create(...)` in place of `new WinstonNexxusLogger(...)`.
92
+ */
93
+ static create(services: NexxusLoggerServices): Promise<WinstonNexxusLogger>;
94
+ /**
95
+ * Maps each transport config entry to a constructed Winston transport.
96
+ * Built-in types are instantiated synchronously; everything else falls
97
+ * through to `loadCustomTransport`, which dynamically imports the npm
98
+ * package named by `type`.
99
+ *
100
+ * If the config has no transports (undefined or empty array), defaults to
101
+ * a single Console transport so the logger is never silent.
102
+ */
103
+ private static resolveTransports;
104
+ /**
105
+ * Dynamically imports the npm package named by `transport.type` and instantiates
106
+ * its transport class. The class is resolved in priority order:
107
+ * 1. `mod[transport.export]` if `transport.export` is set in config
108
+ * 2. `mod.default` if it's a function/class (ESM default export)
109
+ * 3. The module itself if it's a function/class (CJS `module.exports = Cls`)
110
+ *
111
+ * On any failure (package missing, no resolvable class, constructor throws)
112
+ * we re-wrap as `InvalidConfigException` so the operator sees an actionable
113
+ * message rather than a raw module-resolution stack trace.
114
+ */
115
+ private static loadCustomTransport;
116
+ log(level: NexxusLoggerLevels, message: string, attributes?: LogAttributes, label?: string): void;
47
117
  }
48
118
  export {};