@simpill/utils 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CONTRIBUTING.md +787 -0
- package/README.md +186 -0
- package/__tests__/README.md +32 -0
- package/__tests__/e2e/all-packages-resolve.e2e.test.ts +40 -0
- package/__tests__/integration/env-and-async.integration.test.ts +12 -0
- package/__tests__/integration/errors-and-uuid.integration.test.ts +14 -0
- package/__tests__/integration/object-and-array.integration.test.ts +15 -0
- package/__tests__/unit/@simpill/_resolver/resolve-packages.unit.test.ts +47 -0
- package/__tests__/unit/@simpill/array.utils/array.utils.unit.test.ts +11 -0
- package/__tests__/unit/@simpill/async.utils/async.utils.unit.test.ts +12 -0
- package/__tests__/unit/@simpill/cache.utils/cache.utils.unit.test.ts +21 -0
- package/__tests__/unit/@simpill/env.utils/env.utils.unit.test.ts +13 -0
- package/__tests__/unit/@simpill/errors.utils/errors.utils.unit.test.ts +13 -0
- package/__tests__/unit/@simpill/object.utils/object.utils.unit.test.ts +11 -0
- package/__tests__/unit/@simpill/patterns.utils/patterns.utils.unit.test.ts +23 -0
- package/__tests__/unit/@simpill/string.utils/string.utils.unit.test.ts +11 -0
- package/__tests__/unit/@simpill/time.utils/time.utils.unit.test.ts +12 -0
- package/__tests__/unit/@simpill/uuid.utils/uuid.utils.unit.test.ts +12 -0
- package/docs/PUBLISHING_AND_PACKAGES.md +258 -0
- package/docs/template/.env.sample +0 -0
- package/docs/template/README.md +0 -0
- package/docs/template/TEMPLATE.md +1040 -0
- package/docs/template/assets/logo-banner.svg +20 -0
- package/docs/template/package.json +14 -0
- package/index.ts +89 -0
- package/package.json +87 -0
- package/scripts/README.md +57 -0
- package/scripts/github/github-set-all-topics.js +120 -0
- package/scripts/github/github-set-repo-topics.sh +33 -0
- package/scripts/github/github-set-repos-public.sh +71 -0
- package/scripts/lib/package-topics.js +57 -0
- package/scripts/lib/publish-order.js +140 -0
- package/scripts/lib/sync-repo-links.js +75 -0
- package/scripts/monorepo/install-hooks.sh +64 -0
- package/scripts/monorepo/monorepo-clean.sh +7 -0
- package/scripts/monorepo/monorepo-sync-deps.js +81 -0
- package/scripts/monorepo/monorepo-verify-deps.js +37 -0
- package/scripts/monorepo/use-local-utils-at-root.js +49 -0
- package/scripts/publish/publish-all.sh +152 -0
- package/scripts/utils/utils-fix-repo-metadata.js +61 -0
- package/scripts/utils/utils-prepare-all.sh +107 -0
- package/scripts/utils/utils-set-npm-keywords.js +132 -0
- package/scripts/utils/utils-update-readme-badges.js +83 -0
- package/scripts/utils/utils-use-local-deps.js +43 -0
- package/scripts/utils/utils-verify-all.sh +45 -0
- package/tsconfig.json +14 -0
package/README.md
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="./logo.png" alt="@simpill" width="100%" />
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<p align="center">
|
|
6
|
+
<strong>A collection of lightweight, type-safe TypeScript utility packages for modern JavaScript applications.</strong>
|
|
7
|
+
</p>
|
|
8
|
+
|
|
9
|
+
<p align="center">
|
|
10
|
+
<a href="#philosophy">Philosophy</a> •
|
|
11
|
+
<a href="#repositories">Repositories</a> •
|
|
12
|
+
<a href="#quick-start">Quick Start</a> •
|
|
13
|
+
<a href="#discoverability">Discoverability</a> •
|
|
14
|
+
<a href="#credits-and-inspiration">Credits</a>
|
|
15
|
+
</p>
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Philosophy
|
|
20
|
+
|
|
21
|
+
- **Minimal** — Each package does one thing well with minimal dependencies.
|
|
22
|
+
- **Type-safe** — Full TypeScript support with strict mode enabled.
|
|
23
|
+
- **Tested** — 80%+ code coverage required for all packages.
|
|
24
|
+
- **Consistent** — Unified code style, structure, and tooling across all packages.
|
|
25
|
+
|
|
26
|
+
Each package is published under the `@simpill` scope on npm. Source code lives in **separate GitHub repositories**; this repo is the landing page and index.
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Repositories
|
|
31
|
+
|
|
32
|
+
Each package has its own repository. Click through for source, README, and contribution instructions.
|
|
33
|
+
|
|
34
|
+
| Package | Description | Status |
|
|
35
|
+
|---------|-------------|--------|
|
|
36
|
+
| [**adapters.utils**](https://github.com/SkinnnyJay/adapters.utils) | Adapter helpers, logger and cache adapter interfaces (Node and Edge). | New |
|
|
37
|
+
| [**algorithms.utils**](https://github.com/SkinnnyJay/algorithms.utils) | Algorithms: stable merge sort, quick sort, binary search, lower/upper bound (Node and Edge). | New |
|
|
38
|
+
| [**annotations.utils**](https://github.com/SkinnnyJay/annotations.utils) | Typed metadata store and annotation helpers for symbols and keys (Node and Edge). | New |
|
|
39
|
+
| [**api.utils**](https://github.com/SkinnnyJay/api.utils) | Typed API client with Zod validation, handler registry, and middleware (Node and Edge). | New |
|
|
40
|
+
| [**array.utils**](https://github.com/SkinnnyJay/array.utils) | Array utilities: unique, chunk, compact, groupBy, sortBy, flattenOnce (Node and Edge). | New |
|
|
41
|
+
| [**async.utils**](https://github.com/SkinnnyJay/async.utils) | Retry failed promises with timeout, delay, and backoff; limit concurrency with Semaphore (Node and Edge). | New |
|
|
42
|
+
| [**cache.utils**](https://github.com/SkinnnyJay/cache.utils) | In-memory LRU and TTL cache with memoize; small and tree-shakeable (Node and Edge). | New |
|
|
43
|
+
| [**collections.utils**](https://github.com/SkinnnyJay/collections.utils) | Type-safe LinkedList, Queue, Stack, LRU/TTL, MultiMap, BiMap—no full collections lib (Node and Edge). | New |
|
|
44
|
+
| [**crypto.utils**](https://github.com/SkinnnyJay/crypto.utils) | Hash, randomBytes, and timing-safe compare for Node.js. | New |
|
|
45
|
+
| [**data.utils**](https://github.com/SkinnnyJay/data.utils) | Data utilities: validate, prepare, lifecycle, extend, config (Node and Edge). | New |
|
|
46
|
+
| [**env.utils**](https://github.com/SkinnnyJay/env.utils) | Lightweight, type-safe environment variable utilities for Node.js and Edge Runtime. | Stable |
|
|
47
|
+
| [**enum.utils**](https://github.com/SkinnnyJay/enum.utils) | Enum helpers: getEnumValue, isValidEnumValue, EnumHelper (Node and Edge). | New |
|
|
48
|
+
| [**errors.utils**](https://github.com/SkinnnyJay/errors.utils) | Typed error classes, error codes, and serializeError for logging and RPC (Node and Edge). | New |
|
|
49
|
+
| [**events.utils**](https://github.com/SkinnnyJay/events.utils) | PubSub, observer, and typed event emitter (Node and Edge). | New |
|
|
50
|
+
| [**factories.utils**](https://github.com/SkinnnyJay/factories.utils) | Typed factory builder, singleton factory, and error factory helpers (Node and Edge). | New |
|
|
51
|
+
| [**file.utils**](https://github.com/SkinnnyJay/file.utils) | Typed file I/O: readFileUtf8, readFileJson, writeFile, ensureDir for Node.js. | New |
|
|
52
|
+
| [**function.utils**](https://github.com/SkinnnyJay/function.utils) | Debounce, throttle, once, pipe, and compose with TypeScript inference (Node and Edge). | New |
|
|
53
|
+
| [**http.utils**](https://github.com/SkinnnyJay/http.utils) | Fetch with timeout, retry, and typed HTTP client—no axios required (Node and Edge). | New |
|
|
54
|
+
| [**ai-image-generated-ai-cli**](https://github.com/simpill/ai-image-generated-ai-cli) | Image AI toolkit: core SDK, CLI (`ai-image-gen`), and prompt discovery web UI (Gemini, OpenAI, xAI). | New |
|
|
55
|
+
| [**logger.utils**](https://github.com/SkinnnyJay/logger.utils) | Lightweight, type-safe structured logging with correlation context for Node.js and Edge Runtime. | In Development |
|
|
56
|
+
| [**middleware.utils**](https://github.com/SkinnnyJay/middleware.utils) | Framework-agnostic middleware types and correlation ID middleware (Node and Edge). | New |
|
|
57
|
+
| [**misc.utils**](https://github.com/SkinnnyJay/misc.utils) | Backend misc: singleton, debounce, throttle, LRU, polling, intervals, enums, once, memoize (Node and Edge). | New |
|
|
58
|
+
| [**nextjs.utils**](https://github.com/SkinnnyJay/nextjs.utils) | Next.js App Router helpers: safe server actions, route handlers, request context, middleware. | New |
|
|
59
|
+
| [**number.utils**](https://github.com/SkinnnyJay/number.utils) | Number utilities: clamp, roundTo, toInt/Float, isInRange, lerp, sum, avg (Node and Edge). | New |
|
|
60
|
+
| [**object.utils**](https://github.com/SkinnnyJay/object.utils) | Type-safe object utilities: pick, omit, merge, get/set by path, guards (Node and Edge). | Stable |
|
|
61
|
+
| [**observability.utils**](https://github.com/SkinnnyJay/observability.utils) | Single integration surface for correlation middleware, request context, and logger (Node). | New |
|
|
62
|
+
| [**patterns.utils**](https://github.com/SkinnnyJay/patterns.utils) | Composable design patterns: Result/Either, strategySelector, pipeAsync (Node and Edge). | New |
|
|
63
|
+
| [**protocols.utils**](https://github.com/SkinnnyJay/protocols.utils) | Shared protocol constants and types for HTTP, correlation, and env parsing (Node and Edge). | New |
|
|
64
|
+
| [**react.utils**](https://github.com/SkinnnyJay/react.utils) | Framework-agnostic React utilities: hooks, safe context, stable callbacks, transitions. | New |
|
|
65
|
+
| [**request-context.utils**](https://github.com/SkinnnyJay/request-context.utils) | AsyncLocalStorage request context (requestId, traceId) for Node.js logging and tracing. | New |
|
|
66
|
+
| [**resilience.utils**](https://github.com/SkinnnyJay/resilience.utils) | Circuit breaker, rate limiter, bulkhead, and jittered backoff for fault-tolerant APIs (Node and Edge). | New |
|
|
67
|
+
| [**socket.utils**](https://github.com/SkinnnyJay/socket.utils) | Reconnecting WebSocket client with optional heartbeat (Node and Edge). | New |
|
|
68
|
+
| [**string.utils**](https://github.com/SkinnnyJay/string.utils) | String utilities: formatting, casing, trim, slugify (Node and Edge). | New |
|
|
69
|
+
| [**test.utils**](https://github.com/SkinnnyJay/test.utils) | Test patterns, faker wrapper, enricher, and test-runner helpers (Node and Edge). | New |
|
|
70
|
+
| [**time.utils**](https://github.com/SkinnnyJay/time.utils) | Time utilities: debounce, throttle, interval manager, managed timeout (Node and Edge). | Stable |
|
|
71
|
+
| [**token-optimizer.utils**](https://github.com/SkinnnyJay/token-optimizer.utils) | Token optimization utilities: cleaning, strategies, telemetry (Node and Edge). | New |
|
|
72
|
+
| [**uuid.utils**](https://github.com/SkinnnyJay/uuid.utils) | Generate and validate UUIDs (v1/v4/v5) with full TypeScript support (Node and Edge). | Stable |
|
|
73
|
+
| [**zod.utils**](https://github.com/SkinnnyJay/zod.utils) | Zod schema helpers: builders, safe-parse, transforms, OpenAPI metadata (Node and Edge). | New |
|
|
74
|
+
| [**zustand.utils**](https://github.com/SkinnnyJay/zustand.utils) | Zustand store helpers: factory, persist, devtools, slices (Node and Edge). | New |
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## Quick Start
|
|
79
|
+
|
|
80
|
+
Install any package from npm:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
npm install @simpill/env.utils
|
|
84
|
+
npm install @simpill/logger.utils
|
|
85
|
+
npm install @simpill/cache.utils
|
|
86
|
+
npm install @simpill/async.utils
|
|
87
|
+
npm install @simpill/function.utils
|
|
88
|
+
npm install @simpill/string.utils
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Use the **Repositories** table above to open a package’s GitHub repo for docs, API reference, and examples.
|
|
92
|
+
|
|
93
|
+
**Consumption:** Every package is consumable **separately** (npm or `github:SkinnnyJay/<repo>`) and **via @simpill/utils** (run `npm install` at root; all packages land in `node_modules`). Run `npm run verify:deps` to confirm. **No `utils/` folder is required**—package source lives in the GitHub repos above; this repo pulls them in via dependencies. You can remove `utils/` if present.
|
|
94
|
+
|
|
95
|
+
### Use the main repo in another project
|
|
96
|
+
|
|
97
|
+
The main project references all util packages via GitHub. To pull in the full set of utils from this repo into another project, add the monorepo as a dependency:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
npm install github:SkinnnyJay/simpill-utils
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
(or add `"@simpill/utils": "github:SkinnnyJay/simpill-utils"` to your `package.json`). Installing it will fetch each util from its GitHub repo (`github:SkinnnyJay/adapters.utils`, etc.) so you can import any util in your code:
|
|
104
|
+
|
|
105
|
+
```ts
|
|
106
|
+
import { createAdapter } from "@simpill/adapters.utils";
|
|
107
|
+
import { unique } from "@simpill/array.utils";
|
|
108
|
+
import { getEnvString } from "@simpill/env.utils";
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
To depend on only one util, install that package from npm or GitHub (e.g. `npm install @simpill/adapters.utils` or `npm install github:SkinnnyJay/adapters.utils`).
|
|
112
|
+
|
|
113
|
+
### Using @simpill/utils (this repo)
|
|
114
|
+
|
|
115
|
+
Clone and install from the repo root. All @simpill utils are installed from GitHub into `node_modules` and are usable as-is (e.g. `@simpill/env.utils` ships `dist/` in its repo):
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
npm install
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Then any script or app at the repo root can require/import them, e.g.:
|
|
122
|
+
|
|
123
|
+
```js
|
|
124
|
+
const { getEdgeString } = require("@simpill/env.utils/client");
|
|
125
|
+
const { unique } = require("@simpill/array.utils");
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
To confirm all installed packages are resolvable and load correctly:
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
npm run verify:deps
|
|
132
|
+
npm test
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
`npm test` imports all 38 @simpill packages and prints NODE_ENV; if any package failed to install (e.g. empty folder), re-run `npm install` or `rm -rf node_modules && npm install`.
|
|
136
|
+
|
|
137
|
+
**Sandbox apps** (e.g. todo-app) live in a separate repo: [simpill-sandbox](https://github.com/simpill/simpill-sandbox). To develop individual util packages, clone their GitHub repos (see [Repositories](#repositories) table).
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## Discoverability
|
|
142
|
+
|
|
143
|
+
- **GitHub:** Add topics (e.g. `simpill`, `typescript`, `utilities`, `nodejs`, `edge-runtime`) so the org and repos appear in search. See [.github/TOPICS.md](./.github/TOPICS.md) for a full list.
|
|
144
|
+
- **npm:** Every package lists `simpill` and package-specific keywords. Use `npm search simpill` to find all published packages.
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## Documentation
|
|
149
|
+
|
|
150
|
+
- [CONTRIBUTING.md](./CONTRIBUTING.md) — How to create and maintain packages (and where they live).
|
|
151
|
+
|
|
152
|
+
---
|
|
153
|
+
|
|
154
|
+
## Credits and inspiration
|
|
155
|
+
|
|
156
|
+
We build on and are inspired by the following projects and standards.
|
|
157
|
+
|
|
158
|
+
### Dependencies
|
|
159
|
+
|
|
160
|
+
Packages depend on these core libraries (each link goes to the official repository):
|
|
161
|
+
|
|
162
|
+
| Library | Use in @simpill | Repository |
|
|
163
|
+
|--------|------------------|------------|
|
|
164
|
+
| [Zod](https://github.com/colinhacks/zod) | Schema validation, API types, safe parsing | [colinhacks/zod](https://github.com/colinhacks/zod) |
|
|
165
|
+
| [Zustand](https://github.com/pmndrs/zustand) | Store factory, persist, devtools | [pmndrs/zustand](https://github.com/pmndrs/zustand) |
|
|
166
|
+
| [Next.js](https://github.com/vercel/next.js) | App Router, server actions, middleware | [vercel/next.js](https://github.com/vercel/next.js) |
|
|
167
|
+
| [React](https://github.com/facebook/react) | Hooks, context, transitions | [facebook/react](https://github.com/facebook/react) |
|
|
168
|
+
| [uuid](https://github.com/uuidjs/uuid) | UUID v1/v4/v5 generation and validation | [uuidjs/uuid](https://github.com/uuidjs/uuid) |
|
|
169
|
+
| [Faker](https://github.com/faker-js/faker) | Test data and mocks | [faker-js/faker](https://github.com/faker-js/faker) |
|
|
170
|
+
| [Biome](https://github.com/biomejs/biome) | Linting and formatting (dev) | [biomejs/biome](https://github.com/biomejs/biome) |
|
|
171
|
+
| [Jest](https://github.com/jestjs/jest) | Unit and integration tests (dev) | [jestjs/jest](https://github.com/jestjs/jest) |
|
|
172
|
+
| [TypeScript](https://github.com/microsoft/TypeScript) | Type checking and emit | [microsoft/TypeScript](https://github.com/microsoft/TypeScript) |
|
|
173
|
+
|
|
174
|
+
### Inspiration and prior art
|
|
175
|
+
|
|
176
|
+
- [Lodash](https://github.com/lodash/lodash) — Array, object, and function utility patterns.
|
|
177
|
+
- [Vercel](https://github.com/vercel) — Next.js, [t3-env](https://github.com/t3-oss/t3-env), and server/edge patterns.
|
|
178
|
+
- [Node.js](https://github.com/nodejs/node) — [AsyncLocalStorage](https://nodejs.org/api/async_context.html#class-asynclocalstorage), `fs`, and runtime separation.
|
|
179
|
+
- [RFC 4122](https://www.rfc-editor.org/rfc/rfc4122) — UUID specification.
|
|
180
|
+
- [TC39](https://github.com/tc39) — ECMAScript and standard library evolution.
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
## License
|
|
185
|
+
|
|
186
|
+
ISC
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Monorepo tests
|
|
2
|
+
|
|
3
|
+
Vitest runs unit, integration, and e2e tests for the @simpill monorepo.
|
|
4
|
+
|
|
5
|
+
## Prerequisites
|
|
6
|
+
|
|
7
|
+
- Run `npm install` at repo root so all `@simpill/*` packages and devDependencies (vitest, vite, typescript, tsx, std-env) are installed.
|
|
8
|
+
- **To run root build, test.ts (smoke), and Vitest against built packages:** root normally installs packages from GitHub (which may not include built `dist/`). To use your local utils instead:
|
|
9
|
+
1. `npm run utils:prepare` — build all utils packages (install, audit, typecheck, test, build).
|
|
10
|
+
2. `npm run use:local` — point root at `file:./utils/@simpill-*.utils` and run `npm install`.
|
|
11
|
+
3. Then `npm run build`, `npm run test:smoke`, and `npm test` use the local built packages.
|
|
12
|
+
- To restore root to GitHub deps: `npm run sync:deps`, then `npm install`.
|
|
13
|
+
|
|
14
|
+
## Commands
|
|
15
|
+
|
|
16
|
+
From repo root:
|
|
17
|
+
|
|
18
|
+
- `npm test` — run all tests
|
|
19
|
+
- `npm run test:unit` — `__tests__/unit` only
|
|
20
|
+
- `npm run test:integration` — `__tests__/integration` only
|
|
21
|
+
- `npm run test:e2e` — `__tests__/e2e` only
|
|
22
|
+
|
|
23
|
+
## Layout
|
|
24
|
+
|
|
25
|
+
- **unit** — per-package resolution and behavior: `__tests__/unit/@simpill/<package>/`.
|
|
26
|
+
- **unit/_resolver** — dynamic resolution of packages that do not have a dedicated unit test file.
|
|
27
|
+
- **integration** — cross-package flows (e.g. env + async, errors + uuid, object + array).
|
|
28
|
+
- **e2e** — critical path: core packages resolve and work together (env, uuid, object, array, errors, time).
|
|
29
|
+
|
|
30
|
+
## Config
|
|
31
|
+
|
|
32
|
+
`vitest.config.ts` at repo root: Node environment, globals, `__tests__/**/*.test.ts`.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { getEdgeString } from "@simpill/env.utils/client";
|
|
3
|
+
import * as Env from "@simpill/env.utils";
|
|
4
|
+
import * as Uuid from "@simpill/uuid.utils";
|
|
5
|
+
import * as ObjectUtils from "@simpill/object.utils";
|
|
6
|
+
import * as Async from "@simpill/async.utils";
|
|
7
|
+
import * as ArrayUtils from "@simpill/array.utils";
|
|
8
|
+
import * as Errors from "@simpill/errors.utils";
|
|
9
|
+
import * as Time from "@simpill/time.utils";
|
|
10
|
+
|
|
11
|
+
describe("E2E: all critical packages resolve and work", () => {
|
|
12
|
+
it("env client getEdgeString returns string", () => {
|
|
13
|
+
expect(getEdgeString("NODE_ENV", "development")).toBeDefined();
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it("all listed packages are non-null", () => {
|
|
17
|
+
const packages: Record<string, unknown> = {
|
|
18
|
+
Env,
|
|
19
|
+
Uuid,
|
|
20
|
+
ObjectUtils,
|
|
21
|
+
Async,
|
|
22
|
+
ArrayUtils,
|
|
23
|
+
Errors,
|
|
24
|
+
Time,
|
|
25
|
+
};
|
|
26
|
+
for (const [name, mod] of Object.entries(packages)) {
|
|
27
|
+
expect(mod, `Package ${name} should resolve`).not.toBeNull();
|
|
28
|
+
expect(mod, `Package ${name} should be object`).toBeDefined();
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it("cross-package flow: uuid in object pick and array unique", () => {
|
|
33
|
+
const id = Uuid.generateUUID();
|
|
34
|
+
const record = { id, name: "a" };
|
|
35
|
+
const picked = ObjectUtils.pick(record, ["id"]);
|
|
36
|
+
const keys = ArrayUtils.unique(Object.keys(picked));
|
|
37
|
+
expect(keys).toContain("id");
|
|
38
|
+
expect(Uuid.isUUID(picked.id as string)).toBe(true);
|
|
39
|
+
});
|
|
40
|
+
});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { getEdgeString } from "@simpill/env.utils/client";
|
|
3
|
+
import { delay } from "@simpill/async.utils";
|
|
4
|
+
|
|
5
|
+
describe("env.utils + async.utils integration", () => {
|
|
6
|
+
it("env value is string and delay completes", async () => {
|
|
7
|
+
const envVal = getEdgeString("NODE_ENV", "test");
|
|
8
|
+
expect(typeof envVal).toBe("string");
|
|
9
|
+
await delay(5);
|
|
10
|
+
expect(envVal).toBeDefined();
|
|
11
|
+
});
|
|
12
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { serializeError, AppError } from "@simpill/errors.utils";
|
|
3
|
+
import { generateUUID, isUUID } from "@simpill/uuid.utils";
|
|
4
|
+
|
|
5
|
+
describe("errors.utils + uuid.utils integration", () => {
|
|
6
|
+
it("serializeError and generateUUID work together", () => {
|
|
7
|
+
const id = generateUUID();
|
|
8
|
+
expect(isUUID(id)).toBe(true);
|
|
9
|
+
const err = new AppError("test", { code: "E_TEST", meta: { requestId: id } });
|
|
10
|
+
const serialized = serializeError(err);
|
|
11
|
+
expect(serialized).toBeDefined();
|
|
12
|
+
expect(typeof serialized).toBe("object");
|
|
13
|
+
});
|
|
14
|
+
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { pick } from "@simpill/object.utils";
|
|
3
|
+
import { unique, chunk } from "@simpill/array.utils";
|
|
4
|
+
|
|
5
|
+
describe("object.utils + array.utils integration", () => {
|
|
6
|
+
it("pick then unique keys and chunk work together", () => {
|
|
7
|
+
const obj = { a: 1, b: 2, c: 3 };
|
|
8
|
+
const picked = pick(obj, ["a", "c"]);
|
|
9
|
+
const keys = unique(Object.keys(picked));
|
|
10
|
+
expect(keys).toHaveLength(2);
|
|
11
|
+
const chunks = chunk(keys, 1);
|
|
12
|
+
expect(chunks).toHaveLength(2);
|
|
13
|
+
expect(chunks.flat()).toEqual(keys);
|
|
14
|
+
});
|
|
15
|
+
});
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ensures all monolith @simpill packages resolve (types + runtime).
|
|
3
|
+
* Packages with dedicated unit tests are not re-imported here.
|
|
4
|
+
*/
|
|
5
|
+
import { describe, expect, it } from "vitest";
|
|
6
|
+
|
|
7
|
+
const PACKAGES_TO_RESOLVE: Array<{ name: string; loader: () => Promise<Record<string, unknown>> }> = [
|
|
8
|
+
{ name: "adapters.utils", loader: () => import("@simpill/adapters.utils") },
|
|
9
|
+
{ name: "algorithms.utils", loader: () => import("@simpill/algorithms.utils") },
|
|
10
|
+
{ name: "annotations.utils", loader: () => import("@simpill/annotations.utils") },
|
|
11
|
+
{ name: "api.utils", loader: () => import("@simpill/api.utils") },
|
|
12
|
+
{ name: "collections.utils", loader: () => import("@simpill/collections.utils") },
|
|
13
|
+
{ name: "crypto.utils", loader: () => import("@simpill/crypto.utils") },
|
|
14
|
+
{ name: "data.utils", loader: () => import("@simpill/data.utils") },
|
|
15
|
+
{ name: "enum.utils", loader: () => import("@simpill/enum.utils") },
|
|
16
|
+
{ name: "events.utils", loader: () => import("@simpill/events.utils") },
|
|
17
|
+
{ name: "factories.utils", loader: () => import("@simpill/factories.utils") },
|
|
18
|
+
{ name: "file.utils", loader: () => import("@simpill/file.utils") },
|
|
19
|
+
{ name: "function.utils", loader: () => import("@simpill/function.utils") },
|
|
20
|
+
{ name: "http.utils", loader: () => import("@simpill/http.utils") },
|
|
21
|
+
{ name: "logger.utils", loader: () => import("@simpill/logger.utils") },
|
|
22
|
+
{ name: "middleware.utils", loader: () => import("@simpill/middleware.utils") },
|
|
23
|
+
{ name: "misc.utils", loader: () => import("@simpill/misc.utils") },
|
|
24
|
+
{ name: "nextjs.utils", loader: () => import("@simpill/nextjs.utils") },
|
|
25
|
+
{ name: "number.utils", loader: () => import("@simpill/number.utils") },
|
|
26
|
+
{ name: "observability.utils", loader: () => import("@simpill/observability.utils") },
|
|
27
|
+
{ name: "protocols.utils", loader: () => import("@simpill/protocols.utils") },
|
|
28
|
+
{ name: "react.utils", loader: () => import("@simpill/react.utils") },
|
|
29
|
+
{ name: "request-context.utils", loader: () => import("@simpill/request-context.utils") },
|
|
30
|
+
{ name: "resilience.utils", loader: () => import("@simpill/resilience.utils") },
|
|
31
|
+
{ name: "socket.utils", loader: () => import("@simpill/socket.utils") },
|
|
32
|
+
{ name: "test.utils", loader: () => import("@simpill/test.utils") },
|
|
33
|
+
{ name: "token-optimizer.utils", loader: () => import("@simpill/token-optimizer.utils") },
|
|
34
|
+
{ name: "zod.utils", loader: () => import("@simpill/zod.utils") },
|
|
35
|
+
{ name: "zustand.utils", loader: () => import("@simpill/zustand.utils") },
|
|
36
|
+
];
|
|
37
|
+
|
|
38
|
+
describe("@simpill package resolution", () => {
|
|
39
|
+
for (const { name, loader } of PACKAGES_TO_RESOLVE) {
|
|
40
|
+
it(`resolves @simpill/${name}`, async () => {
|
|
41
|
+
const mod = await loader();
|
|
42
|
+
expect(mod).toBeDefined();
|
|
43
|
+
expect(mod).not.toBeNull();
|
|
44
|
+
expect(typeof mod).toBe("object");
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import * as ArrayUtils from "@simpill/array.utils";
|
|
3
|
+
|
|
4
|
+
describe("@simpill/array.utils", () => {
|
|
5
|
+
it("resolves and unique returns deduped array", () => {
|
|
6
|
+
expect(ArrayUtils).toBeDefined();
|
|
7
|
+
expect(typeof ArrayUtils.unique).toBe("function");
|
|
8
|
+
const out = ArrayUtils.unique([1, 2, 2, 3, 1]);
|
|
9
|
+
expect(out).toEqual([1, 2, 3]);
|
|
10
|
+
});
|
|
11
|
+
});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import * as Async from "@simpill/async.utils";
|
|
3
|
+
|
|
4
|
+
describe("@simpill/async.utils", () => {
|
|
5
|
+
it("resolves and delay resolves after ms", async () => {
|
|
6
|
+
expect(Async).toBeDefined();
|
|
7
|
+
expect(typeof Async.delay).toBe("function");
|
|
8
|
+
const start = Date.now();
|
|
9
|
+
await Async.delay(10);
|
|
10
|
+
expect(Date.now() - start).toBeGreaterThanOrEqual(8);
|
|
11
|
+
});
|
|
12
|
+
});
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import * as Cache from "@simpill/cache.utils";
|
|
3
|
+
|
|
4
|
+
describe("@simpill/cache.utils", () => {
|
|
5
|
+
it("resolves and exports cache utilities", () => {
|
|
6
|
+
expect(Cache).toBeDefined();
|
|
7
|
+
expect(typeof Cache).toBe("object");
|
|
8
|
+
const keys = Object.keys(Cache).filter((k) => (Cache as Record<string, unknown>)[k] != null);
|
|
9
|
+
expect(keys.length).toBeGreaterThan(0);
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it("exposes a memoize or createMemoize-like function when present", () => {
|
|
13
|
+
const C = Cache as Record<string, unknown>;
|
|
14
|
+
const memoizeFn = C.memoize ?? C.createMemoize;
|
|
15
|
+
if (typeof memoizeFn !== "function") return;
|
|
16
|
+
const double = (n: number) => n * 2;
|
|
17
|
+
const memoized = (memoizeFn as (fn: (n: number) => number) => (n: number) => number)(double);
|
|
18
|
+
expect(memoized(2)).toBe(4);
|
|
19
|
+
expect(memoized(2)).toBe(4);
|
|
20
|
+
});
|
|
21
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { getEdgeString } from "@simpill/env.utils/client";
|
|
3
|
+
import * as Env from "@simpill/env.utils";
|
|
4
|
+
|
|
5
|
+
describe("@simpill/env.utils", () => {
|
|
6
|
+
it("resolves and exports client getEdgeString", () => {
|
|
7
|
+
expect(Env).toBeDefined();
|
|
8
|
+
expect(typeof Env).toBe("object");
|
|
9
|
+
const value = getEdgeString("NODE_ENV", "development");
|
|
10
|
+
expect(typeof value).toBe("string");
|
|
11
|
+
expect(value.length).toBeGreaterThanOrEqual(0);
|
|
12
|
+
});
|
|
13
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import * as Errors from "@simpill/errors.utils";
|
|
3
|
+
|
|
4
|
+
describe("@simpill/errors.utils", () => {
|
|
5
|
+
it("resolves and serializeError returns object", () => {
|
|
6
|
+
expect(Errors).toBeDefined();
|
|
7
|
+
expect(typeof Errors.serializeError).toBe("function");
|
|
8
|
+
const out = Errors.serializeError(new Error("test"));
|
|
9
|
+
expect(out).toBeDefined();
|
|
10
|
+
expect(typeof out).toBe("object");
|
|
11
|
+
expect("message" in out || "name" in out).toBe(true);
|
|
12
|
+
});
|
|
13
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import * as ObjectUtils from "@simpill/object.utils";
|
|
3
|
+
|
|
4
|
+
describe("@simpill/object.utils", () => {
|
|
5
|
+
it("resolves and pick returns subset", () => {
|
|
6
|
+
expect(ObjectUtils).toBeDefined();
|
|
7
|
+
expect(typeof ObjectUtils.pick).toBe("function");
|
|
8
|
+
const out = ObjectUtils.pick({ a: 1, b: 2, c: 3 }, ["a", "c"]);
|
|
9
|
+
expect(out).toEqual({ a: 1, c: 3 });
|
|
10
|
+
});
|
|
11
|
+
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import * as Patterns from "@simpill/patterns.utils";
|
|
3
|
+
|
|
4
|
+
describe("@simpill/patterns.utils", () => {
|
|
5
|
+
it("resolves and exports pattern utilities", () => {
|
|
6
|
+
expect(Patterns).toBeDefined();
|
|
7
|
+
expect(typeof Patterns).toBe("object");
|
|
8
|
+
const keys = Object.keys(Patterns).filter((k) => (Patterns as Record<string, unknown>)[k] != null);
|
|
9
|
+
expect(keys.length).toBeGreaterThan(0);
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it("pipeAsync composes async steps when present", async () => {
|
|
13
|
+
const P = Patterns as Record<string, unknown>;
|
|
14
|
+
const pipeAsync = P.pipeAsync as (...fns: Array<(n: number) => Promise<number>>) => (x: number) => Promise<number>;
|
|
15
|
+
if (typeof pipeAsync !== "function") return;
|
|
16
|
+
const addOne = async (n: number) => n + 1;
|
|
17
|
+
const double = async (n: number) => n * 2;
|
|
18
|
+
const composed = pipeAsync(addOne, double);
|
|
19
|
+
const result = await composed(1);
|
|
20
|
+
expect(typeof result).toBe("number");
|
|
21
|
+
expect(result).toBe(4);
|
|
22
|
+
});
|
|
23
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import * as StringUtils from "@simpill/string.utils";
|
|
3
|
+
|
|
4
|
+
describe("@simpill/string.utils", () => {
|
|
5
|
+
it("resolves and exports usable functions", () => {
|
|
6
|
+
expect(StringUtils).toBeDefined();
|
|
7
|
+
expect(typeof StringUtils).toBe("object");
|
|
8
|
+
const keys = Object.keys(StringUtils).filter((k) => typeof (StringUtils as Record<string, unknown>)[k] === "function");
|
|
9
|
+
expect(keys.length).toBeGreaterThan(0);
|
|
10
|
+
});
|
|
11
|
+
});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import * as Time from "@simpill/time.utils";
|
|
3
|
+
|
|
4
|
+
describe("@simpill/time.utils", () => {
|
|
5
|
+
it("resolves and getUnixTimeStamp returns number", () => {
|
|
6
|
+
expect(Time).toBeDefined();
|
|
7
|
+
expect(typeof Time.getUnixTimeStamp).toBe("function");
|
|
8
|
+
const ts = Time.getUnixTimeStamp();
|
|
9
|
+
expect(typeof ts).toBe("number");
|
|
10
|
+
expect(ts).toBeGreaterThan(0);
|
|
11
|
+
});
|
|
12
|
+
});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import * as Uuid from "@simpill/uuid.utils";
|
|
3
|
+
|
|
4
|
+
describe("@simpill/uuid.utils", () => {
|
|
5
|
+
it("resolves and generateUUID returns valid uuid string", () => {
|
|
6
|
+
expect(Uuid).toBeDefined();
|
|
7
|
+
expect(typeof Uuid.generateUUID).toBe("function");
|
|
8
|
+
const id = Uuid.generateUUID();
|
|
9
|
+
expect(typeof id).toBe("string");
|
|
10
|
+
expect(Uuid.isUUID(id)).toBe(true);
|
|
11
|
+
});
|
|
12
|
+
});
|