@travetto/web-rpc 7.1.4 → 8.0.0-alpha.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@travetto/web-rpc",
3
- "version": "7.1.4",
3
+ "version": "8.0.0-alpha.1",
4
4
  "type": "module",
5
5
  "description": "RPC support for a Web Application",
6
6
  "keywords": [
@@ -27,9 +27,9 @@
27
27
  "directory": "module/web-rpc"
28
28
  },
29
29
  "dependencies": {
30
- "@travetto/config": "^7.1.4",
31
- "@travetto/schema": "^7.1.4",
32
- "@travetto/web": "^7.1.4"
30
+ "@travetto/config": "^8.0.0-alpha.1",
31
+ "@travetto/schema": "^8.0.0-alpha.1",
32
+ "@travetto/web": "^8.0.0-alpha.1"
33
33
  },
34
34
  "travetto": {
35
35
  "displayName": "Web RPC Support"
package/src/controller.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Inject } from '@travetto/di';
2
- import { type Any, AppError, JSONUtil } from '@travetto/runtime';
2
+ import { type Any, RuntimeError, JSONUtil } from '@travetto/runtime';
3
3
  import { IsPrivate } from '@travetto/schema';
4
4
  import {
5
5
  HeaderParam, Controller, ExcludeInterceptors, ControllerRegistryIndex,
@@ -36,7 +36,7 @@ export class WebRpcController {
36
36
  const endpoint = ControllerRegistryIndex.getEndpointConfigById(target);
37
37
 
38
38
  if (!endpoint || !endpoint.filter) {
39
- throw new AppError('Unknown endpoint', { category: 'notfound' });
39
+ throw new RuntimeError('Unknown endpoint', { category: 'notfound' });
40
40
  }
41
41
 
42
42
  const { request } = this.ctx;
@@ -45,7 +45,7 @@ export class WebRpcController {
45
45
 
46
46
  // Allow request to read inputs from header
47
47
  if (paramInput) {
48
- params = JSONUtil.parseBase64(paramInput)!;
48
+ params = JSONUtil.fromBase64(paramInput);
49
49
  } else if (Array.isArray(body)) { // Params passed via body
50
50
  params = body;
51
51
 
@@ -54,7 +54,7 @@ export class WebRpcController {
54
54
  request.body = params[bodyParamIdx];
55
55
  }
56
56
  } else if (body) {
57
- throw new AppError('Invalid parameters, must be an array', { category: 'data' });
57
+ throw new RuntimeError('Invalid parameters, must be an array', { category: 'data' });
58
58
  } else {
59
59
  params = [];
60
60
  }
package/src/service.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import path from 'node:path';
2
2
  import fs from 'node:fs/promises';
3
3
 
4
- import { Inject, Injectable } from '@travetto/di';
4
+ import { Inject, Injectable, PostConstruct } from '@travetto/di';
5
5
  import { ControllerRegistryIndex } from '@travetto/web';
6
6
  import { Runtime, RuntimeIndex } from '@travetto/runtime';
7
7
  import { ManifestModuleUtil } from '@travetto/manifest';
@@ -16,7 +16,8 @@ export class WebRpcClientGeneratorService {
16
16
  @Inject()
17
17
  config: WebRpcConfig;
18
18
 
19
- async postConstruct(): Promise<void> {
19
+ @PostConstruct()
20
+ async initialRender(): Promise<void> {
20
21
  this.render();
21
22
  }
22
23
 
@@ -1,10 +1,9 @@
1
1
  import path from 'node:path';
2
2
 
3
3
  import { Env } from '@travetto/runtime';
4
- import { CliCommand, type CliCommandShape, CliValidationResultError } from '@travetto/cli';
4
+ import { CliCommand, type CliCommandShape, CliModuleFlag, CliProfilesFlag, CliValidationResultError } from '@travetto/cli';
5
5
  import { DependencyRegistryIndex } from '@travetto/di';
6
6
  import { Registry } from '@travetto/registry';
7
- import { Ignore } from '@travetto/schema';
8
7
 
9
8
  import type { WebRpcClient } from '../src/config.ts';
10
9
  import { WebRpcClientGeneratorService } from '../src/service.ts';
@@ -12,13 +11,16 @@ import { WebRpcClientGeneratorService } from '../src/service.ts';
12
11
  /**
13
12
  * Generate the web-rpc client
14
13
  */
15
- @CliCommand({ with: { profiles: true, module: true } })
14
+ @CliCommand()
16
15
  export class CliWebRpcCommand implements CliCommandShape {
17
16
 
18
- @Ignore()
17
+ @CliProfilesFlag()
18
+ profile: string[];
19
+
20
+ @CliModuleFlag({ short: 'm' })
19
21
  module: string;
20
22
 
21
- preMain(): void {
23
+ finalize(): void {
22
24
  Env.DEBUG.set(false);
23
25
  }
24
26
 
@@ -33,7 +35,7 @@ export class CliWebRpcCommand implements CliCommandShape {
33
35
  } else {
34
36
  if (!output) {
35
37
  throw new CliValidationResultError(this, [
36
- { message: 'output is required when type is not `config`', source: 'arg' }
38
+ { message: 'output is required when type is not `config`', source: 'arg', kind: 'missing', path: 'output' }
37
39
  ]);
38
40
  }
39
41
  output = path.resolve(output);
@@ -2,11 +2,9 @@ import { consumeError } from './rpc.ts';
2
2
 
3
3
  export async function toNodeError(payload: unknown): Promise<Error> {
4
4
  try {
5
- let result = undefined;
6
- const { AppError } = await import('@travetto/runtime');
7
- result = AppError.fromJSON(payload);
8
- if (result) {
9
- return result;
5
+ const { JSONUtil } = await import('@travetto/runtime');
6
+ if (JSONUtil.isJSONError(payload)) {
7
+ return JSONUtil.jsonErrorToError(payload);
10
8
  }
11
9
  } catch { }
12
10
  return consumeError(payload);
@@ -17,6 +17,22 @@ const extendHeaders = (base: RequestInit['headers'], toAdd: Record<string, strin
17
17
  return headers;
18
18
  };
19
19
 
20
+ const jsonToString = (input: unknown): string =>
21
+ JSON.stringify(input, (key, value): unknown => typeof value === 'bigint' ? `${value.toString()}n` : value);
22
+
23
+ const stringToJson = <T = unknown>(input: string): T =>
24
+ JSON.parse(input, (key, value): unknown => {
25
+ if (typeof value === 'string') {
26
+ if (/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}[.]\d{3}Z$/.test(value)) {
27
+ return new Date(value);
28
+ } else if (/^-?d+n$/.test(value)) {
29
+ return BigInt(value.slice(0, -1));
30
+ }
31
+ }
32
+ return value;
33
+ });
34
+
35
+
20
36
  export type PreRequestHandler = (item: RequestInit) => Promise<RequestInit | undefined | void>;
21
37
  export type PostResponseHandler = (item: Response) => Promise<Response | undefined | void>;
22
38
 
@@ -57,14 +73,14 @@ function isPlainObject(value: unknown): value is Record<string, unknown> {
57
73
  && Object.prototype.toString.call(value) === '[object Object]'; // separate build-in like Math
58
74
  }
59
75
 
60
- function registerTimeout<T extends (number | string | { unref(): unknown })>(
76
+ function registerTimeout<T>(
61
77
  controller: AbortController,
62
78
  timeout: number,
63
79
  start: (fn: (...args: unknown[]) => unknown, delay: number) => T,
64
80
  stop: (value: T) => void
65
81
  ): void {
66
82
  const timer = start(() => controller.abort(), timeout);
67
- if (!(typeof timer === 'number' || typeof timer === 'string')) {
83
+ if (timer && typeof timer === 'object' && 'unref' in timer && typeof timer.unref === 'function') {
68
84
  timer.unref();
69
85
  }
70
86
  controller.signal.onabort = (): void => { timer && stop(timer); };
@@ -85,14 +101,14 @@ export function getBody(inputs: unknown[], isBodyRequest: boolean): { body: Form
85
101
  return {
86
102
  body: undefined,
87
103
  headers: {
88
- 'X-TRV-RPC-INPUTS': btoa(encodeURIComponent(JSON.stringify(inputs)))
104
+ 'X-TRV-RPC-INPUTS': btoa(encodeURIComponent(jsonToString(inputs)))
89
105
  }
90
106
  };
91
107
  }
92
108
  // If we do not have a blob, simple output
93
109
  if (!inputs.some(isBlobLike)) {
94
110
  return {
95
- body: JSON.stringify(inputs),
111
+ body: jsonToString(inputs),
96
112
  headers: {
97
113
  'Content-Type': 'application/json'
98
114
  }
@@ -115,27 +131,24 @@ export function getBody(inputs: unknown[], isBodyRequest: boolean): { body: Form
115
131
  return {
116
132
  body: form,
117
133
  headers: {
118
- 'X-TRV-RPC-INPUTS': btoa(encodeURIComponent(JSON.stringify(plainInputs)))
134
+ 'X-TRV-RPC-INPUTS': btoa(encodeURIComponent(jsonToString(plainInputs)))
119
135
  }
120
136
  };
121
137
  }
122
138
 
123
- export function consumeJSON<T>(text: string | unknown): T {
124
- if (typeof text !== 'string') {
125
- return consumeJSON(JSON.stringify(text));
126
- } else if (text === null || text === undefined || text === '') {
139
+ export function consumeJSON<T>(input: string | unknown): T {
140
+ let text: string;
141
+ if (input === null || input === undefined || input === '') {
127
142
  return undefined!;
143
+ } else if (typeof input !== 'string') {
144
+ text = jsonToString(input);
145
+ } else {
146
+ text = input;
128
147
  }
129
148
  try {
130
- return JSON.parse(text, (key, value): unknown => {
131
- if (typeof value === 'string' && /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}[.]\d{3}Z/.test(value)) {
132
- return new Date(value);
133
- } else {
134
- return value;
135
- }
136
- });
149
+ return stringToJson<T>(text);
137
150
  } catch (error) {
138
- throw new Error(`Unable to parse response: ${text}, Unknown error: ${error}`);
151
+ throw new Error(`Unable to parse response: ${text}`, { cause: error });
139
152
  }
140
153
  }
141
154