telepact 1.0.0-alpha.338 → 1.0.0-alpha.339

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.
@@ -1,16 +1,17 @@
1
1
  [
2
2
  {
3
3
  "///": "Ping the server.",
4
+ "$internal": true,
4
5
  "fn.ping_": {},
5
6
  "->": [
6
7
  {
7
8
  "Ok_": {}
8
9
  }
9
- ],
10
- "_errors": "^errors\\.Validation_$"
10
+ ]
11
11
  },
12
12
  {
13
13
  "///": "Get the telepact `schema` of this server.\n\nSet `includeInternal` to `true` to include Telepact internal definitions.\nSet `includeExamples` to `true` to add deterministic example payloads to\neach schema entry.\n",
14
+ "$internal": true,
14
15
  "fn.api_": {
15
16
  "includeInternal!": "boolean",
16
17
  "includeExamples!": "boolean"
@@ -25,8 +26,7 @@
25
26
  ]
26
27
  }
27
28
  }
28
- ],
29
- "_errors": "^errors\\.Validation_$"
29
+ ]
30
30
  },
31
31
  {
32
32
  "///": "`_ext.Select_` is the selection object used by the `@select_` header. Use\n`->` to narrow fields on the active result union, `struct.*` keys to narrow\nstruct fields, and `union.*` keys to narrow fields for specific union tags.\n\nSee https://raw.githubusercontent.com/Telepact/telepact/main/doc/02-design-apis/04-select-extension.md\nfor full `_ext.Select_` rules and end-to-end examples.\n",
@@ -52,6 +52,7 @@
52
52
  },
53
53
  {
54
54
  "///": "Create a mock stub from an `_ext.Stub_`.\n\nBy default the stub matcher is partial, so extra fields on the actual\nrequest argument are allowed. Set `strictMatch!` to `true` to require exact\nargument equality instead.\n\nSet `count!` to limit how many matching calls consume this stub before it\nstops matching.\n",
55
+ "$internal": true,
55
56
  "fn.createStub_": {
56
57
  "stub": "_ext.Stub_",
57
58
  "strictMatch!": "boolean",
@@ -61,11 +62,11 @@
61
62
  {
62
63
  "Ok_": {}
63
64
  }
64
- ],
65
- "_errors": "^errors\\.Validation_$"
65
+ ]
66
66
  },
67
67
  {
68
68
  "///": "Verify that the mock received a call matching the given `_ext.Call_`.\n\nBy default verification is partial and succeeds if at least one recorded\ncall contains the given argument as a JSON sub-structure. Set\n`strictMatch!` to `true` to require exact argument equality.\n\nSet `count!` to require `Exact`, `AtLeast`, or `AtMost` matching call\ncounts. Matching calls are marked as verified, which affects\n`fn.verifyNoMoreInteractions_`.\n",
69
+ "$internal": true,
69
70
  "fn.verify_": {
70
71
  "call": "_ext.Call_",
71
72
  "strictMatch!": "boolean",
@@ -80,11 +81,11 @@
80
81
  "reason": "union.VerificationFailure_"
81
82
  }
82
83
  }
83
- ],
84
- "_errors": "^errors\\.Validation_$"
84
+ ]
85
85
  },
86
86
  {
87
87
  "///": "Verify that no interactions have occurred with this mock or that all\ninteractions have been verified.\n",
88
+ "$internal": true,
88
89
  "fn.verifyNoMoreInteractions_": {},
89
90
  "->": [
90
91
  {
@@ -97,31 +98,31 @@
97
98
  ]
98
99
  }
99
100
  }
100
- ],
101
- "_errors": "^errors\\.Validation_$"
101
+ ]
102
102
  },
103
103
  {
104
104
  "///": "Clear all stub conditions.",
105
+ "$internal": true,
105
106
  "fn.clearStubs_": {},
106
107
  "->": [
107
108
  {
108
109
  "Ok_": {}
109
110
  }
110
- ],
111
- "_errors": "^errors\\.Validation_$"
111
+ ]
112
112
  },
113
113
  {
114
114
  "///": "Clear all call data.",
115
+ "$internal": true,
115
116
  "fn.clearCalls_": {},
116
117
  "->": [
117
118
  {
118
119
  "Ok_": {}
119
120
  }
120
- ],
121
- "_errors": "^errors\\.Validation_$"
121
+ ]
122
122
  },
123
123
  {
124
124
  "///": "Set the seed of the random generator.",
125
+ "$internal": true,
125
126
  "fn.setRandomSeed_": {
126
127
  "seed": "integer"
127
128
  },
@@ -129,8 +130,7 @@
129
130
  {
130
131
  "Ok_": {}
131
132
  }
132
- ],
133
- "_errors": "^errors\\.Validation_$"
133
+ ]
134
134
  },
135
135
  {
136
136
  "errors.Mock_": [
package/dist/index.cjs.js CHANGED
@@ -1100,34 +1100,13 @@ class ClientOptions {
1100
1100
  }
1101
1101
 
1102
1102
  class FunctionRouter {
1103
- authenticatedFunctionRoutes;
1104
- unauthenticatedFunctionRoutes;
1105
- constructor() {
1106
- this.authenticatedFunctionRoutes = {};
1107
- this.unauthenticatedFunctionRoutes = {};
1108
- }
1109
- registerAuthenticatedRoutes(functionRoutes) {
1110
- for (const [functionName, functionRoute] of Object.entries(functionRoutes)) {
1111
- this.authenticatedFunctionRoutes[functionName] = functionRoute;
1112
- delete this.unauthenticatedFunctionRoutes[functionName];
1113
- }
1114
- }
1115
- registerUnauthenticatedRoutes(functionRoutes) {
1116
- for (const [functionName, functionRoute] of Object.entries(functionRoutes)) {
1117
- this.unauthenticatedFunctionRoutes[functionName] = functionRoute;
1118
- delete this.authenticatedFunctionRoutes[functionName];
1119
- }
1120
- }
1121
- hasAuthenticatedRoutes() {
1122
- return Object.keys(this.authenticatedFunctionRoutes).length > 0;
1123
- }
1124
- requiresAuthentication(functionName) {
1125
- return functionName in this.authenticatedFunctionRoutes;
1103
+ functionRoutes;
1104
+ constructor(functionRoutes = {}) {
1105
+ this.functionRoutes = { ...functionRoutes };
1126
1106
  }
1127
1107
  async route(requestMessage) {
1128
1108
  const functionName = requestMessage.getBodyTarget();
1129
- const functionRoute = this.authenticatedFunctionRoutes[functionName]
1130
- ?? this.unauthenticatedFunctionRoutes[functionName];
1109
+ const functionRoute = this.functionRoutes[functionName];
1131
1110
  if (functionRoute === undefined) {
1132
1111
  throw new Error(`Unknown function: ${functionName}`);
1133
1112
  }
@@ -1874,6 +1853,20 @@ function buildUnknownErrorMessage(error, headers = {}) {
1874
1853
  return new Message(headers, { ErrorUnknown_: { caseId: error.caseId } });
1875
1854
  }
1876
1855
 
1856
+ function requiresAuthentication(telepactSchema, functionName) {
1857
+ const functionDefinition = telepactSchema.full.find((definition) => typeof definition === 'object'
1858
+ && definition !== null
1859
+ && !Array.isArray(definition)
1860
+ && functionName in definition);
1861
+ if (functionName.endsWith('_') || functionDefinition?.['$internal'] === true) {
1862
+ return false;
1863
+ }
1864
+ if (!('union.Auth_' in telepactSchema.parsed)) {
1865
+ return false;
1866
+ }
1867
+ return functionDefinition?.['$authenticated'] !== false;
1868
+ }
1869
+
1877
1870
  const UNAUTHENTICATED_MESSAGE = 'Valid authentication is required.';
1878
1871
  async function handleMessage(requestMessage, updateHeaders, telepactSchema, middleware, functionRouter, onError, onAuth) {
1879
1872
  const responseHeaders = {};
@@ -1897,7 +1890,8 @@ async function handleMessage(requestMessage, updateHeaders, telepactSchema, midd
1897
1890
  const functionName = requestTarget;
1898
1891
  const callType = parsedTelepactSchema[requestTarget];
1899
1892
  const resultUnionType = parsedTelepactSchema[`${requestTarget}.->`];
1900
- const requiresAuthentication = unknownTarget === null && functionRouter.requiresAuthentication(functionName);
1893
+ const functionRequiresAuthentication = unknownTarget === null
1894
+ && requiresAuthentication(telepactSchema, functionName);
1901
1895
  const callId = requestHeaders['@id_'];
1902
1896
  if (callId !== undefined) {
1903
1897
  responseHeaders['@id_'] = callId;
@@ -1914,10 +1908,10 @@ async function handleMessage(requestMessage, updateHeaders, telepactSchema, midd
1914
1908
  if (requestHeaderValidationFailures.length > 0) {
1915
1909
  return getInvalidErrorMessage('ErrorInvalidRequestHeaders_', requestHeaderValidationFailures, resultUnionType, responseHeaders);
1916
1910
  }
1917
- if (requiresAuthentication && !('@auth_' in requestHeaders)) {
1911
+ if (functionRequiresAuthentication && !('@auth_' in requestHeaders)) {
1918
1912
  return buildUnauthenticatedErrorMessage(resultUnionType, responseHeaders);
1919
1913
  }
1920
- if (requiresAuthentication) {
1914
+ if (functionRequiresAuthentication) {
1921
1915
  try {
1922
1916
  const authHeaders = (await onAuth(requestHeaders)) ?? {};
1923
1917
  Object.assign(requestHeaders, authHeaders);
@@ -2378,7 +2372,7 @@ function getDefaultFnScope(parsedTypes) {
2378
2372
  }
2379
2373
  function getSchemaKey(definition) {
2380
2374
  for (const key of Object.keys(definition)) {
2381
- if (key !== '///' && key !== '->' && key !== '_errors') {
2375
+ if (key !== '///' && key !== '->' && key !== '_errors' && !key.startsWith('$')) {
2382
2376
  return key;
2383
2377
  }
2384
2378
  }
@@ -2412,11 +2406,13 @@ class Server {
2412
2406
  telepactSchema;
2413
2407
  serializer;
2414
2408
  constructor(telepactSchema, functionRouter, options) {
2415
- const normalizedFunctionRouter = functionRouter instanceof FunctionRouter ? functionRouter : new FunctionRouter();
2416
- if (!(functionRouter instanceof FunctionRouter)) {
2417
- normalizedFunctionRouter.registerUnauthenticatedRoutes(functionRouter);
2418
- }
2419
- normalizedFunctionRouter.registerUnauthenticatedRoutes(createInternalFunctionRoutes(telepactSchema));
2409
+ const normalizedFunctionRouter = functionRouter instanceof FunctionRouter
2410
+ ? functionRouter
2411
+ : new FunctionRouter(functionRouter);
2412
+ normalizedFunctionRouter.functionRoutes = {
2413
+ ...normalizedFunctionRouter.functionRoutes,
2414
+ ...createInternalFunctionRoutes(telepactSchema),
2415
+ };
2420
2416
  this.functionRouter = normalizedFunctionRouter;
2421
2417
  this.middleware = options.middleware;
2422
2418
  this.onError = options.onError;
@@ -2428,8 +2424,8 @@ class Server {
2428
2424
  const binaryEncoder = new ServerBinaryEncoder(binaryEncoding);
2429
2425
  const base64Encoder = new ServerBase64Encoder();
2430
2426
  this.serializer = new Serializer(options.serialization, binaryEncoder, base64Encoder);
2431
- if (!('union.Auth_' in this.telepactSchema.parsed) && this.functionRouter.hasAuthenticatedRoutes()) {
2432
- throw new Error('Authenticated routes require `union.Auth_` in your schema.');
2427
+ if (!('union.Auth_' in this.telepactSchema.parsed) && options.authRequired) {
2428
+ throw new Error('Unauthenticated server. Either define a `union.Auth_` in your schema or set `options.authRequired` to `false`.');
2433
2429
  }
2434
2430
  }
2435
2431
  async process(requestMessageBytes, updateHeaders) {
@@ -2442,6 +2438,7 @@ class ServerOptions {
2442
2438
  onResponse;
2443
2439
  onAuth;
2444
2440
  middleware;
2441
+ authRequired;
2445
2442
  serialization;
2446
2443
  constructor() {
2447
2444
  this.onError = (_error) => { };
@@ -2449,6 +2446,7 @@ class ServerOptions {
2449
2446
  this.onResponse = (m) => { };
2450
2447
  this.onAuth = (headers) => ({});
2451
2448
  this.middleware = async (requestMessage, functionRouter) => await functionRouter.route(requestMessage);
2449
+ this.authRequired = true;
2452
2450
  this.serialization = new DefaultSerialization();
2453
2451
  }
2454
2452
  }
@@ -2496,6 +2494,7 @@ function isSubMap(part, whole) {
2496
2494
  var internalTelepact = [
2497
2495
  {
2498
2496
  "///": "Ping the server.",
2497
+ $internal: true,
2499
2498
  "fn.ping_": {
2500
2499
  },
2501
2500
  "->": [
@@ -2503,11 +2502,11 @@ var internalTelepact = [
2503
2502
  Ok_: {
2504
2503
  }
2505
2504
  }
2506
- ],
2507
- _errors: "^errors\\.Validation_$"
2505
+ ]
2508
2506
  },
2509
2507
  {
2510
2508
  "///": "Get the telepact `schema` of this server.\n\nSet `includeInternal` to `true` to include Telepact internal definitions.\nSet `includeExamples` to `true` to add deterministic example payloads to\neach schema entry.\n",
2509
+ $internal: true,
2511
2510
  "fn.api_": {
2512
2511
  "includeInternal!": "boolean",
2513
2512
  "includeExamples!": "boolean"
@@ -2522,8 +2521,7 @@ var internalTelepact = [
2522
2521
  ]
2523
2522
  }
2524
2523
  }
2525
- ],
2526
- _errors: "^errors\\.Validation_$"
2524
+ ]
2527
2525
  },
2528
2526
  {
2529
2527
  "///": "`_ext.Select_` is the selection object used by the `@select_` header. Use\n`->` to narrow fields on the active result union, `struct.*` keys to narrow\nstruct fields, and `union.*` keys to narrow fields for specific union tags.\n\nSee https://raw.githubusercontent.com/Telepact/telepact/main/doc/02-design-apis/04-select-extension.md\nfor full `_ext.Select_` rules and end-to-end examples.\n",
@@ -10590,15 +10588,18 @@ function parseFunctionResultType(path, functionDefinitionAsParsedJson, schemaKey
10590
10588
  function parseFunctionErrorsRegex(path, functionDefinitionAsParsedJson, schemaKey, ctx) {
10591
10589
  const parseFailures = [];
10592
10590
  const errorsRegexKey = '_errors';
10591
+ const isInternal = schemaKey.endsWith('_') || functionDefinitionAsParsedJson['$internal'] === true;
10593
10592
  const regexPath = [...path, errorsRegexKey];
10594
10593
  let errorsRegex = null;
10595
- if (errorsRegexKey in functionDefinitionAsParsedJson && !schemaKey.endsWith('_')) {
10594
+ if (errorsRegexKey in functionDefinitionAsParsedJson && !isInternal) {
10596
10595
  parseFailures.push(new SchemaParseFailure(ctx.documentName, regexPath, 'ObjectKeyDisallowed', {}));
10597
10596
  }
10598
10597
  else {
10599
10598
  const errorsRegexInit = errorsRegexKey in functionDefinitionAsParsedJson
10600
10599
  ? functionDefinitionAsParsedJson[errorsRegexKey]
10601
- : '^errors\\..*$';
10600
+ : isInternal
10601
+ ? '^errors\\.Validation_$'
10602
+ : '^errors\\..*$';
10602
10603
  if (typeof errorsRegexInit !== 'string') {
10603
10604
  const thisParseFailures = getTypeUnexpectedParseFailure(ctx.documentName, regexPath, errorsRegexInit, 'String');
10604
10605
  parseFailures.push(...thisParseFailures);
@@ -10615,7 +10616,7 @@ function parseFunctionErrorsRegex(path, functionDefinitionAsParsedJson, schemaKe
10615
10616
 
10616
10617
  function parseStructType(path, structDefinitionAsPseudoJson, schemaKey, ignoreKeys, ctx) {
10617
10618
  const parseFailures = [];
10618
- const otherKeys = new Set(Object.keys(structDefinitionAsPseudoJson));
10619
+ const otherKeys = new Set(Object.keys(structDefinitionAsPseudoJson).filter((key) => !key.startsWith('$')));
10619
10620
  otherKeys.delete(schemaKey);
10620
10621
  otherKeys.delete('///');
10621
10622
  otherKeys.delete('_ignoreIfDuplicate');
@@ -11939,9 +11940,9 @@ class MockServer {
11939
11940
  this.invocations = [];
11940
11941
  const serverOptions = new ServerOptions();
11941
11942
  serverOptions.onError = options.onError;
11943
+ serverOptions.authRequired = false;
11942
11944
  const telepactSchema = new TelepactSchema(mockTelepactSchema.original, mockTelepactSchema.full, mockTelepactSchema.parsed, mockTelepactSchema.parsedRequestHeaders, mockTelepactSchema.parsedResponseHeaders);
11943
- const functionRouter = new FunctionRouter();
11944
- functionRouter.registerUnauthenticatedRoutes(this.createFunctionRoutes(telepactSchema));
11945
+ const functionRouter = new FunctionRouter(this.createFunctionRoutes(telepactSchema));
11945
11946
  this.server = new Server(telepactSchema, functionRouter, serverOptions);
11946
11947
  }
11947
11948
  random;
@@ -12049,6 +12050,7 @@ var mockInternalTelepact = [
12049
12050
  },
12050
12051
  {
12051
12052
  "///": "Create a mock stub from an `_ext.Stub_`.\n\nBy default the stub matcher is partial, so extra fields on the actual\nrequest argument are allowed. Set `strictMatch!` to `true` to require exact\nargument equality instead.\n\nSet `count!` to limit how many matching calls consume this stub before it\nstops matching.\n",
12053
+ $internal: true,
12052
12054
  "fn.createStub_": {
12053
12055
  stub: "_ext.Stub_",
12054
12056
  "strictMatch!": "boolean",
@@ -12059,11 +12061,11 @@ var mockInternalTelepact = [
12059
12061
  Ok_: {
12060
12062
  }
12061
12063
  }
12062
- ],
12063
- _errors: "^errors\\.Validation_$"
12064
+ ]
12064
12065
  },
12065
12066
  {
12066
12067
  "///": "Verify that the mock received a call matching the given `_ext.Call_`.\n\nBy default verification is partial and succeeds if at least one recorded\ncall contains the given argument as a JSON sub-structure. Set\n`strictMatch!` to `true` to require exact argument equality.\n\nSet `count!` to require `Exact`, `AtLeast`, or `AtMost` matching call\ncounts. Matching calls are marked as verified, which affects\n`fn.verifyNoMoreInteractions_`.\n",
12068
+ $internal: true,
12067
12069
  "fn.verify_": {
12068
12070
  call: "_ext.Call_",
12069
12071
  "strictMatch!": "boolean",
@@ -12079,11 +12081,11 @@ var mockInternalTelepact = [
12079
12081
  reason: "union.VerificationFailure_"
12080
12082
  }
12081
12083
  }
12082
- ],
12083
- _errors: "^errors\\.Validation_$"
12084
+ ]
12084
12085
  },
12085
12086
  {
12086
12087
  "///": "Verify that no interactions have occurred with this mock or that all\ninteractions have been verified.\n",
12088
+ $internal: true,
12087
12089
  "fn.verifyNoMoreInteractions_": {
12088
12090
  },
12089
12091
  "->": [
@@ -12098,11 +12100,11 @@ var mockInternalTelepact = [
12098
12100
  ]
12099
12101
  }
12100
12102
  }
12101
- ],
12102
- _errors: "^errors\\.Validation_$"
12103
+ ]
12103
12104
  },
12104
12105
  {
12105
12106
  "///": "Clear all stub conditions.",
12107
+ $internal: true,
12106
12108
  "fn.clearStubs_": {
12107
12109
  },
12108
12110
  "->": [
@@ -12110,11 +12112,11 @@ var mockInternalTelepact = [
12110
12112
  Ok_: {
12111
12113
  }
12112
12114
  }
12113
- ],
12114
- _errors: "^errors\\.Validation_$"
12115
+ ]
12115
12116
  },
12116
12117
  {
12117
12118
  "///": "Clear all call data.",
12119
+ $internal: true,
12118
12120
  "fn.clearCalls_": {
12119
12121
  },
12120
12122
  "->": [
@@ -12122,11 +12124,11 @@ var mockInternalTelepact = [
12122
12124
  Ok_: {
12123
12125
  }
12124
12126
  }
12125
- ],
12126
- _errors: "^errors\\.Validation_$"
12127
+ ]
12127
12128
  },
12128
12129
  {
12129
12130
  "///": "Set the seed of the random generator.",
12131
+ $internal: true,
12130
12132
  "fn.setRandomSeed_": {
12131
12133
  seed: "integer"
12132
12134
  },
@@ -12135,8 +12137,7 @@ var mockInternalTelepact = [
12135
12137
  Ok_: {
12136
12138
  }
12137
12139
  }
12138
- ],
12139
- _errors: "^errors\\.Validation_$"
12140
+ ]
12140
12141
  },
12141
12142
  {
12142
12143
  "errors.Mock_": [