@zudojs/rpc 0.1.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. package/LICENSE +21 -0
  2. package/dist/index.d.ts +8 -4
  3. package/dist/index.js +3 -4
  4. package/dist/rpc/client/index.d.ts +1 -1
  5. package/dist/rpc/client/rpcClient.core.d.ts +57 -3
  6. package/dist/rpc/client/rpcClient.core.js +172 -32
  7. package/dist/rpc/constants/index.d.ts +1 -1
  8. package/dist/rpc/constants/index.js +1 -1
  9. package/dist/rpc/constants/rpcConstants.core.d.ts +18 -0
  10. package/dist/rpc/constants/rpcConstants.core.js +18 -0
  11. package/dist/rpc/dispatcher/index.d.ts +1 -0
  12. package/dist/rpc/dispatcher/rpcDispatcher.core.d.ts +48 -1
  13. package/dist/rpc/dispatcher/rpcDispatcher.core.js +104 -13
  14. package/dist/rpc/middleware/rpcMiddleware.core.d.ts +12 -0
  15. package/dist/rpc/middleware/rpcMiddleware.core.js +29 -6
  16. package/dist/rpc/procedure/rpcProcedure.type.d.ts +25 -3
  17. package/dist/rpc/procedure/rpcProcedure.type.js +9 -0
  18. package/dist/rpc/procedure/rpcProcedureRegistry.core.d.ts +15 -1
  19. package/dist/rpc/procedure/rpcProcedureRegistry.core.js +26 -1
  20. package/dist/rpc/procedure/rpcProcedureRouter.core.d.ts +1 -1
  21. package/dist/rpc/procedure/rpcProcedureRouter.core.js +5 -0
  22. package/dist/rpc/reliability/cancellation/rpcCancellation.helper.d.ts +30 -3
  23. package/dist/rpc/reliability/cancellation/rpcCancellation.helper.js +60 -4
  24. package/dist/rpc/reliability/deadline/rpcDeadline.helper.d.ts +14 -1
  25. package/dist/rpc/reliability/deadline/rpcDeadline.helper.js +23 -2
  26. package/dist/rpc/reliability/index.d.ts +5 -4
  27. package/dist/rpc/reliability/index.js +3 -3
  28. package/dist/rpc/reliability/retry/rpcRetry.helper.d.ts +22 -0
  29. package/dist/rpc/reliability/retry/rpcRetry.helper.js +80 -8
  30. package/dist/rpc/reliability/timeout/rpcTimeout.helper.d.ts +18 -2
  31. package/dist/rpc/reliability/timeout/rpcTimeout.helper.js +71 -7
  32. package/dist/rpc/server/index.d.ts +1 -0
  33. package/dist/rpc/server/rpcServer.core.d.ts +41 -2
  34. package/dist/rpc/server/rpcServer.core.js +82 -18
  35. package/dist/rpc/streaming/rpcStreaming.type.d.ts +9 -0
  36. package/dist/rpc/streaming/rpcStreaming.type.js +9 -0
  37. package/dist/rpc/transport/rpcTransport.type.d.ts +9 -1
  38. package/dist/rpc/validation/index.d.ts +3 -0
  39. package/dist/rpc/validation/index.js +2 -0
  40. package/dist/rpc/validation/rpcValidation.core.d.ts +81 -0
  41. package/dist/rpc/validation/rpcValidation.core.js +125 -0
  42. package/package.json +23 -16
  43. package/dist/.tsbuildinfo +0 -1
  44. package/dist/index.d.ts.map +0 -1
  45. package/dist/index.js.map +0 -1
  46. package/dist/rpc/client/index.d.ts.map +0 -1
  47. package/dist/rpc/client/index.js.map +0 -1
  48. package/dist/rpc/client/rpcClient.core.d.ts.map +0 -1
  49. package/dist/rpc/client/rpcClient.core.js.map +0 -1
  50. package/dist/rpc/constants/index.d.ts.map +0 -1
  51. package/dist/rpc/constants/index.js.map +0 -1
  52. package/dist/rpc/constants/rpcConstants.core.d.ts.map +0 -1
  53. package/dist/rpc/constants/rpcConstants.core.js.map +0 -1
  54. package/dist/rpc/context/index.d.ts.map +0 -1
  55. package/dist/rpc/context/index.js.map +0 -1
  56. package/dist/rpc/context/rpcContext.type.d.ts.map +0 -1
  57. package/dist/rpc/context/rpcContext.type.js.map +0 -1
  58. package/dist/rpc/dispatcher/index.d.ts.map +0 -1
  59. package/dist/rpc/dispatcher/index.js.map +0 -1
  60. package/dist/rpc/dispatcher/rpcDispatcher.core.d.ts.map +0 -1
  61. package/dist/rpc/dispatcher/rpcDispatcher.core.js.map +0 -1
  62. package/dist/rpc/errors/index.d.ts.map +0 -1
  63. package/dist/rpc/errors/index.js.map +0 -1
  64. package/dist/rpc/errors/rpc.errors.d.ts.map +0 -1
  65. package/dist/rpc/errors/rpc.errors.js.map +0 -1
  66. package/dist/rpc/interceptor/index.d.ts.map +0 -1
  67. package/dist/rpc/interceptor/index.js.map +0 -1
  68. package/dist/rpc/interceptor/rpcInterceptor.type.d.ts.map +0 -1
  69. package/dist/rpc/interceptor/rpcInterceptor.type.js.map +0 -1
  70. package/dist/rpc/middleware/index.d.ts.map +0 -1
  71. package/dist/rpc/middleware/index.js.map +0 -1
  72. package/dist/rpc/middleware/rpcMiddleware.core.d.ts.map +0 -1
  73. package/dist/rpc/middleware/rpcMiddleware.core.js.map +0 -1
  74. package/dist/rpc/procedure/index.d.ts.map +0 -1
  75. package/dist/rpc/procedure/index.js.map +0 -1
  76. package/dist/rpc/procedure/rpcProcedure.type.d.ts.map +0 -1
  77. package/dist/rpc/procedure/rpcProcedure.type.js.map +0 -1
  78. package/dist/rpc/procedure/rpcProcedureRegistry.core.d.ts.map +0 -1
  79. package/dist/rpc/procedure/rpcProcedureRegistry.core.js.map +0 -1
  80. package/dist/rpc/procedure/rpcProcedureRouter.core.d.ts.map +0 -1
  81. package/dist/rpc/procedure/rpcProcedureRouter.core.js.map +0 -1
  82. package/dist/rpc/reliability/cancellation/rpcCancellation.helper.d.ts.map +0 -1
  83. package/dist/rpc/reliability/cancellation/rpcCancellation.helper.js.map +0 -1
  84. package/dist/rpc/reliability/deadline/rpcDeadline.helper.d.ts.map +0 -1
  85. package/dist/rpc/reliability/deadline/rpcDeadline.helper.js.map +0 -1
  86. package/dist/rpc/reliability/index.d.ts.map +0 -1
  87. package/dist/rpc/reliability/index.js.map +0 -1
  88. package/dist/rpc/reliability/retry/rpcRetry.helper.d.ts.map +0 -1
  89. package/dist/rpc/reliability/retry/rpcRetry.helper.js.map +0 -1
  90. package/dist/rpc/reliability/timeout/rpcTimeout.helper.d.ts.map +0 -1
  91. package/dist/rpc/reliability/timeout/rpcTimeout.helper.js.map +0 -1
  92. package/dist/rpc/server/index.d.ts.map +0 -1
  93. package/dist/rpc/server/index.js.map +0 -1
  94. package/dist/rpc/server/rpcServer.core.d.ts.map +0 -1
  95. package/dist/rpc/server/rpcServer.core.js.map +0 -1
  96. package/dist/rpc/streaming/index.d.ts.map +0 -1
  97. package/dist/rpc/streaming/index.js.map +0 -1
  98. package/dist/rpc/streaming/rpcStreaming.type.d.ts.map +0 -1
  99. package/dist/rpc/streaming/rpcStreaming.type.js.map +0 -1
  100. package/dist/rpc/transport/index.d.ts.map +0 -1
  101. package/dist/rpc/transport/index.js.map +0 -1
  102. package/dist/rpc/transport/rpcTransport.type.d.ts.map +0 -1
  103. package/dist/rpc/transport/rpcTransport.type.js.map +0 -1
  104. package/dist/rpc/types/index.d.ts.map +0 -1
  105. package/dist/rpc/types/index.js.map +0 -1
  106. package/dist/rpc/types/rpcMetadata.type.d.ts.map +0 -1
  107. package/dist/rpc/types/rpcMetadata.type.js.map +0 -1
  108. package/dist/rpc/types/rpcProcedureName.type.d.ts.map +0 -1
  109. package/dist/rpc/types/rpcProcedureName.type.js.map +0 -1
  110. package/dist/rpc/types/rpcRequest.type.d.ts.map +0 -1
  111. package/dist/rpc/types/rpcRequest.type.js.map +0 -1
  112. package/dist/rpc/types/rpcResponse.type.d.ts.map +0 -1
  113. package/dist/rpc/types/rpcResponse.type.js.map +0 -1
  114. package/dist/testing/index.d.ts.map +0 -1
  115. package/dist/testing/index.js.map +0 -1
@@ -0,0 +1,125 @@
1
+ /**
2
+ * @zudojs/rpc/validation
3
+ *
4
+ * Request-level checks applied before a payload reaches a handler.
5
+ *
6
+ * Requests arrive from an untrusted peer over a transport, so these are
7
+ * the first checks the server runs, not the last.
8
+ */
9
+ import { RPCInvalidRequestError, RPCValidationError, } from "../errors/rpc.errors.js";
10
+ import { MAX_PROCEDURE_NAME_LENGTH, MAX_RPC_PAYLOAD_SIZE, PROCEDURE_NAME_PATTERN, } from "../constants/rpcConstants.core.js";
11
+ /**
12
+ * Validates a procedure name.
13
+ *
14
+ * Length is checked before the pattern so a pathological name cannot
15
+ * drive regex backtracking.
16
+ */
17
+ export function assertValidProcedureName(name) {
18
+ if (typeof name !== "string" || name.length === 0) {
19
+ throw new RPCInvalidRequestError("Procedure name must be a non-empty string.");
20
+ }
21
+ if (name.length > MAX_PROCEDURE_NAME_LENGTH) {
22
+ throw new RPCInvalidRequestError(`Procedure name exceeds ${MAX_PROCEDURE_NAME_LENGTH} characters.`);
23
+ }
24
+ if (!PROCEDURE_NAME_PATTERN.test(name)) {
25
+ throw new RPCInvalidRequestError(`Procedure name "${name}" must be dot-separated identifiers, e.g. "users.getUser".`);
26
+ }
27
+ }
28
+ /**
29
+ * Measures the encoded size of a payload in bytes.
30
+ *
31
+ * Returns `undefined` for a payload that cannot be encoded, which the
32
+ * caller reports as an invalid request rather than passing on.
33
+ */
34
+ export function measurePayloadBytes(payload) {
35
+ if (payload === undefined) {
36
+ return 0;
37
+ }
38
+ try {
39
+ const encoded = JSON.stringify(payload);
40
+ if (encoded === undefined) {
41
+ return undefined;
42
+ }
43
+ return Buffer.byteLength(encoded, "utf8");
44
+ }
45
+ catch {
46
+ return undefined;
47
+ }
48
+ }
49
+ /**
50
+ * Validates the shape and size of an incoming request.
51
+ *
52
+ * @throws {RPCInvalidRequestError} when the frame is malformed or the
53
+ * payload exceeds the configured limit.
54
+ */
55
+ export function assertValidRequest(request, limits = {}) {
56
+ if (typeof request !== "object" || request === null) {
57
+ throw new RPCInvalidRequestError("Request must be an object.");
58
+ }
59
+ const candidate = request;
60
+ if (typeof candidate.id !== "string" || candidate.id.length === 0) {
61
+ throw new RPCInvalidRequestError("Request id must be a non-empty string.");
62
+ }
63
+ if (limits.enforceProcedureNamePattern ?? true) {
64
+ assertValidProcedureName(candidate.procedure);
65
+ }
66
+ else if (typeof candidate.procedure !== "string" ||
67
+ candidate.procedure.length === 0) {
68
+ throw new RPCInvalidRequestError("Procedure name must be a non-empty string.", undefined);
69
+ }
70
+ if (candidate.metadata !== undefined &&
71
+ (typeof candidate.metadata !== "object" || candidate.metadata === null)) {
72
+ throw new RPCInvalidRequestError("Request metadata must be an object.", candidate.procedure);
73
+ }
74
+ const maxBytes = limits.maxPayloadBytes ?? MAX_RPC_PAYLOAD_SIZE;
75
+ if (maxBytes > 0) {
76
+ const size = measurePayloadBytes(candidate.payload);
77
+ if (size === undefined) {
78
+ throw new RPCInvalidRequestError("Request payload could not be encoded.", candidate.procedure);
79
+ }
80
+ if (size > maxBytes) {
81
+ throw new RPCInvalidRequestError(`Request payload of ${size} bytes exceeds the ${maxBytes} byte limit.`, candidate.procedure);
82
+ }
83
+ }
84
+ }
85
+ /**
86
+ * Converts schema issues into metadata safe to return to a caller.
87
+ *
88
+ * Only the path, code and message travel; the received input is dropped
89
+ * so a validation response cannot echo back data the caller sent.
90
+ */
91
+ export function toValidationIssues(issues) {
92
+ return issues.map((issue) => ({
93
+ path: issue.path.map(String).join("."),
94
+ code: String(issue.code),
95
+ message: issue.message,
96
+ }));
97
+ }
98
+ /**
99
+ * Parses caller input against a schema.
100
+ *
101
+ * @throws {RPCValidationError} carrying the issues, which are safe to
102
+ * return: they describe the caller's own input.
103
+ */
104
+ export function parseInput(schema, value, procedureName) {
105
+ const result = schema.safeParse(value);
106
+ if (result.success) {
107
+ return result.data;
108
+ }
109
+ throw new RPCValidationError(`Invalid input for procedure "${procedureName}".`, toValidationIssues(result.issues), procedureName);
110
+ }
111
+ /**
112
+ * Parses a handler's result against its output schema.
113
+ *
114
+ * An invalid output is a server defect rather than a caller mistake, so
115
+ * the issues describe internal shape and stay server-side: the thrown
116
+ * error carries no issue detail.
117
+ */
118
+ export function parseOutput(schema, value, procedureName) {
119
+ const result = schema.safeParse(value);
120
+ if (result.success) {
121
+ return result.data;
122
+ }
123
+ throw new RPCValidationError(`Procedure "${procedureName}" produced a response that does not match its output schema.`, undefined, procedureName);
124
+ }
125
+ //# sourceMappingURL=rpcValidation.core.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zudojs/rpc",
3
- "version": "0.1.0",
3
+ "version": "1.0.0",
4
4
  "description": "Remote procedure call infrastructure for Zudojs applications.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -14,26 +14,22 @@
14
14
  }
15
15
  },
16
16
  "files": [
17
- "dist"
17
+ "dist",
18
+ "!dist/**/*.map",
19
+ "!dist/**/*.tsbuildinfo",
20
+ "!dist/.tsbuildinfo"
18
21
  ],
19
- "scripts": {
20
- "build": "tsc -p tsconfig.json",
21
- "typecheck": "tsc -p tsconfig.json --noEmit",
22
- "clean": "rm -rf dist",
23
- "test": "vitest run",
24
- "test:watch": "vitest"
25
- },
26
22
  "engines": {
27
23
  "node": ">=24.0.0"
28
24
  },
29
25
  "dependencies": {
30
- "@zudojs/errors": "0.1.0",
31
- "@zudojs/constants": "0.1.0",
32
- "@zudojs/types": "0.1.0",
33
- "@zudojs/schema": "0.1.0"
26
+ "@zudojs/errors": "1.0.0",
27
+ "@zudojs/constants": "1.0.0",
28
+ "@zudojs/types": "1.0.0",
29
+ "@zudojs/schema": "1.0.0"
34
30
  },
35
31
  "devDependencies": {
36
- "typescript": "^7.0.2",
32
+ "typescript": "7.0.2",
37
33
  "vitest": "^4.1.11"
38
34
  },
39
35
  "publishConfig": {
@@ -46,8 +42,19 @@
46
42
  "procedure"
47
43
  ],
48
44
  "homepage": "https://github.com/oyinlola-tech/zudo#readme",
45
+ "bugs": {
46
+ "url": "https://github.com/oyinlola-tech/zudo/issues"
47
+ },
49
48
  "repository": {
50
49
  "type": "git",
51
- "url": "https://github.com/oyinlola-tech/zudo"
50
+ "url": "https://github.com/oyinlola-tech/zudo",
51
+ "directory": "packages/rpc"
52
+ },
53
+ "scripts": {
54
+ "build": "tsc -p tsconfig.json",
55
+ "typecheck": "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.test.json --noEmit",
56
+ "clean": "rm -rf dist",
57
+ "test": "vitest run",
58
+ "test:watch": "vitest"
52
59
  }
53
- }
60
+ }