From 541c7d6967f6137a41c41601874867495ecd5826 Mon Sep 17 00:00:00 2001 From: Ulad Kasach Date: Sat, 31 Jan 2026 07:00:12 -0600 Subject: [PATCH] feat(codes): support error.codes with backwards compat via optin --- .../.bind/vlad.error-codes.flag | 2 + .../.ref.[feedback].v1.[given].by_human.md | 27 + .behavior/v2026_01_29.error-codes/0.wish.md | 45 + .behavior/v2026_01_29.error-codes/1.vision.md | 282 +++ .../v2026_01_29.error-codes/1.vision.src | 38 + .../2.1.criteria.blackbox.md | 193 ++ .../2.1.criteria.blackbox.src | 61 + .../2.2.criteria.blackbox.matrix.md | 148 ++ .../2.2.criteria.blackbox.matrix.src | 47 + .../2.3.criteria.blueprint.md | 119 ++ .../2.3.criteria.blueprint.src | 65 + .../3.3.blueprint.v1.i1.md | 337 ++++ .../3.3.blueprint.v1.src | 68 + .../4.1.roadmap.v1.i1.md | 492 +++++ .../4.1.roadmap.v1.src | 39 + .../5.1.execution.phase0_to_phaseN.v1.i1.md | 135 ++ .../5.1.execution.phase0_to_phaseN.v1.src | 22 + package.json | 8 +- pnpm-lock.yaml | 1594 +++-------------- readme.md | 88 + src/BadRequestError.test.ts | 45 + src/BadRequestError.ts | 6 + src/HelpfulError.test.ts | 175 ++ src/HelpfulError.ts | 70 +- src/UnexpectedCodePathError.test.ts | 29 + src/UnexpectedCodePathError.ts | 6 + src/index.ts | 2 +- 27 files changed, 2750 insertions(+), 1393 deletions(-) create mode 100644 .behavior/v2026_01_29.error-codes/.bind/vlad.error-codes.flag create mode 100644 .behavior/v2026_01_29.error-codes/.ref.[feedback].v1.[given].by_human.md create mode 100644 .behavior/v2026_01_29.error-codes/0.wish.md create mode 100644 .behavior/v2026_01_29.error-codes/1.vision.md create mode 100644 .behavior/v2026_01_29.error-codes/1.vision.src create mode 100644 .behavior/v2026_01_29.error-codes/2.1.criteria.blackbox.md create mode 100644 .behavior/v2026_01_29.error-codes/2.1.criteria.blackbox.src create mode 100644 .behavior/v2026_01_29.error-codes/2.2.criteria.blackbox.matrix.md create mode 100644 .behavior/v2026_01_29.error-codes/2.2.criteria.blackbox.matrix.src create mode 100644 .behavior/v2026_01_29.error-codes/2.3.criteria.blueprint.md create mode 100644 .behavior/v2026_01_29.error-codes/2.3.criteria.blueprint.src create mode 100644 .behavior/v2026_01_29.error-codes/3.3.blueprint.v1.i1.md create mode 100644 .behavior/v2026_01_29.error-codes/3.3.blueprint.v1.src create mode 100644 .behavior/v2026_01_29.error-codes/4.1.roadmap.v1.i1.md create mode 100644 .behavior/v2026_01_29.error-codes/4.1.roadmap.v1.src create mode 100644 .behavior/v2026_01_29.error-codes/5.1.execution.phase0_to_phaseN.v1.i1.md create mode 100644 .behavior/v2026_01_29.error-codes/5.1.execution.phase0_to_phaseN.v1.src diff --git a/.behavior/v2026_01_29.error-codes/.bind/vlad.error-codes.flag b/.behavior/v2026_01_29.error-codes/.bind/vlad.error-codes.flag new file mode 100644 index 0000000..539c79b --- /dev/null +++ b/.behavior/v2026_01_29.error-codes/.bind/vlad.error-codes.flag @@ -0,0 +1,2 @@ +branch: vlad/error-codes +bound_by: init.behavior skill diff --git a/.behavior/v2026_01_29.error-codes/.ref.[feedback].v1.[given].by_human.md b/.behavior/v2026_01_29.error-codes/.ref.[feedback].v1.[given].by_human.md new file mode 100644 index 0000000..d98b135 --- /dev/null +++ b/.behavior/v2026_01_29.error-codes/.ref.[feedback].v1.[given].by_human.md @@ -0,0 +1,27 @@ +emit your response to the feedback into +- .behavior/v2026_01_29.error-codes/$BEHAVIOR_REF_NAME.[feedback].v1.[taken].by_robot.md + +1. emit your response checklist +2. exec your response plan +3. emit your response checkoffs into the checklist + +--- + +first, bootup your mechanics briefs again + +npx rhachet roles boot --repo ehmpathy --role mechanic + +--- +--- +--- + + +# blocker.1 + +--- + +# nitpick.2 + +--- + +# blocker.3 diff --git a/.behavior/v2026_01_29.error-codes/0.wish.md b/.behavior/v2026_01_29.error-codes/0.wish.md new file mode 100644 index 0000000..02a6db3 --- /dev/null +++ b/.behavior/v2026_01_29.error-codes/0.wish.md @@ -0,0 +1,45 @@ +wish = + +would be awesome if it was easy to declare error codes per error + +both, custom slugs + +as well as http + +e.g., + +error.code.{ slug?: string, http?: number } + +--- + +by default, helpful error has code.http undefined + +but BadRequestError is a 400 error + +and UnexpectedCodepathError is a 500 error + +--- + +also, should be easy for users to supply + +code: { slug } + +via the metadata/options input + +similar to how easily they're able to supply 'cause' + +--- + +also, code should be extractable + +and extensible to be baked in on every subclass + +so that if someone wants to create an + +```ts +AuthorizationError extends BadRequestError { + code = { slug: "AUTHZ", http: 403 } +} +``` + +then they could diff --git a/.behavior/v2026_01_29.error-codes/1.vision.md b/.behavior/v2026_01_29.error-codes/1.vision.md new file mode 100644 index 0000000..f485996 --- /dev/null +++ b/.behavior/v2026_01_29.error-codes/1.vision.md @@ -0,0 +1,282 @@ +# vision: error codes for helpful-errors + +> paint a picture of what the world looks like when this wish is fulfilled + +--- + +## the outcome world + +### before: scattered error handle chaos + +a typical day in a production incident debug session: + +```ts +// somewhere in the api handler +app.use((err, req, res, next) => { + // what status code do i return? + if (err instanceof BadRequestError) { + res.status(400).json({ error: err.message }); // hardcoded assumption + } else if (err instanceof UnexpectedCodePathError) { + res.status(500).json({ error: err.message }); // another hardcoded assumption + } else if (err.name === 'AuthorizationError') { + res.status(403).json({ error: err.message }); // string match yikes + } else if (err.message.includes('not found')) { + res.status(404).json({ error: err.message }); // message parse double yikes + } else { + res.status(500).json({ error: 'internal error' }); // give up + } +}); +``` + +```ts +// somewhere in a service +throw new BadRequestError('invalid input', { userId }); // no machine-readable code +// downstream: how does the caller know this is INVALID_INPUT vs DUPLICATE_EMAIL vs EXCEEDED:RATELIMIT? +// they parse the message string. fragile. +``` + +```ts +// somewhere else, a custom error +class RateLimitError extends Error { + constructor(message: string) { + super(message); + this.name = 'RateLimitError'; + // no standard way to declare this is a 429 + // no standard way to declare a machine-readable code like EXCEEDED:RATELIMIT + } +} +``` + +the pain points: +- http status codes are scattered across error handlers +- machine-readable codes don't exist or are inconsistent +- every team invents their own conventions +- error classification logic is duplicated everywhere +- api responses are inconsistent, docs are wrong, clients are confused + +### after: declarative error codes baked in + +the same day, but peaceful: + +```ts +// error declarations are self-evident +class RatelimitError extends BadRequestError { + public static code = { http: 429, slug: 'EXCEEDED:RATELIMIT' } as const; +} +class AuthorizationError extends BadRequestError { + public static code = { http: 403, slug: 'FORBIDDEN:UNAUTHORIZED' } as const; +} +``` + +```ts +// the api handler is now trivial +app.use((err, req, res, next) => { + const code = err.code ?? { http: 500 }; + res.status(code.http ?? 500).json({ + error: err.message, + code: code.slug, + }); +}); +``` + +```ts +// throw errors with contextual codes, when needed +throw new BadRequestError('email already registered', { + code: { slug: 'FORBIDDEN:DUPLICATE' }, + email, +}); +``` + +```ts +// extract codes for logs, metrics, route decisions +if (error.code?.slug === 'EXCEEDED:RATELIMIT') { + await notifyOpsChannel({ error }); +} +metrics.increment(`errors.${error.code?.slug ?? 'UNKNOWN'}`); +``` + +### the "aha" moment + +the value clicks when a developer realizes: + +> "i can define my error taxonomy once, and everywhere in my system—handlers, clients, logs, metrics, docs—speaks the same language. the http status code lives with the error, not scattered across switch statements." + +or when an on-call engineer sees: + +> "the alert says `code: DECLINED:PAYMENT`. i know exactly what happened without a message string parse. and the client received a 402, not a generic 400." + +--- + +## user experience + +### usecases and goals + +| usecase | goal | how | +| ------------------- | ---------------------------- | ---------------------------------------------------- | +| **api author** | return correct http status | `res.status(error.code.http)` | +| **api author** | return machine-readable code | `{ code: error.code.slug }` | +| **error definer** | bake in standard codes | `static code = { http, slug }` | +| **error thrower** | override code for context | `throw new XError(msg, { code: { slug } })` | +| **error handler** | route by code | `if (error.code.slug === 'X')` | +| **logger/metrics** | categorize errors | `log({ code: error.code.slug })` | +| **client consumer** | understand error type | parse `{ code: 'EXCEEDED:RATELIMIT' }` from response | + +### contract inputs & outputs + +#### define an error class with baked-in code + +```ts +// input: class declaration with static code +class PaymentDeclinedError extends BadRequestError { + public static code = { http: 402, slug: 'DECLINED:PAYMENT' } as const; +} + +// output: instances have .code accessor +const error = new PaymentDeclinedError('card rejected', { cardLast4: '1234' }); +error.code // => { http: 402, slug: 'DECLINED:PAYMENT' } +``` + +#### throw with an ad-hoc code + +```ts +// input: code in metadata +throw new BadRequestError('email already in use', { + code: { slug: 'DUPLICATE_EMAIL' }, + email, +}); + +// output: .code reflects the override +error.code // => { http: 400, slug: 'DUPLICATE_EMAIL' } // http from BadRequestError default +``` + +#### extract codes + +```ts +// output: strongly typed accessor +const slug = error.code?.slug; // string | undefined +const http = error.code?.http; // number | undefined + +// safe to use in conditionals, switches, maps +switch (error.code?.slug) { + case 'EXCEEDED:RATELIMIT': return retryLater(); + case 'DECLINED:PAYMENT': return showPaymentForm(); + default: return showGenericError(); +} +``` + +### timeline: typical adoption path + +1. **day 0**: upgrade helpful-errors, see new `.code` accessor +2. **day 1**: add `static code` to custom errors that already exist +3. **week 1**: simplify api error handlers to use `error.code.http` +4. **week 2**: standardize api responses to include `code: error.code.slug` +5. **month 1**: clients rely on `.code.slug` instead of message parse +6. **continual**: new errors are defined with codes from the start + +--- + +## mental model + +### how users would describe this to a friend + +> "you know how http has status codes like 404 and 500? helpful-errors lets you attach those directly to your error classes. plus you can add your own codes like 'DECLINED:PAYMENT' or 'EXCEEDED:RATELIMIT'. then anywhere you catch the error, you just read `.code.http` and `.code.slug` instead of janky string match." + +### analogies + +| analogy | explanation | +| -------------------------------- | ------------------------------------------------------------------------------------------------ | +| **http status codes for errors** | just as http responses have status codes, errors have `.code.http` | +| **enum-like slugs** | `.code.slug` is like an enum value—machine-readable, finite, documented | +| **barcode on a product** | the error message is the label, the code is the barcode—humans read one, machines read the other | +| **exit codes for processes** | unix programs return exit codes; errors return `.code` | + +### terms: user language vs library language + +| user might say | library calls it | +| -------------- | -------------------------------- | +| "error type" | `code.slug` | +| "status code" | `code.http` | +| "error code" | `code` (the object) | +| "tagged error" | error with `static code` defined | +| "custom code" | `code` passed via metadata | + +--- + +## evaluation + +### how well does it solve the goals? + +| goal | solved? | notes | +| ---------------------------------- | ------- | ------------------------------------------ | +| easy to declare error codes | yes | `static code = { http, slug }` | +| easy to supply codes at throw time | yes | `{ code: { slug } }` in metadata | +| easy to extract codes | yes | `error.code.slug`, `error.code.http` | +| baked-in defaults for subclasses | yes | `BadRequestError.code.http = 400` | +| extensible for user subclasses | yes | class-level `static code` | +| backwards compatible | yes | `.code` is additive, prior code unaffected | + +### pros + +- **declarative**: codes live with error definitions, not scattered in handlers +- **type-safe**: `.code.slug` and `.code.http` are typed +- **composable**: class-level defaults + instance-level overrides +- **minimal api surface**: just one property (`.code`) with two fields +- **http-aligned**: mirrors the http status code mental model developers know +- **machine-readable**: enables automation (route decisions, metrics, alerts) + +### cons + +- **learn curve**: users must understand code hierarchy (class default vs instance override) +- **slug discipline**: teams need conventions for slug name (e.g., SCREAMING_SNAKE) +- **http not always relevant**: some errors (cli tools, background jobs) don't need http codes +- **migration effort**: codebases that already exist need to add `static code` to custom errors + +### edge cases and pit-of-success design + +| edge case | pit-of-success behavior | +| ----------------------------------------- | ------------------------------------------- | +| no code defined anywhere | `.code` returns `undefined` (not an error) | +| class has code, instance doesn't override | `.code` returns class code | +| instance overrides with partial code | merges: `{ ...classCode, ...instanceCode }` | +| user passes `code: null` | clears the code (explicit opt-out) | +| http code without slug | valid: `{ http: 418 }` | +| slug without http code | valid: `{ slug: 'TEAPOT' }` | +| code on HelpfulError base | `undefined` by default (no assumptions) | +| code on BadRequestError | `{ http: 400 }` by default | +| code on UnexpectedCodePathError | `{ http: 500 }` by default | + +### serialization: don't spam logs with defaults + +the `.code` getter always returns the full code object for programmatic access. but serialization (toJSON, logs) omits code unless explicitly set — to prevent log spam. + +| scenario | `.code` getter returns | serialized (toJSON) | +| -------- | ---------------------- | ------------------- | +| `new BadRequestError('x')` | `{ http: 400 }` | code omitted | +| `new BadRequestError('x', { code: { slug: 'X' } })` | `{ http: 400, slug: 'X' }` | `{ code: { http: 400, slug: 'X' } }` | +| `new PaymentDeclinedError('x')` (class has slug) | `{ http: 402, slug: 'DECLINED:PAYMENT' }` | `{ code: { http: 402, slug: 'DECLINED:PAYMENT' } }` | +| `new HelpfulError('x')` | `undefined` | code omitted | + +**the rule**: code appears in serialization only when a slug is present (either from class or instance). + +this keeps logs clean: +```ts +// before: every BadRequestError logs { code: { http: 400 } } — noise +// after: only errors with slugs show code — signal +``` + +### awkwardness uncovered + +1. **type inference**: to ensure `error.code.slug` infers correctly when generics are used (`HelpfulError`) requires careful type work. the `code` metadata field should not pollute `TMetadata` inference. + +--- + +## summary + +when this wish is fulfilled: + +- every error can declare its http status and machine-readable slug +- api handlers become trivial: `res.status(error.code?.http ?? 500)` +- clients receive consistent, parseable responses: `{ code: 'EXCEEDED:RATELIMIT' }` +- metrics and logs categorize errors by code, not string match +- the error taxonomy is self-evident in class definitions +- backwards compatibility is preserved: prior code works unchanged diff --git a/.behavior/v2026_01_29.error-codes/1.vision.src b/.behavior/v2026_01_29.error-codes/1.vision.src new file mode 100644 index 0000000..7a7f232 --- /dev/null +++ b/.behavior/v2026_01_29.error-codes/1.vision.src @@ -0,0 +1,38 @@ +illustrate the vision implied in the wish .behavior/v2026_01_29.error-codes/0.wish.md + +emit into .behavior/v2026_01_29.error-codes/1.vision.md + +--- + +paint a picture of what the world looks like when this wish is fulfilled + +testdrive the contract we propose via realworld examples + +specifically, + +## the outcome world + +- what does a day-in-the-life look like with this in place? +- what's the before/after contrast? +- what's the "aha" moment where the value clicks? + +## user experience + +- what usecases do folks fulfill? what goals? +- what contract inputs & outputs do they leverage? +- what would it look like to leverage them? +- what timelines do they go through? + +## mental model + +- how would users describe this to a friend? +- what analogies or metaphors fit? +- what terms would they use vs what terms would we use? + +## evaluation + +- how well does it solve the goals? +- what are the pros? the cons? +- what edgecases exist and how do our contracts keep users in a pit of success? + +uncover anything awkward diff --git a/.behavior/v2026_01_29.error-codes/2.1.criteria.blackbox.md b/.behavior/v2026_01_29.error-codes/2.1.criteria.blackbox.md new file mode 100644 index 0000000..07ed7d3 --- /dev/null +++ b/.behavior/v2026_01_29.error-codes/2.1.criteria.blackbox.md @@ -0,0 +1,193 @@ +# blackbox criteria: error codes + +> what experience must be delivered to fulfill the wish + +--- + +# usecase.1 = extract code from error + +given('any error instance') + when('the error has a code defined') + then('error.code returns the code object') + sothat('handlers can read error.code.http for status') + sothat('handlers can read error.code.slug for machine-readable type') + then('error.code.http is a number or undefined') + then('error.code.slug is a string or undefined') + + when('the error has no code defined') + then('error.code returns undefined') + sothat('handlers can safely use error.code?.http ?? 500') + +--- + +# usecase.2 = default codes on built-in errors + +given('a HelpfulError instance') + when('no code is supplied') + then('error.code is undefined') + sothat('no assumptions are made about http status') + +given('a BadRequestError instance') + when('no code is supplied') + then('error.code.http is 400') + sothat('handlers know this is a client error') + then('error.code.slug is undefined') + sothat('throwers can supply their own slug') + +given('an UnexpectedCodePathError instance') + when('no code is supplied') + then('error.code.http is 500') + sothat('handlers know this is a server error') + then('error.code.slug is undefined') + sothat('throwers can supply their own slug') + +--- + +# usecase.3 = supply code at throw time + +given('a throw with code in metadata') + when('code has both http and slug') + then('error.code reflects both values') + sothat('throwers can fully specify the code') + + when('code has only slug') + then('error.code.slug reflects the value') + then('error.code.http inherits from class default') + sothat('throwers can specialize slug without repeat of http') + + when('code has only http') + then('error.code.http reflects the value') + then('error.code.slug inherits from class default') + sothat('throwers can override http without loss of slug') + + when('code is null') + then('error.code is undefined') + sothat('throwers can explicitly opt out of any code') + +given('a throw with other metadata alongside code') + when('metadata contains code and other fields') + then('error.code reflects the code') + then('error.metadata contains all fields') + sothat('code does not interfere with other metadata') + +--- + +# usecase.4 = define error class with baked-in code + +given('a custom error class that extends BadRequestError') + when('the class declares static code = { http: 402, slug: "DECLINED:PAYMENT" }') + then('instances of that class have error.code.http = 402') + then('instances of that class have error.code.slug = "DECLINED:PAYMENT"') + sothat('class authors can bake in standard codes') + +given('a custom error class that extends HelpfulError') + when('the class declares static code = { slug: "CUSTOM" }') + then('instances have error.code.slug = "CUSTOM"') + then('instances have error.code.http = undefined') + sothat('class authors can define slug-only codes') + +--- + +# usecase.5 = inherit code through class hierarchy + +given('class A extends class B extends HelpfulError') + when('B declares static code and A does not') + then('instances of A have error.code from B') + sothat('subclasses inherit parent codes automatically') + + when('both A and B declare static code') + then('instances of A have error.code from A') + sothat('subclasses can override parent codes') + + when('neither A nor B declare static code') + then('instances of A have error.code = undefined') + sothat('no code is assumed without declaration') + +--- + +# usecase.6 = merge instance code with class code + +given('a class with static code = { http: 400, slug: "CLASS_SLUG" }') + when('instance is thrown with { code: { slug: "INSTANCE_SLUG" } }') + then('error.code.slug = "INSTANCE_SLUG"') + then('error.code.http = 400') + sothat('instance slug overrides class slug') + sothat('class http is preserved when instance omits it') + + when('instance is thrown with { code: { http: 422 } }') + then('error.code.http = 422') + then('error.code.slug = "CLASS_SLUG"') + sothat('instance http overrides class http') + sothat('class slug is preserved when instance omits it') + + when('instance is thrown with { code: { http: 422, slug: "INSTANCE_SLUG" } }') + then('error.code.http = 422') + then('error.code.slug = "INSTANCE_SLUG"') + sothat('instance fully overrides class code') + +--- + +# usecase.7 = partial codes are valid + +given('an error with only http code') + when('error.code = { http: 418 }') + then('error.code.http = 418') + then('error.code.slug = undefined') + sothat('http-only codes are supported') + +given('an error with only slug') + when('error.code = { slug: "TEAPOT" }') + then('error.code.slug = "TEAPOT"') + then('error.code.http = undefined') + sothat('slug-only codes are supported') + +--- + +# usecase.8 = serialization omits code without slug + +given('an error with default http code but no slug') + when('error is serialized (toJSON, logs)') + then('code is omitted from output') + sothat('logs are not spammed with { code: { http: 400 } }') + sothat('only meaningful codes appear in observability') + +given('an error with a slug') + when('error is serialized (toJSON, logs)') + then('code appears in output with both http and slug') + sothat('observers see the full code when it matters') + +given('a BadRequestError with no code supplied') + when('error.code getter is called') + then('returns { http: 400 }') + sothat('programmatic access still works') + when('error is serialized') + then('code is omitted') + sothat('default codes don't clutter logs') + +given('a BadRequestError with slug supplied') + when('error.code getter is called') + then('returns { http: 400, slug: "X" }') + when('error is serialized') + then('code appears as { http: 400, slug: "X" }') + sothat('explicit codes are visible in logs') + +given('a custom error class with static code = { http: 402, slug: "DECLINED:PAYMENT" }') + when('instance is serialized') + then('code appears in output') + sothat('class-level slugs are always visible') + +--- + +# usecase.9 = backwards compatibility + +given('code that worked before this feature') + when('errors are thrown without code in metadata') + then('error behavior is unchanged') + then('error.message is unchanged') + then('error.metadata is unchanged') + sothat('prior code continues to work') + +given('code that catches errors') + when('the error has no code property') + then('error.code returns undefined, not an error') + sothat('handlers don't break on old errors') diff --git a/.behavior/v2026_01_29.error-codes/2.1.criteria.blackbox.src b/.behavior/v2026_01_29.error-codes/2.1.criteria.blackbox.src new file mode 100644 index 0000000..3027d91 --- /dev/null +++ b/.behavior/v2026_01_29.error-codes/2.1.criteria.blackbox.src @@ -0,0 +1,61 @@ +declare the blackbox criteria required to fulfill +- this wish .behavior/v2026_01_29.error-codes/0.wish.md +- this vision .behavior/v2026_01_29.error-codes/1.vision.md (if declared) + +via bdd declarations, per your briefs + +emit into .behavior/v2026_01_29.error-codes/2.1.criteria.blackbox.md + +--- + +blackbox criteria = experience boundaries (no implementation details) + +## episode experience + +a sequence of exchanges — the narrative flow + +- what workflows do users go through? +- what do they see, do, and receive at each step? +- what are the critical paths through the episode? +- what are the edge cases in the narrative? + +## exchange experience + +atomic — a single input→output contract + +- what inputs does the system accept? +- what outputs does the system return? +- what errors does the system surface? +- what are the boundary conditions? + +--- + +DO NOT include: +- mechanism details (what contracts/components exist) +- implementation details (how things are built) + +note: blackbox is NOT "why to build" — that's the wish + blackbox is "what experience must be delivered" to fulfill the wish + +--- + +## template + +``` +# usecase.1 = ... +given() + when() + then() + sothat() + then() + then() + sothat() + when() + then() + +given() + ... + +# usecase.2 = ... +... +``` diff --git a/.behavior/v2026_01_29.error-codes/2.2.criteria.blackbox.matrix.md b/.behavior/v2026_01_29.error-codes/2.2.criteria.blackbox.matrix.md new file mode 100644 index 0000000..ceb0548 --- /dev/null +++ b/.behavior/v2026_01_29.error-codes/2.2.criteria.blackbox.matrix.md @@ -0,0 +1,148 @@ +# blackbox criteria: coverage matrix + +> distilled from 2.1.criteria.blackbox.md + +--- + +## matrix.1: default codes by error class + +covers: usecase.1, usecase.2 + +| ind: error class | dep: code.http | dep: code.slug | +| ----------------------- | -------------- | -------------- | +| HelpfulError | undefined | undefined | +| BadRequestError | 400 | undefined | +| UnexpectedCodePathError | 500 | undefined | + +**note**: these are the defaults when no code is supplied at throw time. + +--- + +## matrix.2: instance code supply + +covers: usecase.3 + +assumes class has default `{ http: 400 }` (e.g., BadRequestError) + +| ind: instance code supplied | dep: code.http | dep: code.slug | +| --------------------------- | -------------- | -------------- | +| none | 400 (class) | undefined | +| `{ slug: 'X' }` | 400 (class) | 'X' (instance) | +| `{ http: 422 }` | 422 (instance) | undefined | +| `{ http: 422, slug: 'X' }` | 422 (instance) | 'X' (instance) | +| `null` | undefined | undefined | + +**note**: instance values override class values field-by-field. `null` clears entirely. + +--- + +## matrix.3: class inheritance + +covers: usecase.5 + +| ind: parent (B) has code | ind: child (A) has code | dep: instance code source | +| ------------------------ | ----------------------- | ------------------------- | +| no | no | undefined | +| yes | no | B (inherited) | +| no | yes | A (declared) | +| yes | yes | A (overrides B) | + +**note**: standard js static inheritance — child shadows parent. + +--- + +## matrix.4: merge semantics + +covers: usecase.6 + +class code: `{ http: 400, slug: 'CLASS' }` + +| ind: instance supplies http | ind: instance supplies slug | dep: final http | dep: final slug | +| --------------------------- | --------------------------- | --------------- | --------------- | +| no | no | 400 | 'CLASS' | +| no | yes ('INST') | 400 | 'INST' | +| yes (422) | no | 422 | 'CLASS' | +| yes (422) | yes ('INST') | 422 | 'INST' | + +**note**: merge is field-by-field. instance wins per field, class fills gaps. + +--- + +## matrix.5: partial codes + +covers: usecase.7 + +| ind: http present | ind: slug present | dep: code valid? | +| ----------------- | ----------------- | ---------------- | +| no | no | yes (undefined) | +| yes | no | yes | +| no | yes | yes | +| yes | yes | yes | + +**note**: all combinations valid. no required fields. + +--- + +## matrix.6: serialization behavior + +covers: usecase.8 + +| ind: slug present | ind: slug source | dep: code in toJSON | +| ----------------- | ----------------- | ------------------- | +| no | n/a | omitted | +| yes | class static | included | +| yes | instance metadata | included | + +**note**: the rule is simple — slug present → serialize code; no slug → omit code. + +expanded with http source for completeness: + +| ind: slug present | ind: http source | dep: code in toJSON | dep: code.http in output | +| ----------------- | ------------------- | ------------------- | ------------------------ | +| no | class default (400) | omitted | n/a | +| no | class default (500) | omitted | n/a | +| no | instance override | omitted | n/a | +| yes | class default | included | yes | +| yes | class explicit | included | yes | +| yes | instance override | included | yes | + +**note**: http source doesn't affect serialization decision — only slug presence matters. + +--- + +## matrix.7: backwards compatibility + +covers: usecase.9 + +| ind: code in metadata | ind: access pattern | dep: behavior | +| --------------------- | --------------------- | ------------------------- | +| none | error.message | unchanged | +| none | error.metadata | unchanged | +| none | error.code | undefined (safe) | +| none | JSON.stringify(error) | unchanged (no code field) | + +**note**: zero breaks. code is purely additive. + +--- + +## gap analysis + +**no gaps found** — all meaningful combinations are covered. + +**decomposition opportunities**: none required. each matrix has 2-3 independent dimensions, which is manageable. the largest matrix (matrix.6 expanded) has 6 rows, well within reason. + +--- + +## summary + +| matrix | independent vars | combinations | status | +| ------------------- | ----------------- | ------------ | -------- | +| 1. default codes | 1 (class) | 3 | complete | +| 2. instance supply | 1 (supplied) | 5 | complete | +| 3. inheritance | 2 (parent, child) | 4 | complete | +| 4. merge semantics | 2 (http, slug) | 4 | complete | +| 5. partial codes | 2 (http, slug) | 4 | complete | +| 6. serialization | 2 (slug, source) | 6 | complete | +| 7. backwards compat | 2 (code, access) | 4 | complete | + +total coverage: **30 combinations** across 7 matrices. diff --git a/.behavior/v2026_01_29.error-codes/2.2.criteria.blackbox.matrix.src b/.behavior/v2026_01_29.error-codes/2.2.criteria.blackbox.matrix.src new file mode 100644 index 0000000..71cb277 --- /dev/null +++ b/.behavior/v2026_01_29.error-codes/2.2.criteria.blackbox.matrix.src @@ -0,0 +1,47 @@ +distill the blackbox criteria in .behavior/v2026_01_29.error-codes/2.1.criteria.blackbox.md into a coverage matrix + +emit into .behavior/v2026_01_29.error-codes/2.2.criteria.blackbox.matrix.md + +--- + +create a matrix table for each related set of usecases + +## process + +1. **extract dimensions** — identify the independent variables that vary across usecases +2. **enumerate combinations** — list all dimension value combinations +3. **map outcomes** — for each combination, record the expected outcome from blackbox criteria +4. **flag gaps** — if any combination lacks a specified outcome, call it out +5. **flag decomposition opportunities** — if too many dimensions, suggest narrower behavioral boundaries + +## structure + +| ind: var 1 | ind: var 2 | ... | dep: var 1 | dep: var 2 | ... | +|-------------------|-------------------|-----|-----------------|-----------------|-----| +| condition A | condition X | ... | outcome 1 | outcome 2 | ... | +| condition A | condition Y | ... | outcome 1 | outcome 2 | ... | +| condition B | condition X | ... | outcome 1 | outcome 2 | ... | + +explicitly label the ind(ependent) vs dep(endent) varialbes in the table header, as well + +## terminology + +- independent variables: the inputs/conditions that vary between subcases +- dependent variables: the expected outcomes for each combination (can be multiple per row) + +## why + +- visualize all combinations at a glance +- spot gaps via symmetric analysis — if a row is absent, ask why +- verify the blackbox criteria covers all meaningful permutations + +## decomposition signal + +if there are too many independent variables (matrix explodes) — this signals the usecase is too broad + +callout opportunities to decompose into smaller behavioral boundaries when: +- the matrix has 4+ independent dimensions +- combinations exceed what's reasonable to enumerate +- unrelated concerns are bundled together + +a narrower scope = a clearer matrix = a more maintainable and recomposable system diff --git a/.behavior/v2026_01_29.error-codes/2.3.criteria.blueprint.md b/.behavior/v2026_01_29.error-codes/2.3.criteria.blueprint.md new file mode 100644 index 0000000..5a50404 --- /dev/null +++ b/.behavior/v2026_01_29.error-codes/2.3.criteria.blueprint.md @@ -0,0 +1,119 @@ +# blueprint criteria: error codes + +> what mechanisms must exist to deliver the blackbox experience + +--- + +## blackbox criteria satisfied + +- usecase.1 = extract code from error ✓ +- usecase.2 = default codes on built-in errors ✓ +- usecase.3 = supply code at throw time ✓ +- usecase.4 = define error class with baked-in code ✓ +- usecase.5 = inherit code through class hierarchy ✓ +- usecase.6 = merge instance code with class code ✓ +- usecase.7 = partial codes are valid ✓ +- usecase.8 = serialization omits code without slug ✓ +- usecase.9 = backwards compatibility ✓ + +--- + +## subcomponent contracts + +### code type + +given('HelpfulErrorCode type contract') + then('shape is { http?: number; slug?: string }') + then('both fields are optional') + then('exported for consumer use') + +### HelpfulError.code getter + +given('HelpfulError.prototype.code getter contract') + then('returns HelpfulErrorCode | undefined') + then('merges class static code with instance metadata code') + then('instance code fields override class code fields') + then('returns undefined when no code exists anywhere in chain') + +### HelpfulError.code static + +given('HelpfulError static code contract') + then('HelpfulError.code is undefined') + then('subclasses may declare static code: HelpfulErrorCode') + then('static code is inherited via standard js prototype chain') + +### BadRequestError.code static + +given('BadRequestError static code contract') + then('BadRequestError.code is { http: 400 }') + then('slug is undefined by default') + +### UnexpectedCodePathError.code static + +given('UnexpectedCodePathError static code contract') + then('UnexpectedCodePathError.code is { http: 500 }') + then('slug is undefined by default') + +### constructor metadata.code + +given('HelpfulError constructor contract for code') + then('accepts optional code field in metadata') + then('code: HelpfulErrorCode stores for merge with class code') + then('code: null clears any class code') + then('other metadata fields are unaffected') + +### toJSON serialization + +given('HelpfulError.prototype.toJSON contract for code') + then('includes code in output only when slug is present') + then('omits code when slug is absent') + then('when included, code contains both http and slug') + +--- + +## composition boundaries + +given('code getter composition') + then('reads static code from constructor prototype chain') + then('reads instance code from metadata') + then('merges with instance fields over class fields') + then('returns undefined if both sources are empty') + +given('code serialization composition') + then('toJSON checks merged code for slug presence') + then('if slug present, includes full code object') + then('if slug absent, omits code field entirely') + +given('metadata isolation') + then('code field in metadata does not pollute error.metadata') + then('error.metadata returns metadata without code extracted') + sothat('code does not appear twice in serialization') + +--- + +## test coverage criteria + +given('unit tests') + then('tests HelpfulError.code returns undefined by default') + then('tests BadRequestError.code.http is 400') + then('tests UnexpectedCodePathError.code.http is 500') + then('tests instance code override via metadata') + then('tests code: null clears class code') + then('tests partial code merge (slug only, http only)') + then('tests toJSON omits code when no slug') + then('tests toJSON includes code when slug present') + +given('inheritance tests') + then('tests custom subclass inherits parent code') + then('tests custom subclass can override parent code') + then('tests multi-level inheritance chain') + +given('integration tests') + then('tests full throw-catch-serialize cycle') + then('tests error.code accessible in catch block') + then('tests JSON.stringify produces expected output') + +given('backwards compatibility tests') + then('tests prior error instantiation patterns still work') + then('tests error.message unchanged') + then('tests error.metadata unchanged for non-code metadata') diff --git a/.behavior/v2026_01_29.error-codes/2.3.criteria.blueprint.src b/.behavior/v2026_01_29.error-codes/2.3.criteria.blueprint.src new file mode 100644 index 0000000..6f7c376 --- /dev/null +++ b/.behavior/v2026_01_29.error-codes/2.3.criteria.blueprint.src @@ -0,0 +1,65 @@ +declare the blueprint criteria (mechanism bounds) that satisfies the blackbox criteria + +ref: +- blackbox criteria .behavior/v2026_01_29.error-codes/2.1.criteria.blackbox.md +- wish .behavior/v2026_01_29.error-codes/0.wish.md +- vision .behavior/v2026_01_29.error-codes/1.vision.md (if declared) + +emit into .behavior/v2026_01_29.error-codes/2.3.criteria.blueprint.md + +--- + +blueprint criteria = MECHANISM BOUNDS +- constraints on what contracts & composition must exist to deliver the experience +- this is OPTIONAL — not all behaviors need prescribed mechanism bounds + +first, confirm which blackbox experience bounds will be satisfied + +then, declare ONLY: +- what subcomponents are demanded by the wish, vision, or criteria.blackbox? and with what contracts and boundaries? +- how do subcomponents compose together? +- what integration boundaries exist? +- what test coverage is required? + +DO NOT prescribe: +- internal implementation details of subcomponents +- how subcomponents achieve their contracts internally +- any subcomponents not explicitly demanded in the wish, vision, or criteria.blackbox + +note: blueprint criteria is NOT "how to build" — that's decided in blueprint.md (3.3) + blueprint criteria is "what mechanisms must exist" to deliver the experience + +the HOW is discovered during research (3.1) and decided during blueprint (3.3) + +--- + +## template + +``` +## blackbox criteria satisfied + +- usecase.1 = ... ✓ +- usecase.2 = ... ✓ + +## subcomponent contracts + +given('componentName contract') + then('exposes: methodName(input: Type) => ReturnType') + then('throws ErrorType for invalid inputs') + +given('anotherComponent contract') + then('exposes: ...') + +## composition boundaries + +given('feature implementation') + then('composes componentA and componentB') + then('componentA provides X, componentB transforms to Y') + +## test coverage criteria + +given('feature') + then('has unit tests for ...') + then('has integration tests for ...') + then('has acceptance test for full usecase') +``` diff --git a/.behavior/v2026_01_29.error-codes/3.3.blueprint.v1.i1.md b/.behavior/v2026_01_29.error-codes/3.3.blueprint.v1.i1.md new file mode 100644 index 0000000..52eb894 --- /dev/null +++ b/.behavior/v2026_01_29.error-codes/3.3.blueprint.v1.i1.md @@ -0,0 +1,337 @@ +# blueprint: error codes + +> how we implement the wish + +--- + +## references + +- wish: .behavior/v2026_01_29.error-codes/0.wish.md +- vision: .behavior/v2026_01_29.error-codes/1.vision.md +- blackbox criteria: .behavior/v2026_01_29.error-codes/2.1.criteria.blackbox.md +- blueprint criteria: .behavior/v2026_01_29.error-codes/2.3.criteria.blueprint.md + +--- + +## treestruct: filediffs + +``` +src/ + [~] index.ts # export HelpfulErrorCode type + [~] HelpfulError.ts # add code type, static, getter, toJSON update + [~] HelpfulError.test.ts # add code tests + [~] BadRequestError.ts # add static code = { http: 400 } + [~] BadRequestError.test.ts # add code tests + [~] UnexpectedCodePathError.ts # add static code = { http: 500 } + [~] UnexpectedCodePathError.test.ts # add code tests +``` + +**legend**: `[+]` create, `[~]` update, `[-]` delete + +--- + +## treestruct: codepaths + +### HelpfulError.ts + +``` +HelpfulErrorCode type + [+] export type HelpfulErrorCode = { http?: number; slug?: string } + +HelpfulError class + [+] static code: HelpfulErrorCode | undefined = undefined + + constructor() + [○] retain message format + [○] retain cause extraction + [~] update metadataWithoutCause to also omit 'code' + [~] update original storage to include code separately + + original (private) + [~] add code?: HelpfulErrorCode | null field + + [+] get code(): HelpfulErrorCode | undefined + // merge class static code with instance code + // instance fields override class fields + // return undefined if no code anywhere + // code: null in metadata clears code entirely + + get metadata() + [~] return metadata without code field (omit 'code') + + toJSON() + [~] conditionally include code only when slug present +``` + +### BadRequestError.ts + +``` +BadRequestError class + [+] static code = { http: 400 } as const + [○] retain constructor +``` + +### UnexpectedCodePathError.ts + +``` +UnexpectedCodePathError class + [+] static code = { http: 500 } as const + [○] retain constructor +``` + +### index.ts + +``` +exports + [+] export type { HelpfulErrorCode } from './HelpfulError' + [○] retain other exports +``` + +**legend**: `[+]` create, `[~]` update, `[○]` retain, `[-]` delete, `[←]` reuse, `[→]` eject + +--- + +## contracts + +### HelpfulErrorCode type + +```ts +/** + * .what = error code with optional http status and machine-readable slug + * .why = enables declarative error classification + */ +export type HelpfulErrorCode = { + http?: number; + slug?: string; +}; +``` + +### HelpfulError.code getter + +```ts +/** + * .what = accessor for merged error code (class + instance) + * .why = enables programmatic access to error classification + */ +public get code(): HelpfulErrorCode | undefined { + // get class static code via prototype chain + const classCode = (this.constructor as typeof HelpfulError).code; + + // get instance code from original + const instanceCode = this.original.code; + + // handle explicit null (opt-out) + if (instanceCode === null) return undefined; + + // merge: instance fields override class fields + if (!classCode && !instanceCode) return undefined; + + return { + ...classCode, + ...instanceCode, + }; +} +``` + +### toJSON code inclusion + +```ts +/** + * .what = serialize error to json, include code only when slug present + * .why = prevents log spam with default http codes + */ +toJSON(): Record { + const obj: Record = {}; + + // prior property enumeration + Object.getOwnPropertyNames(this) + .filter((key) => key !== 'original') + .sort() + .forEach((key) => { + obj[key] = (this as any)[key]; + }); + + // conditionally add code if slug present + const code = this.code; + if (code?.slug) { + obj.code = code; + } + + return obj; +} +``` + +--- + +## composition + +### code resolution flow + +``` +throw new BadRequestError('x', { code: { slug: 'Y' } }) + │ + ├─ constructor stores code in original.code + │ + └─ .code getter called + │ + ├─ read BadRequestError.code (static) → { http: 400 } + │ + ├─ read original.code → { slug: 'Y' } + │ + └─ merge → { http: 400, slug: 'Y' } +``` + +### serialization flow + +``` +JSON.stringify(error) + │ + └─ toJSON() called + │ + ├─ enumerate own properties (message, stack, etc) + │ + ├─ check this.code?.slug + │ │ + │ ├─ if slug present → include code in output + │ │ + │ └─ if no slug → omit code + │ + └─ return obj +``` + +### metadata isolation + +``` +error.metadata + │ + └─ returns original.metadata without 'code' field + │ + └─ ensures code doesn't appear twice in serialization + (once in error.code, once in metadata) +``` + +--- + +## test coverage + +### unit tests: HelpfulError.test.ts + +```ts +describe('code', () => { + describe('getter', () => { + it('returns undefined for base HelpfulError') + it('returns class code when no instance code') + it('returns instance code when no class code') + it('merges instance code over class code') + it('returns undefined when code: null in metadata') + }) + + describe('static code', () => { + it('HelpfulError.code is undefined') + }) + + describe('serialization', () => { + it('omits code from toJSON when no slug') + it('includes code in toJSON when slug present') + it('includes full merged code in toJSON') + }) + + describe('metadata isolation', () => { + it('error.metadata does not include code field') + it('code in metadata does not appear in message') + }) + + describe('inheritance', () => { + it('custom subclass inherits parent code') + it('custom subclass can override parent code') + it('multi-level inheritance works') + }) +}) +``` + +### unit tests: BadRequestError.test.ts + +```ts +describe('code', () => { + it('has static code = { http: 400 }') + it('instance.code.http is 400') + it('instance.code.slug is undefined by default') + it('instance can override with slug') + it('instance can override http') + it('toJSON omits code (no slug by default)') + it('toJSON includes code when slug supplied') +}) +``` + +### unit tests: UnexpectedCodePathError.test.ts + +```ts +describe('code', () => { + it('has static code = { http: 500 }') + it('instance.code.http is 500') + it('instance.code.slug is undefined by default') + it('instance can override with slug') + it('toJSON omits code (no slug by default)') +}) +``` + +### integration tests: HelpfulError.test.ts + +```ts +describe('code integration', () => { + it('full throw-catch-serialize cycle preserves code') + it('error.code accessible in catch block') + it('JSON.stringify produces expected output with slug') + it('JSON.stringify produces expected output without slug') +}) +``` + +### backwards compatibility tests + +```ts +describe('backwards compatibility', () => { + it('prior error instantiation patterns still work') + it('error.message unchanged') + it('error.metadata unchanged for non-code metadata') + it('errors without code work as before') +}) +``` + +--- + +## execution phases + +### phase 1: type and static code + +1. add `HelpfulErrorCode` type to HelpfulError.ts +2. add `static code = undefined` to HelpfulError +3. add `static code = { http: 400 }` to BadRequestError +4. add `static code = { http: 500 }` to UnexpectedCodePathError +5. export `HelpfulErrorCode` from index.ts + +### phase 2: code getter + +1. update `original` type to include `code?: HelpfulErrorCode | null` +2. update constructor to store `code` from metadata +3. implement `code` getter with merge logic +4. update `metadata` getter to omit `code` + +### phase 3: serialization + +1. update `toJSON` to conditionally include code +2. update constructor to omit `code` from message serialization + +### phase 4: tests + +1. add unit tests for code getter +2. add unit tests for static codes on subclasses +3. add unit tests for serialization behavior +4. add integration tests for full cycle +5. add backwards compatibility tests + +### phase 5: validation + +1. run `npm run test:types` +2. run `npm run test:unit` +3. run `npm run test:lint` +4. verify all criteria satisfied diff --git a/.behavior/v2026_01_29.error-codes/3.3.blueprint.v1.src b/.behavior/v2026_01_29.error-codes/3.3.blueprint.v1.src new file mode 100644 index 0000000..1923ebf --- /dev/null +++ b/.behavior/v2026_01_29.error-codes/3.3.blueprint.v1.src @@ -0,0 +1,68 @@ +propose a blueprint for how we can implement the wish described +- in .behavior/v2026_01_29.error-codes/0.wish.md + +with the domain distillation declared +- in .behavior/v2026_01_29.error-codes/3.2.distill.domain._.v1.i1.md (if declared) + +follow the patterns already present in this repo + +--- + +enforce thorough test coverage for proof of behavior satisfaction +- unit tests for all domain logic +- integration tests for all repo <-> access boundaries (os, apis, sdks, daos, etc) +- integration tests for all end <-> end flows +- acceptance tests for core blackbox behaviors + +--- + +include a treestruct of filediffs + +**legend:** +- `[+] create` — file to create +- `[~] update` — file to update +- `[-] delete` — file to delete + + +--- + +include a treestruct of codepaths + +**legend:** +- `[+]` create — codepath to create +- `[~]` update — codepath to update +- `[○]` retain — codepath to retain +- `[-]` delete — codepath to delete +- `[←]` reuse — codepath to reuse from elsewhere +- `[→]` eject — codepath to decompose for reuse + + +--- + +remember, the purpose of the blueprint is to declare what the execution will adhere to + +we want to see +- what contracts will be used +- how domain.objects and domain.operations are decomposed and recomposed +- what the codepaths are, their ease of maintenance and readability + +--- + +reference the below for full context +- .behavior/v2026_01_29.error-codes/0.wish.md +- .behavior/v2026_01_29.error-codes/1.vision.md (if declared) +- .behavior/v2026_01_29.error-codes/2.1.criteria.blackbox.md (if declared) +- .behavior/v2026_01_29.error-codes/2.3.criteria.blueprint.md (if declared) +- .behavior/v2026_01_29.error-codes/3.1.research.access._.v1.i1.md (if declared) +- .behavior/v2026_01_29.error-codes/3.1.research.claims._.v1.i1.md (if declared) +- .behavior/v2026_01_29.error-codes/3.1.research.domain._.v1.i1.md (if declared) +- .behavior/v2026_01_29.error-codes/3.1.research.domain.terms.v1.i1.md (if declared) +- .behavior/v2026_01_29.error-codes/3.1.research.patterns._.code.prod.v1.i1.md (if declared) +- .behavior/v2026_01_29.error-codes/3.1.research.patterns._.code.test.v1.i1.md (if declared) +- .behavior/v2026_01_29.error-codes/3.1.research.patterns._.oss.levers.v1.i1.md (if declared) +- .behavior/v2026_01_29.error-codes/3.1.research.templates._.v1.i1.md (if declared) +- .behavior/v2026_01_29.error-codes/3.2.distill.domain._.v1.i1.md (if declared) + +--- + +emit to .behavior/v2026_01_29.error-codes/3.3.blueprint.v1.i1.md diff --git a/.behavior/v2026_01_29.error-codes/4.1.roadmap.v1.i1.md b/.behavior/v2026_01_29.error-codes/4.1.roadmap.v1.i1.md new file mode 100644 index 0000000..850065d --- /dev/null +++ b/.behavior/v2026_01_29.error-codes/4.1.roadmap.v1.i1.md @@ -0,0 +1,492 @@ +# roadmap: error codes + +> checklist for execution with acceptance verification at each step + +--- + +## phase 0: preparation + +### read before start + +- [ ] .behavior/v2026_01_29.error-codes/0.wish.md +- [ ] .behavior/v2026_01_29.error-codes/1.vision.md +- [ ] .behavior/v2026_01_29.error-codes/2.1.criteria.blackbox.md +- [ ] .behavior/v2026_01_29.error-codes/2.3.criteria.blueprint.md +- [ ] .behavior/v2026_01_29.error-codes/3.3.blueprint.v1.i1.md + +### acceptance + +- [ ] builder understands the wish, vision, and criteria +- [ ] builder understands the blueprint contracts and composition + +### verification + +```sh +# none — human verification +``` + +--- + +## phase 1: type and static code + +> add HelpfulErrorCode type and static code properties + +### read before phase + +- [ ] .behavior/v2026_01_29.error-codes/3.3.blueprint.v1.i1.md (contracts section) + +### checklist + +- [ ] 1.1: add `HelpfulErrorCode` type to src/HelpfulError.ts +- [ ] 1.2: add `static code: HelpfulErrorCode | undefined = undefined` to HelpfulError +- [ ] 1.3: add `static code = { http: 400 } as const` to BadRequestError +- [ ] 1.4: add `static code = { http: 500 } as const` to UnexpectedCodePathError +- [ ] 1.5: export `HelpfulErrorCode` type from src/index.ts + +### acceptance criteria + +``` +given('HelpfulError class') + then('HelpfulError.code is undefined') + +given('BadRequestError class') + then('BadRequestError.code is { http: 400 }') + +given('UnexpectedCodePathError class') + then('UnexpectedCodePathError.code is { http: 500 }') + +given('index.ts exports') + then('HelpfulErrorCode type is exported') +``` + +### verification + +```sh +npm run test:types +``` + +--- + +## phase 2: constructor and original storage + +> update constructor to handle code in metadata + +### read before phase + +- [ ] .behavior/v2026_01_29.error-codes/3.3.blueprint.v1.i1.md (contracts section) + +### depends on + +- [x] phase 1 complete + +### checklist + +- [ ] 2.1: update `original` private type to include `code?: HelpfulErrorCode | null` +- [ ] 2.2: update constructor to extract `code` from metadata and store in `original.code` +- [ ] 2.3: update `metadataWithoutCause` to also omit `code` (for message serialization) + +### acceptance criteria + +``` +given('error thrown with code in metadata') + then('code is stored in original.code') + then('code does not appear in error.message') + +given('error thrown with code: null in metadata') + then('original.code is null') + +given('error thrown without code in metadata') + then('original.code is undefined') +``` + +### verification + +```sh +npm run test:types +``` + +--- + +## phase 3: code getter + +> implement the code getter with merge logic + +### read before phase + +- [ ] .behavior/v2026_01_29.error-codes/3.3.blueprint.v1.i1.md (contracts section, composition section) + +### depends on + +- [x] phase 2 complete + +### checklist + +- [ ] 3.1: implement `get code(): HelpfulErrorCode | undefined` on HelpfulError +- [ ] 3.2: getter reads static code from `this.constructor` +- [ ] 3.3: getter reads instance code from `this.original.code` +- [ ] 3.4: getter returns undefined if `original.code === null` (explicit opt-out) +- [ ] 3.5: getter merges class + instance (instance fields override) +- [ ] 3.6: getter returns undefined if no code anywhere + +### acceptance criteria + +``` +given('HelpfulError instance') + when('no code supplied') + then('error.code is undefined') + +given('BadRequestError instance') + when('no code supplied') + then('error.code.http is 400') + then('error.code.slug is undefined') + +given('BadRequestError instance') + when('code: { slug: "X" } supplied') + then('error.code.http is 400') + then('error.code.slug is "X"') + +given('BadRequestError instance') + when('code: { http: 422, slug: "X" } supplied') + then('error.code.http is 422') + then('error.code.slug is "X"') + +given('BadRequestError instance') + when('code: null supplied') + then('error.code is undefined') +``` + +### verification + +```sh +npm run test:types +``` + +--- + +## phase 4: metadata getter update + +> update metadata getter to exclude code field + +### read before phase + +- [ ] .behavior/v2026_01_29.error-codes/3.3.blueprint.v1.i1.md (metadata isolation section) + +### depends on + +- [x] phase 3 complete + +### checklist + +- [ ] 4.1: update `get metadata()` to omit `code` field from returned metadata + +### acceptance criteria + +``` +given('error thrown with { code: { slug: "X" }, userId: 123 }') + then('error.metadata is { userId: 123 }') + then('error.metadata does not contain code') + then('error.code.slug is "X"') +``` + +### verification + +```sh +npm run test:types +``` + +--- + +## phase 5: serialization + +> update toJSON to conditionally include code + +### read before phase + +- [ ] .behavior/v2026_01_29.error-codes/3.3.blueprint.v1.i1.md (toJSON contract, serialization flow) +- [ ] .behavior/v2026_01_29.error-codes/1.vision.md (serialization section) + +### depends on + +- [x] phase 4 complete + +### checklist + +- [ ] 5.1: update `toJSON()` to check `this.code?.slug` +- [ ] 5.2: if slug present, include `code` in output object +- [ ] 5.3: if slug absent, omit `code` from output object + +### acceptance criteria + +``` +given('BadRequestError instance') + when('no slug supplied') + then('JSON.stringify does not include code') + +given('BadRequestError instance') + when('slug supplied') + then('JSON.stringify includes code with http and slug') + +given('custom error class with static code = { http: 402, slug: "DECLINED:PAYMENT" }') + when('instance serialized') + then('JSON.stringify includes code') +``` + +### verification + +```sh +npm run test:types +``` + +--- + +## phase 6: unit tests — HelpfulError + +> add unit tests for code functionality on HelpfulError + +### read before phase + +- [ ] .behavior/v2026_01_29.error-codes/3.3.blueprint.v1.i1.md (test coverage section) +- [ ] src/HelpfulError.test.ts (prior test patterns) + +### depends on + +- [x] phase 5 complete + +### checklist + +- [ ] 6.1: add `describe('code')` block +- [ ] 6.2: add tests for getter (undefined, class code, instance code, merge, null opt-out) +- [ ] 6.3: add tests for static code (HelpfulError.code is undefined) +- [ ] 6.4: add tests for serialization (omit when no slug, include when slug) +- [ ] 6.5: add tests for metadata isolation (code not in metadata, code not in message) +- [ ] 6.6: add tests for inheritance (subclass inherits, subclass overrides, multi-level) + +### acceptance criteria + +``` +given('HelpfulError.test.ts') + then('all code-related tests pass') + then('tests cover getter, static, serialization, isolation, inheritance') +``` + +### verification + +```sh +npm run test:unit -- HelpfulError.test.ts +``` + +--- + +## phase 7: unit tests — BadRequestError + +> add unit tests for code functionality on BadRequestError + +### read before phase + +- [ ] .behavior/v2026_01_29.error-codes/3.3.blueprint.v1.i1.md (test coverage section) +- [ ] src/BadRequestError.test.ts (prior test patterns) + +### depends on + +- [x] phase 6 complete + +### checklist + +- [ ] 7.1: add `describe('code')` block +- [ ] 7.2: add test for static code = { http: 400 } +- [ ] 7.3: add test for instance.code.http is 400 +- [ ] 7.4: add test for instance.code.slug is undefined by default +- [ ] 7.5: add test for instance can override with slug +- [ ] 7.6: add test for instance can override http +- [ ] 7.7: add test for toJSON omits code (no slug by default) +- [ ] 7.8: add test for toJSON includes code when slug supplied + +### acceptance criteria + +``` +given('BadRequestError.test.ts') + then('all code-related tests pass') + then('tests cover static code, getter, override, serialization') +``` + +### verification + +```sh +npm run test:unit -- BadRequestError.test.ts +``` + +--- + +## phase 8: unit tests — UnexpectedCodePathError + +> add unit tests for code functionality on UnexpectedCodePathError + +### read before phase + +- [ ] .behavior/v2026_01_29.error-codes/3.3.blueprint.v1.i1.md (test coverage section) +- [ ] src/UnexpectedCodePathError.test.ts (prior test patterns) + +### depends on + +- [x] phase 7 complete + +### checklist + +- [ ] 8.1: add `describe('code')` block +- [ ] 8.2: add test for static code = { http: 500 } +- [ ] 8.3: add test for instance.code.http is 500 +- [ ] 8.4: add test for instance.code.slug is undefined by default +- [ ] 8.5: add test for instance can override with slug +- [ ] 8.6: add test for toJSON omits code (no slug by default) + +### acceptance criteria + +``` +given('UnexpectedCodePathError.test.ts') + then('all code-related tests pass') + then('tests cover static code, getter, override, serialization') +``` + +### verification + +```sh +npm run test:unit -- UnexpectedCodePathError.test.ts +``` + +--- + +## phase 9: backwards compatibility tests + +> verify prior behavior is unchanged + +### read before phase + +- [ ] .behavior/v2026_01_29.error-codes/2.1.criteria.blackbox.md (usecase.9) +- [ ] src/HelpfulError.test.ts (prior backwards compatibility tests) + +### depends on + +- [x] phase 8 complete + +### checklist + +- [ ] 9.1: verify prior error instantiation patterns still work +- [ ] 9.2: verify error.message unchanged for errors without code +- [ ] 9.3: verify error.metadata unchanged for non-code metadata +- [ ] 9.4: verify snapshots still match (or update if intentional) + +### acceptance criteria + +``` +given('prior error patterns') + then('all prior tests pass without modification') + then('error.message unchanged') + then('error.metadata unchanged') +``` + +### verification + +```sh +npm run test:unit +``` + +--- + +## phase 10: full validation + +> run all checks and verify criteria satisfaction + +### read before phase + +- [ ] .behavior/v2026_01_29.error-codes/2.1.criteria.blackbox.md (all usecases) +- [ ] .behavior/v2026_01_29.error-codes/2.2.criteria.blackbox.matrix.md (all matrices) + +### depends on + +- [x] phase 9 complete + +### checklist + +- [ ] 10.1: run type checks +- [ ] 10.2: run all unit tests +- [ ] 10.3: run lint checks +- [ ] 10.4: run format checks +- [ ] 10.5: verify all blackbox criteria satisfied + +### acceptance criteria + +``` +given('full test suite') + then('npm run test:types passes') + then('npm run test:unit passes') + then('npm run test:lint passes') + then('npm run test:format passes') + +given('blackbox criteria') + then('usecase.1 (extract code) satisfied') + then('usecase.2 (default codes) satisfied') + then('usecase.3 (supply code at throw) satisfied') + then('usecase.4 (class baked-in code) satisfied') + then('usecase.5 (inheritance) satisfied') + then('usecase.6 (merge semantics) satisfied') + then('usecase.7 (partial codes) satisfied') + then('usecase.8 (serialization) satisfied') + then('usecase.9 (backwards compat) satisfied') +``` + +### verification + +```sh +npm run test:types && npm run test:unit && npm run test:lint && npm run test:format +``` + +--- + +## phase 11: cleanup and commit + +> finalize changes + +### depends on + +- [x] phase 10 complete + +### checklist + +- [ ] 11.1: review all changes +- [ ] 11.2: update snapshots if needed (`RESNAP=true npm run test:unit`) +- [ ] 11.3: stage changes +- [ ] 11.4: commit with descriptive message + +### acceptance criteria + +``` +given('all changes') + then('git status shows only expected files') + then('commit message describes the feature') +``` + +### verification + +```sh +git status +git diff --staged +``` + +--- + +## summary + +| phase | description | depends on | verification | +|-------|-------------|------------|--------------| +| 0 | preparation | — | human | +| 1 | type and static code | — | test:types | +| 2 | constructor and original storage | 1 | test:types | +| 3 | code getter | 2 | test:types | +| 4 | metadata getter update | 3 | test:types | +| 5 | serialization | 4 | test:types | +| 6 | unit tests — HelpfulError | 5 | test:unit | +| 7 | unit tests — BadRequestError | 6 | test:unit | +| 8 | unit tests — UnexpectedCodePathError | 7 | test:unit | +| 9 | backwards compatibility | 8 | test:unit | +| 10 | full validation | 9 | all tests | +| 11 | cleanup and commit | 10 | git status | diff --git a/.behavior/v2026_01_29.error-codes/4.1.roadmap.v1.src b/.behavior/v2026_01_29.error-codes/4.1.roadmap.v1.src new file mode 100644 index 0000000..7109fe8 --- /dev/null +++ b/.behavior/v2026_01_29.error-codes/4.1.roadmap.v1.src @@ -0,0 +1,39 @@ +declare a roadmap, + +- checklist style +- with ordered dependencies +- with behavioral acceptance criteria +- with behavioral acceptance verification at each step + +for how to execute the blueprint specified in .behavior/v2026_01_29.error-codes/3.3.blueprint.v1.i1.md + +ref: +- .behavior/v2026_01_29.error-codes/0.wish.md +- .behavior/v2026_01_29.error-codes/1.vision.md (if declared) +- .behavior/v2026_01_29.error-codes/2.1.criteria.blackbox.md (if declared) +- .behavior/v2026_01_29.error-codes/2.3.criteria.blueprint.md (if declared) +- .behavior/v2026_01_29.error-codes/3.1.research.access._.v1.i1.md (if declared) +- .behavior/v2026_01_29.error-codes/3.1.research.claims._.v1.i1.md (if declared) +- .behavior/v2026_01_29.error-codes/3.1.research.domain._.v1.i1.md (if declared) +- .behavior/v2026_01_29.error-codes/3.1.research.patterns._.code.prod.v1.i1.md (if declared) +- .behavior/v2026_01_29.error-codes/3.1.research.patterns._.code.test.v1.i1.md (if declared) +- .behavior/v2026_01_29.error-codes/3.1.research.patterns._.oss.levers.v1.i1.md (if declared) +- .behavior/v2026_01_29.error-codes/3.1.research.templates._.v1.i1.md (if declared) +- .behavior/v2026_01_29.error-codes/3.2.distill.domain._.v1.i1.md (if declared) + +--- + +be clear as to which briefs should be read before each phase + +for example, +- if the phase includes tests, remind the builder to read + - .behavior/v2026_01_29.error-codes/3.1.research.patterns._.code.test.v1.i1.md (if declared) +- if the phase includes acceptance tests, remind the builder to read + - .behavior/v2026_01_29.error-codes/2.1.criteria.blackbox.md (if declared) +- if the phase includes domain.objects, remind the builder to read + - .behavior/v2026_01_29.error-codes/3.1.research.domain._.v1.i1.md (if declared) +etc + +--- + +emit into .behavior/v2026_01_29.error-codes/4.1.roadmap.v1.i1.md diff --git a/.behavior/v2026_01_29.error-codes/5.1.execution.phase0_to_phaseN.v1.i1.md b/.behavior/v2026_01_29.error-codes/5.1.execution.phase0_to_phaseN.v1.i1.md new file mode 100644 index 0000000..d513930 --- /dev/null +++ b/.behavior/v2026_01_29.error-codes/5.1.execution.phase0_to_phaseN.v1.i1.md @@ -0,0 +1,135 @@ +# execution: error codes + +> progress tracker for the roadmap + +--- + +## phase 0: preparation + +- [x] read .behavior/v2026_01_29.error-codes/0.wish.md +- [x] read .behavior/v2026_01_29.error-codes/1.vision.md +- [x] read .behavior/v2026_01_29.error-codes/2.1.criteria.blackbox.md +- [x] read .behavior/v2026_01_29.error-codes/2.3.criteria.blueprint.md +- [x] read .behavior/v2026_01_29.error-codes/3.3.blueprint.v1.i1.md +- [x] read .behavior/v2026_01_29.error-codes/4.1.roadmap.v1.i1.md + +**status**: ✅ complete + +--- + +## phase 1: type and static code + +- [x] 1.1: add `HelpfulErrorCode` type to src/HelpfulError.ts +- [x] 1.2: add `static code: HelpfulErrorCode | undefined = undefined` to HelpfulError +- [x] 1.3: add `static code = { http: 400 } as const` to BadRequestError +- [x] 1.4: add `static code = { http: 500 } as const` to UnexpectedCodePathError +- [x] 1.5: export `HelpfulErrorCode` type from src/index.ts + +**status**: ✅ complete (verified: npm run test:types passed) + +--- + +## phase 2: constructor and original storage + +- [x] 2.1: update `original` private type to include `code?: HelpfulErrorCode | null` +- [x] 2.2: update constructor to extract `code` from metadata and store in `original.code` +- [x] 2.3: update `metadataWithoutCause` to also omit `code` (renamed to `metadataForMessage`) + +**status**: ✅ complete (verified: npm run test:types passed) + +--- + +## phase 3: code getter + +- [x] 3.1: implement `get code(): HelpfulErrorCode | undefined` on HelpfulError +- [x] 3.2: getter reads static code from `this.constructor` +- [x] 3.3: getter reads instance code from `this.original.code` +- [x] 3.4: getter returns undefined if `original.code === null` +- [x] 3.5: getter merges class + instance (instance fields override) +- [x] 3.6: getter returns undefined if no code anywhere + +**status**: ✅ complete + +--- + +## phase 4: metadata getter update + +- [x] 4.1: update `get metadata()` to omit `code` field from returned metadata + +**status**: ✅ complete + +--- + +## phase 5: serialization + +- [x] 5.1: update `toJSON()` to check `this.code?.slug` +- [x] 5.2: if slug present, include `code` in output object +- [x] 5.3: if slug absent, omit `code` from output object + +**status**: ✅ complete (verified: npm run test:types passed) + +--- + +## phase 6: unit tests — HelpfulError + +- [x] 6.1: add `describe('code')` block +- [x] 6.2: add tests for getter +- [x] 6.3: add tests for static code +- [x] 6.4: add tests for serialization +- [x] 6.5: add tests for metadata isolation +- [x] 6.6: add tests for inheritance + +**status**: ✅ complete (56 tests passed) + +--- + +## phase 7: unit tests — BadRequestError + +- [x] 7.1: add `describe('code')` block +- [x] 7.2-7.8: add code tests + +**status**: ✅ complete (11 tests passed) + +--- + +## phase 8: unit tests — UnexpectedCodePathError + +- [x] 8.1: add `describe('code')` block +- [x] 8.2-8.6: add code tests + +**status**: ✅ complete (9 tests passed) + +--- + +## phase 9: backwards compatibility + +- [x] 9.1: verify prior patterns still work +- [x] 9.2: verify error.message unchanged +- [x] 9.3: verify error.metadata unchanged +- [x] 9.4: verify snapshots + +**status**: ✅ complete (all prior tests pass, snapshots unchanged) + +--- + +## phase 10: full validation + +- [x] 10.1: run type checks (passed) +- [x] 10.2: run all unit tests (79 tests passed) +- [x] 10.3: run lint checks (passed) +- [x] 10.4: run format checks (passed) +- [x] 10.5: verify all blackbox criteria satisfied + +**status**: ✅ complete + +--- + +## phase 11: cleanup and commit + +- [x] 11.1: review all changes +- [x] 11.2: update snapshots if needed (none needed) +- [x] 11.3: update readme.md with .code documentation +- [ ] 11.4: stage changes +- [ ] 11.5: commit with descriptive message + +**status**: 🔄 ready for user commit diff --git a/.behavior/v2026_01_29.error-codes/5.1.execution.phase0_to_phaseN.v1.src b/.behavior/v2026_01_29.error-codes/5.1.execution.phase0_to_phaseN.v1.src new file mode 100644 index 0000000..bedb988 --- /dev/null +++ b/.behavior/v2026_01_29.error-codes/5.1.execution.phase0_to_phaseN.v1.src @@ -0,0 +1,22 @@ +bootup your mechanic's role via `npx rhachet roles boot --repo ehmpathy --role mechanic` + +then, start or continue to execute +- phase0 to phaseN +of roadmap +- .behavior/v2026_01_29.error-codes/4.1.roadmap.v1.i1.md + +ref: +- .behavior/v2026_01_29.error-codes/0.wish.md +- .behavior/v2026_01_29.error-codes/1.vision.md (if declared) +- .behavior/v2026_01_29.error-codes/2.1.criteria.blackbox.md (if declared) +- .behavior/v2026_01_29.error-codes/2.3.criteria.blueprint.md (if declared) +- .behavior/v2026_01_29.error-codes/3.2.distill.domain._.v1.i1.md (if declared) +- .behavior/v2026_01_29.error-codes/3.3.blueprint.v1.i1.md + + +--- + +track your progress + +emit todos and check them off into +- .behavior/v2026_01_29.error-codes/5.1.execution.phase0_to_phaseN.v1.i1.md diff --git a/package.json b/package.json index 01f92e8..521d962 100644 --- a/package.json +++ b/package.json @@ -83,10 +83,10 @@ "esbuild-register": "3.6.0", "husky": "8.0.3", "jest": "30.2.0", - "rhachet": "1.22.7", - "rhachet-roles-bhrain": "0.5.11", - "rhachet-roles-bhuild": "0.6.6", - "rhachet-roles-ehmpathy": "1.17.20", + "rhachet": "1.28.1", + "rhachet-roles-bhrain": "0.7.1", + "rhachet-roles-bhuild": "0.6.14", + "rhachet-roles-ehmpathy": "1.17.34", "test-fns": "1.7.2", "ts-jest": "29.1.3", "ts-node": "10.9.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e724538..c590336 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -59,7 +59,7 @@ importers: version: 1.7.3(domain-objects@0.31.9) declastruct-github: specifier: 1.3.0 - version: 1.3.0(@anthropic-ai/sdk@0.51.0)(@types/node@22.15.21)(hono@4.11.7)(zod@3.25.76) + version: 1.3.0(@types/node@22.15.21)(zod@4.3.4) depcheck: specifier: 1.4.3 version: 1.4.3 @@ -73,17 +73,17 @@ importers: specifier: 30.2.0 version: 30.2.0(@types/node@22.15.21)(esbuild-register@3.6.0(esbuild@0.25.12))(ts-node@10.9.2(@swc/core@1.15.3)(@types/node@22.15.21)(typescript@5.4.5)) rhachet: - specifier: 1.22.7 - version: 1.22.7(zod@3.25.76) + specifier: 1.28.1 + version: 1.28.1(zod@4.3.4) rhachet-roles-bhrain: - specifier: 0.5.11 - version: 0.5.11(@types/node@22.15.21)(hono@4.11.7) + specifier: 0.7.1 + version: 0.7.1(@openai/codex-sdk@0.92.0)(@types/node@22.15.21)(rhachet@1.28.1(zod@4.3.4)) rhachet-roles-bhuild: - specifier: 0.6.6 - version: 0.6.6(@types/node@22.15.21)(hono@4.11.7) + specifier: 0.6.14 + version: 0.6.14 rhachet-roles-ehmpathy: - specifier: 1.17.20 - version: 1.17.20(@anthropic-ai/sdk@0.51.0)(@types/node@22.15.21)(hono@4.11.7)(zod@3.25.76) + specifier: 1.17.34 + version: 1.17.34(@types/node@22.15.21)(zod@4.3.4) test-fns: specifier: 1.7.2 version: 1.7.2 @@ -108,22 +108,6 @@ importers: packages: - '@ai-sdk/gateway@2.0.29': - resolution: {integrity: sha512-1b7E9F/B5gex/1uCkhs+sGIbH0KsZOItHnNz3iY5ir+nc4ZUA6WOU5Cu2w1USlc+3UVbhf+H+iNLlxVjLe4VvQ==} - engines: {node: '>=18'} - peerDependencies: - zod: ^3.25.76 || ^4.1.8 - - '@ai-sdk/provider-utils@3.0.20': - resolution: {integrity: sha512-iXHVe0apM2zUEzauqJwqmpC37A5rihrStAih5Ks+JE32iTe4LZ58y17UGBjpQQTCRw9YxMeo2UFLxLpBluyvLQ==} - engines: {node: '>=18'} - peerDependencies: - zod: ^3.25.76 || ^4.1.8 - - '@ai-sdk/provider@2.0.1': - resolution: {integrity: sha512-KCUwswvsC5VsW2PWFqF8eJgSCu5Ysj7m1TxiHTVA6g7k360bk0RNQENT8KTMAYEs+8fWPD3Uu4dEmzGHc+jGng==} - engines: {node: '>=18'} - '@anthropic-ai/sdk@0.51.0': resolution: {integrity: sha512-fAFC/uHhyzfw7rs65EPVV+scXDytGNm5BjttxHf6rP/YGvaBRKEvp2lwyuMigTwMI95neeG4bzrZigz7KCikjw==} hasBin: true @@ -667,10 +651,6 @@ packages: resolution: {integrity: sha512-aypjHU1zkwzwJyg/C3ktdUhhgciaBSu8nEXpkgh5p0lKaWTBvhWbEr6t62P5wBzOVwumlxelv1OwyFFtL1zupQ==} engines: {node: '>=8.0.0'} - '@ehmpathy/uni-time@1.9.0': - resolution: {integrity: sha512-4btv6Iib/TniQnr941N6oPXod7trrZVvAOH0oNEJa60/Ey+/ESXNeu/X7fdh6vQSJhlSvjzVoMi6IPfbbyrxPw==} - engines: {node: '>=8.0.0'} - '@emnapi/core@1.8.1': resolution: {integrity: sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg==} @@ -836,10 +816,6 @@ packages: cpu: [x64] os: [win32] - '@google/generative-ai@0.21.0': - resolution: {integrity: sha512-7XhUbtnlkSEZK15kN3t+tzIMxsbKm/dSkKBFalj+20NvPKe1kBY7mR2P7vuijEn+f06z5+A8bVGKO0v39cr6Wg==} - engines: {node: '>=18.0.0'} - '@hapi/address@5.1.1': resolution: {integrity: sha512-A+po2d/dVoY7cYajycYI43ZbYMXukuopIsqCjh5QzsBCipDtdofHntljDlpccMjIfTy6UOkg+5KPriwYch2bXA==} engines: {node: '>=14.0.0'} @@ -866,12 +842,6 @@ packages: '@hapi/topo@6.0.2': resolution: {integrity: sha512-KR3rD5inZbGMrHmgPxsJ9dbi6zEK+C3ZwUwTa+eMwWLz7oijWUTWD2pMSNNYJAU6Qq+65NkxXjqHr/7LM2Xkqg==} - '@hono/node-server@1.19.9': - resolution: {integrity: sha512-vHL6w3ecZsky+8P5MD+eFfaGTyCeOHUIFYMGpQGbrBTSmNNoxv0if69rEZ5giu36weC5saFuznL411gRX7bJDw==} - engines: {node: '>=18.14.1'} - peerDependencies: - hono: ^4 - '@inquirer/ansi@1.0.2': resolution: {integrity: sha512-S8qNSZiYzFd0wAcyG5AXCvUHC5Sr7xpZ9wZ2py9XR88jUz8wooStVx5M6dRzczbBWjic9NP7+rY0Xi7qqK/aMQ==} engines: {node: '>=18'} @@ -1006,14 +976,6 @@ packages: '@types/node': optional: true - '@isaacs/balanced-match@4.0.1': - resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==} - engines: {node: 20 || >=22} - - '@isaacs/brace-expansion@5.0.0': - resolution: {integrity: sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==} - engines: {node: 20 || >=22} - '@isaacs/cliui@8.0.2': resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} @@ -1151,41 +1113,6 @@ packages: '@jridgewell/trace-mapping@0.3.9': resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} - '@modelcontextprotocol/sdk@1.25.3': - resolution: {integrity: sha512-vsAMBMERybvYgKbg/l4L1rhS7VXV1c0CtyJg72vwxONVX0l4ZfKVAnZEWTQixJGTzKnELjQ59e4NbdFDALRiAQ==} - engines: {node: '>=18'} - peerDependencies: - '@cfworker/json-schema': ^4.1.1 - zod: ^3.25 || ^4.0 - peerDependenciesMeta: - '@cfworker/json-schema': - optional: true - - '@morphllm/morphmcp@0.8.60': - resolution: {integrity: sha512-eTTrzlFXloqLy14Elz9pIpIg7IFBiaoyAGNoepb68k7GvqxIJemtrDb2BVx6tnIubyWVR2/bf2PqWhZFcW+WDw==} - hasBin: true - - '@morphllm/morphsdk@0.2.87': - resolution: {integrity: sha512-PzfoM8UDT4RgpcLRXtq8/N01fGtN1SRqCadcySNzNxdROXazLXu65ATAiOqgP0wfq3kw130H1/ZQ1TVtzhHdFw==} - engines: {node: '>=18'} - peerDependencies: - '@anthropic-ai/sdk': '>=0.25.0' - '@google/generative-ai': '>=0.21.0' - ai: '>=5.0.0' - openai: '>=4.0.0' - zod: '>=3.23.0' - peerDependenciesMeta: - '@anthropic-ai/sdk': - optional: true - '@google/generative-ai': - optional: true - ai: - optional: true - openai: - optional: true - zod: - optional: true - '@napi-rs/wasm-runtime@0.2.12': resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==} @@ -1259,9 +1186,9 @@ packages: '@octokit/types@14.1.0': resolution: {integrity: sha512-1y6DgTy8Jomcpu33N+p5w58l6xyt55Ar2I91RPiIA0xCJBXyUAhXCcmZaDWSANiha7R9a6qJJ2CRomGPZ6f46g==} - '@opentelemetry/api@1.9.0': - resolution: {integrity: sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==} - engines: {node: '>=8.0.0'} + '@openai/codex-sdk@0.92.0': + resolution: {integrity: sha512-3NdbpydiFdhhS5dauv5DrFl0dKwAsN+DvaPGKzuq/IeyEOH+A0af6GnTcvUmjTVAn6JvIf6vToaWKbvRhrI14A==} + engines: {node: '>=18'} '@parcel/watcher-android-arm64@2.5.6': resolution: {integrity: sha512-YQxSS34tPF/6ZG7r/Ih9xy+kP/WwediEUsqmtf0cuCV5TPPKw/PQHRhueUo6JdeFJaqV3pyjm0GdYjZotbRt/A==} @@ -1849,13 +1776,6 @@ packages: cpu: [x64] os: [win32] - '@vercel/oidc@3.1.0': - resolution: {integrity: sha512-Fw28YZpRnA3cAHHDlkt7xQHiJ0fcL+NRcIqsocZQUSmbzeIKRpwttJjik5ZGanXP+vlA4SbTg+AbA3bP363l+w==} - engines: {node: '>= 20'} - - '@vscode/ripgrep@1.17.0': - resolution: {integrity: sha512-mBRKm+ASPkUcw4o9aAgfbusIu6H4Sdhw09bjeP1YOBFTJEZAnrnk6WZwzv8NEjgC82f7ILvhmb1WIElSugea6g==} - '@vue/compiler-core@3.5.27': resolution: {integrity: sha512-gnSBQjZA+//qDZen+6a2EdHqJ68Z7uybrMf3SPjEGgG4dicklwDVmMC1AeIHxtLVPT7sn6sH1KOO+tS6gwOUeQ==} @@ -1875,14 +1795,6 @@ packages: resolution: {integrity: sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==} hasBin: true - abort-controller@3.0.0: - resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} - engines: {node: '>=6.5'} - - accepts@2.0.0: - resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} - engines: {node: '>= 0.6'} - acorn-walk@8.3.4: resolution: {integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==} engines: {node: '>=0.4.0'} @@ -1892,24 +1804,6 @@ packages: engines: {node: '>=0.4.0'} hasBin: true - agent-base@7.1.4: - resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} - engines: {node: '>= 14'} - - ai@5.0.123: - resolution: {integrity: sha512-V3Imb0tg0pHCa6a/VsoW/FZpT07mwUw/4Hj6nexJC1Nvf1eyKQJyaYVkl+YTLnA8cKQSUkoarKhXWbFy4CSgjw==} - engines: {node: '>=18'} - peerDependencies: - zod: ^3.25.76 || ^4.1.8 - - ajv-formats@3.0.1: - resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} - peerDependencies: - ajv: ^8.0.0 - peerDependenciesMeta: - ajv: - optional: true - ajv@8.17.1: resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} @@ -1977,31 +1871,14 @@ packages: resolution: {integrity: sha512-dnWCi51YDVMEHeDrEsMhMMOOBEJLS59altq48N7WSoJKepiJfXRA7x6NETFCGP9jk2Ti6eeYO3+CA27j+XlPUQ==} engines: {node: '>=8.0.0'} - as-procedure@1.1.6: - resolution: {integrity: sha512-z1pWF1MGzP2t8tb+5A3FOBCWfPiQh+Ipas6knpfwQiLZJMSMJaDEEwxYrsVY0PBHTo4ZpF2Z/FstN5/76eZBpA==} - engines: {node: '>=8.0.0'} - as-procedure@1.1.7: resolution: {integrity: sha512-NovxtaDLUcwI8rANiXnpfLE4oo9xKf65qka0jBkStckRMgJcGZL4+Vm9+peAJ6+VE6X3n8/fIXhionfCTGas7g==} engines: {node: '>=8.0.0'} - async-lock@1.4.1: - resolution: {integrity: sha512-Az2ZTpuytrtqENulXwO3GGv1Bztugx6TT37NIo7imr/Qo0gsYiGtSdBa2B6fsXhTpVZDNfu1Qn3pk531e3q+nQ==} - - asynckit@0.4.0: - resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} - at-least-node@1.0.0: resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==} engines: {node: '>= 4.0.0'} - available-typed-arrays@1.0.7: - resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} - engines: {node: '>= 0.4'} - - axios@1.13.3: - resolution: {integrity: sha512-ERT8kdX7DZjtUm7IitEyV7InTHAF42iJuMArIiDIV5YtPanJkgw4hw5Dyg9fh0mihdWNn1GKaeIWErfe56UQ1g==} - babel-jest@30.2.0: resolution: {integrity: sha512-0YiBEOxWqKkSQWL9nNGGEgndoeL0ZpWrbLMNL5u/Kaxrli3Eaxlt3ZtIDktEvXt4L/R9r3ODr2zKwGM/2BjxVw==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} @@ -2047,10 +1924,6 @@ packages: bl@4.1.0: resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} - body-parser@2.2.2: - resolution: {integrity: sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==} - engines: {node: '>=18'} - bottleneck@2.19.5: resolution: {integrity: sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw==} @@ -2079,38 +1952,16 @@ packages: bser@2.1.1: resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} - buffer-crc32@0.2.13: - resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==} - buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} buffer@5.7.1: resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} - buffer@6.0.3: - resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} - - bytes@3.1.2: - resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} - engines: {node: '>= 0.8'} - cachedir@2.3.0: resolution: {integrity: sha512-A+Fezp4zxnit6FanDmv9EqXNAi3vt9DWp51/71UEhXukb7QUuvtv9344h91dyAxuTLoSYJFU299qzR3tzwPAhw==} engines: {node: '>=6'} - call-bind-apply-helpers@1.0.2: - resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} - engines: {node: '>= 0.4'} - - call-bind@1.0.8: - resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==} - engines: {node: '>= 0.4'} - - call-bound@1.0.4: - resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} - engines: {node: '>= 0.4'} - callsites@3.1.0: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} @@ -2180,9 +2031,6 @@ packages: cjs-module-lexer@2.2.0: resolution: {integrity: sha512-4bHTS2YuzUvtoLjdy+98ykbNB5jS0+07EvFNXerqZQJ89F7DI6ET7OQo/HJuW6K0aVsKA9hj9/RVb2kQVOrPDQ==} - clean-git-ref@2.0.1: - resolution: {integrity: sha512-bLSptAy2P0s6hU4PzuIMKmMJJSE6gLXGH1cntDu7bWJUksvuM+7ReOK61mozULErYvP6a15rnYl0zFDef+pyPw==} - cli-cursor@3.1.0: resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} engines: {node: '>=8'} @@ -2230,10 +2078,6 @@ packages: color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - combined-stream@1.0.8: - resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} - engines: {node: '>= 0.8'} - commander@12.1.0: resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==} engines: {node: '>=18'} @@ -2264,14 +2108,6 @@ packages: constant-case@3.0.4: resolution: {integrity: sha512-I2hSBi7Vvs7BEuJDr5dDHfzb/Ruj3FyvFyh7KLilAjNQw3Be+xgqUBA2W6scVEcL0hL1dwPRtIqEPVUCKkSsyQ==} - content-disposition@1.0.1: - resolution: {integrity: sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==} - engines: {node: '>=18'} - - content-type@1.0.5: - resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} - engines: {node: '>= 0.6'} - conventional-changelog-angular@7.0.0: resolution: {integrity: sha512-ROjNchA9LgfNMTTFSIWPzebCwOGFdgkEq45EnvvrmSLvCtAw0HSmrCs7/ty+wAeYUZyNay0YMUNYFTRL72PkBQ==} engines: {node: '>=16'} @@ -2291,21 +2127,9 @@ packages: convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} - cookie-signature@1.2.2: - resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} - engines: {node: '>=6.6.0'} - - cookie@0.7.2: - resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} - engines: {node: '>= 0.6'} - core-js@3.26.1: resolution: {integrity: sha512-21491RRQVzUn0GGM9Z1Jrpr6PNPxPi+Za8OM9q4tksTSnlbXXGKK1nXNg/QvwFYettXvSX6zWKCtHHfjN4puyA==} - cors@2.8.6: - resolution: {integrity: sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==} - engines: {node: '>= 0.10'} - cosmiconfig-typescript-loader@6.2.0: resolution: {integrity: sha512-GEN39v7TgdxgIoNcdkRE3uiAzQt3UXLyHbRHD6YoL048XAeOomyxaP+Hh/+2C6C2wYjxJ2onhJcsQp+L4YEkVQ==} engines: {node: '>=v18'} @@ -2327,11 +2151,6 @@ packages: typescript: optional: true - crc-32@1.2.2: - resolution: {integrity: sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==} - engines: {node: '>=0.8'} - hasBin: true - create-require@1.1.1: resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} @@ -2387,10 +2206,6 @@ packages: peerDependencies: domain-objects: '>=0.31.3' - decompress-response@6.0.0: - resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} - engines: {node: '>=10'} - dedent@0.7.0: resolution: {integrity: sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==} @@ -2409,23 +2224,11 @@ packages: defaults@1.0.4: resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==} - define-data-property@1.1.4: - resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} - engines: {node: '>= 0.4'} - - delayed-stream@1.0.0: - resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} - engines: {node: '>=0.4.0'} - depcheck@1.4.3: resolution: {integrity: sha512-vy8xe1tlLFu7t4jFyoirMmOR7x7N601ubU9Gkifyr9z8rjBFtEdWHDBMqXyk6OkK+94NXutzddVXJuo0JlUQKQ==} engines: {node: '>=10'} hasBin: true - depd@2.0.0: - resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} - engines: {node: '>= 0.8'} - deps-regex@0.1.4: resolution: {integrity: sha512-3tzwGYogSJi8HoG93R5x9NrdefZQOXgHgGih/7eivloOq6yC6O+yoFxZnkgP661twvfILONfoKRdF9GQOGx2RA==} @@ -2449,21 +2252,10 @@ packages: resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - diff3@0.0.3: - resolution: {integrity: sha512-iSq8ngPOt0K53A6eVr4d5Kn6GNrM2nQZtC740pzIriHtn4pOQ2lyzEXQMBeVcWERN0ye7fhBsk9PbLLQOnUx/g==} - diff@4.0.4: resolution: {integrity: sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==} engines: {node: '>=0.3.1'} - diff@5.2.2: - resolution: {integrity: sha512-vtcDfH3TOjP8UekytvnHH1o1P4FcUdt4eQ1Y+Abap1tk/OB2MWQvcwS2ClCd1zuIhc3JKOx6p3kod8Vfys3E+A==} - engines: {node: '>=0.3.1'} - - diff@7.0.0: - resolution: {integrity: sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw==} - engines: {node: '>=0.3.1'} - dir-glob@3.0.1: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} engines: {node: '>=8'} @@ -2503,16 +2295,9 @@ packages: resolution: {integrity: sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==} engines: {node: '>=8'} - dunder-proto@1.0.1: - resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} - engines: {node: '>= 0.4'} - eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} - ee-first@1.1.1: - resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} - electron-to-chromium@1.5.279: resolution: {integrity: sha512-0bblUU5UNdOt5G7XqGiJtpZMONma6WAfq9vsFmtn9x1+joAObr6x1chfqyxFSDCAFwFhCQDrqeAr6MYdpwJ9Hg==} @@ -2530,14 +2315,10 @@ packages: resolution: {integrity: sha512-RvCj6ERJKhfySTogP/9CcQgB/jBnsMWC30V7loE5+jaIzB2m9rEVepSRVm48ALnyQ8x26yIdgRM9SQ6Wsbf3IQ==} engines: {node: '>=8.0.0'} - emoji-space-shim@0.1.2: - resolution: {integrity: sha512-xt2hbs/B5D6aKHn8w0iXwsi8+smE0aJxGp0sjNPlBU3+JDbhGbrugNZdfJ5om3AI+gMvupeFUnVOWG696kjQVA==} + emoji-space-shim@0.1.3: + resolution: {integrity: sha512-kBblE25OLjkfjLzy5NzeaAmk+4YdB+jWmPZ72l+Wk+cZPpov6w2QI8viICxhNX8s3gNdhiLIfNfnk/NykCBsFw==} engines: {node: '>=8.0.0'} - encodeurl@2.0.0: - resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} - engines: {node: '>= 0.8'} - entities@7.0.1: resolution: {integrity: sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==} engines: {node: '>=0.12'} @@ -2549,22 +2330,6 @@ packages: error-ex@1.3.4: resolution: {integrity: sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==} - es-define-property@1.0.1: - resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} - engines: {node: '>= 0.4'} - - es-errors@1.3.0: - resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} - engines: {node: '>= 0.4'} - - es-object-atoms@1.1.1: - resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} - engines: {node: '>= 0.4'} - - es-set-tostringtag@2.1.0: - resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} - engines: {node: '>= 0.4'} - esbuild-register@3.6.0: resolution: {integrity: sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg==} peerDependencies: @@ -2579,9 +2344,6 @@ packages: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} - escape-html@1.0.3: - resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} - escape-string-regexp@1.0.5: resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} engines: {node: '>=0.8.0'} @@ -2598,26 +2360,6 @@ packages: estree-walker@2.0.2: resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} - etag@1.8.1: - resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} - engines: {node: '>= 0.6'} - - event-target-shim@5.0.1: - resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} - engines: {node: '>=6'} - - events@3.3.0: - resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} - engines: {node: '>=0.8.x'} - - eventsource-parser@3.0.6: - resolution: {integrity: sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==} - engines: {node: '>=18.0.0'} - - eventsource@3.0.7: - resolution: {integrity: sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==} - engines: {node: '>=18.0.0'} - execa@5.1.1: resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} engines: {node: '>=10'} @@ -2642,16 +2384,6 @@ packages: resolution: {integrity: sha512-u/feCi0GPsI+988gU2FLcsHyAHTU0MX1Wg68NhAnN7z/+C5wqG+CY8J53N9ioe8RXgaoz0nBR/TYMf3AycUuPw==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - express-rate-limit@7.5.1: - resolution: {integrity: sha512-7iN8iPMDzOMHPUYllBEsQdWVB6fPDMPqwjBaFrgr4Jgr/+okjvzAy+UHlYYL/Vs0OsOrMkwS6PJDkFlJwoxUnw==} - engines: {node: '>= 16'} - peerDependencies: - express: '>= 4.11' - - express@5.2.1: - resolution: {integrity: sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==} - engines: {node: '>= 18'} - external-editor@3.1.0: resolution: {integrity: sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==} engines: {node: '>=4'} @@ -2680,15 +2412,16 @@ packages: resolution: {integrity: sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ==} hasBin: true + fastest-levenshtein@1.0.16: + resolution: {integrity: sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==} + engines: {node: '>= 4.9.1'} + fastq@1.20.1: resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} fb-watchman@2.0.2: resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} - fd-slicer@1.1.0: - resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==} - figures@3.2.0: resolution: {integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==} engines: {node: '>=8'} @@ -2697,10 +2430,6 @@ packages: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} - finalhandler@2.1.1: - resolution: {integrity: sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==} - engines: {node: '>= 18.0.0'} - find-nearest-package-json@2.0.1: resolution: {integrity: sha512-tKybJ3JqUtuUoHwoe86yEIsday9w23uOF6JQPa9bWKnBrZS4n7f4Me8nSEynMAiL8c11dQerzgexY+hgmH+OXg==} @@ -2734,35 +2463,10 @@ packages: resolution: {integrity: sha512-9UbaD6XdAL97+k/n+N7JwX46K/M6Zc6KcFYskrYL8wbBV/Uyk0CTAMY0VT+qiK5PM7AIc9aTWYtq65U7T+aCNQ==} engines: {node: '>=8'} - follow-redirects@1.15.11: - resolution: {integrity: sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==} - engines: {node: '>=4.0'} - peerDependencies: - debug: '*' - peerDependenciesMeta: - debug: - optional: true - - for-each@0.3.5: - resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} - engines: {node: '>= 0.4'} - foreground-child@3.3.1: resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} engines: {node: '>=14'} - form-data@4.0.5: - resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==} - engines: {node: '>= 6'} - - forwarded@0.2.0: - resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} - engines: {node: '>= 0.6'} - - fresh@2.0.0: - resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} - engines: {node: '>= 0.8'} - fs-extra@8.1.0: resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} engines: {node: '>=6 <7 || >=8'} @@ -2790,18 +2494,10 @@ packages: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} - get-intrinsic@1.3.0: - resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} - engines: {node: '>= 0.4'} - get-package-type@0.1.0: resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} engines: {node: '>=8.0.0'} - get-proto@1.0.1: - resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} - engines: {node: '>= 0.4'} - get-stream@6.0.1: resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} engines: {node: '>=10'} @@ -2842,10 +2538,6 @@ packages: resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} engines: {node: '>=10'} - gopd@1.2.0: - resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} - engines: {node: '>= 0.4'} - graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} @@ -2857,17 +2549,6 @@ packages: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} - has-property-descriptors@1.0.2: - resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} - - has-symbols@1.1.0: - resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} - engines: {node: '>= 0.4'} - - has-tostringtag@1.0.2: - resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} - engines: {node: '>= 0.4'} - hash-fns@1.1.0: resolution: {integrity: sha512-U5qEFLH3QMR70vAmNkODMv0dff41bek64IM+8eUXvWHMAF55pX0jLWZOFZn7pvyOMibAKN+gjCAqdNtBn4N5qw==} engines: {node: '>=8.0.0'} @@ -2891,21 +2572,9 @@ packages: resolution: {integrity: sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==} engines: {node: '>=0.10.0'} - hono@4.11.7: - resolution: {integrity: sha512-l7qMiNee7t82bH3SeyUCt9UF15EVmaBvsppY2zQtrbIhl/yzBTny+YUxsVjSjQ6gaqaeVtZmGocom8TzBlA4Yw==} - engines: {node: '>=16.9.0'} - html-escaper@2.0.2: resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} - http-errors@2.0.1: - resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==} - engines: {node: '>= 0.8'} - - https-proxy-agent@7.0.6: - resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} - engines: {node: '>= 14'} - human-signals@2.1.0: resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} engines: {node: '>=10.17.0'} @@ -2994,10 +2663,6 @@ packages: invariant@2.2.4: resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==} - ipaddr.js@1.9.1: - resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} - engines: {node: '>= 0.10'} - is-arrayish@0.2.1: resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} @@ -3005,10 +2670,6 @@ packages: resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} engines: {node: '>=8'} - is-callable@1.2.7: - resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} - engines: {node: '>= 0.4'} - is-core-module@2.16.1: resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} engines: {node: '>= 0.4'} @@ -3041,9 +2702,6 @@ packages: resolution: {integrity: sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==} engines: {node: '>=8'} - is-promise@4.0.0: - resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} - is-stream@2.0.1: resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} engines: {node: '>=8'} @@ -3052,10 +2710,6 @@ packages: resolution: {integrity: sha512-+oDTluR6WEjdXEJMnC2z6A4FRwFoYuvShVVEGsS7ewc0UTi2QtAKMDJuL4BDEVt+5T7MjFo12RP8ghOM75oKJw==} engines: {node: '>=8'} - is-typed-array@1.1.15: - resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} - engines: {node: '>= 0.4'} - is-unicode-supported@0.1.0: resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} engines: {node: '>=10'} @@ -3067,25 +2721,27 @@ packages: resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==} engines: {node: '>=0.10.0'} - isarray@2.0.5: - resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} - isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + iso-price@1.1.1: + resolution: {integrity: sha512-PixJ5kwVU4mrYnDvOEJHJpytPAT5G8R6ImRB+yJd/OQRP0hb8Y13tFqATu2MCN7rGMB6+hu/3HN7ORezjnoUBw==} + engines: {node: '>=8.0.0'} + peerDependencies: + domain-objects: '>=0.24.2' + iso-time@1.10.1: resolution: {integrity: sha512-3BQe0H4ZPM7O1w3TIxwoRSCf9gQ/h+dzcbOEn8Dos3OByQ0mLRV1tqnk0hwzjnXYNgXjWHxF2dHZVq2rdfpnWg==} engines: {node: '>=8.0.0'} + iso-time@1.11.1: + resolution: {integrity: sha512-HQB4BQJyqOpP3c0lxdsXTu36/61c/eTr3pu7kBJfnUEQFLc8+lveNgsTEAA5Pk50WF0tVfEF5WF2xGRPX13mcQ==} + engines: {node: '>=8.0.0'} + iso-time@1.11.3: resolution: {integrity: sha512-JAoCDOFPmRBjO3BE36RtnVgoMBlcaA62wIQsR9ZEPvu2/7vDM/OMrpMlaTnALxXouAGXtz2O9/EPI6lldh80jg==} engines: {node: '>=8.0.0'} - isomorphic-git@1.36.3: - resolution: {integrity: sha512-bHF1nQTjL0IfSo13BHDO8oQ6SvYNQduTAdPJdSmrJ5JwZY2fsyjLujEXav5hqPCegSCAnc75ZsBUHqT/NqR7QA==} - engines: {node: '>=14.17'} - hasBin: true - istanbul-lib-coverage@3.2.2: resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} engines: {node: '>=8'} @@ -3276,8 +2932,8 @@ packages: resolution: {integrity: sha512-RuCOQMIt78LWnktPoeBL0GErkNaJPTBGcYuyaBvUOQSpcpcLfWrHPPihYdOGbV5pam9VTWbeoF7TsGiHugcjGA==} engines: {node: '>= 20'} - jose@6.1.3: - resolution: {integrity: sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ==} + js-tiktoken@1.0.18: + resolution: {integrity: sha512-hFYx4xYf6URgcttcGvGuOBJhTxPYZ2R5eIesqCaNRJmYH8sNmsfTeWg4yu//7u1VD/qIUkgKJTpGom9oHXmB4g==} js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -3301,12 +2957,6 @@ packages: json-schema-traverse@1.0.0: resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} - json-schema-typed@8.0.2: - resolution: {integrity: sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==} - - json-schema@0.4.0: - resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==} - json5@2.2.3: resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} engines: {node: '>=6'} @@ -3426,22 +3076,10 @@ packages: makeerror@1.0.12: resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} - math-intrinsics@1.1.0: - resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} - engines: {node: '>= 0.4'} - - media-typer@1.1.0: - resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} - engines: {node: '>= 0.8'} - meow@12.1.1: resolution: {integrity: sha512-BhXM0Au22RwUneMPwSCnyhTOizdWoIEPU9sp0Aqa1PnDMR5Wv2FGXYDjuzJEIX+Eo2Rb8xuYe5jrnm5QowQFkw==} engines: {node: '>=16.10'} - merge-descriptors@2.0.0: - resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==} - engines: {node: '>=18'} - merge-stream@2.0.0: resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} @@ -3456,34 +3094,10 @@ packages: resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} - mime-db@1.52.0: - resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} - engines: {node: '>= 0.6'} - - mime-db@1.54.0: - resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==} - engines: {node: '>= 0.6'} - - mime-types@2.1.35: - resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} - engines: {node: '>= 0.6'} - - mime-types@3.0.2: - resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==} - engines: {node: '>=18'} - mimic-fn@2.1.0: resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} engines: {node: '>=6'} - mimic-response@3.1.0: - resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} - engines: {node: '>=10'} - - minimatch@10.1.1: - resolution: {integrity: sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==} - engines: {node: 20 || >=22} - minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} @@ -3497,9 +3111,6 @@ packages: minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - minimisted@2.0.1: - resolution: {integrity: sha512-1oPjfuLQa2caorJUM8HV8lGgWCc0qqAO1MNv/k05G4qslmsndV/5WdNZrqCiyqiz3wohia2Ij2B7w2Dr7/IyrA==} - minipass@7.1.2: resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} engines: {node: '>=16 || 14 >=14.17'} @@ -3535,10 +3146,6 @@ packages: natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - negotiator@1.0.0: - resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} - engines: {node: '>= 0.6'} - no-case@3.0.4: resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==} @@ -3570,17 +3177,77 @@ packages: resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} engines: {node: '>=8'} - object-assign@4.1.1: - resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} - engines: {node: '>=0.10.0'} - - object-inspect@1.13.4: - resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} - engines: {node: '>= 0.4'} - - on-finished@2.4.1: - resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} - engines: {node: '>= 0.8'} + npm@11.7.0: + resolution: {integrity: sha512-wiCZpv/41bIobCoJ31NStIWKfAxxYyD1iYnWCtiyns8s5v3+l8y0HCP/sScuH6B5+GhIfda4HQKiqeGZwJWhFw==} + engines: {node: ^20.17.0 || >=22.9.0} + hasBin: true + bundledDependencies: + - '@isaacs/string-locale-compare' + - '@npmcli/arborist' + - '@npmcli/config' + - '@npmcli/fs' + - '@npmcli/map-workspaces' + - '@npmcli/metavuln-calculator' + - '@npmcli/package-json' + - '@npmcli/promise-spawn' + - '@npmcli/redact' + - '@npmcli/run-script' + - '@sigstore/tuf' + - abbrev + - archy + - cacache + - chalk + - ci-info + - cli-columns + - fastest-levenshtein + - fs-minipass + - glob + - graceful-fs + - hosted-git-info + - ini + - init-package-json + - is-cidr + - json-parse-even-better-errors + - libnpmaccess + - libnpmdiff + - libnpmexec + - libnpmfund + - libnpmorg + - libnpmpack + - libnpmpublish + - libnpmsearch + - libnpmteam + - libnpmversion + - make-fetch-happen + - minimatch + - minipass + - minipass-pipeline + - ms + - node-gyp + - nopt + - npm-audit-report + - npm-install-checks + - npm-package-arg + - npm-pick-manifest + - npm-profile + - npm-registry-fetch + - npm-user-validate + - p-map + - pacote + - parse-conflict-json + - proc-log + - qrcode-terminal + - read + - semver + - spdx-expression-parse + - ssri + - supports-color + - tar + - text-table + - tiny-relative-date + - treeverse + - validate-npm-package-name + - which once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} @@ -3609,10 +3276,6 @@ packages: resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==} engines: {node: '>=0.10.0'} - p-defer@4.0.1: - resolution: {integrity: sha512-Mr5KC5efvAK5VUptYEIopP1bakB85k2IWXaRC0rsh1uwn1L6M0LVml8OIQ4Gudg4oyZakf7FmeRLkMMtZW1i5A==} - engines: {node: '>=12'} - p-limit@2.3.0: resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} engines: {node: '>=6'} @@ -3644,9 +3307,6 @@ packages: package-json-from-dist@1.0.1: resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} - pako@1.0.11: - resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==} - param-case@3.0.4: resolution: {integrity: sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==} @@ -3662,10 +3322,6 @@ packages: resolution: {integrity: sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==} engines: {node: '>=0.10.0'} - parseurl@1.3.3: - resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} - engines: {node: '>= 0.8'} - pascal-case@3.1.2: resolution: {integrity: sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==} @@ -3695,16 +3351,10 @@ packages: resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} engines: {node: '>=16 || 14 >=14.18'} - path-to-regexp@8.3.0: - resolution: {integrity: sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==} - path-type@4.0.0: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} - pend@1.2.0: - resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} - picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -3716,18 +3366,10 @@ packages: resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} engines: {node: '>=12'} - pify@4.0.1: - resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} - engines: {node: '>=6'} - pirates@4.0.7: resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} engines: {node: '>= 6'} - pkce-challenge@5.0.1: - resolution: {integrity: sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==} - engines: {node: '>=16.20.0'} - pkg-dir@4.2.0: resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} engines: {node: '>=8'} @@ -3739,10 +3381,6 @@ packages: resolution: {integrity: sha512-B7+VDyb8Tl6oMJT9oSO2CW8XC/T4UcJGrwOVoNGwOQsQYhlpfajmrMj5xeejqaASq3V/EqThyOeATEOMuSEXiA==} engines: {node: '>=12'} - possible-typed-array-names@1.1.0: - resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} - engines: {node: '>= 0.4'} - postcss@8.5.6: resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} engines: {node: ^10 || ^12 || >=14} @@ -3763,24 +3401,9 @@ packages: resolution: {integrity: sha512-c/N7xkOHXGBx5gpQ775Ygk3QTp2J/esCYRBgE8TTgCfPPCtirqnuMej+p4b6Pqp/oKnKFbEbkaujAqEe/oJMKA==} engines: {node: '>=8.0.0'} - process@0.11.10: - resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} - engines: {node: '>= 0.6.0'} - - proxy-addr@2.0.7: - resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} - engines: {node: '>= 0.10'} - - proxy-from-env@1.1.0: - resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} - pure-rand@7.0.1: resolution: {integrity: sha512-oTUZM/NAZS8p7ANR3SHh30kXB+zK2r2BPcEn/awJIbOvq82WoMN4p62AWWp3Hhw50G0xMsw1mhIBLqHw64EcNQ==} - qs@6.14.1: - resolution: {integrity: sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==} - engines: {node: '>=0.6'} - query-ast@1.0.5: resolution: {integrity: sha512-JK+1ma4YDuLjvKKcz9JZ70G+CM9qEOs/l1cZzstMMfwKUabTJ9sud5jvDGrUNuv03yKUgs82bLkHXJkDyhRmBw==} @@ -3791,14 +3414,6 @@ packages: queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} - range-parser@1.2.1: - resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} - engines: {node: '>= 0.6'} - - raw-body@3.0.2: - resolution: {integrity: sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==} - engines: {node: '>= 0.10'} - react-is@18.3.1: resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} @@ -3806,10 +3421,6 @@ packages: resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} engines: {node: '>= 6'} - readable-stream@4.7.0: - resolution: {integrity: sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - readdirp@3.6.0: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} @@ -3889,42 +3500,38 @@ packages: resolution: {integrity: sha512-yzDL+Dv1az5WGpVvrRZT6gLBwDAzxLO/7newlyrfMM+ku91PFR9OvlADoqyulBCCUWnazv3eXl0vzrIyak4hAQ==} engines: {node: '>=8.0.0'} - rhachet-roles-bhrain@0.5.11: - resolution: {integrity: sha512-WZfGI1a+kun67Nb+9uA7PXFuMctNtFvJiIWYFDy3NyclXgu8rN9HEY0G5L3WJ1MpsdPReHfkgX0G/O0zqk+vSQ==} + rhachet-brains-openai@0.2.0: + resolution: {integrity: sha512-eQBBiy4j3McqbqhZKxrHKaZqaxtHcWPgfPc+hLAZXS1sWYY2SkfP0flLHdNTh30rE3ba5isXGfmMN74c/8hyig==} engines: {node: '>=8.0.0'} + peerDependencies: + '@openai/codex-sdk': '>=0.77.0' + rhachet: '>=1.21.4' - rhachet-roles-bhrain@0.5.9: - resolution: {integrity: sha512-tBx17IkE+gromCOOuKo01hSGSnDaHaMRTJPQa8ew1i9ulKGhD3HCHAndL/MKQ5L+4p+CgsJfsi5ydflbRXrMRQ==} + rhachet-brains-xai@0.2.0: + resolution: {integrity: sha512-CRaslwL7KzZ6PkEEEDFr3vREbpNVTU0iPuTuvmlyLGROO+nlVYppJYLQ34E8HpjJ/em5b6QEgOsY44c+LSUPKg==} engines: {node: '>=8.0.0'} + peerDependencies: + rhachet: '>=1.21.4' - rhachet-roles-bhuild@0.1.3: - resolution: {integrity: sha512-wVJrFafD/JEmufaMl/tRbmKyQ7RFhXyixV+HopXiMn1MUq83egfnaMVPd98vrbx9Q9xRhJVwKUOfcjJlul8j0g==} + rhachet-roles-bhrain@0.7.1: + resolution: {integrity: sha512-rvcDIdAjtgypL0ZKVc6CH2j9wiQM6eF/I3yJuSRcnudYOx0lPXW6yGU+m2a6aDlx8DcQaZsGk7x1OZc2HswnOQ==} engines: {node: '>=8.0.0'} - rhachet-roles-bhuild@0.6.6: - resolution: {integrity: sha512-VuFUGQcVsOowmZmJE+5WAqXjJO8qV3m4/I3XrhpKqDL8j6SAXfeS80gZb5fCed0fEM02ku8AXt1f6KIubsG+Vg==} - engines: {node: '>=8.0.0'} + rhachet-roles-bhuild@0.6.14: + resolution: {integrity: sha512-Ix3zptM6slQer9Jyn0kewQCjxewkPbbxohJeXXH2zoQ1rGVBrp01NYWLNVhfZopOyk+6U8iwJqZl19Q8ivERXA==} + engines: {node: '>=18.0.0'} - rhachet-roles-ehmpathy@1.17.20: - resolution: {integrity: sha512-4R04aHzaqvXmscj5yD1Iu3S3geFlLmS8HD/F+y+xttmPAw9CT5LlUfSiS7j4kxHcXVqG0ec2va3ZoGhNN2viJg==} + rhachet-roles-ehmpathy@1.17.34: + resolution: {integrity: sha512-ijyQwcEyOzfSmhteXYmAVANOaFuIPXXUoSJc7N/sjI+Gdd7mTt9lcm3ON8kMEYPddM+FDxWAA6CHKRcxP9i8kA==} engines: {node: '>=8.0.0'} - rhachet@1.15.2: - resolution: {integrity: sha512-XuW46wL8FDT70TPJOnKLWR+TVsAGP0pWPcCf7ee+K9nKUehoCNDObEH+jDruVvj9f1Id65VTEmhc4csmXQlygA==} - engines: {node: '>=22.0.0'} - hasBin: true - - rhachet@1.22.7: - resolution: {integrity: sha512-bNB9h9PBRUaxvbtWYq1axhs+t2LbsawxLyIbMQRhpQE6vdHuom7e+4626ZgjnBdgtCKGdRSQydYCl9BMOlOASg==} + rhachet@1.28.1: + resolution: {integrity: sha512-OQY6RQP5Whr8Bt3Qd0C3Psdy0hDfqpHdA1l7x3SOcQvIMvOxAfJDKKfnGVO4nA8ZFChOvO5agpX4M9oitbBDXg==} engines: {node: '>=22.0.0'} hasBin: true peerDependencies: zod: '>=4.3.0' - router@2.2.0: - resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} - engines: {node: '>= 18'} - run-async@2.4.1: resolution: {integrity: sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==} engines: {node: '>=0.12.0'} @@ -3966,10 +3573,6 @@ packages: engines: {node: '>=10'} hasBin: true - send@1.2.1: - resolution: {integrity: sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==} - engines: {node: '>= 18'} - sentence-case@3.0.4: resolution: {integrity: sha512-8LS0JInaQMCRoQ7YUytAo/xUu5W2XnQxV2HI/6uM6U7CITS1RqPElr30V6uIqyMKM9lJGRVFy5/4CuzcixNYSg==} @@ -3989,22 +3592,6 @@ packages: resolution: {integrity: sha512-9utpMQqdOokSv+odAU5qeOZGPmAK/SerwBnwK8S54Dyt+BNEBh00RtHWB6TirKRmPF6nDhP4TZkNAtY1PxgIJA==} engines: {node: '>=8.0.0'} - serve-static@2.2.1: - resolution: {integrity: sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==} - engines: {node: '>= 18'} - - set-function-length@1.2.2: - resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} - engines: {node: '>= 0.4'} - - setprototypeof@1.2.0: - resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} - - sha.js@2.4.12: - resolution: {integrity: sha512-8LzC5+bvI45BjpfXU8V5fdU2mfeKiQe1D1gIMn7XUlF3OTUrpdJpPPH4EMAnF0DsHHdSZqCdSss5qCmJKuiO3w==} - engines: {node: '>= 0.10'} - hasBin: true - shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} @@ -4018,22 +3605,6 @@ packages: engines: {node: '>=4'} hasBin: true - side-channel-list@1.0.0: - resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} - engines: {node: '>= 0.4'} - - side-channel-map@1.0.1: - resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} - engines: {node: '>= 0.4'} - - side-channel-weakmap@1.0.2: - resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} - engines: {node: '>= 0.4'} - - side-channel@1.1.0: - resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} - engines: {node: '>= 0.4'} - signal-exit@3.0.7: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} @@ -4041,12 +3612,6 @@ packages: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} - simple-concat@1.0.1: - resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==} - - simple-get@4.0.1: - resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==} - simple-in-memory-cache@0.4.0: resolution: {integrity: sha512-FizjX3DqiWquodrMGgdpo7GBk9x745e/haifLJper3k1sC4Y9pibn8ysKgcfCtQNtga7V/HDsKNYnP6qyFW8rw==} engines: {node: '>=8.0.0'} @@ -4096,14 +3661,6 @@ packages: resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} engines: {node: '>=10'} - statuses@2.0.2: - resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} - engines: {node: '>= 0.8'} - - string-argv@0.3.2: - resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==} - engines: {node: '>=0.6.19'} - string-length@4.0.2: resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==} engines: {node: '>=10'} @@ -4199,18 +3756,10 @@ packages: tmpl@1.0.5: resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} - to-buffer@1.2.2: - resolution: {integrity: sha512-db0E3UJjcFhpDhAF4tLo03oli3pwl3dbnzXOUIlRKrp+ldk/VUxzpWYZENsw2SZiuBjHAk7DfB0VU7NKdpb6sw==} - engines: {node: '>= 0.4'} - to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} - toidentifier@1.0.1: - resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} - engines: {node: '>=0.6'} - ts-jest@29.1.3: resolution: {integrity: sha512-6L9qz3ginTd1NKhOxmkP0qU3FyKjj5CPoY+anszfVn6Pmv/RIKzhiMCsH7Yb7UvJR9I2A64rm4zQl531s2F1iw==} engines: {node: ^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0} @@ -4297,14 +3846,6 @@ packages: resolution: {integrity: sha512-LT5QCbGx2/ANPggKQ2NkibnJ7qNpufUpaoHjGfAwEYrkJSO32MGezWHPsXdHQp9u6fKZEVYNPAHvMXRLSDMDcg==} engines: {node: '>=8.0.0'} - type-is@2.0.1: - resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==} - engines: {node: '>= 0.6'} - - typed-array-buffer@1.0.3: - resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} - engines: {node: '>= 0.4'} - typescript@5.4.5: resolution: {integrity: sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==} engines: {node: '>=14.17'} @@ -4328,10 +3869,6 @@ packages: resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} engines: {node: '>= 10.0.0'} - unpipe@1.0.0: - resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} - engines: {node: '>= 0.8'} - unrs-resolver@1.11.1: resolution: {integrity: sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==} @@ -4381,10 +3918,6 @@ packages: resolution: {integrity: sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==} engines: {node: '>=10.12.0'} - vary@1.1.2: - resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} - engines: {node: '>= 0.8'} - visualogic@1.3.2: resolution: {integrity: sha512-lq7tL9lg4X0EJCuEcvLtPC57D/g1B6US108dlhrPl+4WBfnzM+lU57lePgQL4T9JdgybtOAvw/q/qVn9wDy7vg==} engines: {node: '>=8.0.0'} @@ -4399,10 +3932,6 @@ packages: wcwidth@1.0.1: resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} - which-typed-array@1.1.20: - resolution: {integrity: sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==} - engines: {node: '>= 0.4'} - which@1.3.1: resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==} hasBin: true @@ -4440,6 +3969,10 @@ packages: resolution: {integrity: sha512-5W3qAvFIeHviyH/XyOp38cbboBDagJblLahE+b6/WueqpiJmyfL96ayJuaPuuIsJH6tL+CxL+hFGz1mOHVMnQg==} engines: {node: '>=8.0.0'} + wrapper-fns@1.1.7: + resolution: {integrity: sha512-h+M2rwKFKuHxYydepWeZC/TVYZKtFqJPUB7lmQQYDRBLVBNmofO3Mg71p52UK9m3VzyULLACQa4rGFGFFSJTow==} + engines: {node: '>=8.0.0'} + wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} @@ -4487,9 +4020,6 @@ packages: resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} engines: {node: '>=12'} - yauzl@2.10.0: - resolution: {integrity: sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==} - yn@3.1.1: resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} engines: {node: '>=6'} @@ -4506,45 +4036,14 @@ packages: resolution: {integrity: sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==} engines: {node: '>=18'} - zod-to-json-schema@3.25.0: - resolution: {integrity: sha512-HvWtU2UG41LALjajJrML6uQejQhNJx+JBO9IflpSja4R03iNWfKXrj6W2h7ljuLyc1nKS+9yDyL/9tD1U/yBnQ==} - peerDependencies: - zod: ^3.25 || ^4 - - zod-to-json-schema@3.25.1: - resolution: {integrity: sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA==} - peerDependencies: - zod: ^3.25 || ^4 - - zod@3.25.76: - resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} - zod@4.3.4: resolution: {integrity: sha512-Zw/uYiiyF6pUT1qmKbZziChgNPRu+ZRneAsMUDU6IwmXdWt5JwcUfy2bvLOCUtz5UniaN/Zx5aFttZYbYc7O/A==} snapshots: - '@ai-sdk/gateway@2.0.29(zod@3.25.76)': - dependencies: - '@ai-sdk/provider': 2.0.1 - '@ai-sdk/provider-utils': 3.0.20(zod@3.25.76) - '@vercel/oidc': 3.1.0 - zod: 3.25.76 - - '@ai-sdk/provider-utils@3.0.20(zod@3.25.76)': - dependencies: - '@ai-sdk/provider': 2.0.1 - '@standard-schema/spec': 1.1.0 - eventsource-parser: 3.0.6 - zod: 3.25.76 + '@anthropic-ai/sdk@0.51.0': {} - '@ai-sdk/provider@2.0.1': - dependencies: - json-schema: 0.4.0 - - '@anthropic-ai/sdk@0.51.0': {} - - '@aws-crypto/crc32@5.2.0': + '@aws-crypto/crc32@5.2.0': dependencies: '@aws-crypto/util': 5.2.0 '@aws-sdk/types': 3.973.1 @@ -5514,14 +5013,6 @@ snapshots: test-fns: 1.5.0 type-fns: 1.19.0 - '@ehmpathy/uni-time@1.9.0': - dependencies: - '@ehmpathy/error-fns': 1.0.2 - date-fns: 3.6.0 - domain-glossaries: 1.0.0 - test-fns: 1.5.0 - type-fns: 1.19.0 - '@emnapi/core@1.8.1': dependencies: '@emnapi/wasi-threads': 1.1.0 @@ -5616,8 +5107,6 @@ snapshots: '@esbuild/win32-x64@0.25.12': optional: true - '@google/generative-ai@0.21.0': {} - '@hapi/address@5.1.1': dependencies: '@hapi/hoek': 11.0.7 @@ -5640,10 +5129,6 @@ snapshots: dependencies: '@hapi/hoek': 11.0.7 - '@hono/node-server@1.19.9(hono@4.11.7)': - dependencies: - hono: 4.11.7 - '@inquirer/ansi@1.0.2': {} '@inquirer/checkbox@4.3.2(@types/node@22.15.21)': @@ -5769,12 +5254,6 @@ snapshots: optionalDependencies: '@types/node': 22.15.21 - '@isaacs/balanced-match@4.0.1': {} - - '@isaacs/brace-expansion@5.0.0': - dependencies: - '@isaacs/balanced-match': 4.0.1 - '@isaacs/cliui@8.0.2': dependencies: string-width: 5.1.2 @@ -6024,67 +5503,6 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 - '@modelcontextprotocol/sdk@1.25.3(hono@4.11.7)(zod@3.25.76)': - dependencies: - '@hono/node-server': 1.19.9(hono@4.11.7) - ajv: 8.17.1 - ajv-formats: 3.0.1(ajv@8.17.1) - content-type: 1.0.5 - cors: 2.8.6 - cross-spawn: 7.0.6 - eventsource: 3.0.7 - eventsource-parser: 3.0.6 - express: 5.2.1 - express-rate-limit: 7.5.1(express@5.2.1) - jose: 6.1.3 - json-schema-typed: 8.0.2 - pkce-challenge: 5.0.1 - raw-body: 3.0.2 - zod: 3.25.76 - zod-to-json-schema: 3.25.1(zod@3.25.76) - transitivePeerDependencies: - - hono - - supports-color - - '@morphllm/morphmcp@0.8.60(@anthropic-ai/sdk@0.51.0)(ai@5.0.123(zod@3.25.76))(hono@4.11.7)(openai@5.8.2(zod@3.25.76))': - dependencies: - '@google/generative-ai': 0.21.0 - '@modelcontextprotocol/sdk': 1.25.3(hono@4.11.7)(zod@3.25.76) - '@morphllm/morphsdk': 0.2.87(@anthropic-ai/sdk@0.51.0)(@google/generative-ai@0.21.0)(ai@5.0.123(zod@3.25.76))(openai@5.8.2(zod@3.25.76))(zod@3.25.76) - '@vscode/ripgrep': 1.17.0 - axios: 1.13.3 - chalk: 5.6.2 - diff: 5.2.2 - glob: 10.5.0 - minimatch: 10.1.1 - p-defer: 4.0.1 - semver: 7.7.3 - string-argv: 0.3.2 - zod: 3.25.76 - zod-to-json-schema: 3.25.1(zod@3.25.76) - transitivePeerDependencies: - - '@anthropic-ai/sdk' - - '@cfworker/json-schema' - - ai - - debug - - hono - - openai - - supports-color - - '@morphllm/morphsdk@0.2.87(@anthropic-ai/sdk@0.51.0)(@google/generative-ai@0.21.0)(ai@5.0.123(zod@3.25.76))(openai@5.8.2(zod@3.25.76))(zod@3.25.76)': - dependencies: - '@vscode/ripgrep': 1.17.0 - diff: 7.0.0 - isomorphic-git: 1.36.3 - optionalDependencies: - '@anthropic-ai/sdk': 0.51.0 - '@google/generative-ai': 0.21.0 - ai: 5.0.123(zod@3.25.76) - openai: 5.8.2(zod@3.25.76) - zod: 3.25.76 - transitivePeerDependencies: - - supports-color - '@napi-rs/wasm-runtime@0.2.12': dependencies: '@emnapi/core': 1.8.1 @@ -6172,7 +5590,7 @@ snapshots: dependencies: '@octokit/openapi-types': 25.1.0 - '@opentelemetry/api@1.9.0': {} + '@openai/codex-sdk@0.92.0': {} '@parcel/watcher-android-arm64@2.5.6': optional: true @@ -6801,16 +6219,6 @@ snapshots: '@unrs/resolver-binding-win32-x64-msvc@1.11.1': optional: true - '@vercel/oidc@3.1.0': {} - - '@vscode/ripgrep@1.17.0': - dependencies: - https-proxy-agent: 7.0.6 - proxy-from-env: 1.1.0 - yauzl: 2.10.0 - transitivePeerDependencies: - - supports-color - '@vue/compiler-core@3.5.27': dependencies: '@babel/parser': 7.28.6 @@ -6848,35 +6256,12 @@ snapshots: jsonparse: 1.3.1 through: 2.3.8 - abort-controller@3.0.0: - dependencies: - event-target-shim: 5.0.1 - - accepts@2.0.0: - dependencies: - mime-types: 3.0.2 - negotiator: 1.0.0 - acorn-walk@8.3.4: dependencies: acorn: 8.15.0 acorn@8.15.0: {} - agent-base@7.1.4: {} - - ai@5.0.123(zod@3.25.76): - dependencies: - '@ai-sdk/gateway': 2.0.29(zod@3.25.76) - '@ai-sdk/provider': 2.0.1 - '@ai-sdk/provider-utils': 3.0.20(zod@3.25.76) - '@opentelemetry/api': 1.9.0 - zod: 3.25.76 - - ajv-formats@3.0.1(ajv@8.17.1): - optionalDependencies: - ajv: 8.17.1 - ajv@8.17.1: dependencies: fast-deep-equal: 3.1.3 @@ -6942,15 +6327,6 @@ snapshots: simple-log-methods: 0.6.9 type-fns: 1.21.0 - as-procedure@1.1.6: - dependencies: - '@ehmpathy/error-fns': 1.3.2 - domain-glossary-procedure: 1.0.0 - serde-fns: 1.0.0 - simple-log-methods: 0.6.1 - test-fns: 1.4.2 - type-fns: 1.17.0 - as-procedure@1.1.7: dependencies: '@ehmpathy/error-fns': 1.3.2 @@ -6960,24 +6336,8 @@ snapshots: test-fns: 1.4.2 type-fns: 1.17.0 - async-lock@1.4.1: {} - - asynckit@0.4.0: {} - at-least-node@1.0.0: {} - available-typed-arrays@1.0.7: - dependencies: - possible-typed-array-names: 1.1.0 - - axios@1.13.3: - dependencies: - follow-redirects: 1.15.11 - form-data: 4.0.5 - proxy-from-env: 1.1.0 - transitivePeerDependencies: - - debug - babel-jest@30.2.0(@babel/core@7.28.6): dependencies: '@babel/core': 7.28.6 @@ -7046,20 +6406,6 @@ snapshots: inherits: 2.0.4 readable-stream: 3.6.2 - body-parser@2.2.2: - dependencies: - bytes: 3.1.2 - content-type: 1.0.5 - debug: 4.4.3 - http-errors: 2.0.1 - iconv-lite: 0.7.2 - on-finished: 2.4.1 - qs: 6.14.1 - raw-body: 3.0.2 - type-is: 2.0.1 - transitivePeerDependencies: - - supports-color - bottleneck@2.19.5: {} bowser@2.13.1: {} @@ -7093,8 +6439,6 @@ snapshots: dependencies: node-int64: 0.4.0 - buffer-crc32@0.2.13: {} - buffer-from@1.1.2: {} buffer@5.7.1: @@ -7102,32 +6446,8 @@ snapshots: base64-js: 1.5.1 ieee754: 1.2.1 - buffer@6.0.3: - dependencies: - base64-js: 1.5.1 - ieee754: 1.2.1 - - bytes@3.1.2: {} - cachedir@2.3.0: {} - call-bind-apply-helpers@1.0.2: - dependencies: - es-errors: 1.3.0 - function-bind: 1.1.2 - - call-bind@1.0.8: - dependencies: - call-bind-apply-helpers: 1.0.2 - es-define-property: 1.0.1 - get-intrinsic: 1.3.0 - set-function-length: 1.2.2 - - call-bound@1.0.4: - dependencies: - call-bind-apply-helpers: 1.0.2 - get-intrinsic: 1.3.0 - callsites@3.1.0: {} camel-case@4.1.2: @@ -7205,8 +6525,6 @@ snapshots: cjs-module-lexer@2.2.0: {} - clean-git-ref@2.0.1: {} - cli-cursor@3.1.0: dependencies: restore-cursor: 3.1.0 @@ -7247,10 +6565,6 @@ snapshots: color-name@1.1.4: {} - combined-stream@1.0.8: - dependencies: - delayed-stream: 1.0.0 - commander@12.1.0: {} commander@14.0.0: {} @@ -7292,10 +6606,6 @@ snapshots: tslib: 2.8.1 upper-case: 2.0.2 - content-disposition@1.0.1: {} - - content-type@1.0.5: {} - conventional-changelog-angular@7.0.0: dependencies: compare-func: 2.0.0 @@ -7315,17 +6625,8 @@ snapshots: convert-source-map@2.0.0: {} - cookie-signature@1.2.2: {} - - cookie@0.7.2: {} - core-js@3.26.1: {} - cors@2.8.6: - dependencies: - object-assign: 4.1.1 - vary: 1.1.2 - cosmiconfig-typescript-loader@6.2.0(@types/node@22.15.21)(cosmiconfig@9.0.0(typescript@5.4.5))(typescript@5.4.5): dependencies: '@types/node': 22.15.21 @@ -7350,8 +6651,6 @@ snapshots: optionalDependencies: typescript: 5.4.5 - crc-32@1.2.2: {} - create-require@1.1.1: {} cross-path-sort@1.0.0: {} @@ -7420,12 +6719,12 @@ snapshots: uuid: 9.0.0 yaml: 1.6.0 - declastruct-github@1.3.0(@anthropic-ai/sdk@0.51.0)(@types/node@22.15.21)(hono@4.11.7)(zod@3.25.76): + declastruct-github@1.3.0(@types/node@22.15.21)(zod@4.3.4): dependencies: '@ehmpathy/uni-time': 1.7.4 '@octokit/rest': 21.1.1 as-procedure: 1.1.1 - domain-objects: 0.31.7(@anthropic-ai/sdk@0.51.0)(@types/node@22.15.21)(hono@4.11.7)(zod@3.25.76) + domain-objects: 0.31.7(@types/node@22.15.21)(zod@4.3.4) helpful-errors: 1.5.3 libsodium-wrappers: 0.7.16 simple-in-memory-cache: 0.4.0 @@ -7433,13 +6732,8 @@ snapshots: visualogic: 1.3.2 with-simple-cache: 0.15.1 transitivePeerDependencies: - - '@anthropic-ai/sdk' - - '@cfworker/json-schema' - '@types/node' - aws-crt - - debug - - hono - - supports-color - ws - zod @@ -7457,10 +6751,6 @@ snapshots: type-fns: 1.21.0 uuid-fns: 1.0.2 - decompress-response@6.0.0: - dependencies: - mimic-response: 3.1.0 - dedent@0.7.0: {} dedent@1.7.1: {} @@ -7471,14 +6761,6 @@ snapshots: dependencies: clone: 1.0.4 - define-data-property@1.1.4: - dependencies: - es-define-property: 1.0.1 - es-errors: 1.3.0 - gopd: 1.2.0 - - delayed-stream@1.0.0: {} - depcheck@1.4.3: dependencies: '@babel/parser': 7.16.4 @@ -7507,8 +6789,6 @@ snapshots: transitivePeerDependencies: - supports-color - depd@2.0.0: {} - deps-regex@0.1.4: {} detect-file@1.0.0: {} @@ -7522,14 +6802,8 @@ snapshots: diff-sequences@29.6.3: {} - diff3@0.0.3: {} - diff@4.0.4: {} - diff@5.2.2: {} - - diff@7.0.0: {} - dir-glob@3.0.1: dependencies: path-type: 4.0.0 @@ -7565,24 +6839,19 @@ snapshots: type-fns: 1.21.0 uuid-fns: 1.1.3 - domain-objects@0.31.7(@anthropic-ai/sdk@0.51.0)(@types/node@22.15.21)(hono@4.11.7)(zod@3.25.76): + domain-objects@0.31.7(@types/node@22.15.21)(zod@4.3.4): dependencies: change-case: 4.1.2 domain-objects: 0.31.3 helpful-errors: 1.5.3 joi: 17.4.0 - rhachet: 1.22.7(zod@3.25.76) - rhachet-roles-ehmpathy: 1.17.20(@anthropic-ai/sdk@0.51.0)(@types/node@22.15.21)(hono@4.11.7)(zod@3.25.76) + rhachet: 1.28.1(zod@4.3.4) + rhachet-roles-ehmpathy: 1.17.34(@types/node@22.15.21)(zod@4.3.4) type-fns: 1.21.0 uuid-fns: 1.1.3 transitivePeerDependencies: - - '@anthropic-ai/sdk' - - '@cfworker/json-schema' - '@types/node' - aws-crt - - debug - - hono - - supports-color - ws - zod @@ -7602,16 +6871,8 @@ snapshots: dependencies: is-obj: 2.0.0 - dunder-proto@1.0.1: - dependencies: - call-bind-apply-helpers: 1.0.2 - es-errors: 1.3.0 - gopd: 1.2.0 - eastasianwidth@0.2.0: {} - ee-first@1.1.1: {} - electron-to-chromium@1.5.279: {} emittery@0.13.1: {} @@ -7632,13 +6893,11 @@ snapshots: serde-fns: 1.3.0 type-fns: 1.21.0 - emoji-space-shim@0.1.2: + emoji-space-shim@0.1.3: dependencies: domain-objects: 0.31.9 helpful-errors: 1.5.3 - encodeurl@2.0.0: {} - entities@7.0.1: {} env-paths@2.2.1: {} @@ -7647,21 +6906,6 @@ snapshots: dependencies: is-arrayish: 0.2.1 - es-define-property@1.0.1: {} - - es-errors@1.3.0: {} - - es-object-atoms@1.1.1: - dependencies: - es-errors: 1.3.0 - - es-set-tostringtag@2.1.0: - dependencies: - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - has-tostringtag: 1.0.2 - hasown: 2.0.2 - esbuild-register@3.6.0(esbuild@0.25.12): dependencies: debug: 4.4.3 @@ -7700,8 +6944,6 @@ snapshots: escalade@3.2.0: {} - escape-html@1.0.3: {} - escape-string-regexp@1.0.5: {} escape-string-regexp@2.0.0: {} @@ -7710,18 +6952,6 @@ snapshots: estree-walker@2.0.2: {} - etag@1.8.1: {} - - event-target-shim@5.0.1: {} - - events@3.3.0: {} - - eventsource-parser@3.0.6: {} - - eventsource@3.0.7: - dependencies: - eventsource-parser: 3.0.6 - execa@5.1.1: dependencies: cross-spawn: 7.0.6 @@ -7765,43 +6995,6 @@ snapshots: jest-mock: 30.2.0 jest-util: 30.2.0 - express-rate-limit@7.5.1(express@5.2.1): - dependencies: - express: 5.2.1 - - express@5.2.1: - dependencies: - accepts: 2.0.0 - body-parser: 2.2.2 - content-disposition: 1.0.1 - content-type: 1.0.5 - cookie: 0.7.2 - cookie-signature: 1.2.2 - debug: 4.4.3 - depd: 2.0.0 - encodeurl: 2.0.0 - escape-html: 1.0.3 - etag: 1.8.1 - finalhandler: 2.1.1 - fresh: 2.0.0 - http-errors: 2.0.1 - merge-descriptors: 2.0.0 - mime-types: 3.0.2 - on-finished: 2.4.1 - once: 1.4.0 - parseurl: 1.3.3 - proxy-addr: 2.0.7 - qs: 6.14.1 - range-parser: 1.2.1 - router: 2.2.0 - send: 1.2.1 - serve-static: 2.2.1 - statuses: 2.0.2 - type-is: 2.0.1 - vary: 1.1.2 - transitivePeerDependencies: - - supports-color - external-editor@3.1.0: dependencies: chardet: 0.7.0 @@ -7837,6 +7030,8 @@ snapshots: dependencies: strnum: 2.1.2 + fastest-levenshtein@1.0.16: {} + fastq@1.20.1: dependencies: reusify: 1.1.0 @@ -7845,10 +7040,6 @@ snapshots: dependencies: bser: 2.1.1 - fd-slicer@1.1.0: - dependencies: - pend: 1.2.0 - figures@3.2.0: dependencies: escape-string-regexp: 1.0.5 @@ -7857,17 +7048,6 @@ snapshots: dependencies: to-regex-range: 5.0.1 - finalhandler@2.1.1: - dependencies: - debug: 4.4.3 - encodeurl: 2.0.0 - escape-html: 1.0.3 - on-finished: 2.4.1 - parseurl: 1.3.3 - statuses: 2.0.2 - transitivePeerDependencies: - - supports-color - find-nearest-package-json@2.0.1: {} find-node-modules@2.1.3: @@ -7904,29 +7084,11 @@ snapshots: flattie@1.1.1: {} - follow-redirects@1.15.11: {} - - for-each@0.3.5: - dependencies: - is-callable: 1.2.7 - foreground-child@3.3.1: dependencies: cross-spawn: 7.0.6 signal-exit: 4.1.0 - form-data@4.0.5: - dependencies: - asynckit: 0.4.0 - combined-stream: 1.0.8 - es-set-tostringtag: 2.1.0 - hasown: 2.0.2 - mime-types: 2.1.35 - - forwarded@0.2.0: {} - - fresh@2.0.0: {} - fs-extra@8.1.0: dependencies: graceful-fs: 4.2.11 @@ -7951,26 +7113,8 @@ snapshots: get-caller-file@2.0.5: {} - get-intrinsic@1.3.0: - dependencies: - call-bind-apply-helpers: 1.0.2 - es-define-property: 1.0.1 - es-errors: 1.3.0 - es-object-atoms: 1.1.1 - function-bind: 1.1.2 - get-proto: 1.0.1 - gopd: 1.2.0 - has-symbols: 1.1.0 - hasown: 2.0.2 - math-intrinsics: 1.1.0 - get-package-type@0.1.0: {} - get-proto@1.0.1: - dependencies: - dunder-proto: 1.0.1 - es-object-atoms: 1.1.1 - get-stream@6.0.1: {} get-tsconfig@4.13.0: @@ -8032,24 +7176,12 @@ snapshots: merge2: 1.4.1 slash: 3.0.0 - gopd@1.2.0: {} - graceful-fs@4.2.11: {} has-flag@3.0.0: {} has-flag@4.0.0: {} - has-property-descriptors@1.0.2: - dependencies: - es-define-property: 1.0.1 - - has-symbols@1.1.0: {} - - has-tostringtag@1.0.2: - dependencies: - has-symbols: 1.1.0 - hash-fns@1.1.0: dependencies: domain-glossaries: 1.0.0 @@ -8076,25 +7208,8 @@ snapshots: dependencies: parse-passwd: 1.0.0 - hono@4.11.7: {} - html-escaper@2.0.2: {} - http-errors@2.0.1: - dependencies: - depd: 2.0.0 - inherits: 2.0.4 - setprototypeof: 1.2.0 - statuses: 2.0.2 - toidentifier: 1.0.1 - - https-proxy-agent@7.0.6: - dependencies: - agent-base: 7.1.4 - debug: 4.4.3 - transitivePeerDependencies: - - supports-color - human-signals@2.1.0: {} husky@8.0.3: {} @@ -8182,16 +7297,12 @@ snapshots: dependencies: loose-envify: 1.4.0 - ipaddr.js@1.9.1: {} - is-arrayish@0.2.1: {} is-binary-path@2.1.0: dependencies: binary-extensions: 2.3.0 - is-callable@1.2.7: {} - is-core-module@2.16.1: dependencies: hasown: 2.0.2 @@ -8212,28 +7323,26 @@ snapshots: is-obj@2.0.0: {} - is-promise@4.0.0: {} - is-stream@2.0.1: {} is-text-path@2.0.0: dependencies: text-extensions: 2.4.0 - is-typed-array@1.1.15: - dependencies: - which-typed-array: 1.1.20 - is-unicode-supported@0.1.0: {} is-utf8@0.2.1: {} is-windows@1.0.2: {} - isarray@2.0.5: {} - isexe@2.0.0: {} + iso-price@1.1.1(domain-objects@0.31.9): + dependencies: + domain-glossaries: 1.0.0 + domain-objects: 0.31.9 + helpful-errors: 1.5.3 + iso-time@1.10.1: dependencies: date-fns: 3.6.0 @@ -8241,7 +7350,7 @@ snapshots: helpful-errors: 1.5.3 type-fns: 1.21.0 - iso-time@1.11.3: + iso-time@1.11.1: dependencies: date-fns: 3.6.0 domain-glossaries: 1.0.0 @@ -8249,19 +7358,13 @@ snapshots: simple-log-methods: 0.6.9 type-fns: 1.21.0 - isomorphic-git@1.36.3: + iso-time@1.11.3: dependencies: - async-lock: 1.4.1 - clean-git-ref: 2.0.1 - crc-32: 1.2.2 - diff3: 0.0.3 - ignore: 5.3.2 - minimisted: 2.0.1 - pako: 1.0.11 - pify: 4.0.1 - readable-stream: 4.7.0 - sha.js: 2.4.12 - simple-get: 4.0.1 + date-fns: 3.6.0 + domain-glossaries: 1.0.0 + helpful-errors: 1.5.3 + simple-log-methods: 0.6.9 + type-fns: 1.21.0 istanbul-lib-coverage@3.2.2: {} @@ -8684,7 +7787,9 @@ snapshots: '@hapi/topo': 6.0.2 '@standard-schema/spec': 1.1.0 - jose@6.1.3: {} + js-tiktoken@1.0.18: + dependencies: + base64-js: 1.5.1 js-tokens@4.0.0: {} @@ -8703,10 +7808,6 @@ snapshots: json-schema-traverse@1.0.0: {} - json-schema-typed@8.0.2: {} - - json-schema@0.4.0: {} - json5@2.2.3: {} jsonc-parser@3.3.1: {} @@ -8808,14 +7909,8 @@ snapshots: dependencies: tmpl: 1.0.5 - math-intrinsics@1.1.0: {} - - media-typer@1.1.0: {} - meow@12.1.1: {} - merge-descriptors@2.0.0: {} - merge-stream@2.0.0: {} merge2@1.4.1: {} @@ -8827,26 +7922,8 @@ snapshots: braces: 3.0.3 picomatch: 2.3.1 - mime-db@1.52.0: {} - - mime-db@1.54.0: {} - - mime-types@2.1.35: - dependencies: - mime-db: 1.52.0 - - mime-types@3.0.2: - dependencies: - mime-db: 1.54.0 - mimic-fn@2.1.0: {} - mimic-response@3.1.0: {} - - minimatch@10.1.1: - dependencies: - '@isaacs/brace-expansion': 5.0.0 - minimatch@3.1.2: dependencies: brace-expansion: 1.1.12 @@ -8859,10 +7936,6 @@ snapshots: minimist@1.2.8: {} - minimisted@2.0.1: - dependencies: - minimist: 1.2.8 - minipass@7.1.2: {} ms@2.1.3: {} @@ -8887,8 +7960,6 @@ snapshots: natural-compare@1.4.0: {} - negotiator@1.0.0: {} - no-case@3.0.4: dependencies: lower-case: 2.0.2 @@ -8920,13 +7991,7 @@ snapshots: dependencies: path-key: 3.1.1 - object-assign@4.1.1: {} - - object-inspect@1.13.4: {} - - on-finished@2.4.1: - dependencies: - ee-first: 1.1.1 + npm@11.7.0: {} once@1.4.0: dependencies: @@ -8936,9 +8001,9 @@ snapshots: dependencies: mimic-fn: 2.1.0 - openai@5.8.2(zod@3.25.76): + openai@5.8.2(zod@4.3.4): optionalDependencies: - zod: 3.25.76 + zod: 4.3.4 ora@5.4.1: dependencies: @@ -8954,8 +8019,6 @@ snapshots: os-tmpdir@1.0.2: {} - p-defer@4.0.1: {} - p-limit@2.3.0: dependencies: p-try: 2.2.0 @@ -8984,8 +8047,6 @@ snapshots: package-json-from-dist@1.0.1: {} - pako@1.0.11: {} - param-case@3.0.4: dependencies: dot-case: 3.0.4 @@ -9004,8 +8065,6 @@ snapshots: parse-passwd@1.0.0: {} - parseurl@1.3.3: {} - pascal-case@3.1.2: dependencies: no-case: 3.0.4 @@ -9031,24 +8090,16 @@ snapshots: lru-cache: 10.4.3 minipass: 7.1.2 - path-to-regexp@8.3.0: {} - path-type@4.0.0: {} - pend@1.2.0: {} - picocolors@1.1.1: {} picomatch@2.3.1: {} picomatch@4.0.3: {} - pify@4.0.1: {} - pirates@4.0.7: {} - pkce-challenge@5.0.1: {} - pkg-dir@4.2.0: dependencies: find-up: 4.1.0 @@ -9061,8 +8112,6 @@ snapshots: dependencies: queue-lit: 1.5.2 - possible-typed-array-names@1.1.0: {} - postcss@8.5.6: dependencies: nanoid: 3.3.11 @@ -9094,21 +8143,8 @@ snapshots: test-fns: 1.4.2 type-fns: 1.17.0 - process@0.11.10: {} - - proxy-addr@2.0.7: - dependencies: - forwarded: 0.2.0 - ipaddr.js: 1.9.1 - - proxy-from-env@1.1.0: {} - pure-rand@7.0.1: {} - qs@6.14.1: - dependencies: - side-channel: 1.1.0 - query-ast@1.0.5: dependencies: invariant: 2.2.4 @@ -9118,15 +8154,6 @@ snapshots: queue-microtask@1.2.3: {} - range-parser@1.2.1: {} - - raw-body@3.0.2: - dependencies: - bytes: 3.1.2 - http-errors: 2.0.1 - iconv-lite: 0.7.2 - unpipe: 1.0.0 - react-is@18.3.1: {} readable-stream@3.6.2: @@ -9135,14 +8162,6 @@ snapshots: string_decoder: 1.3.0 util-deprecate: 1.0.2 - readable-stream@4.7.0: - dependencies: - abort-controller: 3.0.0 - buffer: 6.0.3 - events: 3.3.0 - process: 0.11.10 - string_decoder: 1.3.0 - readdirp@3.6.0: dependencies: picomatch: 2.3.1 @@ -9240,111 +8259,85 @@ snapshots: domain-objects: 0.31.9 helpful-errors: 1.5.3 - rhachet-roles-bhrain@0.5.11(@types/node@22.15.21)(hono@4.11.7): + rhachet-brains-openai@0.2.0(@openai/codex-sdk@0.92.0)(rhachet@1.28.1(zod@4.3.4)): dependencies: - '@anthropic-ai/sdk': 0.51.0 - '@ehmpathy/as-command': 1.0.3 - '@ehmpathy/uni-time': 1.8.1 - as-procedure: 1.1.7 + '@openai/codex-sdk': 0.92.0 domain-objects: 0.31.9 - fast-glob: 3.3.3 helpful-errors: 1.5.3 - inquirer: 12.7.0(@types/node@22.15.21) - openai: 5.8.2(zod@3.25.76) - rhachet-artifact: 1.0.0 - rhachet-artifact-git: 1.1.0 - rhachet-roles-bhuild: 0.1.3(@anthropic-ai/sdk@0.51.0)(@types/node@22.15.21)(hono@4.11.7)(zod@3.25.76) - serde-fns: 1.2.0 - simple-in-memory-cache: 0.4.0 + iso-price: 1.1.1(domain-objects@0.31.9) + openai: 5.8.2(zod@4.3.4) + rhachet: 1.28.1(zod@4.3.4) + rhachet-artifact: 1.0.1 + rhachet-artifact-git: 1.1.5 type-fns: 1.21.0 - with-simple-caching: 0.14.2 - wrapper-fns: 1.1.0 - zod: 3.25.76 - zod-to-json-schema: 3.25.0(zod@3.25.76) + wrapper-fns: 1.1.7 + zod: 4.3.4 transitivePeerDependencies: - - '@cfworker/json-schema' - - '@types/node' - - aws-crt - - debug - - hono - - supports-color - ws - rhachet-roles-bhrain@0.5.9(@types/node@22.15.21)(hono@4.11.7): + rhachet-brains-xai@0.2.0(rhachet@1.28.1(zod@4.3.4)): + dependencies: + domain-objects: 0.31.9 + helpful-errors: 1.5.3 + iso-price: 1.1.1(domain-objects@0.31.9) + openai: 5.8.2(zod@4.3.4) + rhachet: 1.28.1(zod@4.3.4) + rhachet-artifact: 1.0.1 + rhachet-artifact-git: 1.1.5 + type-fns: 1.21.0 + zod: 4.3.4 + transitivePeerDependencies: + - ws + + rhachet-roles-bhrain@0.7.1(@openai/codex-sdk@0.92.0)(@types/node@22.15.21)(rhachet@1.28.1(zod@4.3.4)): dependencies: '@anthropic-ai/sdk': 0.51.0 '@ehmpathy/as-command': 1.0.3 '@ehmpathy/uni-time': 1.8.1 as-procedure: 1.1.7 - domain-objects: 0.31.7(@anthropic-ai/sdk@0.51.0)(@types/node@22.15.21)(hono@4.11.7)(zod@3.25.76) + domain-objects: 0.31.9 fast-glob: 3.3.3 helpful-errors: 1.5.3 inquirer: 12.7.0(@types/node@22.15.21) - openai: 5.8.2(zod@3.25.76) + iso-price: 1.1.1(domain-objects@0.31.9) + iso-time: 1.11.1 + npm: 11.7.0 + openai: 5.8.2(zod@4.3.4) rhachet-artifact: 1.0.0 rhachet-artifact-git: 1.1.0 - rhachet-roles-bhuild: 0.1.3(@anthropic-ai/sdk@0.51.0)(@types/node@22.15.21)(hono@4.11.7)(zod@3.25.76) + rhachet-brains-openai: 0.2.0(@openai/codex-sdk@0.92.0)(rhachet@1.28.1(zod@4.3.4)) + rhachet-brains-xai: 0.2.0(rhachet@1.28.1(zod@4.3.4)) serde-fns: 1.2.0 simple-in-memory-cache: 0.4.0 type-fns: 1.21.0 with-simple-caching: 0.14.2 wrapper-fns: 1.1.0 - zod: 3.25.76 - zod-to-json-schema: 3.25.0(zod@3.25.76) - transitivePeerDependencies: - - '@cfworker/json-schema' - - '@types/node' - - aws-crt - - debug - - hono - - supports-color - - ws - - rhachet-roles-bhuild@0.1.3(@anthropic-ai/sdk@0.51.0)(@types/node@22.15.21)(hono@4.11.7)(zod@3.25.76): - dependencies: - domain-objects: 0.31.7(@anthropic-ai/sdk@0.51.0)(@types/node@22.15.21)(hono@4.11.7)(zod@3.25.76) - helpful-errors: 1.5.3 - rhachet: 1.15.2(@anthropic-ai/sdk@0.51.0)(@types/node@22.15.21)(hono@4.11.7)(zod@3.25.76) + zod: 4.3.4 transitivePeerDependencies: - - '@anthropic-ai/sdk' - - '@cfworker/json-schema' + - '@openai/codex-sdk' - '@types/node' - aws-crt - - debug - - hono - - supports-color + - rhachet - ws - - zod - rhachet-roles-bhuild@0.6.6(@types/node@22.15.21)(hono@4.11.7): + rhachet-roles-bhuild@0.6.14: dependencies: domain-objects: 0.31.9 emoji-space-shim: 0.0.0 helpful-errors: 1.5.3 - rhachet-roles-bhrain: 0.5.9(@types/node@22.15.21)(hono@4.11.7) test-fns: 1.7.2 zod: 4.3.4 - transitivePeerDependencies: - - '@cfworker/json-schema' - - '@types/node' - - aws-crt - - debug - - hono - - supports-color - - ws - rhachet-roles-ehmpathy@1.17.20(@anthropic-ai/sdk@0.51.0)(@types/node@22.15.21)(hono@4.11.7)(zod@3.25.76): + rhachet-roles-ehmpathy@1.17.34(@types/node@22.15.21)(zod@4.3.4): dependencies: '@ehmpathy/as-command': 1.0.3 '@ehmpathy/uni-time': 1.8.1 - '@morphllm/morphmcp': 0.8.60(@anthropic-ai/sdk@0.51.0)(ai@5.0.123(zod@3.25.76))(hono@4.11.7)(openai@5.8.2(zod@3.25.76)) - ai: 5.0.123(zod@3.25.76) as-procedure: 1.1.7 domain-objects: 0.31.9 fast-glob: 3.3.3 helpful-errors: 1.5.3 inquirer: 12.7.0(@types/node@22.15.21) - openai: 5.8.2(zod@3.25.76) + openai: 5.8.2(zod@4.3.4) rhachet-artifact: 1.0.0 rhachet-artifact-git: 1.1.0 serde-fns: 1.2.0 @@ -9353,57 +8346,27 @@ snapshots: with-simple-caching: 0.14.2 wrapper-fns: 1.1.0 transitivePeerDependencies: - - '@anthropic-ai/sdk' - - '@cfworker/json-schema' - - '@types/node' - - aws-crt - - debug - - hono - - supports-color - - ws - - zod - - rhachet@1.15.2(@anthropic-ai/sdk@0.51.0)(@types/node@22.15.21)(hono@4.11.7)(zod@3.25.76): - dependencies: - '@ehmpathy/uni-time': 1.9.0 - as-procedure: 1.1.6 - bottleneck: 2.19.5 - chalk: 4.1.2 - commander: 14.0.0 - domain-objects: 0.31.7(@anthropic-ai/sdk@0.51.0)(@types/node@22.15.21)(hono@4.11.7)(zod@3.25.76) - fast-glob: 3.3.3 - flattie: 1.1.1 - helpful-errors: 1.5.3 - openai: 5.8.2(zod@3.25.76) - rhachet-artifact: 1.0.1 - rhachet-artifact-git: 1.1.3 - serde-fns: 1.3.1 - type-fns: 1.21.0 - uuid-fns: 1.0.1 - transitivePeerDependencies: - - '@anthropic-ai/sdk' - - '@cfworker/json-schema' - '@types/node' - aws-crt - - debug - - hono - - supports-color - ws - zod - rhachet@1.22.7(zod@3.25.76): + rhachet@1.28.1(zod@4.3.4): dependencies: as-procedure: 1.1.11 bottleneck: 2.19.5 chalk: 4.1.2 commander: 14.0.0 domain-objects: 0.31.9 - emoji-space-shim: 0.1.2 + emoji-space-shim: 0.1.3 fast-glob: 3.3.3 + fastest-levenshtein: 1.0.16 flattie: 1.1.1 helpful-errors: 1.5.3 - iso-time: 1.10.1 - openai: 5.8.2(zod@3.25.76) + iso-price: 1.1.1(domain-objects@0.31.9) + iso-time: 1.11.1 + js-tiktoken: 1.0.18 + openai: 5.8.2(zod@4.3.4) rhachet-artifact: 1.0.3 rhachet-artifact-git: 1.1.5 serde-fns: 1.3.1 @@ -9411,20 +8374,10 @@ snapshots: type-fns: 1.21.0 uuid-fns: 1.0.1 yaml: 2.8.2 - zod: 3.25.76 + zod: 4.3.4 transitivePeerDependencies: - ws - router@2.2.0: - dependencies: - debug: 4.4.3 - depd: 2.0.0 - is-promise: 4.0.0 - parseurl: 1.3.3 - path-to-regexp: 8.3.0 - transitivePeerDependencies: - - supports-color - run-async@2.4.1: {} run-async@4.0.6: {} @@ -9460,22 +8413,6 @@ snapshots: semver@7.7.3: {} - send@1.2.1: - dependencies: - debug: 4.4.3 - encodeurl: 2.0.0 - escape-html: 1.0.3 - etag: 1.8.1 - fresh: 2.0.0 - http-errors: 2.0.1 - mime-types: 3.0.2 - ms: 2.1.3 - on-finished: 2.4.1 - range-parser: 1.2.1 - statuses: 2.0.2 - transitivePeerDependencies: - - supports-color - sentence-case@3.0.4: dependencies: no-case: 3.0.4 @@ -9498,32 +8435,6 @@ snapshots: dependencies: type-fns: 1.17.0 - serve-static@2.2.1: - dependencies: - encodeurl: 2.0.0 - escape-html: 1.0.3 - parseurl: 1.3.3 - send: 1.2.1 - transitivePeerDependencies: - - supports-color - - set-function-length@1.2.2: - dependencies: - define-data-property: 1.1.4 - es-errors: 1.3.0 - function-bind: 1.1.2 - get-intrinsic: 1.3.0 - gopd: 1.2.0 - has-property-descriptors: 1.0.2 - - setprototypeof@1.2.0: {} - - sha.js@2.4.12: - dependencies: - inherits: 2.0.4 - safe-buffer: 5.2.1 - to-buffer: 1.2.2 - shebang-command@2.0.0: dependencies: shebang-regex: 3.0.0 @@ -9536,46 +8447,10 @@ snapshots: interpret: 1.4.0 rechoir: 0.6.2 - side-channel-list@1.0.0: - dependencies: - es-errors: 1.3.0 - object-inspect: 1.13.4 - - side-channel-map@1.0.1: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - object-inspect: 1.13.4 - - side-channel-weakmap@1.0.2: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - object-inspect: 1.13.4 - side-channel-map: 1.0.1 - - side-channel@1.1.0: - dependencies: - es-errors: 1.3.0 - object-inspect: 1.13.4 - side-channel-list: 1.0.0 - side-channel-map: 1.0.1 - side-channel-weakmap: 1.0.2 - signal-exit@3.0.7: {} signal-exit@4.1.0: {} - simple-concat@1.0.1: {} - - simple-get@4.0.1: - dependencies: - decompress-response: 6.0.0 - once: 1.4.0 - simple-concat: 1.0.1 - simple-in-memory-cache@0.4.0: dependencies: '@ehmpathy/uni-time': 1.7.4 @@ -9583,7 +8458,7 @@ snapshots: simple-log-methods@0.6.1: dependencies: '@ehmpathy/error-fns': 1.3.7 - '@ehmpathy/uni-time': 1.8.1 + '@ehmpathy/uni-time': 1.10.0 domain-glossary-procedure: 1.0.0 type-fns: 1.21.0 @@ -9606,12 +8481,12 @@ snapshots: simple-on-disk-cache@1.7.3: dependencies: '@aws-sdk/client-s3': 3.975.0 - '@ehmpathy/uni-time': 1.8.1 + '@ehmpathy/uni-time': 1.10.0 bottleneck: 2.19.5 domain-objects: 0.31.0 hash-fns: 1.1.0 helpful-errors: 1.5.3 - serde-fns: 1.2.0 + serde-fns: 1.3.1 simple-in-memory-cache: 0.4.0 type-fns: 1.21.0 transitivePeerDependencies: @@ -9641,10 +8516,6 @@ snapshots: dependencies: escape-string-regexp: 2.0.0 - statuses@2.0.2: {} - - string-argv@0.3.2: {} - string-length@4.0.2: dependencies: char-regex: 1.0.2 @@ -9734,18 +8605,10 @@ snapshots: tmpl@1.0.5: {} - to-buffer@1.2.2: - dependencies: - isarray: 2.0.5 - safe-buffer: 5.2.1 - typed-array-buffer: 1.0.3 - to-regex-range@5.0.1: dependencies: is-number: 7.0.0 - toidentifier@1.0.1: {} - ts-jest@29.1.3(@babel/core@7.28.6)(@jest/types@29.6.3)(esbuild@0.25.12)(jest@30.2.0(@types/node@22.15.21)(esbuild-register@3.6.0(esbuild@0.25.12))(ts-node@10.9.2(@swc/core@1.15.3)(@types/node@22.15.21)(typescript@5.4.5)))(typescript@5.4.5): dependencies: bs-logger: 0.2.6 @@ -9835,18 +8698,6 @@ snapshots: dependencies: helpful-errors: 1.5.3 - type-is@2.0.1: - dependencies: - content-type: 1.0.5 - media-typer: 1.1.0 - mime-types: 3.0.2 - - typed-array-buffer@1.0.3: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - is-typed-array: 1.1.15 - typescript@5.4.5: {} undici-types@6.21.0: {} @@ -9859,8 +8710,6 @@ snapshots: universalify@2.0.1: {} - unpipe@1.0.0: {} - unrs-resolver@1.11.1: dependencies: napi-postinstall: 0.3.4 @@ -9930,8 +8779,6 @@ snapshots: '@types/istanbul-lib-coverage': 2.0.6 convert-source-map: 2.0.0 - vary@1.1.2: {} - visualogic@1.3.2: dependencies: '@ehmpathy/error-fns': 1.0.2 @@ -9953,16 +8800,6 @@ snapshots: dependencies: defaults: 1.0.4 - which-typed-array@1.1.20: - dependencies: - available-typed-arrays: 1.0.7 - call-bind: 1.0.8 - call-bound: 1.0.4 - for-each: 0.3.5 - get-proto: 1.0.1 - gopd: 1.2.0 - has-tostringtag: 1.0.2 - which@1.3.1: dependencies: isexe: 2.0.0 @@ -9984,8 +8821,8 @@ snapshots: with-simple-caching@0.14.2: dependencies: - '@ehmpathy/uni-time': 1.8.1 - serde-fns: 1.2.0 + '@ehmpathy/uni-time': 1.10.0 + serde-fns: 1.3.1 simple-in-memory-cache: 0.4.0 simple-on-disk-cache: 1.7.3 type-fns: 1.21.0 @@ -10020,6 +8857,16 @@ snapshots: domain-glossary-procedure: 1.0.0 visualogic: 1.3.2 + wrapper-fns@1.1.7: + dependencies: + as-procedure: 1.1.11 + bottleneck: 2.19.5 + domain-glossary-procedure: 1.0.0 + domain-objects: 0.31.9 + helpful-errors: 1.5.3 + iso-time: 1.10.1 + simple-log-methods: 0.6.9 + wrappy@1.0.2: {} write-file-atomic@5.0.1: @@ -10074,11 +8921,6 @@ snapshots: y18n: 5.0.8 yargs-parser: 21.1.1 - yauzl@2.10.0: - dependencies: - buffer-crc32: 0.2.13 - fd-slicer: 1.1.0 - yn@3.1.1: {} yocto-queue@0.1.0: {} @@ -10087,14 +8929,4 @@ snapshots: yoctocolors-cjs@2.1.3: {} - zod-to-json-schema@3.25.0(zod@3.25.76): - dependencies: - zod: 3.25.76 - - zod-to-json-schema@3.25.1(zod@3.25.76): - dependencies: - zod: 3.25.76 - - zod@3.25.76: {} - zod@4.3.4: {} diff --git a/readme.md b/readme.md index 1fee4d1..bdbbb9f 100644 --- a/readme.md +++ b/readme.md @@ -334,3 +334,91 @@ JSON.stringify(error); // useful for api responses res.status(500).json({ error: error.toJSON() }); ``` + +### .code + +Errors extended from `HelpfulError` support declarative error codes via the `.code` property. This enables machine-readable error classification for api responses, logs, and metrics. + +#### default codes + +The built-in error classes have default http codes: +- `BadRequestError` has `{ http: 400 }` +- `UnexpectedCodePathError` has `{ http: 500 }` +- `HelpfulError` has no default code + +```ts +const error = new BadRequestError('invalid input'); +console.log(error.code?.http); // 400 +console.log(error.code?.slug); // undefined +``` + +#### custom error classes with baked-in codes + +Define error classes with baked-in codes for consistent classification: + +```ts +class DeclinedPaymentError extends BadRequestError { + public static code = { http: 402, slug: 'DECLINED:PAYMENT' } as const; +} + +const error = new DeclinedPaymentError('card rejected'); +console.log(error.code); // { http: 402, slug: 'DECLINED:PAYMENT' } +``` + +#### instance-level code override + +Supply a code at throw time for context-specific classification: + +```ts +throw new BadRequestError('email already registered', { + code: { slug: 'DUPLICATE_EMAIL' }, + email, +}); + +// error.code => { http: 400, slug: 'DUPLICATE_EMAIL' } +``` + +Instance codes merge with class codes — instance fields override class fields: + +```ts +throw new BadRequestError('validation failed', { + code: { http: 422, slug: 'VALIDATION' }, +}); + +// error.code => { http: 422, slug: 'VALIDATION' } +``` + +#### opt-out with code: null + +Explicitly clear any inherited code: + +```ts +const error = new DeclinedPaymentError('card rejected', { code: null }); +console.log(error.code); // undefined +``` + +#### serialization + +Error codes only appear in JSON serialization when a slug is present — this prevents log spam with default http codes and ensures opt-in only behavior: + +```ts +// no slug => code omitted from JSON +const error1 = new BadRequestError('test'); +JSON.stringify(error1); // no "code" field + +// slug present => code included in JSON +const error2 = new BadRequestError('test', { code: { slug: 'CUSTOM' } }); +JSON.stringify(error2); // includes { "code": { "http": 400, "slug": "CUSTOM" } } +``` + +#### api handler example + +```ts +app.use((err, req, res, next) => { + const code = err.code ?? { http: 500 }; + res.status(code.http ?? 500).json({ + error: err.message, + code: code.slug, + }); +}); +``` diff --git a/src/BadRequestError.test.ts b/src/BadRequestError.test.ts index 45a7872..879f3a4 100644 --- a/src/BadRequestError.test.ts +++ b/src/BadRequestError.test.ts @@ -45,4 +45,49 @@ describe('BadRequestError', () => { new TypedBadRequest('error', { wrong: 'key' }); }); }); + describe('code', () => { + it('should have static code = { http: 400 }', () => { + expect(BadRequestError.code).toEqual({ http: 400 }); + }); + + it('should have instance.code.http as 400', () => { + const error = new BadRequestError('test error'); + expect(error.code?.http).toEqual(400); + }); + + it('should have instance.code.slug as undefined by default', () => { + const error = new BadRequestError('test error'); + expect(error.code?.slug).toBeUndefined(); + }); + + it('should allow instance to override with slug', () => { + const error = new BadRequestError('test error', { + code: { slug: 'VALIDATION' }, + }); + expect(error.code).toEqual({ http: 400, slug: 'VALIDATION' }); + }); + + it('should allow instance to override http', () => { + const error = new BadRequestError('test error', { + code: { http: 422, slug: 'UNPROCESSABLE' }, + }); + expect(error.code).toEqual({ http: 422, slug: 'UNPROCESSABLE' }); + }); + + it('should omit code from toJSON (no slug by default)', () => { + const error = new BadRequestError('test error'); + const json = JSON.stringify(error); + const parsed = JSON.parse(json); + expect(parsed.code).toBeUndefined(); + }); + + it('should include code in toJSON when slug supplied', () => { + const error = new BadRequestError('test error', { + code: { slug: 'DUPLICATE_EMAIL' }, + }); + const json = JSON.stringify(error); + const parsed = JSON.parse(json); + expect(parsed.code).toEqual({ http: 400, slug: 'DUPLICATE_EMAIL' }); + }); + }); }); diff --git a/src/BadRequestError.ts b/src/BadRequestError.ts index 148b724..79d9d34 100644 --- a/src/BadRequestError.ts +++ b/src/BadRequestError.ts @@ -13,6 +13,12 @@ import { HelpfulError, type HelpfulErrorMetadata } from './HelpfulError'; export class BadRequestError< TMetadata extends HelpfulErrorMetadata = HelpfulErrorMetadata, > extends HelpfulError { + /** + * .what = default http code for bad request errors + * .why = aligns with http 400 semantics + */ + public static code = { http: 400 } as const; + constructor( message: string, ...[metadata]: HelpfulErrorMetadata extends TMetadata diff --git a/src/HelpfulError.test.ts b/src/HelpfulError.test.ts index 15c91a3..928f84a 100644 --- a/src/HelpfulError.test.ts +++ b/src/HelpfulError.test.ts @@ -401,4 +401,179 @@ describe('HelpfulError', () => { expect(error).toBeInstanceOf(TypedError); }); }); + describe('code', () => { + describe('getter', () => { + it('should return undefined for base HelpfulError', () => { + const error = new HelpfulError('test error'); + expect(error.code).toBeUndefined(); + }); + + it('should return class code when no instance code', () => { + class ErrorWithCode extends HelpfulError { + public static code = { http: 418, slug: 'TEAPOT' } as const; + } + const error = new ErrorWithCode('test error'); + expect(error.code).toEqual({ http: 418, slug: 'TEAPOT' }); + }); + + it('should return instance code when no class code', () => { + const error = new HelpfulError('test error', { + code: { slug: 'CUSTOM' }, + }); + expect(error.code).toEqual({ slug: 'CUSTOM' }); + }); + + it('should merge instance code over class code', () => { + class ErrorWithCode extends HelpfulError { + public static code = { http: 400 } as const; + } + const error = new ErrorWithCode('test error', { + code: { slug: 'CUSTOM' }, + }); + expect(error.code).toEqual({ http: 400, slug: 'CUSTOM' }); + }); + + it('should allow instance to override http from class', () => { + class ErrorWithCode extends HelpfulError { + public static code = { http: 400 } as const; + } + const error = new ErrorWithCode('test error', { + code: { http: 422, slug: 'VALIDATION' }, + }); + expect(error.code).toEqual({ http: 422, slug: 'VALIDATION' }); + }); + + it('should return undefined when code: null in metadata (explicit opt-out)', () => { + class ErrorWithCode extends HelpfulError { + public static code = { http: 400 } as const; + } + const error = new ErrorWithCode('test error', { code: null }); + expect(error.code).toBeUndefined(); + }); + }); + + describe('static code', () => { + it('should have HelpfulError.code as undefined', () => { + expect(HelpfulError.code).toBeUndefined(); + }); + + it('should allow subclass to define static code', () => { + class CustomError extends HelpfulError { + public static code = { + http: 503, + slug: 'SERVICE_UNAVAILABLE', + } as const; + } + expect(CustomError.code).toEqual({ + http: 503, + slug: 'SERVICE_UNAVAILABLE', + }); + }); + }); + + describe('serialization', () => { + it('should omit code from toJSON when no slug', () => { + class ErrorWithHttpOnly extends HelpfulError { + public static code = { http: 400 } as const; + } + const error = new ErrorWithHttpOnly('test error'); + const json = JSON.stringify(error); + const parsed = JSON.parse(json); + expect(parsed.code).toBeUndefined(); + }); + + it('should include code in toJSON when slug present from class', () => { + class ErrorWithSlug extends HelpfulError { + public static code = { http: 402, slug: 'DECLINED:PAYMENT' } as const; + } + const error = new ErrorWithSlug('payment declined'); + const json = JSON.stringify(error); + const parsed = JSON.parse(json); + expect(parsed.code).toEqual({ http: 402, slug: 'DECLINED:PAYMENT' }); + }); + + it('should include code in toJSON when slug present from instance', () => { + class ErrorWithHttpOnly extends HelpfulError { + public static code = { http: 400 } as const; + } + const error = new ErrorWithHttpOnly('test error', { + code: { slug: 'CUSTOM' }, + }); + const json = JSON.stringify(error); + const parsed = JSON.parse(json); + expect(parsed.code).toEqual({ http: 400, slug: 'CUSTOM' }); + }); + + it('should include full merged code in toJSON', () => { + class ErrorWithHttpOnly extends HelpfulError { + public static code = { http: 400 } as const; + } + const error = new ErrorWithHttpOnly('test error', { + code: { http: 422, slug: 'VALIDATION' }, + }); + const json = JSON.stringify(error); + const parsed = JSON.parse(json); + expect(parsed.code).toEqual({ http: 422, slug: 'VALIDATION' }); + }); + }); + + describe('metadata isolation', () => { + it('should not include code field in error.metadata', () => { + const error = new HelpfulError('test error', { + code: { slug: 'TEST' }, + userId: 123, + }); + expect(error.metadata).toEqual({ userId: 123 }); + expect((error.metadata as any)?.code).toBeUndefined(); + }); + + it('should not include code in error message', () => { + const error = new HelpfulError('test error', { + code: { slug: 'TEST' }, + userId: 123, + }); + expect(error.message).not.toContain('code'); + expect(error.message).not.toContain('TEST'); + expect(error.message).toContain('userId'); + expect(error.message).toContain('123'); + }); + }); + + describe('inheritance', () => { + it('should allow custom subclass to inherit parent code', () => { + class ParentError extends HelpfulError { + public static code = { http: 400 }; + } + class ChildError extends ParentError {} + + const error = new ChildError('test error'); + expect(error.code).toEqual({ http: 400 }); + }); + + it('should allow custom subclass to override parent code', () => { + class ParentError extends HelpfulError { + public static code = { http: 400 }; + } + class ChildError extends ParentError { + public static code = { http: 422, slug: 'VALIDATION' }; + } + + const error = new ChildError('test error'); + expect(error.code).toEqual({ http: 422, slug: 'VALIDATION' }); + }); + + it('should support multi-level inheritance', () => { + class Level1 extends HelpfulError { + public static code = { http: 400 }; + } + class Level2 extends Level1 { + public static code = { http: 400, slug: 'LEVEL2' }; + } + class Level3 extends Level2 {} + + const error = new Level3('test error'); + expect(error.code).toEqual({ http: 400, slug: 'LEVEL2' }); + }); + }); + }); }); diff --git a/src/HelpfulError.ts b/src/HelpfulError.ts index 5093737..c1a5271 100644 --- a/src/HelpfulError.ts +++ b/src/HelpfulError.ts @@ -5,6 +5,15 @@ import { omit } from 'type-fns/dist/companions/omit'; import { getEnvOptions } from './utils/env'; import { withHelpfulError } from './withHelpfulError'; +/** + * .what = error code with optional http status and machine-readable slug + * .why = enables declarative error classification + */ +export type HelpfulErrorCode = { + http?: number; + slug?: string; +}; + export type HelpfulErrorMetadata = Record & { /** * .what = declares the error that triggered this error @@ -30,6 +39,12 @@ export type HelpfulErrorConstructor = new ( export class HelpfulError< TMetadata extends HelpfulErrorMetadata = HelpfulErrorMetadata, > extends Error { + /** + * .what = default error code for this error class + * .why = enables subclasses to declare baked-in codes + */ + public static code: HelpfulErrorCode | undefined = undefined; + /** * .what = the procedure executed on new HelpfulError() calls to instantiate errors * .why = @@ -44,27 +59,29 @@ export class HelpfulError< ? [metadata?: TMetadata] // default type - optional : [metadata: TMetadata] // specific type - required ) { - const metadataWithoutCause = metadata - ? omit(metadata, ['cause']) + // extract code and cause from metadata, omit both from message serialization + const metadataForMessage = metadata + ? omit(metadata, ['cause', 'code']) : metadata; const fullMessage = [ message, - metadataWithoutCause && Object.keys(metadataWithoutCause).length + metadataForMessage && Object.keys(metadataForMessage).length ? getEnvOptions().expand - ? JSON.stringify(metadataWithoutCause, null, 2) - : JSON.stringify(metadataWithoutCause) + ? JSON.stringify(metadataForMessage, null, 2) + : JSON.stringify(metadataForMessage) : null, ] .filter(isPresent) .join('\n\n'); super(fullMessage, metadata?.cause ? { cause: metadata.cause } : undefined); - // store the original message, metadata, and cause for later access (non-enumerable) + // store the original message, metadata, cause, and code for later access (non-enumerable) Object.defineProperty(this, 'original', { value: { message, metadata, cause: metadata?.cause, + code: metadata?.code, }, enumerable: false, // non enumerable, so it wont pollute toJSON, Object.keys(), nor for...in loops; its only intended for internal use writable: false, @@ -79,18 +96,48 @@ export class HelpfulError< message: string; metadata?: TMetadata; cause?: Error; + code?: HelpfulErrorCode | null; }; + /** + * .what = accessor for merged error code (class + instance) + * .why = enables programmatic access to error classification + */ + public get code(): HelpfulErrorCode | undefined { + // get class static code via prototype chain + const classCode = (this.constructor as typeof HelpfulError).code; + + // get instance code from original + const instanceCode = this.original.code; + + // handle explicit null (opt-out) + if (instanceCode === null) return undefined; + + // if no code anywhere, return undefined + if (!classCode && !instanceCode) return undefined; + + // merge: instance fields override class fields + return { + ...classCode, + ...instanceCode, + }; + } + /** * .what = public accessor for the metadata passed to the error * .why = enables programmatic access to metadata without parse of the message * .note = getter is non-enumerable by default, so it won't pollute toJSON or Object.keys() + * .note = excludes 'code' field since code is accessed via error.code */ public get metadata(): HelpfulErrorMetadata extends TMetadata ? TMetadata | undefined // default type - metadata was optional : TMetadata { // specific type - metadata was required - return this.original.metadata as HelpfulErrorMetadata extends TMetadata + const raw = this.original.metadata; + if (!raw) return raw as any; + + // omit code from metadata to avoid duplication (code is accessed via error.code) + return omit(raw, ['code']) as HelpfulErrorMetadata extends TMetadata ? TMetadata | undefined : TMetadata; } @@ -214,12 +261,21 @@ export class HelpfulError< this: T, // https://stackoverflow.com/a/51749145/3068233 ): Record { const obj: Record = {}; + + // enumerate own properties Object.getOwnPropertyNames(this) .filter((key) => key !== 'original') .sort() .forEach((key) => { obj[key] = (this as any)[key as any]; }, this); + + // conditionally include code only when slug is present (prevents log spam with default http codes) + const code = (this as unknown as HelpfulError).code; + if (code?.slug) { + obj.code = code; + } + return obj; } } diff --git a/src/UnexpectedCodePathError.test.ts b/src/UnexpectedCodePathError.test.ts index 8133ad6..bb45bbd 100644 --- a/src/UnexpectedCodePathError.test.ts +++ b/src/UnexpectedCodePathError.test.ts @@ -53,4 +53,33 @@ describe('UnexpectedCodePathError', () => { new TypedUnexpected('error', { wrong: 'key' }); }); }); + describe('code', () => { + it('should have static code = { http: 500 }', () => { + expect(UnexpectedCodePathError.code).toEqual({ http: 500 }); + }); + + it('should have instance.code.http as 500', () => { + const error = new UnexpectedCodePathError('test error'); + expect(error.code?.http).toEqual(500); + }); + + it('should have instance.code.slug as undefined by default', () => { + const error = new UnexpectedCodePathError('test error'); + expect(error.code?.slug).toBeUndefined(); + }); + + it('should allow instance to override with slug', () => { + const error = new UnexpectedCodePathError('test error', { + code: { slug: 'IMPOSSIBLE:STATE' }, + }); + expect(error.code).toEqual({ http: 500, slug: 'IMPOSSIBLE:STATE' }); + }); + + it('should omit code from toJSON (no slug by default)', () => { + const error = new UnexpectedCodePathError('test error'); + const json = JSON.stringify(error); + const parsed = JSON.parse(json); + expect(parsed.code).toBeUndefined(); + }); + }); }); diff --git a/src/UnexpectedCodePathError.ts b/src/UnexpectedCodePathError.ts index ed0e863..22e093f 100644 --- a/src/UnexpectedCodePathError.ts +++ b/src/UnexpectedCodePathError.ts @@ -6,6 +6,12 @@ import { HelpfulError, type HelpfulErrorMetadata } from './HelpfulError'; export class UnexpectedCodePathError< TMetadata extends HelpfulErrorMetadata = HelpfulErrorMetadata, > extends HelpfulError { + /** + * .what = default http code for unexpected code path errors + * .why = aligns with http 500 semantics + */ + public static code = { http: 500 } as const; + constructor( message: string, ...[metadata]: HelpfulErrorMetadata extends TMetadata diff --git a/src/index.ts b/src/index.ts index ec89c47..50d6544 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,5 @@ export { BadRequestError } from './BadRequestError'; export { getError } from './getError'; -export { HelpfulError } from './HelpfulError'; +export { HelpfulError, type HelpfulErrorCode } from './HelpfulError'; export { UnexpectedCodePathError } from './UnexpectedCodePathError'; export { withHelpfulError } from './withHelpfulError';