quidproquo-core 0.1.0 → 0.1.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 (94) hide show
  1. package/lib/commonjs/actions/ai/AiMessage.d.ts +9 -1
  2. package/lib/commonjs/actions/ai/AiPromptActionRequester.d.ts +2 -0
  3. package/lib/commonjs/actions/ai/AiPromptActionRequester.js +1 -0
  4. package/lib/commonjs/actions/ai/AiPromptActionTypes.d.ts +2 -0
  5. package/lib/commonjs/actions/ai/AiPromptStreamActionRequester.d.ts +2 -0
  6. package/lib/commonjs/actions/ai/AiPromptStreamActionRequester.js +1 -0
  7. package/lib/commonjs/actions/ai/AiPromptStreamActionTypes.d.ts +2 -0
  8. package/lib/commonjs/actions/ai/AiReasoningConfig.d.ts +8 -0
  9. package/lib/commonjs/actions/ai/AiReasoningConfig.js +2 -0
  10. package/lib/commonjs/actions/ai/index.d.ts +1 -0
  11. package/lib/commonjs/actions/ai/index.js +1 -0
  12. package/lib/commonjs/actions/date/DateNowActionTypes.d.ts +3 -2
  13. package/lib/commonjs/actions/file/index.d.ts +2 -2
  14. package/lib/commonjs/actions/keyValueStore/KeyValueStoreUpsertActionRequester.d.ts +1 -0
  15. package/lib/commonjs/actions/keyValueStore/KeyValueStoreUpsertActionRequester.js +8 -1
  16. package/lib/commonjs/actions/keyValueStore/KeyValueStoreUpsertActionTypes.d.ts +1 -0
  17. package/lib/commonjs/actions/userDirectory/UserDirectoryActionType.d.ts +2 -1
  18. package/lib/commonjs/config/index.d.ts +1 -1
  19. package/lib/commonjs/config/utils/index.d.ts +2 -2
  20. package/lib/commonjs/index.d.ts +1 -1
  21. package/lib/commonjs/proiseify/getSystemExecuteStoryActionProcessor.js +9 -1
  22. package/lib/commonjs/runtime/resolveStoryWithLogs.js +26 -9
  23. package/lib/commonjs/stories/askRetry.d.ts +5 -1
  24. package/lib/commonjs/stories/askRetry.js +7 -2
  25. package/lib/commonjs/types/QpqIsoDateTime.d.ts +23 -0
  26. package/lib/commonjs/types/QpqIsoDateTime.js +4 -0
  27. package/lib/commonjs/types/index.d.ts +1 -0
  28. package/lib/commonjs/types/index.js +1 -0
  29. package/lib/commonjs/utils/dateTime/getQpqIsoDateTimeFromDate.d.ts +2 -0
  30. package/lib/commonjs/utils/dateTime/getQpqIsoDateTimeFromDate.js +5 -0
  31. package/lib/commonjs/utils/dateTime/getValidQpqIsoDateTime.d.ts +2 -0
  32. package/lib/commonjs/utils/dateTime/getValidQpqIsoDateTime.js +6 -0
  33. package/lib/commonjs/utils/dateTime/index.d.ts +2 -0
  34. package/lib/commonjs/utils/dateTime/index.js +18 -0
  35. package/lib/commonjs/utils/hash/index.d.ts +1 -0
  36. package/lib/commonjs/utils/hash/index.js +1 -0
  37. package/lib/commonjs/utils/hash/sha1.d.ts +12 -0
  38. package/lib/commonjs/utils/hash/sha1.js +85 -0
  39. package/lib/commonjs/utils/index.d.ts +1 -0
  40. package/lib/commonjs/utils/index.js +1 -0
  41. package/lib/commonjs/utils/uuid/generateUuidV5.d.ts +20 -0
  42. package/lib/commonjs/utils/uuid/generateUuidV5.js +54 -0
  43. package/lib/commonjs/utils/uuid/index.d.ts +1 -0
  44. package/lib/commonjs/utils/uuid/index.js +1 -0
  45. package/lib/esm/actions/ai/AiMessage.d.ts +9 -1
  46. package/lib/esm/actions/ai/AiPromptActionRequester.d.ts +2 -0
  47. package/lib/esm/actions/ai/AiPromptActionRequester.js +1 -0
  48. package/lib/esm/actions/ai/AiPromptActionTypes.d.ts +2 -0
  49. package/lib/esm/actions/ai/AiPromptStreamActionRequester.d.ts +2 -0
  50. package/lib/esm/actions/ai/AiPromptStreamActionRequester.js +1 -0
  51. package/lib/esm/actions/ai/AiPromptStreamActionTypes.d.ts +2 -0
  52. package/lib/esm/actions/ai/AiReasoningConfig.d.ts +8 -0
  53. package/lib/esm/actions/ai/AiReasoningConfig.js +1 -0
  54. package/lib/esm/actions/ai/index.d.ts +1 -0
  55. package/lib/esm/actions/ai/index.js +1 -0
  56. package/lib/esm/actions/date/DateNowActionTypes.d.ts +3 -2
  57. package/lib/esm/actions/file/index.d.ts +2 -2
  58. package/lib/esm/actions/file/index.js +2 -2
  59. package/lib/esm/actions/keyValueStore/KeyValueStoreUpsertActionRequester.d.ts +1 -0
  60. package/lib/esm/actions/keyValueStore/KeyValueStoreUpsertActionRequester.js +8 -1
  61. package/lib/esm/actions/keyValueStore/KeyValueStoreUpsertActionTypes.d.ts +1 -0
  62. package/lib/esm/actions/userDirectory/UserDirectoryActionType.d.ts +2 -1
  63. package/lib/esm/config/index.d.ts +1 -1
  64. package/lib/esm/config/index.js +1 -1
  65. package/lib/esm/config/utils/index.d.ts +2 -2
  66. package/lib/esm/config/utils/index.js +2 -2
  67. package/lib/esm/index.d.ts +1 -1
  68. package/lib/esm/index.js +1 -1
  69. package/lib/esm/proiseify/getSystemExecuteStoryActionProcessor.js +9 -1
  70. package/lib/esm/qpqCoreUtilsLib.js +1 -1
  71. package/lib/esm/runtime/resolveStoryWithLogs.js +26 -9
  72. package/lib/esm/stories/askRetry.d.ts +5 -1
  73. package/lib/esm/stories/askRetry.js +8 -3
  74. package/lib/esm/types/QpqIsoDateTime.d.ts +23 -0
  75. package/lib/esm/types/QpqIsoDateTime.js +3 -0
  76. package/lib/esm/types/index.d.ts +1 -0
  77. package/lib/esm/types/index.js +1 -0
  78. package/lib/esm/utils/dateTime/getQpqIsoDateTimeFromDate.d.ts +2 -0
  79. package/lib/esm/utils/dateTime/getQpqIsoDateTimeFromDate.js +1 -0
  80. package/lib/esm/utils/dateTime/getValidQpqIsoDateTime.d.ts +2 -0
  81. package/lib/esm/utils/dateTime/getValidQpqIsoDateTime.js +2 -0
  82. package/lib/esm/utils/dateTime/index.d.ts +2 -0
  83. package/lib/esm/utils/dateTime/index.js +2 -0
  84. package/lib/esm/utils/hash/index.d.ts +1 -0
  85. package/lib/esm/utils/hash/index.js +1 -0
  86. package/lib/esm/utils/hash/sha1.d.ts +12 -0
  87. package/lib/esm/utils/hash/sha1.js +82 -0
  88. package/lib/esm/utils/index.d.ts +1 -0
  89. package/lib/esm/utils/index.js +1 -0
  90. package/lib/esm/utils/uuid/generateUuidV5.d.ts +20 -0
  91. package/lib/esm/utils/uuid/generateUuidV5.js +50 -0
  92. package/lib/esm/utils/uuid/index.d.ts +1 -0
  93. package/lib/esm/utils/uuid/index.js +1 -0
  94. package/package.json +2 -2
@@ -2,12 +2,20 @@ export interface AiTextPart {
2
2
  type: 'text';
3
3
  text: string;
4
4
  }
5
- export interface AiFilePart {
5
+ export interface AiFileUrlPart {
6
6
  type: 'file';
7
7
  url: string;
8
8
  mediaType: string;
9
9
  filename?: string;
10
10
  }
11
+ export interface AiFileDrivePart {
12
+ type: 'file';
13
+ drive: string;
14
+ filepath: string;
15
+ mediaType: string;
16
+ filename?: string;
17
+ }
18
+ export type AiFilePart = AiFileUrlPart | AiFileDrivePart;
11
19
  export interface AiToolCallPart {
12
20
  type: 'tool-call';
13
21
  toolCallId: string;
@@ -1,9 +1,11 @@
1
1
  import { AiMessage } from './AiMessage';
2
2
  import { AiModel } from './AiModel';
3
3
  import { AiPromptActionRequester } from './AiPromptActionTypes';
4
+ import { AiReasoningConfig } from './AiReasoningConfig';
4
5
  export interface AskAiPromptOptions {
5
6
  system?: string;
6
7
  aiName?: string;
7
8
  messages?: AiMessage[];
9
+ reasoning?: AiReasoningConfig;
8
10
  }
9
11
  export declare function askAiPrompt(model: AiModel, prompt: string, options?: AskAiPromptOptions): AiPromptActionRequester;
@@ -8,6 +8,7 @@ export function* askAiPrompt(model, prompt, options) {
8
8
  messages: options?.messages,
9
9
  system: options?.system,
10
10
  aiName: options?.aiName,
11
+ reasoning: options?.reasoning,
11
12
  },
12
13
  };
13
14
  }
@@ -2,12 +2,14 @@ import { Action, ActionProcessor, ActionRequester } from '../../types/Action';
2
2
  import { AiActionType } from './AiActionType';
3
3
  import { AiMessage } from './AiMessage';
4
4
  import { AiModel } from './AiModel';
5
+ import { AiReasoningConfig } from './AiReasoningConfig';
5
6
  export interface AiPromptActionPayload {
6
7
  model: AiModel;
7
8
  prompt: string;
8
9
  messages?: AiMessage[];
9
10
  system?: string;
10
11
  aiName?: string;
12
+ reasoning?: AiReasoningConfig;
11
13
  }
12
14
  export interface AiPromptActionResult {
13
15
  text: string;
@@ -1,9 +1,11 @@
1
1
  import { AiMessage } from './AiMessage';
2
2
  import { AiModel } from './AiModel';
3
3
  import { AiPromptStreamActionRequester } from './AiPromptStreamActionTypes';
4
+ import { AiReasoningConfig } from './AiReasoningConfig';
4
5
  export interface AskAiPromptStreamOptions {
5
6
  system?: string;
6
7
  aiName?: string;
7
8
  messages?: AiMessage[];
9
+ reasoning?: AiReasoningConfig;
8
10
  }
9
11
  export declare function askAiPromptStream(model: AiModel, prompt: string, options?: AskAiPromptStreamOptions): AiPromptStreamActionRequester;
@@ -8,6 +8,7 @@ export function* askAiPromptStream(model, prompt, options) {
8
8
  messages: options?.messages,
9
9
  system: options?.system,
10
10
  aiName: options?.aiName,
11
+ reasoning: options?.reasoning,
11
12
  },
12
13
  };
13
14
  }
@@ -3,6 +3,7 @@ import { StreamHandle } from '../../types/StreamRegistry';
3
3
  import { AiActionType } from './AiActionType';
4
4
  import { AiMessage } from './AiMessage';
5
5
  import { AiModel } from './AiModel';
6
+ import { AiReasoningConfig } from './AiReasoningConfig';
6
7
  import { AiStreamPart } from './types';
7
8
  export interface AiPromptStreamActionPayload {
8
9
  model: AiModel;
@@ -10,6 +11,7 @@ export interface AiPromptStreamActionPayload {
10
11
  messages?: AiMessage[];
11
12
  system?: string;
12
13
  aiName?: string;
14
+ reasoning?: AiReasoningConfig;
13
15
  }
14
16
  export interface AiPromptStreamAction extends Action<AiPromptStreamActionPayload> {
15
17
  type: AiActionType.PromptStream;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Enables extended thinking for a prompt. Presence turns reasoning on; the
3
+ * budget caps how many tokens the model may spend thinking before it answers.
4
+ * Reasoning progress is surfaced as Reasoning* stream parts.
5
+ */
6
+ export interface AiReasoningConfig {
7
+ budgetTokens?: number;
8
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -5,4 +5,5 @@ export * from './AiPromptActionRequester';
5
5
  export * from './AiPromptActionTypes';
6
6
  export * from './AiPromptStreamActionRequester';
7
7
  export * from './AiPromptStreamActionTypes';
8
+ export * from './AiReasoningConfig';
8
9
  export * from './types';
@@ -5,4 +5,5 @@ export * from './AiPromptActionRequester';
5
5
  export * from './AiPromptActionTypes';
6
6
  export * from './AiPromptStreamActionRequester';
7
7
  export * from './AiPromptStreamActionTypes';
8
+ export * from './AiReasoningConfig';
8
9
  export * from './types';
@@ -1,8 +1,9 @@
1
1
  import { Action, ActionProcessor, ActionRequester } from '../../types/Action';
2
+ import { QpqIsoDateTime } from '../../types/QpqIsoDateTime';
2
3
  import { DateActionType } from './DateActionType';
3
4
  export type DateNowActionPayload = undefined;
4
5
  export interface DateNowAction extends Action<DateNowActionPayload> {
5
6
  type: DateActionType.Now;
6
7
  }
7
- export type DateNowActionProcessor = ActionProcessor<DateNowAction, string>;
8
- export type DateNowActionRequester = ActionRequester<DateNowAction, string>;
8
+ export type DateNowActionProcessor = ActionProcessor<DateNowAction, QpqIsoDateTime>;
9
+ export type DateNowActionRequester = ActionRequester<DateNowAction, QpqIsoDateTime>;
@@ -5,8 +5,8 @@ export * from './FileExistsActionRequester';
5
5
  export * from './FileExistsActionTypes';
6
6
  export * from './FileGenerateTemporarySecureUrlActionRequester';
7
7
  export * from './FileGenerateTemporarySecureUrlActionTypes';
8
- export * from "./FileGenerateTemporaryUploadSecureUrlActionRequester";
9
- export * from "./FileGenerateTemporaryUploadSecureUrlActionTypes";
8
+ export * from './FileGenerateTemporaryUploadSecureUrlActionRequester';
9
+ export * from './FileGenerateTemporaryUploadSecureUrlActionTypes';
10
10
  export * from './FileIsColdStorageActionRequester';
11
11
  export * from './FileIsColdStorageActionTypes';
12
12
  export * from './FileListDirectoryActionRequester';
@@ -5,8 +5,8 @@ export * from './FileExistsActionRequester';
5
5
  export * from './FileExistsActionTypes';
6
6
  export * from './FileGenerateTemporarySecureUrlActionRequester';
7
7
  export * from './FileGenerateTemporarySecureUrlActionTypes';
8
- export * from "./FileGenerateTemporaryUploadSecureUrlActionRequester";
9
- export * from "./FileGenerateTemporaryUploadSecureUrlActionTypes";
8
+ export * from './FileGenerateTemporaryUploadSecureUrlActionRequester';
9
+ export * from './FileGenerateTemporaryUploadSecureUrlActionTypes';
10
10
  export * from './FileIsColdStorageActionRequester';
11
11
  export * from './FileIsColdStorageActionTypes';
12
12
  export * from './FileListDirectoryActionRequester';
@@ -1,6 +1,7 @@
1
1
  import { KeyValueStoreUpsertActionRequester, KeyValueStoreUpsertOptions } from './KeyValueStoreUpsertActionTypes';
2
2
  export declare const KeyValueStoreUpsertErrorTypeEnum: {
3
3
  ResourceNotFound: string;
4
+ Conflict: string;
4
5
  ServiceUnavailable: string;
5
6
  };
6
7
  export declare function askKeyValueStoreUpsert<KvsItem>(keyValueStoreName: string, item: KvsItem, options?: KeyValueStoreUpsertOptions): KeyValueStoreUpsertActionRequester<KvsItem>;
@@ -1,6 +1,13 @@
1
1
  import { createErrorEnumForAction } from '../../types';
2
2
  import { KeyValueStoreActionType } from './KeyValueStoreActionType';
3
- export const KeyValueStoreUpsertErrorTypeEnum = createErrorEnumForAction(KeyValueStoreActionType.Upsert, ['ServiceUnavailable', 'ResourceNotFound']);
3
+ export const KeyValueStoreUpsertErrorTypeEnum = createErrorEnumForAction(KeyValueStoreActionType.Upsert, [
4
+ 'ServiceUnavailable',
5
+ 'ResourceNotFound',
6
+ // A conditional (ifNotExists) write lost to an existing item. Namespaced —
7
+ // not ErrorTypeEnum.Conflict — so retry logic can target the write race
8
+ // specifically without also catching domain-level conflicts.
9
+ 'Conflict',
10
+ ]);
4
11
  export function* askKeyValueStoreUpsert(keyValueStoreName, item, options) {
5
12
  return yield {
6
13
  type: KeyValueStoreActionType.Upsert,
@@ -2,6 +2,7 @@ import { Action, ActionProcessor, ActionRequester } from '../../types/Action';
2
2
  import { KeyValueStoreActionType } from './KeyValueStoreActionType';
3
3
  export interface KeyValueStoreUpsertOptions {
4
4
  ttlInSeconds?: number;
5
+ ifNotExists?: boolean;
5
6
  }
6
7
  export interface KeyValueStoreUpsertActionPayload<KvsItem> {
7
8
  keyValueStoreName: string;
@@ -1,3 +1,4 @@
1
+ import { QpqIsoDateTime } from '../../types/QpqIsoDateTime';
1
2
  import { AuthenticateUserChallenge } from './types';
2
3
  export declare enum UserDirectoryActionType {
3
4
  CreateUser = "@quidproquo-core/UserDirectory/CreateUser",
@@ -23,7 +24,7 @@ export declare enum UserDirectoryActionType {
23
24
  export interface AuthenticationInfo {
24
25
  accessToken?: string;
25
26
  expirationDurationInSeconds?: number;
26
- expiresAt?: string;
27
+ expiresAt?: QpqIsoDateTime;
27
28
  idToken?: string;
28
29
  refreshToken?: string;
29
30
  tokenType?: string;
@@ -1,3 +1,3 @@
1
1
  export * from './QPQConfig';
2
2
  export * from './settings';
3
- export * from "./utils";
3
+ export * from './utils';
@@ -1,3 +1,3 @@
1
1
  export * from './QPQConfig';
2
2
  export * from './settings';
3
- export * from "./utils";
3
+ export * from './utils';
@@ -1,2 +1,2 @@
1
- export * from "./crossModuleUtils";
2
- export * from "./qpqFunctionRuntimeUtils";
1
+ export * from './crossModuleUtils';
2
+ export * from './qpqFunctionRuntimeUtils';
@@ -1,2 +1,2 @@
1
- export * from "./crossModuleUtils";
2
- export * from "./qpqFunctionRuntimeUtils";
1
+ export * from './crossModuleUtils';
2
+ export * from './qpqFunctionRuntimeUtils';
@@ -5,7 +5,7 @@ export * from './createImplementationRuntime';
5
5
  export * from './logic';
6
6
  export * from './logic/actionLogic';
7
7
  export * from './proiseify';
8
- export * from "./qpqCoreUtilsLib";
8
+ export * from './qpqCoreUtilsLib';
9
9
  export * from './qpqExecuteLog';
10
10
  export * from './runtime';
11
11
  export * from './stories';
package/lib/esm/index.js CHANGED
@@ -5,7 +5,7 @@ export * from './createImplementationRuntime';
5
5
  export * from './logic';
6
6
  export * from './logic/actionLogic';
7
7
  export * from './proiseify';
8
- export * from "./qpqCoreUtilsLib";
8
+ export * from './qpqCoreUtilsLib';
9
9
  export * from './qpqExecuteLog';
10
10
  export * from './runtime';
11
11
  export * from './stories';
@@ -47,7 +47,15 @@ const getProcessExecuteStory = (qpqConfig) => {
47
47
  return actionResultError(ErrorTypeEnum.NotFound, `Unable to dynamically load: [${payload.runtime}]`);
48
48
  }
49
49
  try {
50
- const qpqPromisifyRuntime = [payload, session, actionProcessors, logger, updateSession, dynamicModuleLoader, streamRegistry];
50
+ const qpqPromisifyRuntime = [
51
+ payload,
52
+ session,
53
+ actionProcessors,
54
+ logger,
55
+ updateSession,
56
+ dynamicModuleLoader,
57
+ streamRegistry,
58
+ ];
51
59
  const result = await story(...payload.params, getRun(qpqPromisifyRuntime));
52
60
  return actionResult(result);
53
61
  }
@@ -3,5 +3,5 @@ import * as qpqCoreUtilsLib from './qpqCoreUtils';
3
3
  // TODO: Cleanup util exports
4
4
  export const qpqCoreUtils = {
5
5
  ...qpqCoreUtilsLib,
6
- ...moreUtils
6
+ ...moreUtils,
7
7
  };
@@ -1,19 +1,36 @@
1
1
  import { resolveStory } from './resolveStory';
2
- export async function resolveStoryWithLogs(story, args, qpqConfig, callerSession, getActionProcessors, getTimeNow, logger, runtimeCorrelation, runtimeType, dynamicModuleLoader, qpqFunctionRuntimeInfo, initialTags, streamRegistry) {
3
- const logs = [];
4
- const oldConsoleLog = console.log;
5
- try {
2
+ let activeLogCollectors = [];
3
+ let unpatchedConsoleLog = null;
4
+ const pushLogCollector = (collector) => {
5
+ if (unpatchedConsoleLog === null) {
6
+ const original = console.log;
7
+ unpatchedConsoleLog = original;
6
8
  console.log = (...args) => {
7
- const logEntry = { t: getTimeNow(), a: args };
8
- logs.push(logEntry);
9
- return oldConsoleLog(...args);
9
+ for (const active of activeLogCollectors) {
10
+ active.logs.push({ t: active.getTimeNow(), a: args });
11
+ }
12
+ return original(...args);
10
13
  };
14
+ }
15
+ activeLogCollectors.push(collector);
16
+ };
17
+ const popLogCollector = (collector) => {
18
+ activeLogCollectors = activeLogCollectors.filter((active) => active !== collector);
19
+ if (activeLogCollectors.length === 0 && unpatchedConsoleLog !== null) {
20
+ console.log = unpatchedConsoleLog;
21
+ unpatchedConsoleLog = null;
22
+ }
23
+ };
24
+ export async function resolveStoryWithLogs(story, args, qpqConfig, callerSession, getActionProcessors, getTimeNow, logger, runtimeCorrelation, runtimeType, dynamicModuleLoader, qpqFunctionRuntimeInfo, initialTags, streamRegistry) {
25
+ const collector = { logs: [], getTimeNow };
26
+ try {
27
+ pushLogCollector(collector);
11
28
  const storyResult = await resolveStory(story, args, qpqConfig, callerSession, getActionProcessors, getTimeNow, logger, runtimeCorrelation, runtimeType, dynamicModuleLoader, qpqFunctionRuntimeInfo, initialTags, streamRegistry);
12
- storyResult.logs = logs;
29
+ storyResult.logs = collector.logs;
13
30
  logger.log(storyResult);
14
31
  return storyResult;
15
32
  }
16
33
  finally {
17
- console.log = oldConsoleLog;
34
+ popLogCollector(collector);
18
35
  }
19
36
  }
@@ -1,3 +1,7 @@
1
1
  import { AskResponse } from '../types';
2
2
  import { askCatch } from './system';
3
- export declare function askRetry<R>(askRunLogic: () => AskResponse<R>, maxRetries: number, timeToWaitMs: number, errorTypeRetryList?: string[]): ReturnType<typeof askCatch<AskResponse<R>>>;
3
+ export type AskRetryOptions = {
4
+ linearBackoff?: boolean;
5
+ maxJitterMs?: number;
6
+ };
7
+ export declare function askRetry<R>(askRunLogic: () => AskResponse<R>, maxRetries: number, timeToWaitMs: number, errorTypeRetryList?: string[], options?: AskRetryOptions): ReturnType<typeof askCatch<AskResponse<R>>>;
@@ -1,6 +1,6 @@
1
- import { askDelay } from '../actions';
1
+ import { askDelay, askNewGuid } from '../actions';
2
2
  import { askCatch } from './system';
3
- export function* askRetry(askRunLogic, maxRetries, timeToWaitMs, errorTypeRetryList) {
3
+ export function* askRetry(askRunLogic, maxRetries, timeToWaitMs, errorTypeRetryList, options) {
4
4
  let attempt = 0;
5
5
  while (true) {
6
6
  const result = yield* askCatch(askRunLogic());
@@ -13,6 +13,11 @@ export function* askRetry(askRunLogic, maxRetries, timeToWaitMs, errorTypeRetryL
13
13
  return result;
14
14
  }
15
15
  }
16
- yield* askDelay(timeToWaitMs);
16
+ let waitMs = options?.linearBackoff ? timeToWaitMs * attempt : timeToWaitMs;
17
+ if (options?.maxJitterMs) {
18
+ const guid = yield* askNewGuid();
19
+ waitMs += Math.floor((parseInt(guid.slice(0, 2), 16) / 255) * options.maxJitterMs);
20
+ }
21
+ yield* askDelay(waitMs);
17
22
  }
18
23
  }
@@ -0,0 +1,23 @@
1
+ export type TYear = `${number}${number}${number}${number}`;
2
+ export type TMonth = `${number}${number}`;
3
+ export type TDay = `${number}${number}`;
4
+ export type THours = `${number}${number}`;
5
+ export type TMinutes = `${number}${number}`;
6
+ export type TSeconds = `${number}${number}`;
7
+ export type TMilliseconds = `${number}${number}${number}`;
8
+ /**
9
+ * Represent a string like `2021-01-08`
10
+ */
11
+ export type TDateISODate = `${TYear}-${TMonth}-${TDay}`;
12
+ /**
13
+ * Represent a string like `14:42:34.678`
14
+ */
15
+ export type TDateISOTime = `${THours}:${TMinutes}:${TSeconds}.${TMilliseconds}`;
16
+ /**
17
+ * Represent a string like `2021-01-08T14:42:34.678Z` (format: ISO 8601).
18
+ *
19
+ * It is not possible to type more precisely (list every possible values for months, hours etc) as
20
+ * it would result in a warning from TypeScript:
21
+ * "Expression produces a union type that is too complex to represent. ts(2590)
22
+ */
23
+ export type QpqIsoDateTime = `${TDateISODate}T${TDateISOTime}Z`;
@@ -0,0 +1,3 @@
1
+ // Template-literal typing for ISO-8601 timestamps
2
+ // (from https://gist.github.com/MrChocolatine/367fb2a35d02f6175cc8ccb3d3a20054)
3
+ export {};
@@ -20,6 +20,7 @@ export * from './Nullable';
20
20
  export * from './QPQBinaryData';
21
21
  export * from './QpqContextIdentifier';
22
22
  export * from './QpqFunctionRuntime';
23
+ export * from './QpqIsoDateTime';
23
24
  export * from './QpqLogger';
24
25
  export * from './QpqPagedData';
25
26
  export * from './QueueEvent';
@@ -20,6 +20,7 @@ export * from './Nullable';
20
20
  export * from './QPQBinaryData';
21
21
  export * from './QpqContextIdentifier';
22
22
  export * from './QpqFunctionRuntime';
23
+ export * from './QpqIsoDateTime';
23
24
  export * from './QpqLogger';
24
25
  export * from './QpqPagedData';
25
26
  export * from './QueueEvent';
@@ -0,0 +1,2 @@
1
+ import { QpqIsoDateTime } from '../../types/QpqIsoDateTime';
2
+ export declare const getQpqIsoDateTimeFromDate: (date: Date) => QpqIsoDateTime;
@@ -0,0 +1 @@
1
+ export const getQpqIsoDateTimeFromDate = (date) => date.toISOString();
@@ -0,0 +1,2 @@
1
+ import { QpqIsoDateTime } from '../../types/QpqIsoDateTime';
2
+ export declare const getValidQpqIsoDateTime: (value: string | undefined) => QpqIsoDateTime | undefined;
@@ -0,0 +1,2 @@
1
+ const qpqIsoDateTimeRegex = /^\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d{3}Z$/;
2
+ export const getValidQpqIsoDateTime = (value) => value && qpqIsoDateTimeRegex.test(value) ? value : undefined;
@@ -0,0 +1,2 @@
1
+ export * from './getQpqIsoDateTimeFromDate';
2
+ export * from './getValidQpqIsoDateTime';
@@ -0,0 +1,2 @@
1
+ export * from './getQpqIsoDateTimeFromDate';
2
+ export * from './getValidQpqIsoDateTime';
@@ -1 +1,2 @@
1
1
  export * from './generateSimpleHash';
2
+ export * from './sha1';
@@ -1 +1,2 @@
1
1
  export * from './generateSimpleHash';
2
+ export * from './sha1';
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Computes the SHA-1 digest of the given bytes.
3
+ *
4
+ * This is a pure TypeScript implementation (RFC 3174) so it stays synchronous and
5
+ * works in both Node and browsers without the async Web Crypto API or a Node-only
6
+ * `crypto` import. SHA-1 is not collision-resistant, so this must never be used for
7
+ * security purposes - it exists for deterministic identifiers like v5 UUIDs.
8
+ *
9
+ * @param {Uint8Array} message - The bytes to hash.
10
+ * @returns {Uint8Array} The 20-byte SHA-1 digest.
11
+ */
12
+ export declare function sha1(message: Uint8Array): Uint8Array;
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Computes the SHA-1 digest of the given bytes.
3
+ *
4
+ * This is a pure TypeScript implementation (RFC 3174) so it stays synchronous and
5
+ * works in both Node and browsers without the async Web Crypto API or a Node-only
6
+ * `crypto` import. SHA-1 is not collision-resistant, so this must never be used for
7
+ * security purposes - it exists for deterministic identifiers like v5 UUIDs.
8
+ *
9
+ * @param {Uint8Array} message - The bytes to hash.
10
+ * @returns {Uint8Array} The 20-byte SHA-1 digest.
11
+ */
12
+ export function sha1(message) {
13
+ // Pad to a multiple of 64 bytes: a 0x80 byte, zeros, then the 64-bit big-endian bit length.
14
+ const messageLength = message.length;
15
+ const paddedLength = Math.ceil((messageLength + 1 + 8) / 64) * 64;
16
+ const padded = new Uint8Array(paddedLength);
17
+ padded.set(message);
18
+ padded[messageLength] = 0x80;
19
+ const view = new DataView(padded.buffer);
20
+ const bitLength = messageLength * 8;
21
+ view.setUint32(paddedLength - 8, Math.floor(bitLength / 0x100000000));
22
+ view.setUint32(paddedLength - 4, bitLength >>> 0);
23
+ let h0 = 0x67452301;
24
+ let h1 = 0xefcdab89;
25
+ let h2 = 0x98badcfe;
26
+ let h3 = 0x10325476;
27
+ let h4 = 0xc3d2e1f0;
28
+ const w = new Uint32Array(80);
29
+ for (let block = 0; block < paddedLength; block += 64) {
30
+ for (let t = 0; t < 16; t++) {
31
+ w[t] = view.getUint32(block + t * 4);
32
+ }
33
+ for (let t = 16; t < 80; t++) {
34
+ const x = w[t - 3] ^ w[t - 8] ^ w[t - 14] ^ w[t - 16];
35
+ w[t] = (x << 1) | (x >>> 31);
36
+ }
37
+ let a = h0;
38
+ let b = h1;
39
+ let c = h2;
40
+ let d = h3;
41
+ let e = h4;
42
+ for (let t = 0; t < 80; t++) {
43
+ let f;
44
+ let k;
45
+ if (t < 20) {
46
+ f = (b & c) | (~b & d);
47
+ k = 0x5a827999;
48
+ }
49
+ else if (t < 40) {
50
+ f = b ^ c ^ d;
51
+ k = 0x6ed9eba1;
52
+ }
53
+ else if (t < 60) {
54
+ f = (b & c) | (b & d) | (c & d);
55
+ k = 0x8f1bbcdc;
56
+ }
57
+ else {
58
+ f = b ^ c ^ d;
59
+ k = 0xca62c1d6;
60
+ }
61
+ const temp = (((a << 5) | (a >>> 27)) + f + e + k + w[t]) >>> 0;
62
+ e = d;
63
+ d = c;
64
+ c = (b << 30) | (b >>> 2);
65
+ b = a;
66
+ a = temp;
67
+ }
68
+ h0 = (h0 + a) >>> 0;
69
+ h1 = (h1 + b) >>> 0;
70
+ h2 = (h2 + c) >>> 0;
71
+ h3 = (h3 + d) >>> 0;
72
+ h4 = (h4 + e) >>> 0;
73
+ }
74
+ const digest = new Uint8Array(20);
75
+ const digestView = new DataView(digest.buffer);
76
+ digestView.setUint32(0, h0);
77
+ digestView.setUint32(4, h1);
78
+ digestView.setUint32(8, h2);
79
+ digestView.setUint32(12, h3);
80
+ digestView.setUint32(16, h4);
81
+ return digest;
82
+ }
@@ -1,4 +1,5 @@
1
1
  export * from './array';
2
+ export * from './dateTime';
2
3
  export * from './functions';
3
4
  export * from './hash';
4
5
  export * from './logs';
@@ -1,4 +1,5 @@
1
1
  export * from './array';
2
+ export * from './dateTime';
2
3
  export * from './functions';
3
4
  export * from './hash';
4
5
  export * from './logs';
@@ -0,0 +1,20 @@
1
+ export declare enum UuidNamespace {
2
+ dns = "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
3
+ url = "6ba7b811-9dad-11d1-80b4-00c04fd430c8",
4
+ oid = "6ba7b812-9dad-11d1-80b4-00c04fd430c8",
5
+ x500 = "6ba7b814-9dad-11d1-80b4-00c04fd430c8"
6
+ }
7
+ /**
8
+ * Generates a deterministic name-based (version 5) UUID - the sister of `generateUuid`.
9
+ *
10
+ * Where `generateUuid` mints a random v4 UUID, this derives a UUID from a name and a
11
+ * namespace UUID per RFC 4122: the same inputs always produce the same UUID, so it is
12
+ * useful for stable identifiers (e.g. mapping an external key to a UUID). It hashes with
13
+ * the bundled pure-TypeScript SHA-1 so it stays synchronous and dependency-free in both
14
+ * Node and browsers.
15
+ *
16
+ * @param {string} name - The name to derive the UUID from.
17
+ * @param {string} namespace - The namespace UUID, e.g. `UuidNamespace.dns` or any UUID of your own.
18
+ * @returns {string} The derived v5 UUID, e.g. `2ed6657d-e927-568b-95e1-2665a8aea6a2`.
19
+ */
20
+ export declare function generateUuidV5(name: string, namespace: string): string;
@@ -0,0 +1,50 @@
1
+ import { sha1 } from '../hash/sha1';
2
+ // The well-known namespace UUIDs from RFC 4122 Appendix C.
3
+ export var UuidNamespace;
4
+ (function (UuidNamespace) {
5
+ UuidNamespace["dns"] = "6ba7b810-9dad-11d1-80b4-00c04fd430c8";
6
+ UuidNamespace["url"] = "6ba7b811-9dad-11d1-80b4-00c04fd430c8";
7
+ UuidNamespace["oid"] = "6ba7b812-9dad-11d1-80b4-00c04fd430c8";
8
+ UuidNamespace["x500"] = "6ba7b814-9dad-11d1-80b4-00c04fd430c8";
9
+ })(UuidNamespace || (UuidNamespace = {}));
10
+ const uuidFormatRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
11
+ const uuidToBytes = (uuid) => {
12
+ const hex = uuid.replace(/-/g, '');
13
+ const bytes = new Uint8Array(16);
14
+ for (let i = 0; i < 16; i++) {
15
+ bytes[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
16
+ }
17
+ return bytes;
18
+ };
19
+ const bytesToUuid = (bytes) => {
20
+ const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, '0')).join('');
21
+ return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20, 32)}`;
22
+ };
23
+ /**
24
+ * Generates a deterministic name-based (version 5) UUID - the sister of `generateUuid`.
25
+ *
26
+ * Where `generateUuid` mints a random v4 UUID, this derives a UUID from a name and a
27
+ * namespace UUID per RFC 4122: the same inputs always produce the same UUID, so it is
28
+ * useful for stable identifiers (e.g. mapping an external key to a UUID). It hashes with
29
+ * the bundled pure-TypeScript SHA-1 so it stays synchronous and dependency-free in both
30
+ * Node and browsers.
31
+ *
32
+ * @param {string} name - The name to derive the UUID from.
33
+ * @param {string} namespace - The namespace UUID, e.g. `UuidNamespace.dns` or any UUID of your own.
34
+ * @returns {string} The derived v5 UUID, e.g. `2ed6657d-e927-568b-95e1-2665a8aea6a2`.
35
+ */
36
+ export function generateUuidV5(name, namespace) {
37
+ if (!uuidFormatRegex.test(namespace)) {
38
+ throw new Error(`Invalid namespace UUID [${namespace}]`);
39
+ }
40
+ const namespaceBytes = uuidToBytes(namespace);
41
+ const nameBytes = new TextEncoder().encode(name);
42
+ const input = new Uint8Array(namespaceBytes.length + nameBytes.length);
43
+ input.set(namespaceBytes);
44
+ input.set(nameBytes, namespaceBytes.length);
45
+ const bytes = sha1(input).slice(0, 16);
46
+ // RFC 4122: the high nibble of byte 6 carries the version, the top bits of byte 8 the variant.
47
+ bytes[6] = (bytes[6] & 0x0f) | 0x50;
48
+ bytes[8] = (bytes[8] & 0x3f) | 0x80;
49
+ return bytesToUuid(bytes);
50
+ }
@@ -1 +1,2 @@
1
1
  export * from './generateUuid';
2
+ export * from './generateUuidV5';