@webpieces/core-util 0.4.963 → 0.4.965

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 (64) hide show
  1. package/package.json +1 -1
  2. package/src/http/ApiCallInfo.d.ts +3 -3
  3. package/src/http/ApiCallInfo.js +1 -1
  4. package/src/http/ApiCallInfo.js.map +1 -1
  5. package/src/http/ApiMethodInfo.d.ts +1 -1
  6. package/src/http/ApiMethodInfo.js.map +1 -1
  7. package/src/http/ApiRegistry.d.ts +91 -0
  8. package/src/http/ApiRegistry.js +129 -0
  9. package/src/http/ApiRegistry.js.map +1 -0
  10. package/src/http/CallScope.d.ts +35 -8
  11. package/src/http/CallScope.js +59 -5
  12. package/src/http/CallScope.js.map +1 -1
  13. package/src/http/CallStrategy.d.ts +1 -1
  14. package/src/http/CallStrategy.js.map +1 -1
  15. package/src/http/ClientRegistry.d.ts +38 -71
  16. package/src/http/ClientRegistry.js +127 -97
  17. package/src/http/ClientRegistry.js.map +1 -1
  18. package/src/http/ClientRegistryCompileAssertions.js +63 -0
  19. package/src/http/ClientRegistryCompileAssertions.js.map +1 -0
  20. package/src/http/DeletedAuthCompileAssertions.js +1 -1
  21. package/src/http/DeletedAuthCompileAssertions.js.map +1 -1
  22. package/src/http/ErrorClassifier.d.ts +7 -7
  23. package/src/http/ErrorClassifier.js.map +1 -1
  24. package/src/http/ErrorLadderCompileAssertions.js +41 -17
  25. package/src/http/ErrorLadderCompileAssertions.js.map +1 -1
  26. package/src/http/ErrorTranslator.d.ts +6 -6
  27. package/src/http/ErrorTranslator.js.map +1 -1
  28. package/src/http/LogApiCall.d.ts +1 -1
  29. package/src/http/LogApiCall.js +4 -4
  30. package/src/http/LogApiCall.js.map +1 -1
  31. package/src/http/RetryStrategy.d.ts +2 -2
  32. package/src/http/RetryStrategy.js +4 -4
  33. package/src/http/RetryStrategy.js.map +1 -1
  34. package/src/http/RouteMetadata.d.ts +1 -1
  35. package/src/http/RouteMetadata.js +1 -1
  36. package/src/http/RouteMetadata.js.map +1 -1
  37. package/src/http/StreamErrorControl.js +2 -2
  38. package/src/http/StreamErrorControl.js.map +1 -1
  39. package/src/http/TransportDefault.d.ts +2 -2
  40. package/src/http/TransportDefault.js +2 -2
  41. package/src/http/TransportDefault.js.map +1 -1
  42. package/src/http/WebpiecesDefaultErrorTranslator.d.ts +2 -2
  43. package/src/http/WebpiecesDefaultErrorTranslator.js +2 -2
  44. package/src/http/WebpiecesDefaultErrorTranslator.js.map +1 -1
  45. package/src/http/auth-mode.d.ts +6 -4
  46. package/src/http/auth-mode.js +6 -4
  47. package/src/http/auth-mode.js.map +1 -1
  48. package/src/http/decorators.d.ts +1 -1
  49. package/src/http/decorators.js +3 -3
  50. package/src/http/decorators.js.map +1 -1
  51. package/src/index.d.ts +2 -3
  52. package/src/index.js +7 -5
  53. package/src/index.js.map +1 -1
  54. package/src/ipc/IpcErrorTranslator.d.ts +1 -1
  55. package/src/ipc/IpcErrorTranslator.js.map +1 -1
  56. package/src/ipc/IpcRegistry.d.ts +1 -1
  57. package/src/ipc/IpcRegistry.js +1 -1
  58. package/src/ipc/IpcRegistry.js.map +1 -1
  59. package/src/http/CallRegistry.d.ts +0 -42
  60. package/src/http/CallRegistry.js +0 -143
  61. package/src/http/CallRegistry.js.map +0 -1
  62. package/src/http/CallRegistryCompileAssertions.js +0 -27
  63. package/src/http/CallRegistryCompileAssertions.js.map +0 -1
  64. /package/src/http/{CallRegistryCompileAssertions.d.ts → ClientRegistryCompileAssertions.d.ts} +0 -0
@@ -1,143 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.CallRegistry = void 0;
4
- const CallStrategy_1 = require("./CallStrategy");
5
- const CallDeadline_1 = require("./CallDeadline");
6
- const ClientRegistry_1 = require("./ClientRegistry");
7
- const ErrorClassifier_1 = require("./ErrorClassifier");
8
- const ApiMethodInfo_1 = require("./ApiMethodInfo");
9
- const LogManager_1 = require("../logging/LogManager");
10
- const ApiCallLogName_1 = require("./ApiCallLogName");
11
- const errorUtils_1 = require("../lib/errorUtils");
12
- const CallScope_1 = require("./CallScope");
13
- // The same logger LogApiCall writes its [API-*] lines to, so an attempt line sits beside the final one.
14
- const log = LogManager_1.LogManager.getLogger(ApiCallLogName_1.LOG_API_CALL_LOGGER_NAME);
15
- class CallPolicy {
16
- timeoutMs;
17
- // webpieces-disable no-any-unknown -- global policy spans heterogeneous response DTOs
18
- strategy;
19
- }
20
- /**
21
- * Counts the attempts of ONE call and logs each retried TRANSIENT failure. It wraps the attempt
22
- * BEFORE any strategy sees it, so an app-written strategy gets the same lines as `RetryStrategy`.
23
- *
24
- * The line for attempt N is written when attempt N+1 STARTS — i.e. only for an attempt that was
25
- * actually retried. The last attempt's failure is what escapes, and `LogApiCall`'s final
26
- * `[API-client-resp-FAIL]` line covers it, so a call that gave up after 4 attempts logs 3 attempt
27
- * lines and 1 FAIL line, never the last failure twice. An EXPECTED or FAILURE attempt is not logged
28
- * here either; the final line covers it.
29
- */
30
- class LoggedAttempts {
31
- context;
32
- attempt;
33
- attempts = 0;
34
- pendingTransient;
35
- constructor(context, attempt) {
36
- this.context = context;
37
- this.attempt = attempt;
38
- }
39
- run = async (timeoutMs) => {
40
- this.flushRetried();
41
- this.attempts += 1;
42
- // webpieces-disable no-unmanaged-exceptions -- observe the attempt's failure, rethrow it unchanged
43
- // eslint-disable-next-line @webpieces/no-unmanaged-exceptions
44
- try {
45
- return await this.attempt(timeoutMs);
46
- }
47
- catch (err) {
48
- const error = (0, errorUtils_1.toError)(err);
49
- const methodInfo = new ApiMethodInfo_1.ApiMethodInfo('client', this.context.apiName, this.context.methodName, this.context.contract);
50
- this.pendingTransient =
51
- ClientRegistry_1.ClientRegistry.classify(error, methodInfo) === ErrorClassifier_1.CallOutcome.TRANSIENT_FAILURE
52
- ? error
53
- : undefined;
54
- // eslint-disable-next-line @webpieces/no-unmanaged-exceptions -- rethrows the attempt's own failure unchanged
55
- throw err;
56
- }
57
- };
58
- flushRetried() {
59
- const error = this.pendingTransient;
60
- if (error === undefined)
61
- return;
62
- this.pendingTransient = undefined;
63
- log.warn(`[API-client-attempt-TRANSIENT] ${this.context.apiName}.${this.context.methodName} ` +
64
- `attempt ${this.attempts} errorType=${error.constructor.name} error=${error.message}`);
65
- }
66
- }
67
- /**
68
- * Shared startup registry for browser RPC, node RPC, and Cloud Tasks ENQUEUE — ONE implementation,
69
- * every transport calls {@link CallRegistry.execute}.
70
- *
71
- * Ladder: strategy method -> API -> ALL first; ANY strategy replaces the ENTIRE timeout ladder.
72
- * Otherwise timeout method -> API -> ALL. Otherwise the transport's {@link TransportDefault} (its
73
- * timeout, and its strategy if it has one). A registered TIMEOUT is therefore a decision for a single
74
- * attempt and also replaces a transport's default strategy; to keep retrying with a different attempt
75
- * deadline, register a `RetryStrategy` instead.
76
- *
77
- * RPC has no default retry (only the application knows whether repeating a POST is safe); Cloud Tasks
78
- * enqueue does (see `TransportDefault`). An app opts RPC in with
79
- * `CallRegistry.setStrategy(new RetryStrategy(...).run, CatalogApi)` — and `RetryStrategy` never
80
- * retries a `WRITE`, even registered at ALL.
81
- */
82
- class CallRegistry {
83
- static ladder = new CallScope_1.CallScopeLadder(() => new CallPolicy());
84
- // webpieces-disable no-function-outside-class -- process-global startup registry
85
- static setTimeout(timeoutMs, ...scope) {
86
- if (timeoutMs !== undefined)
87
- CallDeadline_1.CallDeadline.validate(timeoutMs);
88
- CallRegistry.ladder.at(...scope).timeoutMs = timeoutMs;
89
- }
90
- // webpieces-disable no-function-outside-class -- process-global startup registry
91
- static setStrategy(
92
- // webpieces-disable no-any-unknown -- registry strategies span heterogeneous response DTOs
93
- strategy, ...scope) {
94
- CallRegistry.ladder.at(...scope).strategy = strategy;
95
- }
96
- /**
97
- * Run one call under its registered policy. `context` names the method (its `methodName` selects
98
- * the per-method policy) and carries the endpoint's declared operation, so the SAME context a
99
- * strategy sees is the one the transport's deadline puts on an `ApiCallTimeoutError`. The context
100
- * a strategy sees always carries `api` as its {@link CallContext.contract}, so the error
101
- * classification inside a strategy resolves on the same ladder.
102
- *
103
- * Every attempt is wrapped so a retried TRANSIENT failure logs one
104
- * `WARN [API-client-attempt-TRANSIENT]` line (see {@link LoggedAttempts}).
105
- */
106
- // webpieces-disable no-function-outside-class -- transport-independent policy execution
107
- static async execute(api, context, attempt, fallback) {
108
- const scoped = context.contract === api
109
- ? context
110
- : new CallStrategy_1.CallContext(context.apiName, context.methodName, context.operation, api);
111
- const logged = new LoggedAttempts(scoped, attempt).run;
112
- const rungs = CallRegistry.ladder.rungs(api, scoped.methodName);
113
- const strategy = rungs.find((p) => p.strategy !== undefined)?.strategy;
114
- if (strategy !== undefined) {
115
- return (await strategy(logged, scoped));
116
- }
117
- const timeoutMs = rungs.find((p) => p.timeoutMs !== undefined)?.timeoutMs;
118
- if (timeoutMs !== undefined) {
119
- return logged(timeoutMs);
120
- }
121
- if (fallback.strategy !== undefined) {
122
- return (await fallback.strategy(logged, scoped));
123
- }
124
- return logged(fallback.timeoutMs);
125
- }
126
- /**
127
- * The registered TIMEOUT for a call — method -> API -> ALL -> `defaultMs` — ignoring every
128
- * strategy. For a transport that hands timing to someone else for this call (Cloud Tasks enqueue
129
- * with caller-supplied gax `CallOptions`) and still needs ONE safety cap so a hung channel cannot
130
- * block forever. Raise it with {@link CallRegistry.setTimeout}.
131
- */
132
- // webpieces-disable no-function-outside-class -- process-global registry lookup
133
- static resolveTimeout(api, methodName, defaultMs) {
134
- const rungs = CallRegistry.ladder.rungs(api, methodName);
135
- return rungs.find((p) => p.timeoutMs !== undefined)?.timeoutMs ?? defaultMs;
136
- }
137
- // webpieces-disable no-function-outside-class -- process-global registry reset for tests
138
- static clear() {
139
- CallRegistry.ladder.clear();
140
- }
141
- }
142
- exports.CallRegistry = CallRegistry;
143
- //# sourceMappingURL=CallRegistry.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"CallRegistry.js","sourceRoot":"","sources":["../../../../../../packages/core/core-util/src/http/CallRegistry.ts"],"names":[],"mappings":"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","sourcesContent":["import { Attempt, CallContext, CallStrategy } from './CallStrategy';\nimport { CallDeadline } from './CallDeadline';\nimport { TransportDefault } from './TransportDefault';\nimport { ClientRegistry } from './ClientRegistry';\nimport { CallOutcome } from './ErrorClassifier';\nimport { ApiMethodInfo } from './ApiMethodInfo';\nimport { LogManager } from '../logging/LogManager';\nimport { LOG_API_CALL_LOGGER_NAME } from './ApiCallLogName';\nimport { toError } from '../lib/errorUtils';\nimport { CallScope, CallScopeLadder } from './CallScope';\n\n// The same logger LogApiCall writes its [API-*] lines to, so an attempt line sits beside the final one.\nconst log = LogManager.getLogger(LOG_API_CALL_LOGGER_NAME);\n\nclass CallPolicy {\n timeoutMs?: number;\n // webpieces-disable no-any-unknown -- global policy spans heterogeneous response DTOs\n strategy?: CallStrategy<unknown>;\n}\n\n/**\n * Counts the attempts of ONE call and logs each retried TRANSIENT failure. It wraps the attempt\n * BEFORE any strategy sees it, so an app-written strategy gets the same lines as `RetryStrategy`.\n *\n * The line for attempt N is written when attempt N+1 STARTS — i.e. only for an attempt that was\n * actually retried. The last attempt's failure is what escapes, and `LogApiCall`'s final\n * `[API-client-resp-FAIL]` line covers it, so a call that gave up after 4 attempts logs 3 attempt\n * lines and 1 FAIL line, never the last failure twice. An EXPECTED or FAILURE attempt is not logged\n * here either; the final line covers it.\n */\nclass LoggedAttempts<T> {\n private attempts = 0;\n private pendingTransient?: Error;\n\n constructor(\n private readonly context: CallContext,\n private readonly attempt: Attempt<T>,\n ) {}\n\n readonly run: Attempt<T> = async (timeoutMs: number): Promise<T> => {\n this.flushRetried();\n this.attempts += 1;\n // webpieces-disable no-unmanaged-exceptions -- observe the attempt's failure, rethrow it unchanged\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n return await this.attempt(timeoutMs);\n } catch (err: unknown) {\n const error = toError(err);\n const methodInfo = new ApiMethodInfo(\n 'client',\n this.context.apiName,\n this.context.methodName,\n this.context.contract,\n );\n this.pendingTransient =\n ClientRegistry.classify(error, methodInfo) === CallOutcome.TRANSIENT_FAILURE\n ? error\n : undefined;\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions -- rethrows the attempt's own failure unchanged\n throw err;\n }\n };\n\n private flushRetried(): void {\n const error = this.pendingTransient;\n if (error === undefined) return;\n this.pendingTransient = undefined;\n log.warn(\n `[API-client-attempt-TRANSIENT] ${this.context.apiName}.${this.context.methodName} ` +\n `attempt ${this.attempts} errorType=${error.constructor.name} error=${error.message}`,\n );\n }\n}\n\n/**\n * Shared startup registry for browser RPC, node RPC, and Cloud Tasks ENQUEUE — ONE implementation,\n * every transport calls {@link CallRegistry.execute}.\n *\n * Ladder: strategy method -> API -> ALL first; ANY strategy replaces the ENTIRE timeout ladder.\n * Otherwise timeout method -> API -> ALL. Otherwise the transport's {@link TransportDefault} (its\n * timeout, and its strategy if it has one). A registered TIMEOUT is therefore a decision for a single\n * attempt and also replaces a transport's default strategy; to keep retrying with a different attempt\n * deadline, register a `RetryStrategy` instead.\n *\n * RPC has no default retry (only the application knows whether repeating a POST is safe); Cloud Tasks\n * enqueue does (see `TransportDefault`). An app opts RPC in with\n * `CallRegistry.setStrategy(new RetryStrategy(...).run, CatalogApi)` — and `RetryStrategy` never\n * retries a `WRITE`, even registered at ALL.\n */\nexport class CallRegistry {\n private static readonly ladder = new CallScopeLadder<CallPolicy>(() => new CallPolicy());\n\n // webpieces-disable no-function-outside-class -- process-global startup registry\n static setTimeout(timeoutMs: number | undefined, ...scope: CallScope): void {\n if (timeoutMs !== undefined) CallDeadline.validate(timeoutMs);\n CallRegistry.ladder.at(...scope).timeoutMs = timeoutMs;\n }\n\n // webpieces-disable no-function-outside-class -- process-global startup registry\n static setStrategy(\n // webpieces-disable no-any-unknown -- registry strategies span heterogeneous response DTOs\n strategy: CallStrategy<unknown> | undefined,\n ...scope: CallScope\n ): void {\n CallRegistry.ladder.at(...scope).strategy = strategy;\n }\n\n /**\n * Run one call under its registered policy. `context` names the method (its `methodName` selects\n * the per-method policy) and carries the endpoint's declared operation, so the SAME context a\n * strategy sees is the one the transport's deadline puts on an `ApiCallTimeoutError`. The context\n * a strategy sees always carries `api` as its {@link CallContext.contract}, so the error\n * classification inside a strategy resolves on the same ladder.\n *\n * Every attempt is wrapped so a retried TRANSIENT failure logs one\n * `WARN [API-client-attempt-TRANSIENT]` line (see {@link LoggedAttempts}).\n */\n // webpieces-disable no-function-outside-class -- transport-independent policy execution\n static async execute<T>(\n api: Function,\n context: CallContext,\n attempt: Attempt<T>,\n fallback: TransportDefault,\n ): Promise<T> {\n const scoped =\n context.contract === api\n ? context\n : new CallContext(context.apiName, context.methodName, context.operation, api);\n const logged = new LoggedAttempts<T>(scoped, attempt).run;\n const rungs = CallRegistry.ladder.rungs(api, scoped.methodName);\n const strategy = rungs.find((p: CallPolicy) => p.strategy !== undefined)?.strategy;\n if (strategy !== undefined) {\n return (await strategy(logged, scoped)) as T;\n }\n const timeoutMs = rungs.find((p: CallPolicy) => p.timeoutMs !== undefined)?.timeoutMs;\n if (timeoutMs !== undefined) {\n return logged(timeoutMs);\n }\n if (fallback.strategy !== undefined) {\n return (await fallback.strategy(logged, scoped)) as T;\n }\n return logged(fallback.timeoutMs);\n }\n\n /**\n * The registered TIMEOUT for a call — method -> API -> ALL -> `defaultMs` — ignoring every\n * strategy. For a transport that hands timing to someone else for this call (Cloud Tasks enqueue\n * with caller-supplied gax `CallOptions`) and still needs ONE safety cap so a hung channel cannot\n * block forever. Raise it with {@link CallRegistry.setTimeout}.\n */\n // webpieces-disable no-function-outside-class -- process-global registry lookup\n static resolveTimeout(api: Function, methodName: string, defaultMs: number): number {\n const rungs = CallRegistry.ladder.rungs(api, methodName);\n return rungs.find((p: CallPolicy) => p.timeoutMs !== undefined)?.timeoutMs ?? defaultMs;\n }\n\n // webpieces-disable no-function-outside-class -- process-global registry reset for tests\n static clear(): void {\n CallRegistry.ladder.clear();\n }\n}\n"]}
@@ -1,27 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const CallRegistry_1 = require("./CallRegistry");
4
- const CallStrategy_1 = require("./CallStrategy");
5
- const HttpEndpointOptions_1 = require("./HttpEndpointOptions");
6
- /** Compiled by tsc (spec files are not), never executed. */
7
- class CallRegistryCompileAssertions {
8
- check() {
9
- // @ts-expect-error ALL cannot select a method
10
- CallRegistry_1.CallRegistry.setTimeout(100, 'ALL', 'work');
11
- // @ts-expect-error ALL cannot select a method
12
- CallRegistry_1.CallRegistry.setStrategy(undefined, 'ALL', 'work');
13
- }
14
- /** A CallContext's contract is the CLASS, never undefined (#1350). */
15
- contractIsNeverUndefined() {
16
- // @ts-expect-error CallContext's contract is a CLASS, never undefined — pass the real contract class
17
- void new CallStrategy_1.CallContext('Api', 'work', HttpEndpointOptions_1.WRITE, undefined);
18
- }
19
- /** The transport fallback is a TransportDefault (timeout + optional strategy), never a bare number. */
20
- fallbackIsATransportDefault() {
21
- const context = new CallStrategy_1.CallContext('Api', 'work', HttpEndpointOptions_1.WRITE, CallRegistryCompileAssertions);
22
- void CallRegistry_1.CallRegistry.execute(CallRegistryCompileAssertions, context, (ms) => Promise.resolve(ms),
23
- // @ts-expect-error execute(..., defaultMs: number) became execute(..., fallback: TransportDefault)
24
- 30_000);
25
- }
26
- }
27
- //# sourceMappingURL=CallRegistryCompileAssertions.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"CallRegistryCompileAssertions.js","sourceRoot":"","sources":["../../../../../../packages/core/core-util/src/http/CallRegistryCompileAssertions.ts"],"names":[],"mappings":";;AAAA,iDAA8C;AAC9C,iDAA6C;AAC7C,+DAA8C;AAE9C,4DAA4D;AAC5D,MAAM,6BAA6B;IAC/B,KAAK;QACD,8CAA8C;QAC9C,2BAAY,CAAC,UAAU,CAAC,GAAG,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;QAC5C,8CAA8C;QAC9C,2BAAY,CAAC,WAAW,CAAC,SAAS,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;IACvD,CAAC;IAED,sEAAsE;IACtE,wBAAwB;QACpB,qGAAqG;QACrG,KAAK,IAAI,0BAAW,CAAC,KAAK,EAAE,MAAM,EAAE,2BAAK,EAAE,SAAS,CAAC,CAAC;IAC1D,CAAC;IAED,uGAAuG;IACvG,2BAA2B;QACvB,MAAM,OAAO,GAAG,IAAI,0BAAW,CAAC,KAAK,EAAE,MAAM,EAAE,2BAAK,EAAE,6BAA6B,CAAC,CAAC;QACrF,KAAK,2BAAY,CAAC,OAAO,CACrB,6BAA6B,EAC7B,OAAO,EACP,CAAC,EAAU,EAAE,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QACnC,mGAAmG;QACnG,MAAM,CACT,CAAC;IACN,CAAC;CACJ","sourcesContent":["import { CallRegistry } from './CallRegistry';\nimport { CallContext } from './CallStrategy';\nimport { WRITE } from './HttpEndpointOptions';\n\n/** Compiled by tsc (spec files are not), never executed. */\nclass CallRegistryCompileAssertions {\n check(): void {\n // @ts-expect-error ALL cannot select a method\n CallRegistry.setTimeout(100, 'ALL', 'work');\n // @ts-expect-error ALL cannot select a method\n CallRegistry.setStrategy(undefined, 'ALL', 'work');\n }\n\n /** A CallContext's contract is the CLASS, never undefined (#1350). */\n contractIsNeverUndefined(): void {\n // @ts-expect-error CallContext's contract is a CLASS, never undefined — pass the real contract class\n void new CallContext('Api', 'work', WRITE, undefined);\n }\n\n /** The transport fallback is a TransportDefault (timeout + optional strategy), never a bare number. */\n fallbackIsATransportDefault(): void {\n const context = new CallContext('Api', 'work', WRITE, CallRegistryCompileAssertions);\n void CallRegistry.execute(\n CallRegistryCompileAssertions,\n context,\n (ms: number) => Promise.resolve(ms),\n // @ts-expect-error execute(..., defaultMs: number) became execute(..., fallback: TransportDefault)\n 30_000,\n );\n }\n}\n"]}