@tstdl/base 0.93.139 → 0.93.141

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 (218) hide show
  1. package/README.md +166 -0
  2. package/ai/genkit/multi-region.plugin.js +5 -3
  3. package/ai/genkit/tests/multi-region.test.d.ts +1 -0
  4. package/ai/genkit/tests/multi-region.test.js +5 -2
  5. package/ai/parser/parser.js +2 -2
  6. package/ai/prompts/build.js +1 -0
  7. package/ai/prompts/instructions-formatter.d.ts +15 -2
  8. package/ai/prompts/instructions-formatter.js +36 -31
  9. package/ai/prompts/prompt-builder.js +5 -5
  10. package/ai/prompts/steering.d.ts +3 -2
  11. package/ai/prompts/steering.js +3 -1
  12. package/ai/tests/instructions-formatter.test.js +1 -0
  13. package/api/README.md +403 -0
  14. package/api/client/client.js +7 -13
  15. package/api/client/tests/api-client.test.js +10 -10
  16. package/api/default-error-handlers.js +1 -1
  17. package/api/response.d.ts +2 -2
  18. package/api/response.js +22 -33
  19. package/api/server/api-controller.d.ts +1 -1
  20. package/api/server/api-controller.js +3 -3
  21. package/api/server/api-request-token.provider.d.ts +1 -0
  22. package/api/server/api-request-token.provider.js +1 -0
  23. package/api/server/middlewares/allowed-methods.middleware.js +2 -1
  24. package/api/server/middlewares/content-type.middleware.js +2 -1
  25. package/api/types.d.ts +3 -2
  26. package/application/README.md +240 -0
  27. package/application/application.d.ts +1 -1
  28. package/application/application.js +3 -3
  29. package/application/providers.d.ts +20 -2
  30. package/application/providers.js +34 -7
  31. package/audit/README.md +267 -0
  32. package/audit/module.d.ts +5 -0
  33. package/audit/module.js +9 -1
  34. package/authentication/README.md +288 -0
  35. package/authentication/client/authentication.service.d.ts +12 -11
  36. package/authentication/client/authentication.service.js +21 -21
  37. package/authentication/client/http-client.middleware.js +2 -2
  38. package/authentication/server/module.d.ts +5 -0
  39. package/authentication/server/module.js +9 -1
  40. package/authentication/tests/authentication.api-controller.test.js +1 -1
  41. package/authentication/tests/authentication.api-request-token.provider.test.js +1 -1
  42. package/authentication/tests/authentication.client-error-handling.test.js +2 -1
  43. package/authentication/tests/authentication.client-service-refresh.test.js +5 -3
  44. package/authentication/tests/authentication.client-service.test.js +1 -1
  45. package/browser/README.md +401 -0
  46. package/cancellation/README.md +156 -0
  47. package/cancellation/tests/coverage.test.d.ts +1 -0
  48. package/cancellation/tests/coverage.test.js +49 -0
  49. package/cancellation/tests/leak.test.js +24 -29
  50. package/cancellation/tests/token.test.d.ts +1 -0
  51. package/cancellation/tests/token.test.js +136 -0
  52. package/cancellation/token.d.ts +53 -177
  53. package/cancellation/token.js +132 -208
  54. package/circuit-breaker/postgres/module.d.ts +1 -0
  55. package/circuit-breaker/postgres/module.js +5 -1
  56. package/context/README.md +174 -0
  57. package/cookie/README.md +161 -0
  58. package/css/README.md +157 -0
  59. package/data-structures/README.md +320 -0
  60. package/decorators/README.md +140 -0
  61. package/distributed-loop/README.md +231 -0
  62. package/distributed-loop/distributed-loop.js +1 -1
  63. package/document-management/README.md +403 -0
  64. package/document-management/server/configure.js +5 -1
  65. package/document-management/server/module.d.ts +1 -1
  66. package/document-management/server/module.js +1 -1
  67. package/document-management/server/services/document-management-ancillary.service.js +1 -1
  68. package/document-management/server/services/document-management.service.js +9 -7
  69. package/document-management/tests/ai-config-hierarchy.test.js +0 -5
  70. package/document-management/tests/document-management-ai-overrides.test.js +0 -1
  71. package/document-management/tests/document-management-core.test.js +2 -7
  72. package/document-management/tests/document-management.api.test.js +6 -7
  73. package/document-management/tests/document-statistics.service.test.js +11 -12
  74. package/document-management/tests/document-validation-ai-overrides.test.js +0 -1
  75. package/document-management/tests/document.service.test.js +3 -3
  76. package/document-management/tests/enum-helpers.test.js +2 -3
  77. package/dom/README.md +213 -0
  78. package/enumerable/README.md +259 -0
  79. package/enumeration/README.md +121 -0
  80. package/errors/README.md +267 -0
  81. package/examples/document-management/main.d.ts +1 -0
  82. package/examples/document-management/main.js +14 -11
  83. package/file/README.md +191 -0
  84. package/formats/README.md +210 -0
  85. package/function/README.md +144 -0
  86. package/http/README.md +318 -0
  87. package/http/client/adapters/undici.adapter.js +1 -1
  88. package/http/client/http-client-request.d.ts +6 -5
  89. package/http/client/http-client-request.js +8 -9
  90. package/http/server/node/node-http-server.js +1 -2
  91. package/image-service/README.md +137 -0
  92. package/injector/README.md +491 -0
  93. package/intl/README.md +113 -0
  94. package/json-path/README.md +182 -0
  95. package/jsx/README.md +154 -0
  96. package/key-value-store/README.md +191 -0
  97. package/key-value-store/postgres/module.d.ts +1 -0
  98. package/key-value-store/postgres/module.js +5 -1
  99. package/lock/README.md +249 -0
  100. package/lock/postgres/module.d.ts +1 -0
  101. package/lock/postgres/module.js +5 -1
  102. package/lock/web/web-lock.js +119 -47
  103. package/logger/README.md +287 -0
  104. package/mail/README.md +256 -0
  105. package/mail/module.d.ts +5 -1
  106. package/mail/module.js +11 -6
  107. package/memory/README.md +144 -0
  108. package/message-bus/README.md +244 -0
  109. package/message-bus/message-bus-base.js +1 -1
  110. package/module/README.md +182 -0
  111. package/module/module.d.ts +1 -1
  112. package/module/module.js +77 -17
  113. package/module/modules/web-server.module.js +3 -4
  114. package/notification/server/module.d.ts +1 -0
  115. package/notification/server/module.js +5 -1
  116. package/notification/tests/notification-flow.test.js +2 -2
  117. package/notification/tests/notification-type.service.test.js +24 -15
  118. package/object-storage/README.md +300 -0
  119. package/openid-connect/README.md +274 -0
  120. package/orm/README.md +423 -0
  121. package/orm/decorators.d.ts +5 -1
  122. package/orm/decorators.js +1 -1
  123. package/orm/server/drizzle/schema-converter.js +17 -30
  124. package/orm/server/encryption.d.ts +0 -1
  125. package/orm/server/encryption.js +1 -4
  126. package/orm/server/index.d.ts +1 -6
  127. package/orm/server/index.js +1 -6
  128. package/orm/server/migration.d.ts +19 -0
  129. package/orm/server/migration.js +72 -0
  130. package/orm/server/repository.d.ts +1 -1
  131. package/orm/server/transaction.d.ts +5 -10
  132. package/orm/server/transaction.js +22 -26
  133. package/orm/server/transactional.js +3 -3
  134. package/orm/tests/database-migration.test.d.ts +1 -0
  135. package/orm/tests/database-migration.test.js +82 -0
  136. package/orm/tests/encryption.test.js +3 -4
  137. package/orm/utils.d.ts +17 -2
  138. package/orm/utils.js +49 -1
  139. package/package.json +9 -6
  140. package/password/README.md +164 -0
  141. package/pdf/README.md +246 -0
  142. package/polyfills.js +1 -0
  143. package/pool/README.md +198 -0
  144. package/process/README.md +237 -0
  145. package/promise/README.md +252 -0
  146. package/promise/cancelable-promise.js +1 -1
  147. package/random/README.md +193 -0
  148. package/rate-limit/postgres/module.d.ts +1 -0
  149. package/rate-limit/postgres/module.js +5 -1
  150. package/reflection/README.md +305 -0
  151. package/reflection/decorator-data.js +11 -12
  152. package/rpc/README.md +386 -0
  153. package/rxjs-utils/README.md +262 -0
  154. package/schema/README.md +342 -0
  155. package/serializer/README.md +342 -0
  156. package/signals/implementation/README.md +134 -0
  157. package/sse/README.md +278 -0
  158. package/task-queue/README.md +293 -0
  159. package/task-queue/postgres/drizzle/{0000_simple_invisible_woman.sql → 0000_wakeful_sunspot.sql} +22 -14
  160. package/task-queue/postgres/drizzle/meta/0000_snapshot.json +160 -82
  161. package/task-queue/postgres/drizzle/meta/_journal.json +2 -2
  162. package/task-queue/postgres/module.d.ts +1 -0
  163. package/task-queue/postgres/module.js +5 -1
  164. package/task-queue/postgres/schemas.d.ts +9 -6
  165. package/task-queue/postgres/schemas.js +4 -3
  166. package/task-queue/postgres/task-queue.d.ts +4 -13
  167. package/task-queue/postgres/task-queue.js +462 -355
  168. package/task-queue/postgres/task.model.d.ts +12 -5
  169. package/task-queue/postgres/task.model.js +51 -25
  170. package/task-queue/task-context.d.ts +2 -2
  171. package/task-queue/task-context.js +8 -8
  172. package/task-queue/task-queue.d.ts +53 -19
  173. package/task-queue/task-queue.js +121 -55
  174. package/task-queue/tests/cascading-cancellations.test.d.ts +1 -0
  175. package/task-queue/tests/cascading-cancellations.test.js +38 -0
  176. package/task-queue/tests/complex.test.js +45 -229
  177. package/task-queue/tests/coverage-branch.test.d.ts +1 -0
  178. package/task-queue/tests/coverage-branch.test.js +407 -0
  179. package/task-queue/tests/coverage-enhancement.test.d.ts +1 -0
  180. package/task-queue/tests/coverage-enhancement.test.js +144 -0
  181. package/task-queue/tests/dag-dependencies.test.d.ts +1 -0
  182. package/task-queue/tests/dag-dependencies.test.js +41 -0
  183. package/task-queue/tests/dependencies.test.js +28 -26
  184. package/task-queue/tests/extensive-dependencies.test.js +64 -139
  185. package/task-queue/tests/fan-out-spawning.test.d.ts +1 -0
  186. package/task-queue/tests/fan-out-spawning.test.js +53 -0
  187. package/task-queue/tests/idempotent-replacement.test.d.ts +1 -0
  188. package/task-queue/tests/idempotent-replacement.test.js +61 -0
  189. package/task-queue/tests/missing-idempotent-tasks.test.d.ts +1 -0
  190. package/task-queue/tests/missing-idempotent-tasks.test.js +38 -0
  191. package/task-queue/tests/queue.test.js +128 -8
  192. package/task-queue/tests/worker.test.js +39 -16
  193. package/task-queue/tests/zombie-parent.test.d.ts +1 -0
  194. package/task-queue/tests/zombie-parent.test.js +45 -0
  195. package/task-queue/tests/zombie-recovery.test.d.ts +1 -0
  196. package/task-queue/tests/zombie-recovery.test.js +51 -0
  197. package/templates/README.md +287 -0
  198. package/test5.js +5 -5
  199. package/testing/README.md +157 -0
  200. package/testing/integration-setup.d.ts +4 -4
  201. package/testing/integration-setup.js +54 -29
  202. package/text/README.md +346 -0
  203. package/text/localization.service.js +2 -2
  204. package/threading/README.md +238 -0
  205. package/types/README.md +311 -0
  206. package/utils/README.md +322 -0
  207. package/utils/async-iterable-helpers/observable-iterable.d.ts +1 -1
  208. package/utils/async-iterable-helpers/observable-iterable.js +4 -8
  209. package/utils/async-iterable-helpers/take-until.js +4 -4
  210. package/utils/backoff.js +89 -30
  211. package/utils/file-reader.js +1 -2
  212. package/utils/retry-with-backoff.js +1 -1
  213. package/utils/timer.d.ts +1 -1
  214. package/utils/timer.js +5 -7
  215. package/utils/timing.d.ts +1 -1
  216. package/utils/timing.js +2 -4
  217. package/utils/z-base32.d.ts +1 -0
  218. package/utils/z-base32.js +1 -0
package/README.md ADDED
@@ -0,0 +1,166 @@
1
+ # @tstdl/base - A Comprehensive TypeScript Library
2
+
3
+ **The Comprehensive TypeScript Standard Library for Modern Applications.**
4
+
5
+ `@tstdl/base` is a robust, modular, and strictly type-safe foundation designed to accelerate the development of enterprise-grade applications. Whether you are building a server-side microservice, a complex web application, or a cross-platform tool, this library provides the architectural building blocks you need—from Dependency Injection and ORM to AI integration and reactive state management.
6
+
7
+ ## ✨ Key Philosophy
8
+
9
+ - **Type Safety First:** Built entirely in TypeScript with rigorous type definitions, schemas, and generics to catch errors at compile time.
10
+ - **Dependency Injection:** A powerful DI container (`@tstdl/base/injector`) sits at the core, allowing for testable, decoupled, and modular architectures.
11
+ - **Code-First & Definition-First**: Define your data models and API contracts once in TypeScript and let the framework generate the necessary boilerplate and ensure consistency.
12
+ - **Isomorphic Design:** Many modules work seamlessly across Node.js, Browsers, and Workers.
13
+ - **Reactive & Async:** Built-in support for Signals, RxJS, and modern async patterns (Cancellation signals, Async iterables).
14
+ - **Batteries Included:** Stop glueing together dozens of micro-packages. Get a cohesive set of tools that work together out of the box.
15
+
16
+ ## 📦 Installation
17
+
18
+ ```bash
19
+ npm install @tstdl/base
20
+ ```
21
+
22
+ ## 🚀 Quick Start
23
+
24
+ Most applications start by bootstrapping the Dependency Injection container and the Application lifecycle manager.
25
+
26
+ ```typescript
27
+ import { Application, provideModule, provideSignalHandler } from '@tstdl/base/application';
28
+ import { inject, Singleton } from '@tstdl/base/injector';
29
+ import { Logger, provideConsoleLogTransport, PrettyPrintLogFormatter } from '@tstdl/base/logger';
30
+
31
+ // 1. Define a Service
32
+ @Singleton()
33
+ class HelloWorldService {
34
+ private logger = inject(Logger, 'HelloWorld');
35
+
36
+ sayHello() {
37
+ this.logger.info('Hello from @tstdl/base!');
38
+ }
39
+ }
40
+
41
+ // 2. Define your Main Module
42
+ async function main() {
43
+ const service = inject(HelloWorldService);
44
+ service.sayHello();
45
+ }
46
+
47
+ // 3. Run the Application
48
+ Application.run('MyFirstApp', [
49
+ provideModule(main),
50
+ provideConsoleLogTransport(PrettyPrintLogFormatter), // Enable logging
51
+ provideSignalHandler(), // Handle Ctrl+C gracefully
52
+ ]);
53
+ ```
54
+
55
+ ## 🧩 Modules Overview
56
+
57
+ ### 🏗️ Architecture & Core
58
+
59
+ Building blocks for application structure and lifecycle.
60
+
61
+ - **`@tstdl/base/application`**: Bootstrapping, lifecycle management, and graceful shutdown.
62
+ - **`@tstdl/base/injector`**: Powerful Dependency Injection container with scopes, tokens, and async resolution.
63
+ - **`@tstdl/base/module`**: Standardized contracts for start/stop components and workers.
64
+ - **`@tstdl/base/cancellation`**: RxJS-based cancellation tokens for managing async flows.
65
+ - **`@tstdl/base/message-bus`**: Decoupled communication via local subjects or BroadcastChannel.
66
+ - **`@tstdl/base/context`**: Type-safe execution context management (prop-drilling killer).
67
+
68
+ ### 🌐 API & Networking
69
+
70
+ Robust tools for client-server communication.
71
+
72
+ - **`@tstdl/base/api`**: Contract-first API definition sharing between client and server.
73
+ - **`@tstdl/base/http`**: Isomorphic HTTP client/server abstraction with middleware support.
74
+ - **`@tstdl/base/rpc`**: Type-safe Remote Procedure Calls for Workers and cross-window comms.
75
+ - **`@tstdl/base/sse`**: Server-Sent Events with delta-compression support.
76
+
77
+ ### 💾 Data & Storage
78
+
79
+ Persistence layers for databases, files, and caching.
80
+
81
+ - **`@tstdl/base/orm`**: Code-first ORM for PostgreSQL (built on Drizzle) featuring repositories, transactions, **transparent column encryption** and **migrations**.
82
+ - **`@tstdl/base/key-value-store`**: Abstract KV store with PostgreSQL implementation.
83
+ - **`@tstdl/base/object-storage`**: S3-compatible storage abstraction with pre-signed URL support.
84
+ - **`@tstdl/base/queue`**: Persistent background job queues with prioritization and batching.
85
+ - **`@tstdl/base/lock`**: Distributed locking (Postgres) and local locking (Web Locks).
86
+ - **`@tstdl/base/distributed-loop`**: Mechanism for running distributed loops synchronized across processes.
87
+ - **`@tstdl/base/document-management`**: Full document lifecycle, classification, and workflow engine.
88
+
89
+ ### 🔒 Security & Auth
90
+
91
+ Secure your application with ease.
92
+
93
+ - **`@tstdl/base/authentication`**: Full-stack auth with JWTs, sessions, and impersonation.
94
+ - **`@tstdl/base/openid-connect`**: OIDC client with PKCE and auto-discovery.
95
+ - **`@tstdl/base/audit`**: Structured audit logging with contextual enrichment.
96
+ - **`@tstdl/base/password`**: Strength estimation (zxcvbn) and breach detection (HIBP).
97
+
98
+ ### 🛠️ Utilities & Helpers
99
+
100
+ Essential tools for everyday coding.
101
+
102
+ - **`@tstdl/base/schema`**: Runtime validation and type inference.
103
+ - **`@tstdl/base/utils`**: Extensive collection of async iterable helpers, crypto, JSONPath, and deep object manipulation.
104
+ - **`@tstdl/base/serializer`**: JSON-compatible serialization handling circular refs and custom types.
105
+ - **`@tstdl/base/data-structures`**: specialized data structures like circular buffers and weak ref maps.
106
+ - **`@tstdl/base/error`**: Standardized serializable error classes (`NotFoundError`, `ForbiddenError`, etc.).
107
+ - **`@tstdl/base/promise`**: Advanced promise implementations (`DeferredPromise`, `LazyPromise`, `CancelablePromise`).
108
+ - **`@tstdl/base/disposable`**: Implementations of the `Disposable` and `AsyncDisposable` patterns.
109
+ - **`@tstdl/base/logger`**: Structured logging with hierarchical contexts and pluggable transports.
110
+ - **`@tstdl/base/types`**: Advanced TypeScript utility types (GeoJSON, Tagged types, DeepPartial).
111
+ - **`@tstdl/base/enumerable`**: LINQ-inspired fluent API for collections and async streams.
112
+
113
+ ### 🤖 AI & Processing
114
+
115
+ Modern capabilities for intelligent apps.
116
+
117
+ - **`@tstdl/base/ai`**: Unified wrapper for Google Gemini and Vertex AI with structured output.
118
+ - **`@tstdl/base/image`**: Abstraction for image processing services (e.g., Imgproxy).
119
+ - **`@tstdl/base/process`**: Promise/Stream-based child process management.
120
+ - **`@tstdl/base/threading`**: Thread pools for Node.js threads and Web Workers with RPC.
121
+ - **`@tstdl/base/pool`**: Async object pooling for resource management.
122
+
123
+ ### 🖥️ UI & Rendering
124
+
125
+ Tools for frontend logic and content generation.
126
+
127
+ - **`@tstdl/base/signals`**: High-performance reactive state management based on Angular Signals.
128
+ - **`@tstdl/base/dom`**: Reactive wrappers for DOM observers (Resize, Intersection) and file handling.
129
+ - **`@tstdl/base/browser`**: Controller-based wrapper for Playwright automation.
130
+ - **`@tstdl/base/pdf`**: Generate PDFs from HTML/Templates via headless browser.
131
+ - **`@tstdl/base/mail`**: Email sending service with rich template support.
132
+ - **`@tstdl/base/jsx`**: Lightweight SSR for JSX/TSX (Preact-based).
133
+ - **`@tstdl/base/text`**: Reactive i18n/localization built on Signals.
134
+ - **`@tstdl/base/templates`**: Multi-engine template rendering (Handlebars, JSX, MJML).
135
+ - **`@tstdl/base/theme`**: Services for managing color palettes and CSS variables.
136
+ - **`@tstdl/base/rxjs`**: A collection of RxJS operators.
137
+
138
+ ---
139
+
140
+ ## 🔧 Configuration
141
+
142
+ Most server-side modules (`orm`, `mail`, `queue`, `ai`) require configuration during the application bootstrap phase.
143
+
144
+ ```typescript
145
+ import { configureOrm } from '@tstdl/base/orm/server';
146
+ import { configureAiService } from '@tstdl/base/ai';
147
+
148
+ // Example bootstrap function
149
+ export async function bootstrap() {
150
+ // Configure Database
151
+ configureOrm({
152
+ connection: {
153
+ /* Postgres config */
154
+ },
155
+ });
156
+
157
+ // Configure AI
158
+ configureAiService({
159
+ apiKey: process.env.GOOGLE_API_KEY,
160
+ });
161
+ }
162
+ ```
163
+
164
+ ## 📖 Getting Started & Examples
165
+
166
+ The best way to get started is to explore the **`examples/`** directory in the repository. It contains practical, runnable examples for many of the core modules, demonstrating how they work together to build a complete application.
@@ -39,7 +39,7 @@ export function vertexAiMultiLocation(options) {
39
39
  ...request,
40
40
  config: {
41
41
  ...request.config,
42
- location: location,
42
+ location,
43
43
  },
44
44
  }, {
45
45
  onChunk: streamingCallback,
@@ -65,13 +65,15 @@ export function vertexAiMultiLocation(options) {
65
65
  };
66
66
  return genkitPlugin(pluginKey, async (_ai) => {
67
67
  // Register nothing initially, rely on lazy resolution via resolver
68
- }, async (ai, actionType, target) => {
68
+ },
69
+ // biome-ignore lint/suspicious/useAwait: given
70
+ async (ai, actionType, target) => {
69
71
  if (actionType != 'model') {
70
72
  return;
71
73
  }
72
74
  // Register the action immediately so the lookup succeeds
73
75
  // We must register it directly in the registry since ai.defineModel is async and might be too late
74
- (ai.registry).registerActionAsync('model', target, createVirtualizedModelAction(ai, target), { namespace: pluginKey });
76
+ ai.registry.registerActionAsync('model', target, createVirtualizedModelAction(ai, target), { namespace: pluginKey });
75
77
  });
76
78
  }
77
79
  vertexAiMultiLocation.model = function multiLocationModel(baseModel) {
@@ -1 +1,2 @@
1
+ /** biome-ignore-all lint/suspicious/useAwait: defineModel requires async */
1
2
  export {};
@@ -1,3 +1,4 @@
1
+ /** biome-ignore-all lint/suspicious/useAwait: defineModel requires async */
1
2
  import { genkit, GenkitError, z } from 'genkit';
2
3
  import { beforeAll, beforeEach, describe, expect, it, vi } from 'vitest';
3
4
  import { CircuitBreakerState } from '../../../circuit-breaker/index.js';
@@ -13,6 +14,7 @@ vi.mock('#/utils/array/index.js', async (importOriginal) => {
13
14
  };
14
15
  });
15
16
  vi.mock('@genkit-ai/google-genai', () => ({
17
+ // biome-ignore lint/style/useNamingConvention: given
16
18
  vertexAI: {
17
19
  model: vi.fn((name) => ({
18
20
  name: `vertexai/${name}`,
@@ -20,6 +22,7 @@ vi.mock('@genkit-ai/google-genai', () => ({
20
22
  configSchema: z.object({}),
21
23
  })),
22
24
  },
25
+ // biome-ignore lint/style/useNamingConvention: given
23
26
  googleAI: vi.fn(),
24
27
  }));
25
28
  describe('Genkit vertexai-multi-location Plugin Tests', () => {
@@ -39,11 +42,11 @@ describe('Genkit vertexai-multi-location Plugin Tests', () => {
39
42
  locations: ['region-1', 'region-2'],
40
43
  circuitBreakerProvider: cbProvider,
41
44
  logger,
42
- circuitBreakerConfig: { resetTimeout: 1000000, threshold: 1 },
45
+ circuitBreakerConfig: { resetTimeout: 1_000_000, threshold: 1 },
43
46
  }),
44
47
  ],
45
48
  });
46
- const config = { threshold: 1, resetTimeout: 1000000 };
49
+ const config = { threshold: 1, resetTimeout: 1_000_000 };
47
50
  await cbProvider.provide('genkit:vertex-ai:location:region-1', config).recordSuccess();
48
51
  await cbProvider.provide('genkit:vertex-ai:location:region-2', config).recordSuccess();
49
52
  await cbProvider.provide('genkit:vertex-ai:location:cb-fail', config).recordSuccess();
@@ -5,7 +5,7 @@ import { isDate, isUndefined } from '../../utils/type-guards.js';
5
5
  */
6
6
  export function parseAiNullableText(text) {
7
7
  const trimmed = text?.trim();
8
- if (isUndefined(trimmed) || (trimmed == 'null')) {
8
+ if (isUndefined(trimmed) || (trimmed === 'null')) {
9
9
  return null;
10
10
  }
11
11
  return trimmed;
@@ -16,10 +16,10 @@ export function parseAiDateToNumericDate(dateOrString, allowNull = true, fallbac
16
16
  }
17
17
  const date = new Date(dateOrString);
18
18
  if (Number.isNaN(date.getTime())) {
19
- console.warn(`Invalid date string from AI: ${dateOrString}`);
20
19
  if (allowNull) {
21
20
  return null;
22
21
  }
22
+ // biome-ignore lint/complexity/noArguments: fallback can be passed as undefined
23
23
  if (arguments.length >= 3) {
24
24
  return fallback;
25
25
  }
@@ -8,6 +8,7 @@ export function buildPrompts(data) {
8
8
  const systemInstructions = (isDefined(data.additionalSystemInstructions) && (isString(data.additionalSystemInstructions) || (objectKeys(data.additionalSystemInstructions).length > 0)))
9
9
  ? [data.baseSystemInstructions, { 'Additional Instructions': data.additionalSystemInstructions }]
10
10
  : data.baseSystemInstructions;
11
+ // biome-ignore lint/style/useNamingConvention: prompt
11
12
  const dataInstructions = isDefined(data.data) ? { Data: `\`\`\`toon\n${formatData(data.data)}\n\`\`\`` } : undefined;
12
13
  const outputLanguageInstructions = isDefined(data.language) ? { 'Output Language': languagePrompt(data.language) } : undefined;
13
14
  const userInstructions = sections(((isDefined(data.additionalUserInstructions) && (isString(data.additionalUserInstructions) || (objectKeys(data.additionalUserInstructions).length > 0)))
@@ -70,6 +70,19 @@ export declare function unorderedList(items: InstructionsListContent): Instructi
70
70
  * @param items - The list items or map.
71
71
  */
72
72
  export declare function unorderedList(instruction: string, items: InstructionsListContent): InstructionsList;
73
- export declare const formatInstructions: (node: Instructions | InstructionsList, options?: {
73
+ /**
74
+ * Formats a structured instructions object into a string representation suitable for AI prompts (Markdown).
75
+ *
76
+ * It recursively handles:
77
+ * - `sections`: Creates headers (H1, H2...).
78
+ * - `ordered` / `unordered`: Creates indented lists.
79
+ * - `Instructions`: Objects are formatted as key-value pairs (e.g., `- **Key:** Value`).
80
+ *
81
+ * @param node - The root instructions object, array, or instructions list wrapper.
82
+ * @param options - Formatting options.
83
+ * @param options.initialDepth - The starting indentation level (default: 0).
84
+ * @returns A formatted string.
85
+ */
86
+ export declare function formatInstructions(node: Instructions | InstructionsList, options?: {
74
87
  initialDepth?: number;
75
- }) => string;
88
+ }): string;
@@ -1,6 +1,7 @@
1
1
  import { memoize } from '../../utils/function/memoize.js';
2
2
  import { hasOwnProperty, objectEntries } from '../../utils/object/object.js';
3
3
  import { assertDefined, isArray, isDefined, isObject, isString } from '../../utils/type-guards.js';
4
+ const whitespacePattern = /^\s*/;
4
5
  // --- Factories ---
5
6
  function list(style, instructionOrItems, itemsOrNothing) {
6
7
  const instruction = isString(instructionOrItems) ? instructionOrItems : undefined;
@@ -30,7 +31,7 @@ function getPrefix(style, index, sectionDepth) {
30
31
  case 'unordered':
31
32
  return '- ';
32
33
  case 'sections':
33
- return '#'.repeat(Math.max(1, sectionDepth)) + ' ';
34
+ return `${'#'.repeat(Math.max(1, sectionDepth))} `;
34
35
  default:
35
36
  return '';
36
37
  }
@@ -41,24 +42,24 @@ function dedent(text) {
41
42
  return text.trim();
42
43
  }
43
44
  // Remove leading empty line if any (common in template literals)
44
- if (lines[0].trim().length == 0) {
45
+ if (lines[0].trim().length === 0) {
45
46
  lines.shift();
46
47
  }
47
48
  // Remove trailing empty line if any
48
- if (lines.length > 0 && lines[lines.length - 1].trim().length == 0) {
49
+ if (lines.length > 0 && lines.at(-1).trim().length === 0) {
49
50
  lines.pop();
50
51
  }
51
- if (lines.length == 0) {
52
+ if (lines.length === 0) {
52
53
  return '';
53
54
  }
54
55
  // Find minimum indentation (excluding empty lines)
55
56
  const minIndent = lines
56
57
  .filter((line) => line.trim().length > 0)
57
58
  .reduce((min, line) => {
58
- const match = /^\s*/.exec(line);
59
+ const match = whitespacePattern.exec(line);
59
60
  return Math.min(min, match ? match[0].length : 0);
60
- }, Infinity);
61
- if (minIndent == Infinity) {
61
+ }, Number.POSITIVE_INFINITY);
62
+ if (minIndent == Number.POSITIVE_INFINITY) {
62
63
  return lines.join('\n').trim();
63
64
  }
64
65
  return lines.map((line) => line.slice(minIndent)).join('\n').trim();
@@ -162,14 +163,12 @@ function processNode(node, context) {
162
163
  // Section: Header \n\n Content
163
164
  return `${headerLine}\n\n${dedent(effectiveValue)}`;
164
165
  }
165
- else {
166
- // List: "- **Key:** Value"
167
- // We need to construct the full string to calculate hanging indent correctly.
168
- // headerLine already contains indentation + prefix + key.
169
- // We strip the indentation to feed it into the formatting helper effectively.
170
- const fullLine = `${headerLine} ${dedent(effectiveValue)}`.trim();
171
- return formatWithHangingIndent(fullLine, currentBaseIndent, '');
172
- }
166
+ // List: "- **Key:** Value"
167
+ // We need to construct the full string to calculate hanging indent correctly.
168
+ // headerLine already contains indentation + prefix + key.
169
+ // We strip the indentation to feed it into the formatting helper effectively.
170
+ const fullLine = `${headerLine} ${dedent(effectiveValue)}`.trim();
171
+ return formatWithHangingIndent(fullLine, currentBaseIndent, '');
173
172
  }
174
173
  // If Value is Object/Array/Wrapper
175
174
  const body = processNode(effectiveValue, {
@@ -183,21 +182,7 @@ function processNode(node, context) {
183
182
  return `${headerLine}${bodySeparator}${body}`;
184
183
  }).join(separator);
185
184
  }
186
- export const formatInstructions = memoize(
187
- /**
188
- * Formats a structured instructions object into a string representation suitable for AI prompts (Markdown).
189
- *
190
- * It recursively handles:
191
- * - `sections`: Creates headers (H1, H2...).
192
- * - `ordered` / `unordered`: Creates indented lists.
193
- * - `Instructions`: Objects are formatted as key-value pairs (e.g., `- **Key:** Value`).
194
- *
195
- * @param node - The root instructions object, array, or instructions list wrapper.
196
- * @param options - Formatting options.
197
- * @param options.initialDepth - The starting indentation level (default: 0).
198
- * @returns A formatted string.
199
- */
200
- function formatInstructions(node, options = {}) {
185
+ function _formatInstructions(node, options = {}) {
201
186
  // Heuristic: If passing a raw object, assume it's a Root Section unless specified otherwise.
202
187
  // If passing a Wrapper, the Wrapper dictates the style.
203
188
  const initialStyle = isInstructionsList(node)
@@ -212,4 +197,24 @@ function formatInstructions(node, options = {}) {
212
197
  sectionDepth: 1,
213
198
  style: initialStyle,
214
199
  }).trim();
215
- });
200
+ }
201
+ const formatInstructionsMemoized = memoize(_formatInstructions, { weak: true });
202
+ /**
203
+ * Formats a structured instructions object into a string representation suitable for AI prompts (Markdown).
204
+ *
205
+ * It recursively handles:
206
+ * - `sections`: Creates headers (H1, H2...).
207
+ * - `ordered` / `unordered`: Creates indented lists.
208
+ * - `Instructions`: Objects are formatted as key-value pairs (e.g., `- **Key:** Value`).
209
+ *
210
+ * @param node - The root instructions object, array, or instructions list wrapper.
211
+ * @param options - Formatting options.
212
+ * @param options.initialDepth - The starting indentation level (default: 0).
213
+ * @returns A formatted string.
214
+ */
215
+ export function formatInstructions(node, options = {}) {
216
+ if (isString(node)) {
217
+ return _formatInstructions(node, options);
218
+ }
219
+ return formatInstructionsMemoized(node, options);
220
+ }
@@ -1,9 +1,11 @@
1
1
  import { encodeBase64 } from '../../utils/base64.js';
2
2
  import { fromEntries, objectEntries, objectKeys } from '../../utils/object/index.js';
3
- import { assertObjectPass, isDefined, isString } from '../../utils/type-guards.js';
3
+ import { assertObjectPass, isDefined, isString, isUndefined } from '../../utils/type-guards.js';
4
4
  import { formatData } from './format.js';
5
5
  import { formatInstructions, sections } from './instructions-formatter.js';
6
6
  export class PromptBuilder {
7
+ #systemMedia = [];
8
+ #media = [];
7
9
  #systemRole;
8
10
  #role;
9
11
  #systemTask;
@@ -12,8 +14,6 @@ export class PromptBuilder {
12
14
  #instructions = {};
13
15
  #systemContextParts = {};
14
16
  #contextParts = {};
15
- #systemMedia = [];
16
- #media = [];
17
17
  setSystemRole(role) {
18
18
  this.#systemRole = role;
19
19
  return this;
@@ -47,7 +47,7 @@ export class PromptBuilder {
47
47
  return this;
48
48
  }
49
49
  addSystemContext(titleOrContext, contextOrNothing) {
50
- if ((arguments.length == 1)) {
50
+ if (isUndefined(contextOrNothing)) {
51
51
  this.#systemContextParts = { ...this.#systemContextParts, ...assertObjectPass(titleOrContext) };
52
52
  return this;
53
53
  }
@@ -55,7 +55,7 @@ export class PromptBuilder {
55
55
  return this;
56
56
  }
57
57
  addContext(titleOrContext, contextOrNothing) {
58
- if ((arguments.length == 1)) {
58
+ if (isUndefined(contextOrNothing)) {
59
59
  this.#contextParts = { ...this.#contextParts, ...assertObjectPass(titleOrContext) };
60
60
  return this;
61
61
  }
@@ -1,7 +1,8 @@
1
+ import type { ObjectLiteral } from '../../types/types.js';
1
2
  import { type Instructions } from './instructions-formatter.js';
2
3
  export type FewShotExample = {
3
- input: any;
4
- output: any;
4
+ input: ObjectLiteral | null;
5
+ output: ObjectLiteral | null;
5
6
  /** Whether this is a negative example (showing what NOT to do). */
6
7
  isNegative?: boolean;
7
8
  /** Optional reason explaining why this example is positive or negative. */
@@ -13,9 +13,10 @@ function formatExampleValue(value) {
13
13
  * @returns A formatted few-shot prompt.
14
14
  */
15
15
  export function fewShotPrompt(examples) {
16
- if (examples.length == 0) {
16
+ if (examples.length === 0) {
17
17
  return {};
18
18
  }
19
+ // biome-ignore-start lint/style/useNamingConvention: prompt
19
20
  const entries = examples
20
21
  .map((example, index) => {
21
22
  const type = example.isNegative ? 'NEGATIVE' : 'POSITIVE';
@@ -31,6 +32,7 @@ export function fewShotPrompt(examples) {
31
32
  return {
32
33
  Examples: orderedList('Use the following examples to understand the expected input and output format', fromEntries(entries)),
33
34
  };
35
+ // biome-ignore-end lint/style/useNamingConvention: prompt
34
36
  }
35
37
  /**
36
38
  * Creates a prompt addition to specify the output language.
@@ -1,3 +1,4 @@
1
+ /** biome-ignore-all lint/style/useNamingConvention: instructions are uppercase */
1
2
  import { describe, expect, test } from 'vitest';
2
3
  import { formatInstructions, orderedList, sections, unorderedList } from '../prompts/instructions-formatter.js';
3
4
  describe('Instructions Formatter', () => {