semola 0.6.1 → 0.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/index-DISN0WKZ.d.mts +78 -0
- package/dist/lib/api/index.cjs +1 -1
- package/dist/lib/api/index.d.mts +24 -84
- package/dist/lib/api/index.mjs +1 -1
- package/dist/lib/cache/index.cjs +1 -1
- package/dist/lib/cache/index.mjs +1 -1
- package/dist/lib/cli/index.cjs +3 -0
- package/dist/lib/cli/index.d.cts +1 -0
- package/dist/lib/cli/index.d.mts +90 -0
- package/dist/lib/cli/index.mjs +3 -0
- package/dist/lib/cron/index.cjs +1 -1
- package/dist/lib/cron/index.mjs +1 -1
- package/dist/lib/i18n/index.d.mts +2 -2
- package/dist/lib/orm/index.d.mts +23 -23
- package/dist/lib/policy/index.d.mts +1 -1
- package/dist/lib/workflow/index.cjs +1 -1
- package/dist/lib/workflow/index.d.mts +0 -1
- package/dist/lib/workflow/index.mjs +1 -1
- package/package.json +11 -1
package/README.md
CHANGED
|
@@ -31,6 +31,7 @@ Type-safe APIs, Redis queues, pub/sub, i18n, caching & auth with tree-shakeable
|
|
|
31
31
|
| **⚠️ Errors** | Result-based error handling without try/catch | `semola/errors` |
|
|
32
32
|
| **📃 Logging** | A simple logging utility | `semola/logging` |
|
|
33
33
|
| **⌨️ Prompts** | Interactive zero-dependency CLI prompts | `semola/prompts` |
|
|
34
|
+
| **🖥️ CLI** | Non-interactive CLI builder with schema validation | `semola/cli` |
|
|
34
35
|
| **🗄️ ORM** | Type-safe data layer with query APIs | `semola/orm` |
|
|
35
36
|
|
|
36
37
|
---
|
|
@@ -337,6 +338,7 @@ _Higher is better for req/sec, lower is better for latency._
|
|
|
337
338
|
- [Errors](./docs/errors.md) - Result-based error handling
|
|
338
339
|
- [Logging](./docs/logging.md) - Logging utility
|
|
339
340
|
- [Prompts](./docs/prompts.md) - Interactive CLI prompts
|
|
341
|
+
- [CLI](./docs/cli.md) - Non-interactive CLI builder
|
|
340
342
|
- [ORM](./docs/orm.md) - Type-safe data layer with SQLite support
|
|
341
343
|
|
|
342
344
|
---
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
//#region node_modules/@standard-schema/spec/dist/index.d.ts
|
|
2
|
+
/** The Standard Typed interface. This is a base type extended by other specs. */
|
|
3
|
+
interface StandardTypedV1<Input = unknown, Output = Input> {
|
|
4
|
+
/** The Standard properties. */
|
|
5
|
+
readonly "~standard": StandardTypedV1.Props<Input, Output>;
|
|
6
|
+
}
|
|
7
|
+
declare namespace StandardTypedV1 {
|
|
8
|
+
/** The Standard Typed properties interface. */
|
|
9
|
+
interface Props<Input = unknown, Output = Input> {
|
|
10
|
+
/** The version number of the standard. */
|
|
11
|
+
readonly version: 1;
|
|
12
|
+
/** The vendor name of the schema library. */
|
|
13
|
+
readonly vendor: string;
|
|
14
|
+
/** Inferred types associated with the schema. */
|
|
15
|
+
readonly types?: Types<Input, Output> | undefined;
|
|
16
|
+
}
|
|
17
|
+
/** The Standard Typed types interface. */
|
|
18
|
+
interface Types<Input = unknown, Output = Input> {
|
|
19
|
+
/** The input type of the schema. */
|
|
20
|
+
readonly input: Input;
|
|
21
|
+
/** The output type of the schema. */
|
|
22
|
+
readonly output: Output;
|
|
23
|
+
}
|
|
24
|
+
/** Infers the input type of a Standard Typed. */
|
|
25
|
+
type InferInput<Schema extends StandardTypedV1> = NonNullable<Schema["~standard"]["types"]>["input"];
|
|
26
|
+
/** Infers the output type of a Standard Typed. */
|
|
27
|
+
type InferOutput<Schema extends StandardTypedV1> = NonNullable<Schema["~standard"]["types"]>["output"];
|
|
28
|
+
}
|
|
29
|
+
/** The Standard Schema interface. */
|
|
30
|
+
interface StandardSchemaV1<Input = unknown, Output = Input> {
|
|
31
|
+
/** The Standard Schema properties. */
|
|
32
|
+
readonly "~standard": StandardSchemaV1.Props<Input, Output>;
|
|
33
|
+
}
|
|
34
|
+
declare namespace StandardSchemaV1 {
|
|
35
|
+
/** The Standard Schema properties interface. */
|
|
36
|
+
interface Props<Input = unknown, Output = Input> extends StandardTypedV1.Props<Input, Output> {
|
|
37
|
+
/** Validates unknown input values. */
|
|
38
|
+
readonly validate: (value: unknown, options?: StandardSchemaV1.Options | undefined) => Result<Output> | Promise<Result<Output>>;
|
|
39
|
+
}
|
|
40
|
+
/** The result interface of the validate function. */
|
|
41
|
+
type Result<Output> = SuccessResult<Output> | FailureResult;
|
|
42
|
+
/** The result interface if validation succeeds. */
|
|
43
|
+
interface SuccessResult<Output> {
|
|
44
|
+
/** The typed output value. */
|
|
45
|
+
readonly value: Output;
|
|
46
|
+
/** A falsy value for `issues` indicates success. */
|
|
47
|
+
readonly issues?: undefined;
|
|
48
|
+
}
|
|
49
|
+
interface Options {
|
|
50
|
+
/** Explicit support for additional vendor-specific parameters, if needed. */
|
|
51
|
+
readonly libraryOptions?: Record<string, unknown> | undefined;
|
|
52
|
+
}
|
|
53
|
+
/** The result interface if validation fails. */
|
|
54
|
+
interface FailureResult {
|
|
55
|
+
/** The issues of failed validation. */
|
|
56
|
+
readonly issues: ReadonlyArray<Issue>;
|
|
57
|
+
}
|
|
58
|
+
/** The issue interface of the failure output. */
|
|
59
|
+
interface Issue {
|
|
60
|
+
/** The error message of the issue. */
|
|
61
|
+
readonly message: string;
|
|
62
|
+
/** The path of the issue, if any. */
|
|
63
|
+
readonly path?: ReadonlyArray<PropertyKey | PathSegment> | undefined;
|
|
64
|
+
}
|
|
65
|
+
/** The path segment interface of the issue. */
|
|
66
|
+
interface PathSegment {
|
|
67
|
+
/** The key representing a path segment. */
|
|
68
|
+
readonly key: PropertyKey;
|
|
69
|
+
}
|
|
70
|
+
/** The Standard types interface. */
|
|
71
|
+
interface Types<Input = unknown, Output = Input> extends StandardTypedV1.Types<Input, Output> {}
|
|
72
|
+
/** Infers the input type of a Standard. */
|
|
73
|
+
type InferInput<Schema extends StandardTypedV1> = StandardTypedV1.InferInput<Schema>;
|
|
74
|
+
/** Infers the output type of a Standard. */
|
|
75
|
+
type InferOutput<Schema extends StandardTypedV1> = StandardTypedV1.InferOutput<Schema>;
|
|
76
|
+
}
|
|
77
|
+
//#endregion
|
|
78
|
+
export { StandardSchemaV1 as t };
|
package/dist/lib/api/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e={status:404},t=(e,t)=>{let n=e.split(`/`).slice(1),r=[],i=0;for(let e of n){if(e.startsWith(`:`)){r.push({value:``,paramName:e.slice(1)}),i++;continue}r.push({value:e})}return{segments:r,methods:t,paramStarts:Array(i),paramEnds:Array(i)}},n=(e,t)=>{let n=1,r=0;if(t===`/`)return e.segments.length===0;for(let i of e.segments){let a=t.indexOf(`/`,n),o=t.length;if(a!==-1&&(o=a),i.paramName){if(o===n)return!1;e.paramStarts[r]=n,e.paramEnds[r]=o,r++}else{let e=o-n;if(i.value.length!==e||!t.startsWith(i.value,n))return!1}n=a===-1?t.length:a+1}return n===t.length},r=(e,t)=>{let n={},r=0;for(let i of e.segments)i.paramName&&(n[i.paramName]=t.slice(e.paramStarts[r],e.paramEnds[r]),r++);return n},i=e=>{let t=e.indexOf(`://`),n=e.indexOf(`/`,t+3);if(n===-1)return`/`;let r=e.indexOf(`?`,n),i;return i=r===-1?e.slice(n):e.slice(n,r),i.length>1&&i.endsWith(`/`)?i.slice(0,-1):i},a=a=>{let o=Object.create(null),s=[],c=[];for(let[e,n]of Object.entries(a)){let r=n;if(e.includes(`*`)){c.push({pattern:new URLPattern({pathname:e}),methods:r});continue}if(e.includes(`:`)){s.push(t(e,r));continue}o[e]=r}return t=>{let a=i(t.url),l=t.method,u=o[a]?.[l];if(u)return u(t);for(let e of s){if(!n(e,a))continue;let i=e.methods[l];if(i)return t.params=r(e,a),i(t)}for(let e of c){let n=e.pattern.exec({pathname:a});if(!n)continue;let r=e.methods[l];if(r)return t.params=n.pathname.groups,r(t)}return new Response(`Not found`,e)}},o=e=>{if(Array.isArray(e))return e.map(o);if(typeof e!=`object`||!e)return e;let t=e;if(typeof t.$ref==`string`&&t.$ref.startsWith(`#/$defs/`))return{$ref:`#/components/schemas/${t.$ref.slice(8)}`};let n={};for(let e in t)n[e]=o(t[e]);return n},s=e=>{let t=e.$defs;if(!t||typeof t!=`object`)return{schema:e,components:void 0};let n=o({...e});delete n.$defs;let r=t,i={};for(let e in r)i[e]=o(r[e]);return{schema:n,components:{schemas:i}}},c=(e,t=`input`)=>{let n=e[`~standard`].jsonSchema[t]({target:`draft-2020-12`});return s(n)},l=e=>{let t=e[`~standard`];return t&&`description`in t&&typeof t.description==`string`?t.description:``},u=e=>{let t=e.meta;if(typeof t!=`function`)return;let n=t();if(typeof n==`object`&&n&&typeof n.id==`string`)return n.id},d=(e,t)=>typeof t.id==`string`?t.id:u(e),f=[`body`,`query`,`headers`,`cookies`,`params`],p=(e,t=`input`)=>{let n=c(e,t),{schema:r,components:i}=n,a=d(e,r);if(a){let e={...r};return delete e.id,delete e.$schema,{schema:{$ref:`#/components/schemas/${a}`},components:{...i,schemas:{...i?.schemas,[a]:e}}}}if(r.$schema){let e={...r};return delete e.$schema,{schema:e,components:i}}return n},m=(e,t=`input`)=>{let{schema:n,components:r}=c(e,t),i={...n};return delete i.$schema,delete i.id,{schema:i,components:r}},h=(e,t)=>{let{schema:n,components:r}=m(e);if(n.type!==`object`||!n.properties)return{parameters:[],components:r};let i=[],a=n.required??[];for(let e in n.properties){let r=n.properties[e],o=a.includes(e);i.push({name:e,in:t,required:o,schema:r})}return{parameters:i,components:r}},g=e=>e.replace(/:([a-zA-Z_][a-zA-Z0-9_]*)/g,`{$1}`),_=e=>{let t=e.match(/:([a-zA-Z_][a-zA-Z0-9_]*)/g);return t?t.map(e=>e.slice(1)):[]},ee=[[`query`,`query`],[`headers`,`header`],[`cookies`,`cookie`]],te=(e,t)=>{let n=[],r=[];for(let[t,i]of ee)if(e[t]){let{parameters:a,components:o}=h(e[t],i);n.push(...a),o&&r.push(o)}let i=_(t);if(i.length>0&&e.params){let{schema:t,components:a}=m(e.params);if(a&&r.push(a),t.type===`object`&&t.properties)for(let e of i){let r=t.properties[e];r&&n.push({name:e,in:`path`,required:!0,schema:r})}}return{parameters:n,components:r}},ne=e=>{let{schema:t,components:n}=p(e);return{components:n,requestBody:{required:!0,content:{"application/json":{schema:t}}}}},re=e=>{let t={},n=[];if(!e)return{responses:t,components:n};for(let r in e){let i=String(r),a=e[Number(r)];if(!a)continue;let o=l(a),{schema:s,components:c}=p(a,`output`);c&&n.push(c),t[i]={description:o||`Response with status ${i}`,content:{"application/json":{schema:s}}}}return{responses:t,components:n}},v=(e,t,n)=>{let{request:r,response:i}=y(e,t),a=e.path;n&&(a=n+e.path);let{parameters:o,components:s}=te(r,a),{responses:c,components:l}=re(i),u={responses:c},d=[];d.push(...l),d.push(...s);for(let t of[`summary`,`description`,`operationId`])e[t]&&(u[t]=e[t]);e.tags&&e.tags.length>0&&(u.tags=e.tags),o.length>0&&(u.parameters=o);let f=r.body;if(f){let{requestBody:e,components:t}=ne(f);u.requestBody=e,t&&d.push(t)}return{operation:u,components:d}},y=(e,t)=>{let n={},r={};for(let i of[...t,...e.middlewares??[]])b(n,i.options.request),x(r,i.options.response);b(n,e.request),x(r,e.response);let i;return Object.keys(r).length>0&&(i=r),{request:n,response:i}},b=(e,t)=>{if(t)for(let n of f)t[n]&&(e[n]=t[n])},x=(e,t)=>{if(t)for(let n in t){let r=Number(n),i=t[r];i&&(e[r]=i)}},S=e=>{let t={openapi:`3.1.0`,info:{title:e.title,description:e.description,version:e.version},paths:{}};e.servers&&e.servers.length>0&&(t.servers=e.servers);let n={};for(let r of e.routes){let i=r.path;e.prefix&&(i=e.prefix+r.path);let a=g(i),o=r.method.toLowerCase();t.paths[a]??={};let{operation:s,components:c}=v(r,e.globalMiddlewares??[],e.prefix);t.paths[a][o]=s,c.forEach(e=>{Object.assign(n,e.schemas??{})})}let r=Object.keys(n).length>0;return(e.securitySchemes||r)&&(t.components={},e.securitySchemes&&(t.components.securitySchemes=e.securitySchemes),r&&(t.components.schemas=n)),t};var C=class extends Error{constructor(e){super(e),this.name=`ParseError`}},w=class extends Error{constructor(e){super(e),this.name=`ValidationError`}},T=class extends Error{constructor(e){super(e),this.name=`SchemaConfigError`}};function ie(e){if(e.path?.length){let t=``;for(let n of e.path){let e=typeof n==`object`?n.key:n;if(typeof e==`string`||typeof e==`number`)t?t+=`.${e}`:t+=e;else return null}return t}return null}const ae=e=>ie(e)??`unknown`,E=e=>e.map(e=>`${ae(e)}: ${e.message??`validation failed`}`).join(`, `),D=e=>!(!e.body||e.query||e.headers||e.cookies||e.params),O=e=>{let t=e[`~standard`].validate;return async e=>{let n=e.headers.get(`content-type`)??``,r;if(n.startsWith(`application/json`))try{r=await e.json()}catch{throw new C(`Invalid JSON body`)}else r=await e.text();let i=t(r);if(i instanceof Promise)throw new T(`Async schema validation is not supported`);if(i.issues)throw new w(E(i.issues))}},k=e=>{if(!e.issues)return e.value;throw new w(E(e.issues))},A=(e,t=!1)=>{let n=e;t&&e.includes(`+`)&&(n=e.replaceAll(`+`,` `));try{return decodeURIComponent(n)}catch{return n}},j=(e,t,n)=>{let r=e[t];if(r===void 0){e[t]=n;return}if(Array.isArray(r)){r.push(n);return}e[t]=[r,n]},M=(e,t)=>{let n=e[`~standard`].validate(t);if(n instanceof Promise)throw new T(`Async schema validation is not supported`);return k(n)},N=async(e,t,n)=>{if(!t)return!0;if(n?.parsed)return M(t,n.value);let r=e.headers.get(`content-type`)??``,i;if(r.startsWith(`application/json`))try{i=await e.json()}catch{throw new C(`Invalid JSON body`)}else i=await e.text();return n&&(n.parsed=!0,n.value=i),M(t,i)},P=(e,t)=>{if(!t)return!0;let n=e.url.indexOf(`?`);if(n===-1)return M(t,{});let r=e.url.indexOf(`#`,n+1),i=e.url.length;r!==-1&&(i=r);let a={},o=n+1;for(;o<=i;){let t=e.url.indexOf(`&`,o),n=i;if(t!==-1&&t<i&&(n=t),n>o){let t=e.url.indexOf(`=`,o),r=t!==-1&&t<n,i=e.url.slice(o,n),s=``;r&&(i=e.url.slice(o,t),s=e.url.slice(t+1,n)),j(a,A(i,!0),A(s,!0))}if(t===-1||t>=i)break;o=t+1}return M(t,a)},F=(e,t)=>{if(!t)return!0;let n={};for(let[t,r]of e.headers)n[t]=r;return M(t,n)},I=(e,t)=>{if(!t)return!0;let n=e.headers.get(`cookie`)??``,r={},i=0;for(;i<n.length;){let e=n.indexOf(`;`,i),t=n.length;e!==-1&&(t=e);let a=n.indexOf(`=`,i);if(a!==-1&&a<t){let e=n.slice(i,a).trim();if(e){let i=n.slice(a+1,t).trim();r[e]=A(i)}}if(e===-1)break;i=e+1}return M(t,r)},L=(e,t)=>t?M(t,e.params??{}):!0,R=async(e,t)=>{let n=e.schema;if(n)try{if(n.body){let r=await N(e.req,n.body,e.bodyCache);t&&(t.body=r)}if(n.query){let r=P(e.req,n.query);t&&(t.query=r)}if(n.headers){let r=F(e.req,n.headers);t&&(t.headers=r)}if(n.cookies){let r=I(e.req,n.cookies);t&&(t.cookies=r)}if(n.params){let r=L(e.req,n.params);t&&(t.params=r)}}catch(e){return e}},z=e=>{if(e){if(D(e)){let t=e.body;if(!t)return;let n=O(t);return async e=>{try{await n(e)}catch(e){return e}}}return(t,n)=>R({req:t,schema:e,bodyCache:n})}},B={"Content-Type":`text/html`},V={status:400},H=(e,t)=>e===200?Response.json(t):Response.json(t,{status:e}),U=(e,t)=>e===200?new Response(t):new Response(t,{status:e}),W=(e,t)=>new Response(t,{status:e,headers:B}),G=(e,t)=>Response.redirect(t,e),K=e=>Response.json({message:e},V),q=e=>{if(e instanceof w||e instanceof C)return K(e.message);throw e},oe=e=>(t,n)=>{let r=e[t];if(!r)return H(t,n);try{M(r,n)}catch(e){return q(e)}return H(t,n)},J=Object.freeze({body:void 0,query:void 0,headers:void 0,cookies:void 0,params:void 0}),se={req:J,get:()=>{},json:H,text:U,html:W,redirect:G},Y=(e,t,n,r)=>{let i=Object.create(se);return i.raw=e,t&&(i.req=t),n&&(i.get=n),r&&(i.json=r),i},X=e=>e!==`/`&&e.endsWith(`/`)?e.slice(0,-1):e,ce=e=>{let t=X(e.path)||`/`;if(!e.prefix)return t;let n=X(e.prefix);return n===`/`?t:t===`/`?n:n+t},le=e=>{let t=0;e.request?.body!==void 0&&t++;for(let n of e.middlewares)if(n.options.request?.body!==void 0&&(t++,t>1))return!0;return!1},ue=e=>e===void 0||e===!0?{input:!0,output:!0}:e===!1?{input:!1,output:!1}:{input:e.input!==!1,output:e.output!==!1},de=[],Z=e=>e instanceof Response?e:typeof e==`string`?new Response(e):Response.json(e),Q=async(e,t)=>{let n=Z(e),r=t?.[n.status];if(!r)return n;let i=e;e instanceof Response&&(i=await n.clone().json());try{M(r,i)}catch(e){return q(e)}return n},fe=(e,t)=>{if(e instanceof Response)return Q(e,t);let n=Z(e),r=t?.[n.status];if(!r)return n;try{M(r,e)}catch(e){return q(e)}return n},pe=(e,t,n,r=!1,i=!1)=>{let a=i?n:void 0,o;if(r&&t&&D(t)){let e=t.body;e&&(o=O(e))}let s=r&&!o?z(t):void 0,c=e();if(c instanceof Promise)return async t=>{if(o)try{await o(t)}catch(e){return q(e)}if(s){let e=await s(t);if(e)return q(e)}let n=await e();return Q(n,a)};let l=fe(c,a);if(!o&&!s)return l instanceof Promise?async()=>l:()=>l;if(o)return async e=>{try{await o(e)}catch(e){return q(e)}return l};let u=s;return u?async e=>{let t=await u(e);return t?q(t):l}:l instanceof Promise?async()=>l:()=>l},me=e=>t=>{let n=e(Y(t));return n instanceof Promise?n.then(e=>e instanceof Response?e:Z(e)):n instanceof Response?n:Z(n)},he=(e,t)=>e.middlewares?.length?t.length===0?e.middlewares:[...t,...e.middlewares]:t,ge=(e,t,n)=>{if(!e.input)return!1;if(t)return!0;for(let e of n)if(e.options.request)return!0;return!1},$=async(e,t)=>{let n,r,i;t.validateInput&&le({middlewares:t.middlewares,request:t.routeRequest})&&(i={parsed:!1,value:void 0});let a;t.validateOutput&&t.routeResponse&&(a=oe(t.routeResponse)),t.middlewares.length>0&&(r=e=>n?.[e]);for(let a of t.middlewares){let{request:o,handler:s}=a.options,c=J;if(t.validateInput&&o){let t={},n=await R({req:e,schema:o,bodyCache:i},t);if(n)return q(n);c=t}let l=await s(Y(e,c,r));if(l instanceof Response)return l;l&&(n||={},Object.assign(n,l))}let o=J;if(t.validateInput&&t.routeRequest){let n={},r=await R({req:e,schema:t.routeRequest,bodyCache:i},n);if(r)return q(r);o=n}let s=Y(e,o,r,a);return t.handler(s)},_e=(e,t,n)=>{let r=he(e,t),i=e.handler,a=r.length>0,o=ge(n,e.request,r),s=n.output&&!!e.response;if(!a&&typeof i==`function`&&i.length===0)return pe(i,e.request,e.response,o,s);if(!a&&typeof i==`function`&&i.length===1&&!o&&!s)return me(i);let c={middlewares:r,routeRequest:e.request,routeResponse:e.response,validateInput:o,validateOutput:s,handler:i};return e=>$(e,c)},ve=(e,t,n,r)=>{let i={};for(let a of e){let e=ce({prefix:t,path:a.path});i[e]||(i[e]={}),i[e][a.method]=_e(a,n,r)}return i};var ye=class{options;routes=[];routesDirty=!0;compiled;constructor(e={}){this.options=e}defineRoute(e){this.routes.push(e),this.routesDirty=!0}fetch=e=>this.ensureCompiled().fetch(e);getRouteHandlers(){return this.ensureCompiled().routes}getOpenApiSpec(){return S({title:this.options.openapi?.title??`API`,description:this.options.openapi?.description,version:this.options.openapi?.version??`1.0.0`,prefix:this.options.prefix,servers:this.options.openapi?.servers,securitySchemes:this.options.openapi?.securitySchemes,routes:this.routes,globalMiddlewares:this.options.middlewares})}serve(e,t){let n=Bun.serve({port:e,routes:this.getRouteHandlers(),fetch:()=>new Response(`Not found`,{status:404})});t&&t(n)}ensureCompiled(){if(!this.routesDirty&&this.compiled)return this.compiled;let e=ve(this.routes,this.options.prefix,this.options.middlewares??de,ue(this.options.validation));return this.compiled={routes:e,fetch:a(e)},this.routesDirty=!1,this.compiled}},be=class{options;constructor(e){this.options=e}};exports.Api=ye,exports.Middleware=be;
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e={status:404},t=(e,t)=>{let n=e.split(`/`).slice(1),r=[],i=0;for(let e of n){if(e.startsWith(`:`)){r.push({value:``,paramName:e.slice(1)}),i++;continue}r.push({value:e})}return{segments:r,methods:t,paramStarts:Array(i),paramEnds:Array(i)}},n=(e,t)=>{let n=1,r=0;if(t===`/`)return e.segments.length===0;for(let i of e.segments){let a=t.indexOf(`/`,n),o=t.length;if(a!==-1&&(o=a),i.paramName){if(o===n)return!1;e.paramStarts[r]=n,e.paramEnds[r]=o,r++}else{let e=o-n;if(i.value.length!==e||!t.startsWith(i.value,n))return!1}n=a===-1?t.length:a+1}return n===t.length},r=(e,t)=>{let n={},r=0;for(let i of e.segments)i.paramName&&(n[i.paramName]=t.slice(e.paramStarts[r],e.paramEnds[r]),r++);return n},i=e=>{let t=e.indexOf(`://`),n=e.indexOf(`/`,t+3);if(n===-1)return`/`;let r=e.indexOf(`?`,n),i;return i=r===-1?e.slice(n):e.slice(n,r),i.length>1&&i.endsWith(`/`)?i.slice(0,-1):i},a=a=>{let o=Object.create(null),s=[],c=[];for(let[e,n]of Object.entries(a)){let r=n;if(e.includes(`*`)){c.push({pattern:new URLPattern({pathname:e}),methods:r});continue}if(e.includes(`:`)){s.push(t(e,r));continue}o[e]=r}return t=>{let a=i(t.url),l=t.method,u=o[a]?.[l];if(u)return u(t);for(let e of s){if(!n(e,a))continue;let i=e.methods[l];if(i)return t.params=r(e,a),i(t)}for(let e of c){let n=e.pattern.exec({pathname:a});if(!n)continue;let r=e.methods[l];if(r)return t.params=n.pathname.groups,r(t)}return new Response(`Not found`,e)}};var o=class extends Error{constructor(e){super(e),this.name=`ParseError`}},s=class extends Error{constructor(e){super(e),this.name=`ValidationError`}},c=class extends Error{constructor(e){super(e),this.name=`SchemaConfigError`}},l=class extends Error{constructor(e,t){super(`Duplicate route: ${e} ${t}`),this.name=`DuplicateRouteError`}};function u(e){if(e.path?.length){let t=``;for(let n of e.path){let e=typeof n==`object`?n.key:n;if(typeof e==`string`||typeof e==`number`)t?t+=`.${e}`:t+=e;else return null}return t}return null}const d=e=>u(e)??`unknown`,f=e=>e.map(e=>`${d(e)}: ${e.message??`validation failed`}`).join(`, `),p=e=>{if(!e.issues)return e.value;throw new s(f(e.issues))},m=(e,t=!1)=>{let n=e;t&&e.includes(`+`)&&(n=e.replaceAll(`+`,` `));try{return decodeURIComponent(n)}catch{return n}},ee=(e,t,n)=>{let r=e[t];if(r===void 0){e[t]=n;return}if(Array.isArray(r)){r.push(n);return}e[t]=[r,n]},h=(e,t)=>{let n=e[`~standard`].validate(t);if(n instanceof Promise)throw new c(`Async schema validation is not supported`);return p(n)},g=async(e,t,n)=>{if(!t)return!0;if(n?.parsed)return h(t,n.value);let r=e.headers.get(`content-type`)??``,i;if(r.startsWith(`application/json`))try{i=await e.json()}catch{throw new o(`Invalid JSON body`)}else i=await e.text();return n&&(n.parsed=!0,n.value=i),h(t,i)},te=(e,t)=>{if(!t)return!0;let n=e.url.indexOf(`?`);if(n===-1)return h(t,{});let r=e.url.indexOf(`#`,n+1),i=e.url.length;r!==-1&&(i=r);let a={},o=n+1;for(;o<=i;){let t=e.url.indexOf(`&`,o),n=i;if(t!==-1&&t<i&&(n=t),n>o){let t=e.url.indexOf(`=`,o),r=t!==-1&&t<n,i=e.url.slice(o,n),s=``;r&&(i=e.url.slice(o,t),s=e.url.slice(t+1,n)),ee(a,m(i,!0),m(s,!0))}if(t===-1||t>=i)break;o=t+1}return h(t,a)},_=(e,t)=>{if(!t)return!0;let n={};for(let[t,r]of e.headers)n[t]=r;return h(t,n)},v=(e,t)=>{if(!t)return!0;let n=e.headers.get(`cookie`)??``,r={},i=0;for(;i<n.length;){let e=n.indexOf(`;`,i),t=n.length;e!==-1&&(t=e);let a=n.indexOf(`=`,i);if(a!==-1&&a<t){let e=n.slice(i,a).trim();if(e){let i=n.slice(a+1,t).trim();r[e]=m(i)}}if(e===-1)break;i=e+1}return h(t,r)},ne=(e,t)=>!t||h(t,e.params??{}),y=async(e,t)=>{let n=e.schema;if(n)try{if(n.body){let r=await g(e.req,n.body,e.bodyCache);t&&(t.body=r)}if(n.query){let r=te(e.req,n.query);t&&(t.query=r)}if(n.headers){let r=_(e.req,n.headers);t&&(t.headers=r)}if(n.cookies){let r=v(e.req,n.cookies);t&&(t.cookies=r)}if(n.params){let r=ne(e.req,n.params);t&&(t.params=r)}}catch(e){return e}},b=e=>{if(e)return(t,n)=>y({req:t,schema:e,bodyCache:n})},x={"Content-Type":`text/html`},S={status:400},C=(e,t)=>e===200?Response.json(t):Response.json(t,{status:e}),w=(e,t)=>e===200?new Response(t):new Response(t,{status:e}),T=(e,t)=>new Response(t,{status:e,headers:x}),E=(e,t)=>Response.redirect(t,e),D=e=>Response.json({message:e},S),O=e=>{if(e instanceof s||e instanceof o)return D(e.message);throw e},k=e=>(t,n)=>{let r=e[t];if(!r)return C(t,n);try{h(r,n)}catch(e){return O(e)}return C(t,n)},A=Object.freeze({body:void 0,query:void 0,headers:void 0,cookies:void 0,params:void 0}),re={req:A,get:()=>{},json:C,text:w,html:T,redirect:E},j=(e,t,n,r)=>{let i=Object.create(re);return i.raw=e,t&&(i.req=t),n&&(i.get=n),r&&(i.json=r),i},M=e=>e!==`/`&&e.endsWith(`/`)?e.slice(0,-1):e,N=e=>{let t=M(e.path)||`/`;if(!e.prefix)return t;let n=M(e.prefix);return n===`/`?t:t===`/`?n:n+t},P=e=>{let t=0;e.request?.body!==void 0&&t++;for(let n of e.middlewares)if(n.options.request?.body!==void 0&&(t++,t>1))return!0;return!1},F=e=>e===void 0||e===!0?{input:!0,output:!0}:e===!1?{input:!1,output:!1}:{input:e.input!==!1,output:e.output!==!1},I=[],L=(e,t)=>e?.length?t?.length?[...e,...t]:e:t??I,R=(e,t)=>e?t?N({prefix:e,path:t}):e:t;var z=class{options;routes=[];groups=[];parent;constructor(e={}){this.options=e}defineRoute(e){this.routes.push(e),this.onRoutesChanged()}mount(e){e.parent=this,this.groups.push(e),this.onRoutesChanged()}onRoutesChanged(){this.parent?.onRoutesChanged()}collectRoutes(e=this.options.prefix,t=I){let n=L(t,this.options.middlewares),r=this.routes.map(t=>({...t,path:N({prefix:e,path:t.path}),middlewares:L(n,t.middlewares)}));for(let t of this.groups){let i=t.collectRoutes(R(e,t.options.prefix),n);r.push(...i)}return r}};const B=e=>{if(Array.isArray(e))return e.map(B);if(typeof e!=`object`||!e)return e;let t=e;if(typeof t.$ref==`string`&&t.$ref.startsWith(`#/$defs/`))return{$ref:`#/components/schemas/${t.$ref.slice(8)}`};let n={};for(let e in t)n[e]=B(t[e]);return n},V=e=>{let t=e.$defs;if(!t||typeof t!=`object`)return{schema:e,components:void 0};let n=B({...e});delete n.$defs;let r=t,i={};for(let e in r)i[e]=B(r[e]);return{schema:n,components:{schemas:i}}},H=(e,t=`input`)=>{let n=e[`~standard`].jsonSchema[t]({target:`draft-2020-12`});return V(n)},U=e=>{let t=e[`~standard`];return t&&`description`in t&&typeof t.description==`string`?t.description:``},W=e=>{let t=e.meta;if(typeof t!=`function`)return;let n=t();if(typeof n==`object`&&n&&typeof n.id==`string`)return n.id},G=(e,t)=>typeof t.id==`string`?t.id:W(e),K=[`body`,`query`,`headers`,`cookies`,`params`],q=(e,t=`input`)=>{let n=H(e,t),{schema:r,components:i}=n,a=G(e,r);if(a){let e={...r};return delete e.id,delete e.$schema,{schema:{$ref:`#/components/schemas/${a}`},components:{...i,schemas:{...i?.schemas,[a]:e}}}}if(r.$schema){let e={...r};return delete e.$schema,{schema:e,components:i}}return n},J=(e,t=`input`)=>{let{schema:n,components:r}=H(e,t),i={...n};return delete i.$schema,delete i.id,{schema:i,components:r}},Y=(e,t)=>{let{schema:n,components:r}=J(e);if(n.type!==`object`||!n.properties)return{parameters:[],components:r};let i=[],a=n.required??[];for(let e in n.properties){let r=n.properties[e],o=a.includes(e);i.push({name:e,in:t,required:o,schema:r})}return{parameters:i,components:r}},ie=e=>e.replace(/:([a-zA-Z_][a-zA-Z0-9_]*)/g,`{$1}`),ae=e=>{let t=e.match(/:([a-zA-Z_][a-zA-Z0-9_]*)/g);return t?t.map(e=>e.slice(1)):[]},oe=[[`query`,`query`],[`headers`,`header`],[`cookies`,`cookie`]],se=(e,t)=>{let n=[],r=[];for(let[t,i]of oe)if(e[t]){let{parameters:a,components:o}=Y(e[t],i);n.push(...a),o&&r.push(o)}let i=ae(t);if(i.length>0&&e.params){let{schema:t,components:a}=J(e.params);if(a&&r.push(a),t.type===`object`&&t.properties)for(let e of i){let r=t.properties[e];r&&n.push({name:e,in:`path`,required:!0,schema:r})}}return{parameters:n,components:r}},ce=e=>{let{schema:t,components:n}=q(e);return{components:n,requestBody:{required:!0,content:{"application/json":{schema:t}}}}},le=e=>{let t={},n=[];if(!e)return{responses:t,components:n};for(let r in e){let i=String(r),a=e[Number(r)];if(!a)continue;let o=U(a),{schema:s,components:c}=q(a,`output`);c&&n.push(c),t[i]={description:o||`Response with status ${i}`,content:{"application/json":{schema:s}}}}return{responses:t,components:n}},ue=(e,t,n)=>{let{request:r,response:i}=de(e,t),a=e.path;n&&(a=n+e.path);let{parameters:o,components:s}=se(r,a),{responses:c,components:l}=le(i),u={responses:c},d=[];d.push(...l),d.push(...s);for(let t of[`summary`,`description`,`operationId`])e[t]&&(u[t]=e[t]);e.tags&&e.tags.length>0&&(u.tags=e.tags),o.length>0&&(u.parameters=o);let f=r.body;if(f){let{requestBody:e,components:t}=ce(f);u.requestBody=e,t&&d.push(t)}return{operation:u,components:d}},de=(e,t)=>{let n={},r={};for(let i of[...t,...e.middlewares??[]])X(n,i.options.request),Z(r,i.options.response);X(n,e.request),Z(r,e.response);let i;return Object.keys(r).length>0&&(i=r),{request:n,response:i}},X=(e,t)=>{if(t)for(let n of K)t[n]&&(e[n]=t[n])},Z=(e,t)=>{if(t)for(let n in t){let r=Number(n),i=t[r];i&&(e[r]=i)}},fe=e=>{let t={openapi:`3.1.0`,info:{title:e.title,description:e.description,version:e.version},paths:{}};e.servers&&e.servers.length>0&&(t.servers=e.servers);let n={};for(let r of e.routes){let i=r.path;e.prefix&&(i=e.prefix+r.path);let a=ie(i),o=r.method.toLowerCase();t.paths[a]??={};let{operation:s,components:c}=ue(r,e.globalMiddlewares??[],e.prefix);t.paths[a][o]=s,c.forEach(e=>{Object.assign(n,e.schemas??{})})}let r=Object.keys(n).length>0;return(e.securitySchemes||r)&&(t.components={},e.securitySchemes&&(t.components.securitySchemes=e.securitySchemes),r&&(t.components.schemas=n)),t},pe=[],Q=e=>e instanceof Response?e:typeof e==`string`?new Response(e):Response.json(e),$=async(e,t)=>{let n=Q(e),r=t?.[n.status];if(!r)return n;let i=e;e instanceof Response&&(i=await n.clone().json());try{h(r,i)}catch(e){return O(e)}return n},me=(e,t)=>{if(e instanceof Response)return $(e,t);let n=Q(e),r=t?.[n.status];if(!r)return n;try{h(r,e)}catch(e){return O(e)}return n},he=(e,t,n,r=!1,i=!1)=>{let a=i?n:void 0,o=r?b(t):void 0,s=e();if(s instanceof Promise)return async t=>{if(o){let e=await o(t);if(e)return O(e)}let n=await e();return $(n,a)};let c=me(s,a);return o?async e=>{let t=await o(e);return t?O(t):c}:c instanceof Promise?async()=>c:()=>c},ge=e=>t=>{let n=e(j(t));return n instanceof Promise?n.then(e=>e instanceof Response?e:Q(e)):n instanceof Response?n:Q(n)},_e=(e,t,n)=>{if(!e.input)return!1;if(t)return!0;for(let e of n)if(e.options.request)return!0;return!1},ve=async(e,t)=>{let n,r,i;t.validateInput&&P({middlewares:t.middlewares,request:t.routeRequest})&&(i={parsed:!1,value:void 0});let a;t.validateOutput&&t.routeResponse&&(a=k(t.routeResponse)),t.middlewares.length>0&&(r=e=>n?.[e]);for(let a of t.middlewares){let{request:o,handler:s}=a.options,c=A;if(t.validateInput&&o){let t={},n=await y({req:e,schema:o,bodyCache:i},t);if(n)return O(n);c=t}let l=await s(j(e,c,r));if(l instanceof Response)return l;l&&(n||={},Object.assign(n,l))}let o=A;if(t.validateInput&&t.routeRequest){let n={},r=await y({req:e,schema:t.routeRequest,bodyCache:i},n);if(r)return O(r);o=n}let s=j(e,o,r,a);return t.handler(s)},ye=(e,t)=>{let n=e.middlewares??pe,r=e.handler,i=n.length>0,a=_e(t,e.request,n),o=t.output&&!!e.response;if(!i&&typeof r==`function`&&r.length===0)return he(r,e.request,e.response,a,o);if(!i&&typeof r==`function`&&r.length===1&&!a&&!o)return ge(r);let s={middlewares:n,routeRequest:e.request,routeResponse:e.response,validateInput:a,validateOutput:o,handler:r};return e=>ve(e,s)},be=(e,t)=>{let n={};for(let r of e){let e=n[r.path];if(e||(e={},n[r.path]=e),e[r.method])throw new l(r.method,r.path);e[r.method]=ye(r,t)}return n};var xe=class extends z{options;compiled;needsRecompile=!0;constructor(e={}){super(e),this.options=e}onRoutesChanged(){this.needsRecompile=!0,super.onRoutesChanged()}fetch=e=>this.ensureCompiled().fetch(e);getRouteHandlers(){return this.ensureCompiled().routes}getOpenApiSpec(){return fe({title:this.options.openapi?.title??`API`,description:this.options.openapi?.description,version:this.options.openapi?.version??`1.0.0`,servers:this.options.openapi?.servers,securitySchemes:this.options.openapi?.securitySchemes,routes:this.collectRoutes()})}serve(e,t){let n=Bun.serve({port:e,routes:this.getRouteHandlers(),fetch:()=>new Response(`Not found`,{status:404})});t&&t(n)}ensureCompiled(){if(!this.needsRecompile&&this.compiled)return this.compiled;let e=be(this.collectRoutes(),F(this.options.validation));return this.compiled={routes:e,fetch:a(e)},this.needsRecompile=!1,this.compiled}},Se=class{options;constructor(e){this.options=e}};exports.Api=xe,exports.Group=z,exports.Middleware=Se;
|
package/dist/lib/api/index.d.mts
CHANGED
|
@@ -1,81 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
/** The Standard Typed interface. This is a base type extended by other specs. */
|
|
3
|
-
interface StandardTypedV1<Input = unknown, Output = Input> {
|
|
4
|
-
/** The Standard properties. */
|
|
5
|
-
readonly "~standard": StandardTypedV1.Props<Input, Output>;
|
|
6
|
-
}
|
|
7
|
-
declare namespace StandardTypedV1 {
|
|
8
|
-
/** The Standard Typed properties interface. */
|
|
9
|
-
interface Props<Input = unknown, Output = Input> {
|
|
10
|
-
/** The version number of the standard. */
|
|
11
|
-
readonly version: 1;
|
|
12
|
-
/** The vendor name of the schema library. */
|
|
13
|
-
readonly vendor: string;
|
|
14
|
-
/** Inferred types associated with the schema. */
|
|
15
|
-
readonly types?: Types<Input, Output> | undefined;
|
|
16
|
-
}
|
|
17
|
-
/** The Standard Typed types interface. */
|
|
18
|
-
interface Types<Input = unknown, Output = Input> {
|
|
19
|
-
/** The input type of the schema. */
|
|
20
|
-
readonly input: Input;
|
|
21
|
-
/** The output type of the schema. */
|
|
22
|
-
readonly output: Output;
|
|
23
|
-
}
|
|
24
|
-
/** Infers the input type of a Standard Typed. */
|
|
25
|
-
type InferInput<Schema extends StandardTypedV1> = NonNullable<Schema["~standard"]["types"]>["input"];
|
|
26
|
-
/** Infers the output type of a Standard Typed. */
|
|
27
|
-
type InferOutput<Schema extends StandardTypedV1> = NonNullable<Schema["~standard"]["types"]>["output"];
|
|
28
|
-
}
|
|
29
|
-
/** The Standard Schema interface. */
|
|
30
|
-
interface StandardSchemaV1<Input = unknown, Output = Input> {
|
|
31
|
-
/** The Standard Schema properties. */
|
|
32
|
-
readonly "~standard": StandardSchemaV1.Props<Input, Output>;
|
|
33
|
-
}
|
|
34
|
-
declare namespace StandardSchemaV1 {
|
|
35
|
-
/** The Standard Schema properties interface. */
|
|
36
|
-
interface Props<Input = unknown, Output = Input> extends StandardTypedV1.Props<Input, Output> {
|
|
37
|
-
/** Validates unknown input values. */
|
|
38
|
-
readonly validate: (value: unknown, options?: StandardSchemaV1.Options | undefined) => Result<Output> | Promise<Result<Output>>;
|
|
39
|
-
}
|
|
40
|
-
/** The result interface of the validate function. */
|
|
41
|
-
type Result<Output> = SuccessResult<Output> | FailureResult;
|
|
42
|
-
/** The result interface if validation succeeds. */
|
|
43
|
-
interface SuccessResult<Output> {
|
|
44
|
-
/** The typed output value. */
|
|
45
|
-
readonly value: Output;
|
|
46
|
-
/** A falsy value for `issues` indicates success. */
|
|
47
|
-
readonly issues?: undefined;
|
|
48
|
-
}
|
|
49
|
-
interface Options {
|
|
50
|
-
/** Explicit support for additional vendor-specific parameters, if needed. */
|
|
51
|
-
readonly libraryOptions?: Record<string, unknown> | undefined;
|
|
52
|
-
}
|
|
53
|
-
/** The result interface if validation fails. */
|
|
54
|
-
interface FailureResult {
|
|
55
|
-
/** The issues of failed validation. */
|
|
56
|
-
readonly issues: ReadonlyArray<Issue>;
|
|
57
|
-
}
|
|
58
|
-
/** The issue interface of the failure output. */
|
|
59
|
-
interface Issue {
|
|
60
|
-
/** The error message of the issue. */
|
|
61
|
-
readonly message: string;
|
|
62
|
-
/** The path of the issue, if any. */
|
|
63
|
-
readonly path?: ReadonlyArray<PropertyKey | PathSegment> | undefined;
|
|
64
|
-
}
|
|
65
|
-
/** The path segment interface of the issue. */
|
|
66
|
-
interface PathSegment {
|
|
67
|
-
/** The key representing a path segment. */
|
|
68
|
-
readonly key: PropertyKey;
|
|
69
|
-
}
|
|
70
|
-
/** The Standard types interface. */
|
|
71
|
-
interface Types<Input = unknown, Output = Input> extends StandardTypedV1.Types<Input, Output> {}
|
|
72
|
-
/** Infers the input type of a Standard. */
|
|
73
|
-
type InferInput<Schema extends StandardTypedV1> = StandardTypedV1.InferInput<Schema>;
|
|
74
|
-
/** Infers the output type of a Standard. */
|
|
75
|
-
type InferOutput<Schema extends StandardTypedV1> = StandardTypedV1.InferOutput<Schema>;
|
|
76
|
-
}
|
|
77
|
-
/** The Standard JSON Schema interface. */
|
|
78
|
-
//#endregion
|
|
1
|
+
import { t as StandardSchemaV1 } from "../../index-DISN0WKZ.mjs";
|
|
79
2
|
//#region src/lib/api/middleware.d.ts
|
|
80
3
|
declare class Middleware<TRequest extends RequestSchema = RequestSchema, TResponse extends ResponseSchema = ResponseSchema, TExtension extends Record<string, unknown> = Record<string, unknown>> {
|
|
81
4
|
options: MiddlewareOptions<TRequest, TResponse, TExtension>;
|
|
@@ -112,6 +35,10 @@ type ApiOptions<TMiddlewares extends readonly Middleware[] = readonly []> = {
|
|
|
112
35
|
middlewares?: TMiddlewares;
|
|
113
36
|
validation?: ValidationOptions;
|
|
114
37
|
};
|
|
38
|
+
type GroupOptions<TMiddlewares extends readonly Middleware[] = readonly []> = {
|
|
39
|
+
prefix?: string;
|
|
40
|
+
middlewares?: TMiddlewares;
|
|
41
|
+
};
|
|
115
42
|
type SecuritySchemeApiKey = {
|
|
116
43
|
type: "apiKey";
|
|
117
44
|
name: string;
|
|
@@ -249,14 +176,27 @@ type OpenApiResponse = {
|
|
|
249
176
|
};
|
|
250
177
|
};
|
|
251
178
|
//#endregion
|
|
179
|
+
//#region src/lib/api/group.d.ts
|
|
180
|
+
type InternalRouteConfig = RouteConfig<RequestSchema, ResponseSchema, readonly Middleware[], readonly Middleware[]>;
|
|
181
|
+
declare class Group<TMiddlewares extends readonly Middleware[] = readonly []> {
|
|
182
|
+
protected options: GroupOptions<TMiddlewares>;
|
|
183
|
+
protected routes: InternalRouteConfig[];
|
|
184
|
+
protected groups: Group<readonly Middleware[]>[];
|
|
185
|
+
private parent?;
|
|
186
|
+
constructor(options?: GroupOptions<TMiddlewares>);
|
|
187
|
+
defineRoute<TReq extends RequestSchema = RequestSchema, TRes extends ResponseSchema = ResponseSchema, TRouteMiddlewares extends readonly Middleware[] = readonly []>(config: RouteConfig<TReq, TRes, TMiddlewares, TRouteMiddlewares>): void;
|
|
188
|
+
mount(group: Group<readonly Middleware[]>): void;
|
|
189
|
+
protected onRoutesChanged(): void;
|
|
190
|
+
protected collectRoutes(prefix?: string | undefined, inheritedMiddlewares?: readonly Middleware[]): InternalRouteConfig[];
|
|
191
|
+
}
|
|
192
|
+
//#endregion
|
|
252
193
|
//#region src/lib/api/api.d.ts
|
|
253
|
-
declare class Api<TMiddlewares extends readonly Middleware[] = readonly []> {
|
|
254
|
-
|
|
255
|
-
private routes;
|
|
256
|
-
private routesDirty;
|
|
194
|
+
declare class Api<TMiddlewares extends readonly Middleware[] = readonly []> extends Group<TMiddlewares> {
|
|
195
|
+
protected options: ApiOptions<TMiddlewares>;
|
|
257
196
|
private compiled?;
|
|
197
|
+
private needsRecompile;
|
|
258
198
|
constructor(options?: ApiOptions<TMiddlewares>);
|
|
259
|
-
|
|
199
|
+
protected onRoutesChanged(): void;
|
|
260
200
|
fetch: (req: Request) => Promise<Response> | Response;
|
|
261
201
|
getRouteHandlers(): MethodRoutes;
|
|
262
202
|
getOpenApiSpec(): OpenApiSpec;
|
|
@@ -264,4 +204,4 @@ declare class Api<TMiddlewares extends readonly Middleware[] = readonly []> {
|
|
|
264
204
|
private ensureCompiled;
|
|
265
205
|
}
|
|
266
206
|
//#endregion
|
|
267
|
-
export { Api, type ApiOptions, type Context, type ExtractStatusCodes, type InferInput, type InferMiddlewareExtension, type InferOutput, type MergeMiddlewareExtensions, Middleware, type MiddlewareHandler, type MiddlewareOptions, type OpenApiOptions, type RequestSchema, type ResponseSchema, type RouteConfig, type RouteHandler, type SecurityScheme, type SecuritySchemeApiKey, type SecuritySchemeHttp, type SecuritySchemeOAuth2, type SecuritySchemeOAuth2Flow, type SecuritySchemeOpenIdConnect };
|
|
207
|
+
export { Api, type ApiOptions, type Context, type ExtractStatusCodes, Group, type GroupOptions, type InferInput, type InferMiddlewareExtension, type InferOutput, type MergeMiddlewareExtensions, Middleware, type MiddlewareHandler, type MiddlewareOptions, type OpenApiOptions, type RequestSchema, type ResponseSchema, type RouteConfig, type RouteHandler, type SecurityScheme, type SecuritySchemeApiKey, type SecuritySchemeHttp, type SecuritySchemeOAuth2, type SecuritySchemeOAuth2Flow, type SecuritySchemeOpenIdConnect };
|
package/dist/lib/api/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
const e={status:404},t=(e,t)=>{let n=e.split(`/`).slice(1),r=[],i=0;for(let e of n){if(e.startsWith(`:`)){r.push({value:``,paramName:e.slice(1)}),i++;continue}r.push({value:e})}return{segments:r,methods:t,paramStarts:Array(i),paramEnds:Array(i)}},n=(e,t)=>{let n=1,r=0;if(t===`/`)return e.segments.length===0;for(let i of e.segments){let a=t.indexOf(`/`,n),o=t.length;if(a!==-1&&(o=a),i.paramName){if(o===n)return!1;e.paramStarts[r]=n,e.paramEnds[r]=o,r++}else{let e=o-n;if(i.value.length!==e||!t.startsWith(i.value,n))return!1}n=a===-1?t.length:a+1}return n===t.length},r=(e,t)=>{let n={},r=0;for(let i of e.segments)i.paramName&&(n[i.paramName]=t.slice(e.paramStarts[r],e.paramEnds[r]),r++);return n},i=e=>{let t=e.indexOf(`://`),n=e.indexOf(`/`,t+3);if(n===-1)return`/`;let r=e.indexOf(`?`,n),i;return i=r===-1?e.slice(n):e.slice(n,r),i.length>1&&i.endsWith(`/`)?i.slice(0,-1):i},a=a=>{let o=Object.create(null),s=[],c=[];for(let[e,n]of Object.entries(a)){let r=n;if(e.includes(`*`)){c.push({pattern:new URLPattern({pathname:e}),methods:r});continue}if(e.includes(`:`)){s.push(t(e,r));continue}o[e]=r}return t=>{let a=i(t.url),l=t.method,u=o[a]?.[l];if(u)return u(t);for(let e of s){if(!n(e,a))continue;let i=e.methods[l];if(i)return t.params=r(e,a),i(t)}for(let e of c){let n=e.pattern.exec({pathname:a});if(!n)continue;let r=e.methods[l];if(r)return t.params=n.pathname.groups,r(t)}return new Response(`Not found`,e)}},o=e=>{if(Array.isArray(e))return e.map(o);if(typeof e!=`object`||!e)return e;let t=e;if(typeof t.$ref==`string`&&t.$ref.startsWith(`#/$defs/`))return{$ref:`#/components/schemas/${t.$ref.slice(8)}`};let n={};for(let e in t)n[e]=o(t[e]);return n},s=e=>{let t=e.$defs;if(!t||typeof t!=`object`)return{schema:e,components:void 0};let n=o({...e});delete n.$defs;let r=t,i={};for(let e in r)i[e]=o(r[e]);return{schema:n,components:{schemas:i}}},c=(e,t=`input`)=>{let n=e[`~standard`].jsonSchema[t]({target:`draft-2020-12`});return s(n)},l=e=>{let t=e[`~standard`];return t&&`description`in t&&typeof t.description==`string`?t.description:``},u=e=>{let t=e.meta;if(typeof t!=`function`)return;let n=t();if(typeof n==`object`&&n&&typeof n.id==`string`)return n.id},d=(e,t)=>typeof t.id==`string`?t.id:u(e),f=[`body`,`query`,`headers`,`cookies`,`params`],p=(e,t=`input`)=>{let n=c(e,t),{schema:r,components:i}=n,a=d(e,r);if(a){let e={...r};return delete e.id,delete e.$schema,{schema:{$ref:`#/components/schemas/${a}`},components:{...i,schemas:{...i?.schemas,[a]:e}}}}if(r.$schema){let e={...r};return delete e.$schema,{schema:e,components:i}}return n},m=(e,t=`input`)=>{let{schema:n,components:r}=c(e,t),i={...n};return delete i.$schema,delete i.id,{schema:i,components:r}},h=(e,t)=>{let{schema:n,components:r}=m(e);if(n.type!==`object`||!n.properties)return{parameters:[],components:r};let i=[],a=n.required??[];for(let e in n.properties){let r=n.properties[e],o=a.includes(e);i.push({name:e,in:t,required:o,schema:r})}return{parameters:i,components:r}},g=e=>e.replace(/:([a-zA-Z_][a-zA-Z0-9_]*)/g,`{$1}`),_=e=>{let t=e.match(/:([a-zA-Z_][a-zA-Z0-9_]*)/g);return t?t.map(e=>e.slice(1)):[]},ee=[[`query`,`query`],[`headers`,`header`],[`cookies`,`cookie`]],te=(e,t)=>{let n=[],r=[];for(let[t,i]of ee)if(e[t]){let{parameters:a,components:o}=h(e[t],i);n.push(...a),o&&r.push(o)}let i=_(t);if(i.length>0&&e.params){let{schema:t,components:a}=m(e.params);if(a&&r.push(a),t.type===`object`&&t.properties)for(let e of i){let r=t.properties[e];r&&n.push({name:e,in:`path`,required:!0,schema:r})}}return{parameters:n,components:r}},ne=e=>{let{schema:t,components:n}=p(e);return{components:n,requestBody:{required:!0,content:{"application/json":{schema:t}}}}},re=e=>{let t={},n=[];if(!e)return{responses:t,components:n};for(let r in e){let i=String(r),a=e[Number(r)];if(!a)continue;let o=l(a),{schema:s,components:c}=p(a,`output`);c&&n.push(c),t[i]={description:o||`Response with status ${i}`,content:{"application/json":{schema:s}}}}return{responses:t,components:n}},v=(e,t,n)=>{let{request:r,response:i}=y(e,t),a=e.path;n&&(a=n+e.path);let{parameters:o,components:s}=te(r,a),{responses:c,components:l}=re(i),u={responses:c},d=[];d.push(...l),d.push(...s);for(let t of[`summary`,`description`,`operationId`])e[t]&&(u[t]=e[t]);e.tags&&e.tags.length>0&&(u.tags=e.tags),o.length>0&&(u.parameters=o);let f=r.body;if(f){let{requestBody:e,components:t}=ne(f);u.requestBody=e,t&&d.push(t)}return{operation:u,components:d}},y=(e,t)=>{let n={},r={};for(let i of[...t,...e.middlewares??[]])b(n,i.options.request),x(r,i.options.response);b(n,e.request),x(r,e.response);let i;return Object.keys(r).length>0&&(i=r),{request:n,response:i}},b=(e,t)=>{if(t)for(let n of f)t[n]&&(e[n]=t[n])},x=(e,t)=>{if(t)for(let n in t){let r=Number(n),i=t[r];i&&(e[r]=i)}},S=e=>{let t={openapi:`3.1.0`,info:{title:e.title,description:e.description,version:e.version},paths:{}};e.servers&&e.servers.length>0&&(t.servers=e.servers);let n={};for(let r of e.routes){let i=r.path;e.prefix&&(i=e.prefix+r.path);let a=g(i),o=r.method.toLowerCase();t.paths[a]??={};let{operation:s,components:c}=v(r,e.globalMiddlewares??[],e.prefix);t.paths[a][o]=s,c.forEach(e=>{Object.assign(n,e.schemas??{})})}let r=Object.keys(n).length>0;return(e.securitySchemes||r)&&(t.components={},e.securitySchemes&&(t.components.securitySchemes=e.securitySchemes),r&&(t.components.schemas=n)),t};var C=class extends Error{constructor(e){super(e),this.name=`ParseError`}},w=class extends Error{constructor(e){super(e),this.name=`ValidationError`}},T=class extends Error{constructor(e){super(e),this.name=`SchemaConfigError`}};function ie(e){if(e.path?.length){let t=``;for(let n of e.path){let e=typeof n==`object`?n.key:n;if(typeof e==`string`||typeof e==`number`)t?t+=`.${e}`:t+=e;else return null}return t}return null}const ae=e=>ie(e)??`unknown`,E=e=>e.map(e=>`${ae(e)}: ${e.message??`validation failed`}`).join(`, `),D=e=>!(!e.body||e.query||e.headers||e.cookies||e.params),O=e=>{let t=e[`~standard`].validate;return async e=>{let n=e.headers.get(`content-type`)??``,r;if(n.startsWith(`application/json`))try{r=await e.json()}catch{throw new C(`Invalid JSON body`)}else r=await e.text();let i=t(r);if(i instanceof Promise)throw new T(`Async schema validation is not supported`);if(i.issues)throw new w(E(i.issues))}},k=e=>{if(!e.issues)return e.value;throw new w(E(e.issues))},A=(e,t=!1)=>{let n=e;t&&e.includes(`+`)&&(n=e.replaceAll(`+`,` `));try{return decodeURIComponent(n)}catch{return n}},j=(e,t,n)=>{let r=e[t];if(r===void 0){e[t]=n;return}if(Array.isArray(r)){r.push(n);return}e[t]=[r,n]},M=(e,t)=>{let n=e[`~standard`].validate(t);if(n instanceof Promise)throw new T(`Async schema validation is not supported`);return k(n)},N=async(e,t,n)=>{if(!t)return!0;if(n?.parsed)return M(t,n.value);let r=e.headers.get(`content-type`)??``,i;if(r.startsWith(`application/json`))try{i=await e.json()}catch{throw new C(`Invalid JSON body`)}else i=await e.text();return n&&(n.parsed=!0,n.value=i),M(t,i)},P=(e,t)=>{if(!t)return!0;let n=e.url.indexOf(`?`);if(n===-1)return M(t,{});let r=e.url.indexOf(`#`,n+1),i=e.url.length;r!==-1&&(i=r);let a={},o=n+1;for(;o<=i;){let t=e.url.indexOf(`&`,o),n=i;if(t!==-1&&t<i&&(n=t),n>o){let t=e.url.indexOf(`=`,o),r=t!==-1&&t<n,i=e.url.slice(o,n),s=``;r&&(i=e.url.slice(o,t),s=e.url.slice(t+1,n)),j(a,A(i,!0),A(s,!0))}if(t===-1||t>=i)break;o=t+1}return M(t,a)},F=(e,t)=>{if(!t)return!0;let n={};for(let[t,r]of e.headers)n[t]=r;return M(t,n)},I=(e,t)=>{if(!t)return!0;let n=e.headers.get(`cookie`)??``,r={},i=0;for(;i<n.length;){let e=n.indexOf(`;`,i),t=n.length;e!==-1&&(t=e);let a=n.indexOf(`=`,i);if(a!==-1&&a<t){let e=n.slice(i,a).trim();if(e){let i=n.slice(a+1,t).trim();r[e]=A(i)}}if(e===-1)break;i=e+1}return M(t,r)},L=(e,t)=>t?M(t,e.params??{}):!0,R=async(e,t)=>{let n=e.schema;if(n)try{if(n.body){let r=await N(e.req,n.body,e.bodyCache);t&&(t.body=r)}if(n.query){let r=P(e.req,n.query);t&&(t.query=r)}if(n.headers){let r=F(e.req,n.headers);t&&(t.headers=r)}if(n.cookies){let r=I(e.req,n.cookies);t&&(t.cookies=r)}if(n.params){let r=L(e.req,n.params);t&&(t.params=r)}}catch(e){return e}},z=e=>{if(e){if(D(e)){let t=e.body;if(!t)return;let n=O(t);return async e=>{try{await n(e)}catch(e){return e}}}return(t,n)=>R({req:t,schema:e,bodyCache:n})}},B={"Content-Type":`text/html`},V={status:400},H=(e,t)=>e===200?Response.json(t):Response.json(t,{status:e}),U=(e,t)=>e===200?new Response(t):new Response(t,{status:e}),W=(e,t)=>new Response(t,{status:e,headers:B}),G=(e,t)=>Response.redirect(t,e),K=e=>Response.json({message:e},V),q=e=>{if(e instanceof w||e instanceof C)return K(e.message);throw e},oe=e=>(t,n)=>{let r=e[t];if(!r)return H(t,n);try{M(r,n)}catch(e){return q(e)}return H(t,n)},J=Object.freeze({body:void 0,query:void 0,headers:void 0,cookies:void 0,params:void 0}),se={req:J,get:()=>{},json:H,text:U,html:W,redirect:G},Y=(e,t,n,r)=>{let i=Object.create(se);return i.raw=e,t&&(i.req=t),n&&(i.get=n),r&&(i.json=r),i},X=e=>e!==`/`&&e.endsWith(`/`)?e.slice(0,-1):e,ce=e=>{let t=X(e.path)||`/`;if(!e.prefix)return t;let n=X(e.prefix);return n===`/`?t:t===`/`?n:n+t},le=e=>{let t=0;e.request?.body!==void 0&&t++;for(let n of e.middlewares)if(n.options.request?.body!==void 0&&(t++,t>1))return!0;return!1},ue=e=>e===void 0||e===!0?{input:!0,output:!0}:e===!1?{input:!1,output:!1}:{input:e.input!==!1,output:e.output!==!1},de=[],Z=e=>e instanceof Response?e:typeof e==`string`?new Response(e):Response.json(e),Q=async(e,t)=>{let n=Z(e),r=t?.[n.status];if(!r)return n;let i=e;e instanceof Response&&(i=await n.clone().json());try{M(r,i)}catch(e){return q(e)}return n},fe=(e,t)=>{if(e instanceof Response)return Q(e,t);let n=Z(e),r=t?.[n.status];if(!r)return n;try{M(r,e)}catch(e){return q(e)}return n},pe=(e,t,n,r=!1,i=!1)=>{let a=i?n:void 0,o;if(r&&t&&D(t)){let e=t.body;e&&(o=O(e))}let s=r&&!o?z(t):void 0,c=e();if(c instanceof Promise)return async t=>{if(o)try{await o(t)}catch(e){return q(e)}if(s){let e=await s(t);if(e)return q(e)}let n=await e();return Q(n,a)};let l=fe(c,a);if(!o&&!s)return l instanceof Promise?async()=>l:()=>l;if(o)return async e=>{try{await o(e)}catch(e){return q(e)}return l};let u=s;return u?async e=>{let t=await u(e);return t?q(t):l}:l instanceof Promise?async()=>l:()=>l},me=e=>t=>{let n=e(Y(t));return n instanceof Promise?n.then(e=>e instanceof Response?e:Z(e)):n instanceof Response?n:Z(n)},he=(e,t)=>e.middlewares?.length?t.length===0?e.middlewares:[...t,...e.middlewares]:t,ge=(e,t,n)=>{if(!e.input)return!1;if(t)return!0;for(let e of n)if(e.options.request)return!0;return!1},$=async(e,t)=>{let n,r,i;t.validateInput&&le({middlewares:t.middlewares,request:t.routeRequest})&&(i={parsed:!1,value:void 0});let a;t.validateOutput&&t.routeResponse&&(a=oe(t.routeResponse)),t.middlewares.length>0&&(r=e=>n?.[e]);for(let a of t.middlewares){let{request:o,handler:s}=a.options,c=J;if(t.validateInput&&o){let t={},n=await R({req:e,schema:o,bodyCache:i},t);if(n)return q(n);c=t}let l=await s(Y(e,c,r));if(l instanceof Response)return l;l&&(n||={},Object.assign(n,l))}let o=J;if(t.validateInput&&t.routeRequest){let n={},r=await R({req:e,schema:t.routeRequest,bodyCache:i},n);if(r)return q(r);o=n}let s=Y(e,o,r,a);return t.handler(s)},_e=(e,t,n)=>{let r=he(e,t),i=e.handler,a=r.length>0,o=ge(n,e.request,r),s=n.output&&!!e.response;if(!a&&typeof i==`function`&&i.length===0)return pe(i,e.request,e.response,o,s);if(!a&&typeof i==`function`&&i.length===1&&!o&&!s)return me(i);let c={middlewares:r,routeRequest:e.request,routeResponse:e.response,validateInput:o,validateOutput:s,handler:i};return e=>$(e,c)},ve=(e,t,n,r)=>{let i={};for(let a of e){let e=ce({prefix:t,path:a.path});i[e]||(i[e]={}),i[e][a.method]=_e(a,n,r)}return i};var ye=class{options;routes=[];routesDirty=!0;compiled;constructor(e={}){this.options=e}defineRoute(e){this.routes.push(e),this.routesDirty=!0}fetch=e=>this.ensureCompiled().fetch(e);getRouteHandlers(){return this.ensureCompiled().routes}getOpenApiSpec(){return S({title:this.options.openapi?.title??`API`,description:this.options.openapi?.description,version:this.options.openapi?.version??`1.0.0`,prefix:this.options.prefix,servers:this.options.openapi?.servers,securitySchemes:this.options.openapi?.securitySchemes,routes:this.routes,globalMiddlewares:this.options.middlewares})}serve(e,t){let n=Bun.serve({port:e,routes:this.getRouteHandlers(),fetch:()=>new Response(`Not found`,{status:404})});t&&t(n)}ensureCompiled(){if(!this.routesDirty&&this.compiled)return this.compiled;let e=ve(this.routes,this.options.prefix,this.options.middlewares??de,ue(this.options.validation));return this.compiled={routes:e,fetch:a(e)},this.routesDirty=!1,this.compiled}},be=class{options;constructor(e){this.options=e}};export{ye as Api,be as Middleware};
|
|
1
|
+
const e={status:404},t=(e,t)=>{let n=e.split(`/`).slice(1),r=[],i=0;for(let e of n){if(e.startsWith(`:`)){r.push({value:``,paramName:e.slice(1)}),i++;continue}r.push({value:e})}return{segments:r,methods:t,paramStarts:Array(i),paramEnds:Array(i)}},n=(e,t)=>{let n=1,r=0;if(t===`/`)return e.segments.length===0;for(let i of e.segments){let a=t.indexOf(`/`,n),o=t.length;if(a!==-1&&(o=a),i.paramName){if(o===n)return!1;e.paramStarts[r]=n,e.paramEnds[r]=o,r++}else{let e=o-n;if(i.value.length!==e||!t.startsWith(i.value,n))return!1}n=a===-1?t.length:a+1}return n===t.length},r=(e,t)=>{let n={},r=0;for(let i of e.segments)i.paramName&&(n[i.paramName]=t.slice(e.paramStarts[r],e.paramEnds[r]),r++);return n},i=e=>{let t=e.indexOf(`://`),n=e.indexOf(`/`,t+3);if(n===-1)return`/`;let r=e.indexOf(`?`,n),i;return i=r===-1?e.slice(n):e.slice(n,r),i.length>1&&i.endsWith(`/`)?i.slice(0,-1):i},a=a=>{let o=Object.create(null),s=[],c=[];for(let[e,n]of Object.entries(a)){let r=n;if(e.includes(`*`)){c.push({pattern:new URLPattern({pathname:e}),methods:r});continue}if(e.includes(`:`)){s.push(t(e,r));continue}o[e]=r}return t=>{let a=i(t.url),l=t.method,u=o[a]?.[l];if(u)return u(t);for(let e of s){if(!n(e,a))continue;let i=e.methods[l];if(i)return t.params=r(e,a),i(t)}for(let e of c){let n=e.pattern.exec({pathname:a});if(!n)continue;let r=e.methods[l];if(r)return t.params=n.pathname.groups,r(t)}return new Response(`Not found`,e)}};var o=class extends Error{constructor(e){super(e),this.name=`ParseError`}},s=class extends Error{constructor(e){super(e),this.name=`ValidationError`}},c=class extends Error{constructor(e){super(e),this.name=`SchemaConfigError`}},l=class extends Error{constructor(e,t){super(`Duplicate route: ${e} ${t}`),this.name=`DuplicateRouteError`}};function u(e){if(e.path?.length){let t=``;for(let n of e.path){let e=typeof n==`object`?n.key:n;if(typeof e==`string`||typeof e==`number`)t?t+=`.${e}`:t+=e;else return null}return t}return null}const d=e=>u(e)??`unknown`,f=e=>e.map(e=>`${d(e)}: ${e.message??`validation failed`}`).join(`, `),p=e=>{if(!e.issues)return e.value;throw new s(f(e.issues))},m=(e,t=!1)=>{let n=e;t&&e.includes(`+`)&&(n=e.replaceAll(`+`,` `));try{return decodeURIComponent(n)}catch{return n}},ee=(e,t,n)=>{let r=e[t];if(r===void 0){e[t]=n;return}if(Array.isArray(r)){r.push(n);return}e[t]=[r,n]},h=(e,t)=>{let n=e[`~standard`].validate(t);if(n instanceof Promise)throw new c(`Async schema validation is not supported`);return p(n)},g=async(e,t,n)=>{if(!t)return!0;if(n?.parsed)return h(t,n.value);let r=e.headers.get(`content-type`)??``,i;if(r.startsWith(`application/json`))try{i=await e.json()}catch{throw new o(`Invalid JSON body`)}else i=await e.text();return n&&(n.parsed=!0,n.value=i),h(t,i)},te=(e,t)=>{if(!t)return!0;let n=e.url.indexOf(`?`);if(n===-1)return h(t,{});let r=e.url.indexOf(`#`,n+1),i=e.url.length;r!==-1&&(i=r);let a={},o=n+1;for(;o<=i;){let t=e.url.indexOf(`&`,o),n=i;if(t!==-1&&t<i&&(n=t),n>o){let t=e.url.indexOf(`=`,o),r=t!==-1&&t<n,i=e.url.slice(o,n),s=``;r&&(i=e.url.slice(o,t),s=e.url.slice(t+1,n)),ee(a,m(i,!0),m(s,!0))}if(t===-1||t>=i)break;o=t+1}return h(t,a)},_=(e,t)=>{if(!t)return!0;let n={};for(let[t,r]of e.headers)n[t]=r;return h(t,n)},v=(e,t)=>{if(!t)return!0;let n=e.headers.get(`cookie`)??``,r={},i=0;for(;i<n.length;){let e=n.indexOf(`;`,i),t=n.length;e!==-1&&(t=e);let a=n.indexOf(`=`,i);if(a!==-1&&a<t){let e=n.slice(i,a).trim();if(e){let i=n.slice(a+1,t).trim();r[e]=m(i)}}if(e===-1)break;i=e+1}return h(t,r)},ne=(e,t)=>!t||h(t,e.params??{}),y=async(e,t)=>{let n=e.schema;if(n)try{if(n.body){let r=await g(e.req,n.body,e.bodyCache);t&&(t.body=r)}if(n.query){let r=te(e.req,n.query);t&&(t.query=r)}if(n.headers){let r=_(e.req,n.headers);t&&(t.headers=r)}if(n.cookies){let r=v(e.req,n.cookies);t&&(t.cookies=r)}if(n.params){let r=ne(e.req,n.params);t&&(t.params=r)}}catch(e){return e}},b=e=>{if(e)return(t,n)=>y({req:t,schema:e,bodyCache:n})},x={"Content-Type":`text/html`},S={status:400},C=(e,t)=>e===200?Response.json(t):Response.json(t,{status:e}),w=(e,t)=>e===200?new Response(t):new Response(t,{status:e}),T=(e,t)=>new Response(t,{status:e,headers:x}),E=(e,t)=>Response.redirect(t,e),D=e=>Response.json({message:e},S),O=e=>{if(e instanceof s||e instanceof o)return D(e.message);throw e},k=e=>(t,n)=>{let r=e[t];if(!r)return C(t,n);try{h(r,n)}catch(e){return O(e)}return C(t,n)},A=Object.freeze({body:void 0,query:void 0,headers:void 0,cookies:void 0,params:void 0}),re={req:A,get:()=>{},json:C,text:w,html:T,redirect:E},j=(e,t,n,r)=>{let i=Object.create(re);return i.raw=e,t&&(i.req=t),n&&(i.get=n),r&&(i.json=r),i},M=e=>e!==`/`&&e.endsWith(`/`)?e.slice(0,-1):e,N=e=>{let t=M(e.path)||`/`;if(!e.prefix)return t;let n=M(e.prefix);return n===`/`?t:t===`/`?n:n+t},P=e=>{let t=0;e.request?.body!==void 0&&t++;for(let n of e.middlewares)if(n.options.request?.body!==void 0&&(t++,t>1))return!0;return!1},F=e=>e===void 0||e===!0?{input:!0,output:!0}:e===!1?{input:!1,output:!1}:{input:e.input!==!1,output:e.output!==!1},I=[],L=(e,t)=>e?.length?t?.length?[...e,...t]:e:t??I,R=(e,t)=>e?t?N({prefix:e,path:t}):e:t;var z=class{options;routes=[];groups=[];parent;constructor(e={}){this.options=e}defineRoute(e){this.routes.push(e),this.onRoutesChanged()}mount(e){e.parent=this,this.groups.push(e),this.onRoutesChanged()}onRoutesChanged(){this.parent?.onRoutesChanged()}collectRoutes(e=this.options.prefix,t=I){let n=L(t,this.options.middlewares),r=this.routes.map(t=>({...t,path:N({prefix:e,path:t.path}),middlewares:L(n,t.middlewares)}));for(let t of this.groups){let i=t.collectRoutes(R(e,t.options.prefix),n);r.push(...i)}return r}};const B=e=>{if(Array.isArray(e))return e.map(B);if(typeof e!=`object`||!e)return e;let t=e;if(typeof t.$ref==`string`&&t.$ref.startsWith(`#/$defs/`))return{$ref:`#/components/schemas/${t.$ref.slice(8)}`};let n={};for(let e in t)n[e]=B(t[e]);return n},V=e=>{let t=e.$defs;if(!t||typeof t!=`object`)return{schema:e,components:void 0};let n=B({...e});delete n.$defs;let r=t,i={};for(let e in r)i[e]=B(r[e]);return{schema:n,components:{schemas:i}}},H=(e,t=`input`)=>{let n=e[`~standard`].jsonSchema[t]({target:`draft-2020-12`});return V(n)},U=e=>{let t=e[`~standard`];return t&&`description`in t&&typeof t.description==`string`?t.description:``},W=e=>{let t=e.meta;if(typeof t!=`function`)return;let n=t();if(typeof n==`object`&&n&&typeof n.id==`string`)return n.id},G=(e,t)=>typeof t.id==`string`?t.id:W(e),K=[`body`,`query`,`headers`,`cookies`,`params`],q=(e,t=`input`)=>{let n=H(e,t),{schema:r,components:i}=n,a=G(e,r);if(a){let e={...r};return delete e.id,delete e.$schema,{schema:{$ref:`#/components/schemas/${a}`},components:{...i,schemas:{...i?.schemas,[a]:e}}}}if(r.$schema){let e={...r};return delete e.$schema,{schema:e,components:i}}return n},J=(e,t=`input`)=>{let{schema:n,components:r}=H(e,t),i={...n};return delete i.$schema,delete i.id,{schema:i,components:r}},Y=(e,t)=>{let{schema:n,components:r}=J(e);if(n.type!==`object`||!n.properties)return{parameters:[],components:r};let i=[],a=n.required??[];for(let e in n.properties){let r=n.properties[e],o=a.includes(e);i.push({name:e,in:t,required:o,schema:r})}return{parameters:i,components:r}},ie=e=>e.replace(/:([a-zA-Z_][a-zA-Z0-9_]*)/g,`{$1}`),ae=e=>{let t=e.match(/:([a-zA-Z_][a-zA-Z0-9_]*)/g);return t?t.map(e=>e.slice(1)):[]},oe=[[`query`,`query`],[`headers`,`header`],[`cookies`,`cookie`]],se=(e,t)=>{let n=[],r=[];for(let[t,i]of oe)if(e[t]){let{parameters:a,components:o}=Y(e[t],i);n.push(...a),o&&r.push(o)}let i=ae(t);if(i.length>0&&e.params){let{schema:t,components:a}=J(e.params);if(a&&r.push(a),t.type===`object`&&t.properties)for(let e of i){let r=t.properties[e];r&&n.push({name:e,in:`path`,required:!0,schema:r})}}return{parameters:n,components:r}},ce=e=>{let{schema:t,components:n}=q(e);return{components:n,requestBody:{required:!0,content:{"application/json":{schema:t}}}}},le=e=>{let t={},n=[];if(!e)return{responses:t,components:n};for(let r in e){let i=String(r),a=e[Number(r)];if(!a)continue;let o=U(a),{schema:s,components:c}=q(a,`output`);c&&n.push(c),t[i]={description:o||`Response with status ${i}`,content:{"application/json":{schema:s}}}}return{responses:t,components:n}},ue=(e,t,n)=>{let{request:r,response:i}=de(e,t),a=e.path;n&&(a=n+e.path);let{parameters:o,components:s}=se(r,a),{responses:c,components:l}=le(i),u={responses:c},d=[];d.push(...l),d.push(...s);for(let t of[`summary`,`description`,`operationId`])e[t]&&(u[t]=e[t]);e.tags&&e.tags.length>0&&(u.tags=e.tags),o.length>0&&(u.parameters=o);let f=r.body;if(f){let{requestBody:e,components:t}=ce(f);u.requestBody=e,t&&d.push(t)}return{operation:u,components:d}},de=(e,t)=>{let n={},r={};for(let i of[...t,...e.middlewares??[]])X(n,i.options.request),Z(r,i.options.response);X(n,e.request),Z(r,e.response);let i;return Object.keys(r).length>0&&(i=r),{request:n,response:i}},X=(e,t)=>{if(t)for(let n of K)t[n]&&(e[n]=t[n])},Z=(e,t)=>{if(t)for(let n in t){let r=Number(n),i=t[r];i&&(e[r]=i)}},fe=e=>{let t={openapi:`3.1.0`,info:{title:e.title,description:e.description,version:e.version},paths:{}};e.servers&&e.servers.length>0&&(t.servers=e.servers);let n={};for(let r of e.routes){let i=r.path;e.prefix&&(i=e.prefix+r.path);let a=ie(i),o=r.method.toLowerCase();t.paths[a]??={};let{operation:s,components:c}=ue(r,e.globalMiddlewares??[],e.prefix);t.paths[a][o]=s,c.forEach(e=>{Object.assign(n,e.schemas??{})})}let r=Object.keys(n).length>0;return(e.securitySchemes||r)&&(t.components={},e.securitySchemes&&(t.components.securitySchemes=e.securitySchemes),r&&(t.components.schemas=n)),t},pe=[],Q=e=>e instanceof Response?e:typeof e==`string`?new Response(e):Response.json(e),$=async(e,t)=>{let n=Q(e),r=t?.[n.status];if(!r)return n;let i=e;e instanceof Response&&(i=await n.clone().json());try{h(r,i)}catch(e){return O(e)}return n},me=(e,t)=>{if(e instanceof Response)return $(e,t);let n=Q(e),r=t?.[n.status];if(!r)return n;try{h(r,e)}catch(e){return O(e)}return n},he=(e,t,n,r=!1,i=!1)=>{let a=i?n:void 0,o=r?b(t):void 0,s=e();if(s instanceof Promise)return async t=>{if(o){let e=await o(t);if(e)return O(e)}let n=await e();return $(n,a)};let c=me(s,a);return o?async e=>{let t=await o(e);return t?O(t):c}:c instanceof Promise?async()=>c:()=>c},ge=e=>t=>{let n=e(j(t));return n instanceof Promise?n.then(e=>e instanceof Response?e:Q(e)):n instanceof Response?n:Q(n)},_e=(e,t,n)=>{if(!e.input)return!1;if(t)return!0;for(let e of n)if(e.options.request)return!0;return!1},ve=async(e,t)=>{let n,r,i;t.validateInput&&P({middlewares:t.middlewares,request:t.routeRequest})&&(i={parsed:!1,value:void 0});let a;t.validateOutput&&t.routeResponse&&(a=k(t.routeResponse)),t.middlewares.length>0&&(r=e=>n?.[e]);for(let a of t.middlewares){let{request:o,handler:s}=a.options,c=A;if(t.validateInput&&o){let t={},n=await y({req:e,schema:o,bodyCache:i},t);if(n)return O(n);c=t}let l=await s(j(e,c,r));if(l instanceof Response)return l;l&&(n||={},Object.assign(n,l))}let o=A;if(t.validateInput&&t.routeRequest){let n={},r=await y({req:e,schema:t.routeRequest,bodyCache:i},n);if(r)return O(r);o=n}let s=j(e,o,r,a);return t.handler(s)},ye=(e,t)=>{let n=e.middlewares??pe,r=e.handler,i=n.length>0,a=_e(t,e.request,n),o=t.output&&!!e.response;if(!i&&typeof r==`function`&&r.length===0)return he(r,e.request,e.response,a,o);if(!i&&typeof r==`function`&&r.length===1&&!a&&!o)return ge(r);let s={middlewares:n,routeRequest:e.request,routeResponse:e.response,validateInput:a,validateOutput:o,handler:r};return e=>ve(e,s)},be=(e,t)=>{let n={};for(let r of e){let e=n[r.path];if(e||(e={},n[r.path]=e),e[r.method])throw new l(r.method,r.path);e[r.method]=ye(r,t)}return n};var xe=class extends z{options;compiled;needsRecompile=!0;constructor(e={}){super(e),this.options=e}onRoutesChanged(){this.needsRecompile=!0,super.onRoutesChanged()}fetch=e=>this.ensureCompiled().fetch(e);getRouteHandlers(){return this.ensureCompiled().routes}getOpenApiSpec(){return fe({title:this.options.openapi?.title??`API`,description:this.options.openapi?.description,version:this.options.openapi?.version??`1.0.0`,servers:this.options.openapi?.servers,securitySchemes:this.options.openapi?.securitySchemes,routes:this.collectRoutes()})}serve(e,t){let n=Bun.serve({port:e,routes:this.getRouteHandlers(),fetch:()=>new Response(`Not found`,{status:404})});t&&t(n)}ensureCompiled(){if(!this.needsRecompile&&this.compiled)return this.compiled;let e=be(this.collectRoutes(),F(this.options.validation));return this.compiled={routes:e,fetch:a(e)},this.needsRecompile=!1,this.compiled}},Se=class{options;constructor(e){this.options=e}};export{xe as Api,z as Group,Se as Middleware};
|
package/dist/lib/cache/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../errors/index.cjs");var t=class extends Error{constructor(e){super(e),this.name=`CacheError`}},n=class extends Error{constructor(e){super(e),this.name=`InvalidTTLError`}},r=class extends Error{constructor(e){super(e),this.name=`NotFoundError`}},i=class extends Error{constructor(e){super(e),this.name=`SerializationError`}},a=class extends Error{constructor(e){super(e),this.name=`DeserializationError`}},o=class{options;serialize;deserialize;constructor(e){this.options=e,this.serialize=e.serializer??JSON.stringify,this.deserialize=e.deserializer??(e=>JSON.parse(e))}async get(n){if(!this.isEnabled)throw new r(`Key ${n} not found`);let i=this.resolveKey(n),[o,s]=await e.mightThrow(this.options.redis.get(i));if(o)throw new t(`Unable to get value for key ${n}`);if(s==null)throw new r(`Key ${n} not found`);let[c,l]=e.mightThrowSync(()=>this.deserialize(s));if(c)throw new a(`Unable to deserialize value for key ${n}`);return l}async set(r,a){if(!this.isEnabled)return a;let[o,s]=e.mightThrowSync(()=>this.serialize(a));if(o||s==null)throw new i(`Unable to serialize value for key ${r}`);let[c,l]=e.mightThrowSync(()=>this.resolveTTL(r,a));if(c)throw new n(`Unable to resolve ttl for key ${r}`);if(!this.isTTLValid(l))throw new n(`Unable to save records with ttl equal to ${l}`);let u=this.resolveKey(r),[d]=await e.mightThrow(this.getSetPromise(u,s,l));if(d)throw new t(`Unable to set value for key ${r}`);return a}async delete(n){if(!this.isEnabled)return 0;let r=this.resolveKey(n),[i,a]=await e.mightThrow(this.options.redis.del(r));if(i)throw new t(`Unable to delete key ${n}`);return a}get isEnabled(){return this.options.enabled!==!1}resolveKey(e){return this.options.prefix?`${this.options.prefix}:${e}`:e}resolveTTL(e,t){return typeof this.options.ttl==`function`?this.options.ttl(e,t):this.options.ttl}getSetPromise(e,t,n){return n==null?this.options.redis.set(e,t):this.options.redis.set(e,t,`PX`,n)}isTTLValid(e){return e==null
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../errors/index.cjs");var t=class extends Error{constructor(e){super(e),this.name=`CacheError`}},n=class extends Error{constructor(e){super(e),this.name=`InvalidTTLError`}},r=class extends Error{constructor(e){super(e),this.name=`NotFoundError`}},i=class extends Error{constructor(e){super(e),this.name=`SerializationError`}},a=class extends Error{constructor(e){super(e),this.name=`DeserializationError`}},o=class{options;serialize;deserialize;constructor(e){this.options=e,this.serialize=e.serializer??JSON.stringify,this.deserialize=e.deserializer??(e=>JSON.parse(e))}async get(n){if(!this.isEnabled)throw new r(`Key ${n} not found`);let i=this.resolveKey(n),[o,s]=await e.mightThrow(this.options.redis.get(i));if(o)throw new t(`Unable to get value for key ${n}`);if(s==null)throw new r(`Key ${n} not found`);let[c,l]=e.mightThrowSync(()=>this.deserialize(s));if(c)throw new a(`Unable to deserialize value for key ${n}`);return l}async set(r,a){if(!this.isEnabled)return a;let[o,s]=e.mightThrowSync(()=>this.serialize(a));if(o||s==null)throw new i(`Unable to serialize value for key ${r}`);let[c,l]=e.mightThrowSync(()=>this.resolveTTL(r,a));if(c)throw new n(`Unable to resolve ttl for key ${r}`);if(!this.isTTLValid(l))throw new n(`Unable to save records with ttl equal to ${l}`);let u=this.resolveKey(r),[d]=await e.mightThrow(this.getSetPromise(u,s,l));if(d)throw new t(`Unable to set value for key ${r}`);return a}async delete(n){if(!this.isEnabled)return 0;let r=this.resolveKey(n),[i,a]=await e.mightThrow(this.options.redis.del(r));if(i)throw new t(`Unable to delete key ${n}`);return a}get isEnabled(){return this.options.enabled!==!1}resolveKey(e){return this.options.prefix?`${this.options.prefix}:${e}`:e}resolveTTL(e,t){return typeof this.options.ttl==`function`?this.options.ttl(e,t):this.options.ttl}getSetPromise(e,t,n){return n==null?this.options.redis.set(e,t):this.options.redis.set(e,t,`PX`,n)}isTTLValid(e){return e==null||!(!Number.isFinite(e)||!Number.isInteger(e)||e<0)}};exports.Cache=o;
|
package/dist/lib/cache/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{mightThrow as e,mightThrowSync as t}from"../errors/index.mjs";var n=class extends Error{constructor(e){super(e),this.name=`CacheError`}},r=class extends Error{constructor(e){super(e),this.name=`InvalidTTLError`}},i=class extends Error{constructor(e){super(e),this.name=`NotFoundError`}},a=class extends Error{constructor(e){super(e),this.name=`SerializationError`}},o=class extends Error{constructor(e){super(e),this.name=`DeserializationError`}},s=class{options;serialize;deserialize;constructor(e){this.options=e,this.serialize=e.serializer??JSON.stringify,this.deserialize=e.deserializer??(e=>JSON.parse(e))}async get(r){if(!this.isEnabled)throw new i(`Key ${r} not found`);let a=this.resolveKey(r),[s,c]=await e(this.options.redis.get(a));if(s)throw new n(`Unable to get value for key ${r}`);if(c==null)throw new i(`Key ${r} not found`);let[l,u]=t(()=>this.deserialize(c));if(l)throw new o(`Unable to deserialize value for key ${r}`);return u}async set(i,o){if(!this.isEnabled)return o;let[s,c]=t(()=>this.serialize(o));if(s||c==null)throw new a(`Unable to serialize value for key ${i}`);let[l,u]=t(()=>this.resolveTTL(i,o));if(l)throw new r(`Unable to resolve ttl for key ${i}`);if(!this.isTTLValid(u))throw new r(`Unable to save records with ttl equal to ${u}`);let d=this.resolveKey(i),[f]=await e(this.getSetPromise(d,c,u));if(f)throw new n(`Unable to set value for key ${i}`);return o}async delete(t){if(!this.isEnabled)return 0;let r=this.resolveKey(t),[i,a]=await e(this.options.redis.del(r));if(i)throw new n(`Unable to delete key ${t}`);return a}get isEnabled(){return this.options.enabled!==!1}resolveKey(e){return this.options.prefix?`${this.options.prefix}:${e}`:e}resolveTTL(e,t){return typeof this.options.ttl==`function`?this.options.ttl(e,t):this.options.ttl}getSetPromise(e,t,n){return n==null?this.options.redis.set(e,t):this.options.redis.set(e,t,`PX`,n)}isTTLValid(e){return e==null
|
|
1
|
+
import{mightThrow as e,mightThrowSync as t}from"../errors/index.mjs";var n=class extends Error{constructor(e){super(e),this.name=`CacheError`}},r=class extends Error{constructor(e){super(e),this.name=`InvalidTTLError`}},i=class extends Error{constructor(e){super(e),this.name=`NotFoundError`}},a=class extends Error{constructor(e){super(e),this.name=`SerializationError`}},o=class extends Error{constructor(e){super(e),this.name=`DeserializationError`}},s=class{options;serialize;deserialize;constructor(e){this.options=e,this.serialize=e.serializer??JSON.stringify,this.deserialize=e.deserializer??(e=>JSON.parse(e))}async get(r){if(!this.isEnabled)throw new i(`Key ${r} not found`);let a=this.resolveKey(r),[s,c]=await e(this.options.redis.get(a));if(s)throw new n(`Unable to get value for key ${r}`);if(c==null)throw new i(`Key ${r} not found`);let[l,u]=t(()=>this.deserialize(c));if(l)throw new o(`Unable to deserialize value for key ${r}`);return u}async set(i,o){if(!this.isEnabled)return o;let[s,c]=t(()=>this.serialize(o));if(s||c==null)throw new a(`Unable to serialize value for key ${i}`);let[l,u]=t(()=>this.resolveTTL(i,o));if(l)throw new r(`Unable to resolve ttl for key ${i}`);if(!this.isTTLValid(u))throw new r(`Unable to save records with ttl equal to ${u}`);let d=this.resolveKey(i),[f]=await e(this.getSetPromise(d,c,u));if(f)throw new n(`Unable to set value for key ${i}`);return o}async delete(t){if(!this.isEnabled)return 0;let r=this.resolveKey(t),[i,a]=await e(this.options.redis.del(r));if(i)throw new n(`Unable to delete key ${t}`);return a}get isEnabled(){return this.options.enabled!==!1}resolveKey(e){return this.options.prefix?`${this.options.prefix}:${e}`:e}resolveTTL(e,t){return typeof this.options.ttl==`function`?this.options.ttl(e,t):this.options.ttl}getSetPromise(e,t,n){return n==null?this.options.redis.set(e,t):this.options.redis.set(e,t,`PX`,n)}isTTLValid(e){return e==null||!(!Number.isFinite(e)||!Number.isInteger(e)||e<0)}};export{s as Cache};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=class e{root;constructor(e){this.root=e}command(t,n){let r=this.root.create(t,n);return new e(r)}argument(e,t){for(let t of this.root.arguments)if(t.name===e)throw Error(`Argument "${e}" already exists`);return this.root.arguments.push({name:e,schema:t.schema}),this}option(e,t){let n=t.aliases??[];for(let t of this.root.options){if(t.name===e)throw Error(`Option "${e}" already exists`);if(t.aliases?.includes(e))throw Error(`Option "${e}" conflicts with alias of option "${t.name}"`);for(let e of n){if(t.name===e)throw Error(`Option alias "${e}" conflicts with option "${t.name}"`);if(t.aliases?.includes(e))throw Error(`Option alias "${e}" already exists`)}}return this.root.options.push({name:e,schema:t.schema,aliases:t.aliases}),this}action(e){return this.root.handler=e,this.root.cli}};const t={label:`-h, --help`,description:`Show help`},n=[t,{label:`-v, --version`,description:`Show version`}],r=[t],i=(e,t)=>!(!e||!t.includes(e)),a=e=>i(e,[`--help`,`-h`]),o=e=>i(e,[`--version`,`-v`]),s=e=>e.map(e=>`<${e.name}>`).join(` `),c=e=>Array.from(e,([e,t])=>{let n=[e,s(t.arguments)].filter(e=>e.length>0);return t.description?` ${n.join(` `)} ${t.description}`:` ${n.join(` `)}`}),l=e=>{let t=(e.aliases??[]).map(e=>`-${e}`),n=`--${e.name}`;return[...t,n].join(`, `)},u=e=>({label:l(e),description:f(e.schema)}),d=e=>{let t=e.filter(e=>e.description).reduce((e,t)=>Math.max(e,t.label.length),0);return e.map(e=>e.description?` ${e.label.padEnd(t)} ${e.description}`:` ${e.label}`)},f=e=>{if(!(`jsonSchema`in e[`~standard`]))return``;let{description:t}=e[`~standard`].jsonSchema.input({target:`draft-2020-12`});return typeof t==`string`?t:``},p=e=>{e&&console.log(`${e}\n`)};var m=class{path(e){let t=[],n=e;for(;n?.parent;)t.unshift(n.name),n=n.parent;return t}readCommands(e){return e.commands.keys().toArray()}resolve(e,t){let n=e,r=0;for(;r<t.length;){let e=t[r];if(!e||e.startsWith(`-`))break;let i=n.commands.get(e);if(!i)break;n=i,r++}return r===0?{command:void 0,rest:t.slice(r)}:{command:n,rest:t.slice(r)}}printHelp(e,t){let n=s(e.arguments),i=this.path(e).join(` `),a=[t.name,i,n,`[options]`].filter(e=>e.length>0).join(` `);if(console.log(`Usage: ${a}\n`),p(t.description),e.arguments.length>0){console.log(`Arguments:`);let t=e.arguments.map(e=>({label:e.name,description:f(e.schema)}));for(let e of d(t))console.log(e);console.log(``)}if(e.commands.size>0){console.log(`Commands:`);for(let t of c(e.commands))console.log(t);console.log(``)}console.log(`Options:`);let o=[...e.options.map(u),...r];for(let e of d(o))console.log(e)}},h=class e{cli;name;parent;description;arguments=[];options=[];commands=new Map;handler;constructor(e,t,n,r){this.cli=e,this.name=t,this.parent=n,this.description=r}create(t,n){if(this.commands.has(t))throw Error(`Command "${t}" already exists`);let r=new e(this.cli,t,this,n?.description);return this.commands.set(t,r),r}},g=class extends Error{name=`CliError`},_=class extends g{name=`CliValidationError`},v=class extends g{name=`UnknownCommandError`},y=class extends g{name=`CliConfigurationError`},b=class extends g{name=`MissingArgumentError`};const x=(e,t,n,r)=>{let i=n[r],a=n[r+1];return i!==void 0&&a!==void 0&&(i.indexOf(`=`)===-1&&(a=a.trim()),!a.startsWith(`-`))?(e[t]=a,r+2):(e[t]=!0,r+1)},S=(e,t,n)=>{let r=e.get(t);if(!r)throw new _(n);return r},C=(e,t)=>{let n=new Map;for(let e of t){n.set(e.name,e.name);for(let t of e.aliases??[])n.set(t,e.name)}let r=[],i={},a=0;for(;a<e.length;){let t=e[a];if(!t)break;let o=`Unknown option: ${t}`,s=t.indexOf(`=`),c=s===-1?void 0:s;if(t.charAt(0)===`-`){if(t.length<2)throw new _(`Invalid option: ${t}`);let r=1;t.charAt(1)===`-`&&(r=2);let l=t.slice(r,c).trim();if(l.length===1&&r===2)throw new _(`Invalid option: ${t}`);let u=S(n,l,o);if(s!==-1){i[u]=t.slice(s+1),a++;continue}a=x(i,u,e,a);continue}r.push(t),a++}return{positional:r,options:i}},w=.6;function T(e,t){if(e.length<t.length)return T(t,e);if(t.length===0)return e.length;let n=Array.from({length:t.length+1},(e,t)=>t);for(let r=0;r<e.length;r++){let i=e.charAt(r),a=Array.from({length:t.length}).fill(0),o=[r+1,...a];for(let e=0;e<t.length;e++){let r=t.charAt(e),a=n[e+1],s=o[e],c=n[e];if(a===void 0||s===void 0||c===void 0)return-1;let l=a+1,u=s+1,d=c+(i===r?0:1);o[e+1]=Math.min(l,u,d)}n=o}let r=n[n.length-1];return r===void 0?-1:r}function E(e,t){return D(e.map(e=>{let n=T(e,t),r=Math.max(e.length,t.length);return r===0?{command:e,cost:0}:{command:e,cost:1-n/r}}).filter(e=>{let t=e.cost>w,n=Math.abs(e.cost-w)<2**-52;return t||n}))}function D(e){return e.sort((e,t)=>t.cost-e.cost).slice(0,2).map(e=>e.command)}const O=async(e,t,n)=>{let r=await e[`~standard`].validate(t);if(!r.issues)return r.value;throw new _(r.issues.map(e=>{let t=n;if(Array.isArray(e.path)){let r=e.path.map(String).join(`.`);r.length>0&&(t=`${n}.${r}`)}return`${t}: ${e.message??`validation failed`}`}).join(`, `))},k=async(e,t)=>{if(t.length<e.length){let n=e[t.length];throw n?new b(`Missing argument: ${n.name}`):new b(`Missing argument`)}let n={};for(let[r,i]of e.entries())n[i.name]=await O(i.schema,t[r],i.name);return n},A=async(e,t)=>{let n={};for(let r of e){let e=t[r.name];n[r.name]=await O(r.schema,e,r.name)}return n};var j=class{config;root=new h(this,``);commandHelper=new m;constructor(e){this.config=e}command(t,n){return new e(this.root.create(t,n))}async parse(e){let t=e??process.argv.slice(2),[n]=t;if(n||(this.printHelp(),process.exit(1)),a(n)){this.printHelp();return}if(o(n)){this.printVersion();return}let{command:r,rest:i}=this.commandHelper.resolve(this.root,t),[s]=i;if(!r){let e=this.createSuggestion(n);this.handleCliError(new v(this.formatUnknownCommandMessage(n,e)))}if(a(s)){this.commandHelper.printHelp(r,this.config);return}let c=r.handler;if(!c){if(r.commands.size>0){if(s!==void 0){let e=this.createSuggestion(s);this.handleCliError(new v(this.formatUnknownCommandMessage(s,e)))}this.commandHelper.printHelp(r,this.config);return}let e=this.commandHelper.path(r).join(` `);this.handleCliError(new y(`Command "${e}" has no action handler`))}try{let e=C(i,r.options);await c(await k(r.arguments,e.positional),await A(r.options,e.options))}catch(e){this.handleCliError(e)}}printVersion(){let e=this.config.version??`0.0.0`;console.log(e)}printHelp(){console.log(`Usage: ${this.config.name} <command> [options]\n`),p(this.config.description),console.log(`Commands:`);for(let e of c(this.root.commands))console.log(e);console.log(``),console.log(`Options:`);for(let e of d(n))console.log(e)}handleCliError(e){throw e instanceof g&&(console.error(e.message),process.exit(1)),e}createSuggestion(e){let t=E(this.commandHelper.readCommands(this.root),e);return t.length===0?``:t.length===1?`Did you mean ${t[0]}?`:t.reduce((e,n,r)=>{let i=e.concat(` ${n}`);return r!==t.length-1&&(i=i.concat(`
|
|
2
|
+
`)),i},`Did you mean
|
|
3
|
+
`)}formatUnknownCommandMessage(e,t){return t.length===0?`Unknown command: ${e}`:`Unknown command: ${e}\n${t}`}};exports.CLI=j,exports.CliConfigurationError=y,exports.CliValidationError=_,exports.Command=h,exports.MissingArgumentError=b,exports.UnknownCommandError=v;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type * from './index.d.mts'
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { t as StandardSchemaV1 } from "../../index-DISN0WKZ.mjs";
|
|
2
|
+
//#region src/lib/cli/types.d.ts
|
|
3
|
+
type HandlerFnType = (args: Record<string, unknown>, options: Record<string, unknown>) => void | Promise<void>;
|
|
4
|
+
type CLIConfig = {
|
|
5
|
+
name: string;
|
|
6
|
+
description?: string;
|
|
7
|
+
version?: string;
|
|
8
|
+
};
|
|
9
|
+
type ArgumentConfig = {
|
|
10
|
+
name: string;
|
|
11
|
+
schema: StandardSchemaV1;
|
|
12
|
+
};
|
|
13
|
+
type OptionConfig = {
|
|
14
|
+
name: string;
|
|
15
|
+
schema: StandardSchemaV1;
|
|
16
|
+
aliases?: string[];
|
|
17
|
+
};
|
|
18
|
+
type SafeTypeAccess<T, K extends "input" | "output"> = T extends StandardSchemaV1 ? T["~standard"] extends {
|
|
19
|
+
types?: infer U;
|
|
20
|
+
} ? U extends Record<K, infer V> ? V : never : never : undefined;
|
|
21
|
+
type InferOutput<T extends StandardSchemaV1> = SafeTypeAccess<T, "output">;
|
|
22
|
+
//#endregion
|
|
23
|
+
//#region src/lib/cli/command.d.ts
|
|
24
|
+
declare class Command {
|
|
25
|
+
readonly cli: Cli;
|
|
26
|
+
readonly name: string;
|
|
27
|
+
readonly parent?: Command | undefined;
|
|
28
|
+
readonly description?: string | undefined;
|
|
29
|
+
readonly arguments: ArgumentConfig[];
|
|
30
|
+
readonly options: OptionConfig[];
|
|
31
|
+
readonly commands: Map<string, Command>;
|
|
32
|
+
handler?: HandlerFnType;
|
|
33
|
+
constructor(cli: Cli, name: string, parent?: Command | undefined, description?: string | undefined);
|
|
34
|
+
create(name: string, config?: {
|
|
35
|
+
description?: string;
|
|
36
|
+
}): Command;
|
|
37
|
+
}
|
|
38
|
+
//#endregion
|
|
39
|
+
//#region src/lib/cli/command.control.d.ts
|
|
40
|
+
declare class CommandControl<TArgs extends Record<string, unknown> = Record<string, unknown>, TOptions extends Record<string, unknown> = Record<string, unknown>> {
|
|
41
|
+
private root;
|
|
42
|
+
constructor(root: Command);
|
|
43
|
+
command(name: string, config?: {
|
|
44
|
+
description?: string;
|
|
45
|
+
}): CommandControl<Record<string, unknown>, Record<string, unknown>>;
|
|
46
|
+
argument<K extends string, S extends StandardSchemaV1>(name: K, config: {
|
|
47
|
+
schema: S;
|
|
48
|
+
}): CommandControl<TArgs & Record<K, InferOutput<S>>, TOptions>;
|
|
49
|
+
option<K extends string, S extends StandardSchemaV1>(name: K, config: {
|
|
50
|
+
schema: S;
|
|
51
|
+
aliases?: string[];
|
|
52
|
+
}): CommandControl<TArgs, TOptions & Record<K, InferOutput<S>>>;
|
|
53
|
+
action(handler: (args: TArgs, options: TOptions) => void | Promise<void>): Cli;
|
|
54
|
+
}
|
|
55
|
+
//#endregion
|
|
56
|
+
//#region src/lib/cli/cli.d.ts
|
|
57
|
+
declare class Cli {
|
|
58
|
+
private readonly config;
|
|
59
|
+
private readonly root;
|
|
60
|
+
private readonly commandHelper;
|
|
61
|
+
constructor(config: CLIConfig);
|
|
62
|
+
command(name: string, config?: {
|
|
63
|
+
description?: string;
|
|
64
|
+
}): CommandControl<Record<string, unknown>, Record<string, unknown>>;
|
|
65
|
+
parse(argv?: string[]): Promise<void>;
|
|
66
|
+
private printVersion;
|
|
67
|
+
private printHelp;
|
|
68
|
+
private handleCliError;
|
|
69
|
+
private createSuggestion;
|
|
70
|
+
private formatUnknownCommandMessage;
|
|
71
|
+
}
|
|
72
|
+
//#endregion
|
|
73
|
+
//#region src/lib/cli/errors.d.ts
|
|
74
|
+
declare class CliError extends Error {
|
|
75
|
+
name: string;
|
|
76
|
+
}
|
|
77
|
+
declare class CliValidationError extends CliError {
|
|
78
|
+
name: string;
|
|
79
|
+
}
|
|
80
|
+
declare class UnknownCommandError extends CliError {
|
|
81
|
+
name: string;
|
|
82
|
+
}
|
|
83
|
+
declare class CliConfigurationError extends CliError {
|
|
84
|
+
name: string;
|
|
85
|
+
}
|
|
86
|
+
declare class MissingArgumentError extends CliError {
|
|
87
|
+
name: string;
|
|
88
|
+
}
|
|
89
|
+
//#endregion
|
|
90
|
+
export { Cli as CLI, CliConfigurationError, CliValidationError, Command, MissingArgumentError, UnknownCommandError };
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
var e=class e{root;constructor(e){this.root=e}command(t,n){let r=this.root.create(t,n);return new e(r)}argument(e,t){for(let t of this.root.arguments)if(t.name===e)throw Error(`Argument "${e}" already exists`);return this.root.arguments.push({name:e,schema:t.schema}),this}option(e,t){let n=t.aliases??[];for(let t of this.root.options){if(t.name===e)throw Error(`Option "${e}" already exists`);if(t.aliases?.includes(e))throw Error(`Option "${e}" conflicts with alias of option "${t.name}"`);for(let e of n){if(t.name===e)throw Error(`Option alias "${e}" conflicts with option "${t.name}"`);if(t.aliases?.includes(e))throw Error(`Option alias "${e}" already exists`)}}return this.root.options.push({name:e,schema:t.schema,aliases:t.aliases}),this}action(e){return this.root.handler=e,this.root.cli}};const t={label:`-h, --help`,description:`Show help`},n=[t,{label:`-v, --version`,description:`Show version`}],r=[t],i=(e,t)=>!(!e||!t.includes(e)),a=e=>i(e,[`--help`,`-h`]),o=e=>i(e,[`--version`,`-v`]),s=e=>e.map(e=>`<${e.name}>`).join(` `),c=e=>Array.from(e,([e,t])=>{let n=[e,s(t.arguments)].filter(e=>e.length>0);return t.description?` ${n.join(` `)} ${t.description}`:` ${n.join(` `)}`}),l=e=>{let t=(e.aliases??[]).map(e=>`-${e}`),n=`--${e.name}`;return[...t,n].join(`, `)},u=e=>({label:l(e),description:f(e.schema)}),d=e=>{let t=e.filter(e=>e.description).reduce((e,t)=>Math.max(e,t.label.length),0);return e.map(e=>e.description?` ${e.label.padEnd(t)} ${e.description}`:` ${e.label}`)},f=e=>{if(!(`jsonSchema`in e[`~standard`]))return``;let{description:t}=e[`~standard`].jsonSchema.input({target:`draft-2020-12`});return typeof t==`string`?t:``},p=e=>{e&&console.log(`${e}\n`)};var m=class{path(e){let t=[],n=e;for(;n?.parent;)t.unshift(n.name),n=n.parent;return t}readCommands(e){return e.commands.keys().toArray()}resolve(e,t){let n=e,r=0;for(;r<t.length;){let e=t[r];if(!e||e.startsWith(`-`))break;let i=n.commands.get(e);if(!i)break;n=i,r++}return r===0?{command:void 0,rest:t.slice(r)}:{command:n,rest:t.slice(r)}}printHelp(e,t){let n=s(e.arguments),i=this.path(e).join(` `),a=[t.name,i,n,`[options]`].filter(e=>e.length>0).join(` `);if(console.log(`Usage: ${a}\n`),p(t.description),e.arguments.length>0){console.log(`Arguments:`);let t=e.arguments.map(e=>({label:e.name,description:f(e.schema)}));for(let e of d(t))console.log(e);console.log(``)}if(e.commands.size>0){console.log(`Commands:`);for(let t of c(e.commands))console.log(t);console.log(``)}console.log(`Options:`);let o=[...e.options.map(u),...r];for(let e of d(o))console.log(e)}},h=class e{cli;name;parent;description;arguments=[];options=[];commands=new Map;handler;constructor(e,t,n,r){this.cli=e,this.name=t,this.parent=n,this.description=r}create(t,n){if(this.commands.has(t))throw Error(`Command "${t}" already exists`);let r=new e(this.cli,t,this,n?.description);return this.commands.set(t,r),r}},g=class extends Error{name=`CliError`},_=class extends g{name=`CliValidationError`},v=class extends g{name=`UnknownCommandError`},y=class extends g{name=`CliConfigurationError`},b=class extends g{name=`MissingArgumentError`};const x=(e,t,n,r)=>{let i=n[r],a=n[r+1];return i!==void 0&&a!==void 0&&(i.indexOf(`=`)===-1&&(a=a.trim()),!a.startsWith(`-`))?(e[t]=a,r+2):(e[t]=!0,r+1)},S=(e,t,n)=>{let r=e.get(t);if(!r)throw new _(n);return r},C=(e,t)=>{let n=new Map;for(let e of t){n.set(e.name,e.name);for(let t of e.aliases??[])n.set(t,e.name)}let r=[],i={},a=0;for(;a<e.length;){let t=e[a];if(!t)break;let o=`Unknown option: ${t}`,s=t.indexOf(`=`),c=s===-1?void 0:s;if(t.charAt(0)===`-`){if(t.length<2)throw new _(`Invalid option: ${t}`);let r=1;t.charAt(1)===`-`&&(r=2);let l=t.slice(r,c).trim();if(l.length===1&&r===2)throw new _(`Invalid option: ${t}`);let u=S(n,l,o);if(s!==-1){i[u]=t.slice(s+1),a++;continue}a=x(i,u,e,a);continue}r.push(t),a++}return{positional:r,options:i}},w=.6;function T(e,t){if(e.length<t.length)return T(t,e);if(t.length===0)return e.length;let n=Array.from({length:t.length+1},(e,t)=>t);for(let r=0;r<e.length;r++){let i=e.charAt(r),a=Array.from({length:t.length}).fill(0),o=[r+1,...a];for(let e=0;e<t.length;e++){let r=t.charAt(e),a=n[e+1],s=o[e],c=n[e];if(a===void 0||s===void 0||c===void 0)return-1;let l=a+1,u=s+1,d=c+(i===r?0:1);o[e+1]=Math.min(l,u,d)}n=o}let r=n[n.length-1];return r===void 0?-1:r}function E(e,t){return D(e.map(e=>{let n=T(e,t),r=Math.max(e.length,t.length);return r===0?{command:e,cost:0}:{command:e,cost:1-n/r}}).filter(e=>{let t=e.cost>w,n=Math.abs(e.cost-w)<2**-52;return t||n}))}function D(e){return e.sort((e,t)=>t.cost-e.cost).slice(0,2).map(e=>e.command)}const O=async(e,t,n)=>{let r=await e[`~standard`].validate(t);if(!r.issues)return r.value;throw new _(r.issues.map(e=>{let t=n;if(Array.isArray(e.path)){let r=e.path.map(String).join(`.`);r.length>0&&(t=`${n}.${r}`)}return`${t}: ${e.message??`validation failed`}`}).join(`, `))},k=async(e,t)=>{if(t.length<e.length){let n=e[t.length];throw n?new b(`Missing argument: ${n.name}`):new b(`Missing argument`)}let n={};for(let[r,i]of e.entries())n[i.name]=await O(i.schema,t[r],i.name);return n},A=async(e,t)=>{let n={};for(let r of e){let e=t[r.name];n[r.name]=await O(r.schema,e,r.name)}return n};var j=class{config;root=new h(this,``);commandHelper=new m;constructor(e){this.config=e}command(t,n){return new e(this.root.create(t,n))}async parse(e){let t=e??process.argv.slice(2),[n]=t;if(n||(this.printHelp(),process.exit(1)),a(n)){this.printHelp();return}if(o(n)){this.printVersion();return}let{command:r,rest:i}=this.commandHelper.resolve(this.root,t),[s]=i;if(!r){let e=this.createSuggestion(n);this.handleCliError(new v(this.formatUnknownCommandMessage(n,e)))}if(a(s)){this.commandHelper.printHelp(r,this.config);return}let c=r.handler;if(!c){if(r.commands.size>0){if(s!==void 0){let e=this.createSuggestion(s);this.handleCliError(new v(this.formatUnknownCommandMessage(s,e)))}this.commandHelper.printHelp(r,this.config);return}let e=this.commandHelper.path(r).join(` `);this.handleCliError(new y(`Command "${e}" has no action handler`))}try{let e=C(i,r.options);await c(await k(r.arguments,e.positional),await A(r.options,e.options))}catch(e){this.handleCliError(e)}}printVersion(){let e=this.config.version??`0.0.0`;console.log(e)}printHelp(){console.log(`Usage: ${this.config.name} <command> [options]\n`),p(this.config.description),console.log(`Commands:`);for(let e of c(this.root.commands))console.log(e);console.log(``),console.log(`Options:`);for(let e of d(n))console.log(e)}handleCliError(e){throw e instanceof g&&(console.error(e.message),process.exit(1)),e}createSuggestion(e){let t=E(this.commandHelper.readCommands(this.root),e);return t.length===0?``:t.length===1?`Did you mean ${t[0]}?`:t.reduce((e,n,r)=>{let i=e.concat(` ${n}`);return r!==t.length-1&&(i=i.concat(`
|
|
2
|
+
`)),i},`Did you mean
|
|
3
|
+
`)}formatUnknownCommandMessage(e,t){return t.length===0?`Unknown command: ${e}`:`Unknown command: ${e}\n${t}`}};export{j as CLI,y as CliConfigurationError,_ as CliValidationError,h as Command,b as MissingArgumentError,v as UnknownCommandError};
|
package/dist/lib/cron/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../errors/index.cjs");var t=class extends Error{constructor(e){super(e),this.name=`OutOfBoundError`}},n=class extends TypeError{constructor(e){super(e),this.name=`InvalidRetryError`}};const r=[`minute`,`hour`,`day`,`month`,`weekday`];var i=class{fields=[];add(e){this.fields.push(e)}read(){return this.fields}},a=class{wrapper;constructor(e){this.wrapper=e}any(){return this.wrapper.add({type:`any`}),this}range(e){return this.wrapper.add({type:`range`,...e}),this}step(e){return this.wrapper.add({type:`step`,...e}),this}number(e){return this.wrapper.add({type:`value`,value:e}),this}};function o(e){return{type:`range`,...e}}function s(){return{type:`any`}}function c(e){return{type:`step`,...e}}function l(e){let t=new i;return e(new a(t)),{type:`list`,values:t.read()}}function u(e){return{type:`value`,value:e}}function d(e){let t={minute:void 0,hour:void 0,day:void 0,month:void 0,weekday:void 0},n={minute(e){return t.minute=f(e),n},hour(e){return t.hour=f(e),n},day(e){return t.day=f(e),n},month(e){return t.month=f(e),n},weekday(e){return t.weekday=f(e),n}};return e(n),m(t)}function f(e){if(e.type===`list`){let{values:t}=e;if(t.length===0)throw Error(`EmptyListError: List expression cannot be empty`);return t.map(e=>p(e)).join(`,`)}return p(e)}function p(e){switch(e.type){case`any`:return`*`;case`value`:return`${e.value}`;case`range`:{let{min:n,max:r}=e;if(n>r)throw new t(`Expected ${n} <= ${r}`);return`${n}-${r}`}case`step`:{let{step:n,range:r}=e;if(n===0)throw new t(`Expected step value greater than zero`);if(!r)return`*/${n}`;let{min:i,max:a}=r;if(a===0){if(i>a)throw new t(`Expected max value greater than zero`);return`${i}-${a}/${n}`}if(!a)return`${i}/${n}`;if(i>a)throw new t(`Expected ${i} <= ${a}`);return`${i}-${a}/${n}`}default:return`*`}}function m(e){let t=[];for(let n=0;n<r.length;n++){let i=r[n];if(!i)return``;t.push(e[i]??`*`)}return t.join(` `)}const h={sun:0,mon:1,tue:2,wed:3,thu:4,fri:5,sat:6},g={jan:1,feb:2,mar:3,apr:4,may:5,jun:6,jul:7,aug:8,sep:9,oct:10,nov:11,dec:12};var _=class{constructor(){}};const v={"@yearly":`0 0 1 1 *`,"@annually":`0 0 1 1 *`,"@monthly":`0 0 1 * *`,"@weekly":`0 0 * * 0`,"@daily":`0 0 * * *`,"@midnight":`0 0 * * *`,"@hourly":`0 * * * *`,"@minutely":`* * * * *`};var y=class{getExpression(e){return v[e]||e}getJobName(e){return e.name}next(t,n){let{schedule:r}=t,i=this.getExpression(r),[a,o]=e.mightThrowSync(()=>Bun.cron.parse(i,n));if(a)throw a;return o}},b=class{options;jobs=new Map;constructor(e){if(this.options=e,!this.checkAttempts())throw new n(`Expected 'maxAttempts' to be a finite non-negative integer`)}async update(e){if(e.type===`add`){this.jobs.set(e.name,0);return}let t=this.jobs.get(e.name);if(t===void 0)return;if(e.type===`success`){this.jobs.set(e.name,0);return}let{job:n,error:r,name:i}=e,{maxAttempts:a}=this.options,o=this.runOnRetryError(r,i);if(t<a&&o){let n=this.calculateDelay(t);if(this.options.onFailedAttempt){let e={attemptNumber:t+1,delay:n,error:r,retriesLeft:a-t,jobName:i};await this.options.onFailedAttempt(e)}this.jobs.set(e.name,t+1),await this.runDelay(n);return}if(n.stop(),!this.options.onError)throw r;let s={name:i,error:r,failedAt:Date.now()};await this.options.onError(s)}checkAttempts(){let{maxAttempts:e}=this.options;return e>=0&&Number.isSafeInteger(e)&&!Object.is(e,-0)}runOnRetryError(e,t){return
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../errors/index.cjs");var t=class extends Error{constructor(e){super(e),this.name=`OutOfBoundError`}},n=class extends TypeError{constructor(e){super(e),this.name=`InvalidRetryError`}};const r=[`minute`,`hour`,`day`,`month`,`weekday`];var i=class{fields=[];add(e){this.fields.push(e)}read(){return this.fields}},a=class{wrapper;constructor(e){this.wrapper=e}any(){return this.wrapper.add({type:`any`}),this}range(e){return this.wrapper.add({type:`range`,...e}),this}step(e){return this.wrapper.add({type:`step`,...e}),this}number(e){return this.wrapper.add({type:`value`,value:e}),this}};function o(e){return{type:`range`,...e}}function s(){return{type:`any`}}function c(e){return{type:`step`,...e}}function l(e){let t=new i;return e(new a(t)),{type:`list`,values:t.read()}}function u(e){return{type:`value`,value:e}}function d(e){let t={minute:void 0,hour:void 0,day:void 0,month:void 0,weekday:void 0},n={minute(e){return t.minute=f(e),n},hour(e){return t.hour=f(e),n},day(e){return t.day=f(e),n},month(e){return t.month=f(e),n},weekday(e){return t.weekday=f(e),n}};return e(n),m(t)}function f(e){if(e.type===`list`){let{values:t}=e;if(t.length===0)throw Error(`EmptyListError: List expression cannot be empty`);return t.map(e=>p(e)).join(`,`)}return p(e)}function p(e){switch(e.type){case`any`:return`*`;case`value`:return`${e.value}`;case`range`:{let{min:n,max:r}=e;if(n>r)throw new t(`Expected ${n} <= ${r}`);return`${n}-${r}`}case`step`:{let{step:n,range:r}=e;if(n===0)throw new t(`Expected step value greater than zero`);if(!r)return`*/${n}`;let{min:i,max:a}=r;if(a===0){if(i>a)throw new t(`Expected max value greater than zero`);return`${i}-${a}/${n}`}if(!a)return`${i}/${n}`;if(i>a)throw new t(`Expected ${i} <= ${a}`);return`${i}-${a}/${n}`}default:return`*`}}function m(e){let t=[];for(let n=0;n<r.length;n++){let i=r[n];if(!i)return``;t.push(e[i]??`*`)}return t.join(` `)}const h={sun:0,mon:1,tue:2,wed:3,thu:4,fri:5,sat:6},g={jan:1,feb:2,mar:3,apr:4,may:5,jun:6,jul:7,aug:8,sep:9,oct:10,nov:11,dec:12};var _=class{constructor(){}};const v={"@yearly":`0 0 1 1 *`,"@annually":`0 0 1 1 *`,"@monthly":`0 0 1 * *`,"@weekly":`0 0 * * 0`,"@daily":`0 0 * * *`,"@midnight":`0 0 * * *`,"@hourly":`0 * * * *`,"@minutely":`* * * * *`};var y=class{getExpression(e){return v[e]||e}getJobName(e){return e.name}next(t,n){let{schedule:r}=t,i=this.getExpression(r),[a,o]=e.mightThrowSync(()=>Bun.cron.parse(i,n));if(a)throw a;return o}},b=class{options;jobs=new Map;constructor(e){if(this.options=e,!this.checkAttempts())throw new n(`Expected 'maxAttempts' to be a finite non-negative integer`)}async update(e){if(e.type===`add`){this.jobs.set(e.name,0);return}let t=this.jobs.get(e.name);if(t===void 0)return;if(e.type===`success`){this.jobs.set(e.name,0);return}let{job:n,error:r,name:i}=e,{maxAttempts:a}=this.options,o=this.runOnRetryError(r,i);if(t<a&&o){let n=this.calculateDelay(t);if(this.options.onFailedAttempt){let e={attemptNumber:t+1,delay:n,error:r,retriesLeft:a-t,jobName:i};await this.options.onFailedAttempt(e)}this.jobs.set(e.name,t+1),await this.runDelay(n);return}if(n.stop(),!this.options.onError)throw r;let s={name:i,error:r,failedAt:Date.now()};await this.options.onError(s)}checkAttempts(){let{maxAttempts:e}=this.options;return e>=0&&Number.isSafeInteger(e)&&!Object.is(e,-0)}runOnRetryError(e,t){return!this.options.retryOnError||this.options.retryOnError({error:e,jobName:t})}async runDelay(e){await new Promise(t=>setTimeout(t,e))}calculateDelay(e){let t=1e3*2**e;return Math.round(Math.random()*(Math.min(t,6e4)+1))}},x=class{listener=null;subscribe(e){this.listener=e}unsubscribe(){this.listener=null}async notify(e){this.listener&&await this.listener.update(e)}},S=class extends _{options;status;cron=null;manager;common;constructor(e){super(),this.options=e,this.status=`idle`,this.common=new y,this.options.retry&&(this.manager=new x,this.manager.subscribe(this.options.retry),this.manager.notify({type:`add`,name:this.getJobName()}))}[Symbol.dispose](){this.stop()}getStatus(){return this.status}run(){if(this.status===`running`)return;let{schedule:t,handler:n}=this.options,[r,i]=e.mightThrowSync(()=>{let r=this.common.getExpression(t);return Bun.cron(r,async()=>{let[t]=await e.mightThrow(Promise.resolve().then(()=>n()));if(!t)return this.manager&&await this.manager.notify({type:`success`,name:this.getJobName()}),Promise.resolve();if(this.manager){let e={type:`error`,error:t,job:this,name:this.getJobName()};await this.manager.notify(e);return}await Promise.reject(t)})});if(!r){this.status=`running`,this.cron=i;return}throw r}stop(){this.status===`running`&&this.cron&&(this.cron.stop(),this.status=`idle`)}ref(){this.status===`running`&&this.cron&&this.cron.ref()}unref(){this.status===`running`&&this.cron&&this.cron.unref()}getExpression(){return this.common.getExpression(this.options.schedule)}getJobName(){return this.common.getJobName(this.options)}next(e){return this.common.next(this.options,e)}},C=class{options;common;constructor(e){this.options=e,this.common=new y}async run(){let{path:e,schedule:t,name:n}=this.options,r=this.common.getExpression(t);await Bun.cron(e,r,n)}async stop(){await Bun.cron.remove(this.options.name)}getExpression(){return this.common.getExpression(this.options.schedule)}getJobName(){return this.common.getJobName(this.options)}next(e){return this.common.next(this.options,e)}};exports.Cron=S,exports.CronOS=C,exports.InvalidRetryError=n,exports.Month=g,exports.OutOfBoundError=t,exports.RetryCronJob=b,exports.WeekDay=h,exports.any=s,exports.cronJobBuilder=d,exports.list=l,exports.number=u,exports.range=o,exports.step=c;
|
package/dist/lib/cron/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{mightThrow as e,mightThrowSync as t}from"../errors/index.mjs";var n=class extends Error{constructor(e){super(e),this.name=`OutOfBoundError`}},r=class extends TypeError{constructor(e){super(e),this.name=`InvalidRetryError`}};const i=[`minute`,`hour`,`day`,`month`,`weekday`];var a=class{fields=[];add(e){this.fields.push(e)}read(){return this.fields}},o=class{wrapper;constructor(e){this.wrapper=e}any(){return this.wrapper.add({type:`any`}),this}range(e){return this.wrapper.add({type:`range`,...e}),this}step(e){return this.wrapper.add({type:`step`,...e}),this}number(e){return this.wrapper.add({type:`value`,value:e}),this}};function s(e){return{type:`range`,...e}}function c(){return{type:`any`}}function l(e){return{type:`step`,...e}}function u(e){let t=new a;return e(new o(t)),{type:`list`,values:t.read()}}function d(e){return{type:`value`,value:e}}function f(e){let t={minute:void 0,hour:void 0,day:void 0,month:void 0,weekday:void 0},n={minute(e){return t.minute=p(e),n},hour(e){return t.hour=p(e),n},day(e){return t.day=p(e),n},month(e){return t.month=p(e),n},weekday(e){return t.weekday=p(e),n}};return e(n),h(t)}function p(e){if(e.type===`list`){let{values:t}=e;if(t.length===0)throw Error(`EmptyListError: List expression cannot be empty`);return t.map(e=>m(e)).join(`,`)}return m(e)}function m(e){switch(e.type){case`any`:return`*`;case`value`:return`${e.value}`;case`range`:{let{min:t,max:r}=e;if(t>r)throw new n(`Expected ${t} <= ${r}`);return`${t}-${r}`}case`step`:{let{step:t,range:r}=e;if(t===0)throw new n(`Expected step value greater than zero`);if(!r)return`*/${t}`;let{min:i,max:a}=r;if(a===0){if(i>a)throw new n(`Expected max value greater than zero`);return`${i}-${a}/${t}`}if(!a)return`${i}/${t}`;if(i>a)throw new n(`Expected ${i} <= ${a}`);return`${i}-${a}/${t}`}default:return`*`}}function h(e){let t=[];for(let n=0;n<i.length;n++){let r=i[n];if(!r)return``;t.push(e[r]??`*`)}return t.join(` `)}const g={sun:0,mon:1,tue:2,wed:3,thu:4,fri:5,sat:6},_={jan:1,feb:2,mar:3,apr:4,may:5,jun:6,jul:7,aug:8,sep:9,oct:10,nov:11,dec:12};var v=class{constructor(){}};const y={"@yearly":`0 0 1 1 *`,"@annually":`0 0 1 1 *`,"@monthly":`0 0 1 * *`,"@weekly":`0 0 * * 0`,"@daily":`0 0 * * *`,"@midnight":`0 0 * * *`,"@hourly":`0 * * * *`,"@minutely":`* * * * *`};var b=class{getExpression(e){return y[e]||e}getJobName(e){return e.name}next(e,n){let{schedule:r}=e,i=this.getExpression(r),[a,o]=t(()=>Bun.cron.parse(i,n));if(a)throw a;return o}},x=class{options;jobs=new Map;constructor(e){if(this.options=e,!this.checkAttempts())throw new r(`Expected 'maxAttempts' to be a finite non-negative integer`)}async update(e){if(e.type===`add`){this.jobs.set(e.name,0);return}let t=this.jobs.get(e.name);if(t===void 0)return;if(e.type===`success`){this.jobs.set(e.name,0);return}let{job:n,error:r,name:i}=e,{maxAttempts:a}=this.options,o=this.runOnRetryError(r,i);if(t<a&&o){let n=this.calculateDelay(t);if(this.options.onFailedAttempt){let e={attemptNumber:t+1,delay:n,error:r,retriesLeft:a-t,jobName:i};await this.options.onFailedAttempt(e)}this.jobs.set(e.name,t+1),await this.runDelay(n);return}if(n.stop(),!this.options.onError)throw r;let s={name:i,error:r,failedAt:Date.now()};await this.options.onError(s)}checkAttempts(){let{maxAttempts:e}=this.options;return e>=0&&Number.isSafeInteger(e)&&!Object.is(e,-0)}runOnRetryError(e,t){return
|
|
1
|
+
import{mightThrow as e,mightThrowSync as t}from"../errors/index.mjs";var n=class extends Error{constructor(e){super(e),this.name=`OutOfBoundError`}},r=class extends TypeError{constructor(e){super(e),this.name=`InvalidRetryError`}};const i=[`minute`,`hour`,`day`,`month`,`weekday`];var a=class{fields=[];add(e){this.fields.push(e)}read(){return this.fields}},o=class{wrapper;constructor(e){this.wrapper=e}any(){return this.wrapper.add({type:`any`}),this}range(e){return this.wrapper.add({type:`range`,...e}),this}step(e){return this.wrapper.add({type:`step`,...e}),this}number(e){return this.wrapper.add({type:`value`,value:e}),this}};function s(e){return{type:`range`,...e}}function c(){return{type:`any`}}function l(e){return{type:`step`,...e}}function u(e){let t=new a;return e(new o(t)),{type:`list`,values:t.read()}}function d(e){return{type:`value`,value:e}}function f(e){let t={minute:void 0,hour:void 0,day:void 0,month:void 0,weekday:void 0},n={minute(e){return t.minute=p(e),n},hour(e){return t.hour=p(e),n},day(e){return t.day=p(e),n},month(e){return t.month=p(e),n},weekday(e){return t.weekday=p(e),n}};return e(n),h(t)}function p(e){if(e.type===`list`){let{values:t}=e;if(t.length===0)throw Error(`EmptyListError: List expression cannot be empty`);return t.map(e=>m(e)).join(`,`)}return m(e)}function m(e){switch(e.type){case`any`:return`*`;case`value`:return`${e.value}`;case`range`:{let{min:t,max:r}=e;if(t>r)throw new n(`Expected ${t} <= ${r}`);return`${t}-${r}`}case`step`:{let{step:t,range:r}=e;if(t===0)throw new n(`Expected step value greater than zero`);if(!r)return`*/${t}`;let{min:i,max:a}=r;if(a===0){if(i>a)throw new n(`Expected max value greater than zero`);return`${i}-${a}/${t}`}if(!a)return`${i}/${t}`;if(i>a)throw new n(`Expected ${i} <= ${a}`);return`${i}-${a}/${t}`}default:return`*`}}function h(e){let t=[];for(let n=0;n<i.length;n++){let r=i[n];if(!r)return``;t.push(e[r]??`*`)}return t.join(` `)}const g={sun:0,mon:1,tue:2,wed:3,thu:4,fri:5,sat:6},_={jan:1,feb:2,mar:3,apr:4,may:5,jun:6,jul:7,aug:8,sep:9,oct:10,nov:11,dec:12};var v=class{constructor(){}};const y={"@yearly":`0 0 1 1 *`,"@annually":`0 0 1 1 *`,"@monthly":`0 0 1 * *`,"@weekly":`0 0 * * 0`,"@daily":`0 0 * * *`,"@midnight":`0 0 * * *`,"@hourly":`0 * * * *`,"@minutely":`* * * * *`};var b=class{getExpression(e){return y[e]||e}getJobName(e){return e.name}next(e,n){let{schedule:r}=e,i=this.getExpression(r),[a,o]=t(()=>Bun.cron.parse(i,n));if(a)throw a;return o}},x=class{options;jobs=new Map;constructor(e){if(this.options=e,!this.checkAttempts())throw new r(`Expected 'maxAttempts' to be a finite non-negative integer`)}async update(e){if(e.type===`add`){this.jobs.set(e.name,0);return}let t=this.jobs.get(e.name);if(t===void 0)return;if(e.type===`success`){this.jobs.set(e.name,0);return}let{job:n,error:r,name:i}=e,{maxAttempts:a}=this.options,o=this.runOnRetryError(r,i);if(t<a&&o){let n=this.calculateDelay(t);if(this.options.onFailedAttempt){let e={attemptNumber:t+1,delay:n,error:r,retriesLeft:a-t,jobName:i};await this.options.onFailedAttempt(e)}this.jobs.set(e.name,t+1),await this.runDelay(n);return}if(n.stop(),!this.options.onError)throw r;let s={name:i,error:r,failedAt:Date.now()};await this.options.onError(s)}checkAttempts(){let{maxAttempts:e}=this.options;return e>=0&&Number.isSafeInteger(e)&&!Object.is(e,-0)}runOnRetryError(e,t){return!this.options.retryOnError||this.options.retryOnError({error:e,jobName:t})}async runDelay(e){await new Promise(t=>setTimeout(t,e))}calculateDelay(e){let t=1e3*2**e;return Math.round(Math.random()*(Math.min(t,6e4)+1))}},S=class{listener=null;subscribe(e){this.listener=e}unsubscribe(){this.listener=null}async notify(e){this.listener&&await this.listener.update(e)}},C=class extends v{options;status;cron=null;manager;common;constructor(e){super(),this.options=e,this.status=`idle`,this.common=new b,this.options.retry&&(this.manager=new S,this.manager.subscribe(this.options.retry),this.manager.notify({type:`add`,name:this.getJobName()}))}[Symbol.dispose](){this.stop()}getStatus(){return this.status}run(){if(this.status===`running`)return;let{schedule:n,handler:r}=this.options,[i,a]=t(()=>{let t=this.common.getExpression(n);return Bun.cron(t,async()=>{let[t]=await e(Promise.resolve().then(()=>r()));if(!t)return this.manager&&await this.manager.notify({type:`success`,name:this.getJobName()}),Promise.resolve();if(this.manager){let e={type:`error`,error:t,job:this,name:this.getJobName()};await this.manager.notify(e);return}await Promise.reject(t)})});if(!i){this.status=`running`,this.cron=a;return}throw i}stop(){this.status===`running`&&this.cron&&(this.cron.stop(),this.status=`idle`)}ref(){this.status===`running`&&this.cron&&this.cron.ref()}unref(){this.status===`running`&&this.cron&&this.cron.unref()}getExpression(){return this.common.getExpression(this.options.schedule)}getJobName(){return this.common.getJobName(this.options)}next(e){return this.common.next(this.options,e)}},w=class{options;common;constructor(e){this.options=e,this.common=new b}async run(){let{path:e,schedule:t,name:n}=this.options,r=this.common.getExpression(t);await Bun.cron(e,r,n)}async stop(){await Bun.cron.remove(this.options.name)}getExpression(){return this.common.getExpression(this.options.schedule)}getJobName(){return this.common.getJobName(this.options)}next(e){return this.common.next(this.options,e)}};export{C as Cron,w as CronOS,r as InvalidRetryError,_ as Month,n as OutOfBoundError,x as RetryCronJob,g as WeekDay,c as any,f as cronJobBuilder,u as list,d as number,s as range,l as step};
|
|
@@ -4,9 +4,9 @@ type BuildParamObject<T extends string, Acc = {}> = T extends `${infer _Start}{$
|
|
|
4
4
|
type IsString<T> = T extends string ? true : false;
|
|
5
5
|
type IsArray<T> = T extends readonly unknown[] ? true : false;
|
|
6
6
|
type IsObject<T> = T extends object ? T extends readonly unknown[] ? false : true : false;
|
|
7
|
-
type ArrayKeys<T extends readonly unknown[]> = { [K in keyof T & `${number}`]: `${K}
|
|
7
|
+
type ArrayKeys<T extends readonly unknown[]> = { [K in keyof T & `${number}`]: `${K}`; }[keyof T & `${number}`];
|
|
8
8
|
type ObjectPropertyKeys<K extends string, V> = IsString<V> extends true ? K : IsArray<V> extends true ? V extends readonly unknown[] ? `${K}.${NestedKeyOf<V>}` : never : IsObject<V> extends true ? `${K}.${NestedKeyOf<V>}` : never;
|
|
9
|
-
type NestedKeyOf<T> = IsArray<T> extends true ? T extends readonly unknown[] ? ArrayKeys<T> : never : IsObject<T> extends true ? { [K in keyof T & string]: ObjectPropertyKeys<K, T[K]
|
|
9
|
+
type NestedKeyOf<T> = IsArray<T> extends true ? T extends readonly unknown[] ? ArrayKeys<T> : never : IsObject<T> extends true ? { [K in keyof T & string]: ObjectPropertyKeys<K, T[K]>; }[keyof T & string] : never;
|
|
10
10
|
type GetNestedValue<T, K extends string> = K extends `${infer First}.${infer Rest}` ? First extends keyof T ? GetNestedValue<T[First], Rest> : never : K extends keyof T ? T[K] : never;
|
|
11
11
|
//#endregion
|
|
12
12
|
//#region src/lib/i18n/index.d.ts
|
package/dist/lib/orm/index.d.mts
CHANGED
|
@@ -112,9 +112,9 @@ type HasOne<T extends Table, TKey extends string = string> = {
|
|
|
112
112
|
type TableRelations = Record<string, HasMany<Table> | HasOne<Table>>;
|
|
113
113
|
type RelationsFor<T extends Record<string, Table>> = { [TTableName in keyof T]?: {
|
|
114
114
|
[key: string]: HasMany<Table> | HasOne<Table, keyof T[TTableName]["columns"] & string>;
|
|
115
|
-
} };
|
|
116
|
-
type Prettify<T> = { [TKey in keyof T]: T[TKey] } & {};
|
|
117
|
-
type ExactlyOne<T extends Record<PropertyKey, unknown>> = { [TKey in keyof T]: { [TSelected in TKey]-?: T[TSelected] } & { [TOmitted in Exclude<keyof T, TKey>]?: never } }[keyof T];
|
|
115
|
+
}; };
|
|
116
|
+
type Prettify<T> = { [TKey in keyof T]: T[TKey]; } & {};
|
|
117
|
+
type ExactlyOne<T extends Record<PropertyKey, unknown>> = { [TKey in keyof T]: { [TSelected in TKey]-?: T[TSelected]; } & { [TOmitted in Exclude<keyof T, TKey>]?: never; }; }[keyof T];
|
|
118
118
|
type OrmQueryOptions = {
|
|
119
119
|
$skipHooks?: boolean;
|
|
120
120
|
};
|
|
@@ -125,13 +125,13 @@ type CreateOrmOptions<T extends Record<string, Table> = Record<string, Table>, R
|
|
|
125
125
|
relations?: R;
|
|
126
126
|
hooks?: OrmHooksConfig<T, R>;
|
|
127
127
|
};
|
|
128
|
-
type RelationsForTableByType<TTable extends Table, TAllTables extends Record<string, Table>, TAllRelations> = { [K in keyof TAllTables]: TAllTables[K] extends TTable ? TTable extends TAllTables[K] ? K extends keyof TAllRelations ? NonNullable<TAllRelations[K]> : Record<never, never> : never : never }[keyof TAllTables] extends infer R ? [R] extends [TableRelations] ? R : Record<never, never> : Record<never, never>;
|
|
128
|
+
type RelationsForTableByType<TTable extends Table, TAllTables extends Record<string, Table>, TAllRelations> = { [K in keyof TAllTables]: TAllTables[K] extends TTable ? TTable extends TAllTables[K] ? K extends keyof TAllRelations ? NonNullable<TAllRelations[K]> : Record<never, never> : never : never; }[keyof TAllTables] extends (infer R) ? [R] extends [TableRelations] ? R : Record<never, never> : Record<never, never>;
|
|
129
129
|
type TableRelationsFor<TRelations, TTableName extends PropertyKey> = TTableName extends keyof TRelations ? NonNullable<TRelations[TTableName]> : Record<never, never>;
|
|
130
|
-
type OrmClient<T extends Record<string, Table> = Record<string, Table>, R extends RelationsFor<T> = RelationsFor<T>> = { [TTableName in keyof T]: TableClient<T[TTableName], TableRelationsFor<R, TTableName>, T, R
|
|
130
|
+
type OrmClient<T extends Record<string, Table> = Record<string, Table>, R extends RelationsFor<T> = RelationsFor<T>> = { [TTableName in keyof T]: TableClient<T[TTableName], TableRelationsFor<R, TTableName>, T, R>; } & {
|
|
131
131
|
$raw: Bun.SQL;
|
|
132
132
|
$transaction: <TResult>(callback: (tx: TransactionClient<T, R>) => Promise<TResult>) => Promise<TResult>;
|
|
133
133
|
};
|
|
134
|
-
type TransactionClient<T extends Record<string, Table>, R extends RelationsFor<T> = RelationsFor<T>> = { [TTableName in keyof T]: TableClient<T[TTableName], TableRelationsFor<R, TTableName>, T, R
|
|
134
|
+
type TransactionClient<T extends Record<string, Table>, R extends RelationsFor<T> = RelationsFor<T>> = { [TTableName in keyof T]: TableClient<T[TTableName], TableRelationsFor<R, TTableName>, T, R>; } & {
|
|
135
135
|
$raw: Bun.SQL;
|
|
136
136
|
};
|
|
137
137
|
type ColumnRuntimeValue<T extends Column> = T extends BaseColumn<boolean, boolean, boolean, boolean, infer TValue> ? TValue : never;
|
|
@@ -183,7 +183,7 @@ type ColumnWhereOperatorsMap<T extends Column> = {
|
|
|
183
183
|
};
|
|
184
184
|
type ColumnWhereOperators<T extends Column> = ColumnWhereOperatorsMap<T>[T["type"]];
|
|
185
185
|
type ColumnWhere<T extends Column> = ColumnRuntimeValue<T> extends object ? ColumnWhereOperators<T> : ColumnValue<T> | ColumnWhereOperators<T>;
|
|
186
|
-
type TableLogicalWhere<T extends Table, TRelations extends TableRelations = Record<never, never>> = { [TKey in "$or"]?: TableWhere<T, TRelations>[] } & { [TKey in "$and" | "$not"]?: TableWhere<T, TRelations> | TableWhere<T, TRelations>[] };
|
|
186
|
+
type TableLogicalWhere<T extends Table, TRelations extends TableRelations = Record<never, never>> = { [TKey in "$or"]?: TableWhere<T, TRelations>[]; } & { [TKey in "$and" | "$not"]?: TableWhere<T, TRelations> | TableWhere<T, TRelations>[]; };
|
|
187
187
|
type RelationWhereFilter<R extends HasMany<Table> | HasOne<Table>> = {
|
|
188
188
|
every?: TableWhere<RelationTable<R>>;
|
|
189
189
|
some?: TableWhere<RelationTable<R>>;
|
|
@@ -196,10 +196,10 @@ type RelationWhereFilter<R extends HasMany<Table> | HasOne<Table>> = {
|
|
|
196
196
|
none: TableWhere<RelationTable<R>>;
|
|
197
197
|
});
|
|
198
198
|
type IsOpenTableRelations<TRelations extends TableRelations> = string extends keyof TRelations ? true : false;
|
|
199
|
-
type TableRelationWhere<TRelations extends TableRelations> = IsOpenTableRelations<TRelations> extends true ? Record<never, never> : { [K in keyof TRelations]?: RelationWhereFilter<TRelations[K]
|
|
200
|
-
type TableWhere<T extends Table, TRelations extends TableRelations = Record<never, never>> = TableLogicalWhere<T, TRelations> & { [TColumnName in keyof T["columns"]]?: ColumnWhere<T["columns"][TColumnName]
|
|
201
|
-
type TableSelect<T extends Table> = { [TColumnName in keyof T["columns"]]?: true };
|
|
202
|
-
type TableOrderBy<T extends Table> = { [TColumnName in keyof T["columns"]]?: "asc" | "desc" };
|
|
199
|
+
type TableRelationWhere<TRelations extends TableRelations> = IsOpenTableRelations<TRelations> extends true ? Record<never, never> : { [K in keyof TRelations]?: RelationWhereFilter<TRelations[K]>; };
|
|
200
|
+
type TableWhere<T extends Table, TRelations extends TableRelations = Record<never, never>> = TableLogicalWhere<T, TRelations> & { [TColumnName in keyof T["columns"]]?: ColumnWhere<T["columns"][TColumnName]>; } & TableRelationWhere<TRelations>;
|
|
201
|
+
type TableSelect<T extends Table> = { [TColumnName in keyof T["columns"]]?: true; };
|
|
202
|
+
type TableOrderBy<T extends Table> = { [TColumnName in keyof T["columns"]]?: "asc" | "desc"; };
|
|
203
203
|
type RelationTable<R extends HasMany<Table> | HasOne<Table>> = R extends {
|
|
204
204
|
_table: infer T extends Table;
|
|
205
205
|
} ? T : never;
|
|
@@ -212,7 +212,7 @@ type RelationIncludeOptions<R extends HasMany<Table> | HasOne<Table>, TAllTables
|
|
|
212
212
|
select?: TableSelect<RelationTable<R>>;
|
|
213
213
|
include?: TableInclude<RelationTableRelations<R, TAllTables, TAllRelations>, TAllTables, TAllRelations>;
|
|
214
214
|
};
|
|
215
|
-
type TableInclude<TRelations extends TableRelations = TableRelations, TAllTables extends Record<string, Table> = Record<string, Table>, TAllRelations = Record<string, unknown>> = Partial<{ [K in keyof TRelations]: boolean | RelationIncludeOptions<TRelations[K], TAllTables, TAllRelations
|
|
215
|
+
type TableInclude<TRelations extends TableRelations = TableRelations, TAllTables extends Record<string, Table> = Record<string, Table>, TAllRelations = Record<string, unknown>> = Partial<{ [K in keyof TRelations]: boolean | RelationIncludeOptions<TRelations[K], TAllTables, TAllRelations>; }>;
|
|
216
216
|
type FindManyOptions<T extends Table, TRelations extends TableRelations = TableRelations, TAllTables extends Record<string, Table> = Record<string, Table>, TAllRelations = Record<string, unknown>> = OrmQueryOptions & {
|
|
217
217
|
where?: TableWhere<T, TRelations>;
|
|
218
218
|
select?: TableSelect<T>;
|
|
@@ -226,20 +226,20 @@ type TableColumns<T extends Table> = T["columns"];
|
|
|
226
226
|
type TableColumnByName<T extends Table, TColumnName extends keyof TableColumns<T>> = TableColumns<T>[TColumnName];
|
|
227
227
|
type IsUniqueColumn<TColumn extends Column> = TColumn["_meta"]["isPrimaryKey"] extends true ? true : TColumn["_meta"]["isUnique"];
|
|
228
228
|
type FindUniqueColumnValue<TColumn extends Column> = NonNullable<ColumnValue<TColumn>>;
|
|
229
|
-
type UniqueColumnKeys<T extends Table> = { [TColumnName in keyof TableColumns<T>]: IsUniqueColumn<TableColumnByName<T, TColumnName>> extends true ? TColumnName : never }[keyof TableColumns<T>];
|
|
230
|
-
type UniqueColumnWhereShape<T extends Table> = { [TColumnName in UniqueColumnKeys<T>]: FindUniqueColumnValue<TableColumnByName<T, TColumnName
|
|
229
|
+
type UniqueColumnKeys<T extends Table> = { [TColumnName in keyof TableColumns<T>]: IsUniqueColumn<TableColumnByName<T, TColumnName>> extends true ? TColumnName : never; }[keyof TableColumns<T>];
|
|
230
|
+
type UniqueColumnWhereShape<T extends Table> = { [TColumnName in UniqueColumnKeys<T>]: FindUniqueColumnValue<TableColumnByName<T, TColumnName>>; };
|
|
231
231
|
type NonUniqueColumnKeys<T extends Table> = Exclude<keyof TableColumns<T>, UniqueColumnKeys<T>>;
|
|
232
|
-
type FindUniqueWhere<T extends Table> = ExactlyOne<UniqueColumnWhereShape<T>> & { [TColumnName in NonUniqueColumnKeys<T>]?: ColumnWhere<TableColumnByName<T, TColumnName
|
|
232
|
+
type FindUniqueWhere<T extends Table> = ExactlyOne<UniqueColumnWhereShape<T>> & { [TColumnName in NonUniqueColumnKeys<T>]?: ColumnWhere<TableColumnByName<T, TColumnName>>; };
|
|
233
233
|
type FindUniqueOptions<T extends Table, TRelations extends TableRelations = TableRelations, TAllTables extends Record<string, Table> = Record<string, Table>, TAllRelations = Record<string, unknown>> = OrmQueryOptions & {
|
|
234
234
|
where: FindUniqueWhere<T>;
|
|
235
235
|
select?: TableSelect<T>;
|
|
236
236
|
include?: TableInclude<TRelations, TAllTables, TAllRelations>;
|
|
237
237
|
};
|
|
238
|
-
type TableRow<T extends Table> = Prettify<{ [TColumnName in keyof T["columns"]]: ColumnValue<T["columns"][TColumnName]
|
|
238
|
+
type TableRow<T extends Table> = Prettify<{ [TColumnName in keyof T["columns"]]: ColumnValue<T["columns"][TColumnName]>; }>;
|
|
239
239
|
type TableHookResult<T extends Table> = Prettify<Partial<TableRow<T>> & Record<string, unknown>>;
|
|
240
240
|
type IsRequiredCreateColumn<TColumn extends Column> = TColumn["_meta"]["isNullable"] extends false ? TColumn["_meta"]["hasDefault"] extends true ? false : true : false;
|
|
241
|
-
type CreateRequiredColumnKeys<T extends Table> = { [TColumnName in keyof TableColumns<T>]: IsRequiredCreateColumn<TableColumnByName<T, TColumnName>> extends true ? TColumnName : never }[keyof TableColumns<T>];
|
|
242
|
-
type CreateData<T extends Table> = Prettify<{ [TColumnName in CreateRequiredColumnKeys<T>]: ColumnValue<TableColumnByName<T, TColumnName
|
|
241
|
+
type CreateRequiredColumnKeys<T extends Table> = { [TColumnName in keyof TableColumns<T>]: IsRequiredCreateColumn<TableColumnByName<T, TColumnName>> extends true ? TColumnName : never; }[keyof TableColumns<T>];
|
|
242
|
+
type CreateData<T extends Table> = Prettify<{ [TColumnName in CreateRequiredColumnKeys<T>]: ColumnValue<TableColumnByName<T, TColumnName>>; } & { [TColumnName in Exclude<keyof TableColumns<T>, CreateRequiredColumnKeys<T>>]?: ColumnValue<TableColumnByName<T, TColumnName>>; }>;
|
|
243
243
|
type CreateOptions<T extends Table, TRelations extends TableRelations = TableRelations, TAllTables extends Record<string, Table> = Record<string, Table>, TAllRelations = Record<string, unknown>> = OrmQueryOptions & {
|
|
244
244
|
data: CreateData<T>;
|
|
245
245
|
select?: TableSelect<T>;
|
|
@@ -249,7 +249,7 @@ type CreateResult<T extends Table, TRelations extends TableRelations, TOptions e
|
|
|
249
249
|
select?: TableSelect<T>;
|
|
250
250
|
include?: TableInclude<TRelations, TAllTables, TAllRelations>;
|
|
251
251
|
}, TAllTables extends Record<string, Table> = Record<string, Table>, TAllRelations = Record<string, unknown>> = Prettify<SelectResult<T, TOptions> & IncludeResult<TRelations, TOptions, TAllTables, TAllRelations>>;
|
|
252
|
-
type UpdateData<T extends Table> = Partial<{ [TColumnName in keyof TableColumns<T>]: ColumnValue<TableColumnByName<T, TColumnName
|
|
252
|
+
type UpdateData<T extends Table> = Partial<{ [TColumnName in keyof TableColumns<T>]: ColumnValue<TableColumnByName<T, TColumnName>>; }>;
|
|
253
253
|
type UpdateOptions<T extends Table, TRelations extends TableRelations = TableRelations, TAllTables extends Record<string, Table> = Record<string, Table>, TAllRelations = Record<string, unknown>> = OrmQueryOptions & {
|
|
254
254
|
where: FindUniqueWhere<T>;
|
|
255
255
|
data: UpdateData<T>;
|
|
@@ -277,12 +277,12 @@ type UpdateManyOptions<T extends Table, TRelations extends TableRelations = Tabl
|
|
|
277
277
|
type DeleteManyOptions<T extends Table, TRelations extends TableRelations = TableRelations> = OrmQueryOptions & {
|
|
278
278
|
where?: TableWhere<T, TRelations>;
|
|
279
279
|
};
|
|
280
|
-
type IncludedKeys<TInclude> = keyof { [K in keyof TInclude as TInclude[K] extends false | undefined ? never : K]: unknown };
|
|
280
|
+
type IncludedKeys<TInclude> = keyof { [K in keyof TInclude as TInclude[K] extends false | undefined ? never : K]: unknown; };
|
|
281
281
|
type SelectResult<T extends Table, TOptions extends {
|
|
282
282
|
select?: TableSelect<T>;
|
|
283
283
|
}> = TOptions extends {
|
|
284
284
|
select: infer TSelect extends TableSelect<T>;
|
|
285
|
-
} ? [keyof TSelect] extends [never] ? TableRow<T> : { [K in keyof TSelect & keyof T["columns"]]: ColumnValue<T["columns"][K]
|
|
285
|
+
} ? [keyof TSelect] extends [never] ? TableRow<T> : { [K in keyof TSelect & keyof T["columns"]]: ColumnValue<T["columns"][K]>; } : TableRow<T>;
|
|
286
286
|
type RelationBaseRow<TTable extends Table, TIncludeValue> = TIncludeValue extends {
|
|
287
287
|
select: infer TSelect extends TableSelect<TTable>;
|
|
288
288
|
} ? SelectResult<TTable, {
|
|
@@ -296,7 +296,7 @@ type RelationRow<TTable extends Table, TIncludeValue, TAllTables extends Record<
|
|
|
296
296
|
type RelationResultType<R extends HasMany<Table> | HasOne<Table>, TIncludeValue, TAllTables extends Record<string, Table>, TAllRelations> = R extends HasMany<infer TTable> ? Array<RelationRow<TTable, TIncludeValue, TAllTables, TAllRelations>> : R extends HasOne<infer TTable> ? RelationRow<TTable, TIncludeValue, TAllTables, TAllRelations> | null : never;
|
|
297
297
|
type IncludeResult<TRelations extends TableRelations, TOptions extends {
|
|
298
298
|
include?: TableInclude<TRelations, TAllTables, TAllRelations>;
|
|
299
|
-
}, TAllTables extends Record<string, Table>, TAllRelations> = [keyof TRelations] extends [never] ? {} : TOptions["include"] extends TableInclude<TRelations, TAllTables, TAllRelations> ? { [K in IncludedKeys<NonNullable<TOptions["include"]>>]: K extends keyof TRelations ? RelationResultType<TRelations[K], NonNullable<TOptions["include"]>[K], TAllTables, TAllRelations> : never } : {};
|
|
299
|
+
}, TAllTables extends Record<string, Table>, TAllRelations> = [keyof TRelations] extends [never] ? {} : TOptions["include"] extends TableInclude<TRelations, TAllTables, TAllRelations> ? { [K in IncludedKeys<NonNullable<TOptions["include"]>>]: K extends keyof TRelations ? RelationResultType<TRelations[K], NonNullable<TOptions["include"]>[K], TAllTables, TAllRelations> : never; } : {};
|
|
300
300
|
type FindManyResult<T extends Table, TRelations extends TableRelations, TOptions extends FindManyOptions<T, TRelations, TAllTables, TAllRelations>, TAllTables extends Record<string, Table> = Record<string, Table>, TAllRelations = Record<string, unknown>> = Prettify<SelectResult<T, TOptions> & IncludeResult<TRelations, TOptions, TAllTables, TAllRelations>>;
|
|
301
301
|
type FindFirstResult<T extends Table, TRelations extends TableRelations, TOptions extends FindFirstOptions<T, TRelations, TAllTables, TAllRelations>, TAllTables extends Record<string, Table> = Record<string, Table>, TAllRelations = Record<string, unknown>> = Prettify<SelectResult<T, TOptions> & IncludeResult<TRelations, TOptions, TAllTables, TAllRelations>> | null;
|
|
302
302
|
type FindUniqueResult<T extends Table, TRelations extends TableRelations, TOptions extends FindUniqueOptions<T, TRelations, TAllTables, TAllRelations>, TAllTables extends Record<string, Table> = Record<string, Table>, TAllRelations = Record<string, unknown>> = Prettify<SelectResult<T, TOptions> & IncludeResult<TRelations, TOptions, TAllTables, TAllRelations>> | null;
|
|
@@ -374,7 +374,7 @@ type TableHooks<TTable extends Table, TRelations extends TableRelations = TableR
|
|
|
374
374
|
afterDeleteMany?: (ctx: OrmHookContext<DeleteManyOptions<TTable, TRelations>, Array<TableRow<TTable>>>) => void | Promise<void>;
|
|
375
375
|
};
|
|
376
376
|
type OrmHooksConfig<T extends Record<string, Table>, R extends RelationsFor<T> = RelationsFor<T>> = GlobalOrmHooks & {
|
|
377
|
-
tables?: { [K in keyof T]?: TableHooks<T[K], TableRelationsFor<R, K
|
|
377
|
+
tables?: { [K in keyof T]?: TableHooks<T[K], TableRelationsFor<R, K>>; };
|
|
378
378
|
};
|
|
379
379
|
type TableClient<T extends Table, TRelations extends TableRelations = TableRelations, TAllTables extends Record<string, Table> = Record<string, Table>, TAllRelations = Record<string, unknown>> = {
|
|
380
380
|
findMany<const TOptions extends FindManyOptions<T, TRelations, TAllTables, TAllRelations>>(options?: TOptions): Promise<Array<FindManyResult<T, TRelations, TOptions, TAllTables, TAllRelations>>>;
|
|
@@ -49,7 +49,7 @@ declare const isNullish: () => ConditionHelper<unknown>;
|
|
|
49
49
|
//#region src/lib/policy/types.d.ts
|
|
50
50
|
type Action = "read" | "create" | "update" | "delete" | (string & {});
|
|
51
51
|
type ConditionValue<V> = V extends Record<string, unknown> ? ConditionHelper<V> | Conditions<V> : ConditionHelper<V>;
|
|
52
|
-
type Conditions<T = Record<string, unknown>> = { [K in keyof T]?: ConditionValue<T[K]
|
|
52
|
+
type Conditions<T = Record<string, unknown>> = { [K in keyof T]?: ConditionValue<T[K]>; };
|
|
53
53
|
type PolicyRuleParams<T = Record<string, unknown>> = {
|
|
54
54
|
action: Action | Action[];
|
|
55
55
|
conditions?: Conditions<T>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../../rolldown-runtime-CMqjfN_6.cjs"),t=require("../errors/index.cjs");let n=require("node:assert");n=e.t(n,1);var r=class extends Error{constructor(e){super(e),this.name=`WorkflowError`}},i=class extends Error{constructor(e){super(e),this.name=`NotFoundError`}},a=class extends Error{constructor(e){super(e),this.name=`StateError`}},o=class extends Error{constructor(e){super(e),this.name=`SerializationError`}},s=class extends Error{constructor(e){super(e),this.name=`ExecutionError`}},c=class extends Error{constructor(e){super(e),this.name=`LockError`}},l=class extends Error{constructor(e){super(e),this.name=`CancelledError`}};const u=()=>Date.now(),d=async(e,t,n)=>{if(t.aborted)throw new l(`Workflow execution was aborted during retry backoff`);let r=u()+e;for(;u()<r;){if(t.aborted)throw new l(`Workflow execution was aborted during retry backoff`);if(n&&await n())throw new l(`Workflow execution was cancelled during retry backoff`);let e=r-u();await new Promise(t=>{setTimeout(t,Math.min(50,e))})}},f=e=>JSON.stringify({value:e}),p=e=>{let[n,r]=t.mightThrowSync(()=>JSON.parse(e));if(n)throw n;if(typeof r==`object`&&r&&`value`in r)return r.value},m=[`pending`,`running`,`completed`,`failed`,`cancelled`];var h=class{options;lockTTL;retries;retryBaseDelay;retryMultiplier;retryMaxDelay;constructor(e){this.options=e,this.lockTTL=e.lockTTL??3e5,this.retries=e.retries??3,this.retryBaseDelay=e.retryBackoff?.baseDelay??1e3,this.retryMultiplier=e.retryBackoff?.multiplier??2,this.retryMaxDelay=e.retryBackoff?.maxDelay??3e4,n.default.ok(Number.isFinite(this.retries)&&this.retries>=0,`Invalid retries: must be a non-negative finite number`),n.default.ok(Number.isFinite(this.retryBaseDelay)&&this.retryBaseDelay>0,`Invalid retryBackoff.baseDelay: must be a positive finite number`),n.default.ok(Number.isFinite(this.retryMultiplier)&&this.retryMultiplier>0,`Invalid retryBackoff.multiplier: must be a positive finite number`),n.default.ok(Number.isFinite(this.retryMaxDelay)&&this.retryMaxDelay>0,`Invalid retryBackoff.maxDelay: must be a positive finite number`)}runHook(e){return t.mightThrow(Promise.resolve().then(()=>e()))}computeBackoffDelay(e){return Math.min(this.retryBaseDelay*this.retryMultiplier**(e-1),this.retryMaxDelay)}async start(e,t){let n=t?.executionId??crypto.randomUUID();return await this.createExecution(n,e),this.execute(n,e)}async run(e,t){let n=await this.start(e,t);if(n.status===`cancelled`)throw new l(`Workflow execution ${n.executionId} was cancelled`);return(await this.get(n.executionId)).result}async resume(e){let t=await this.get(e);return t.status===`completed`||t.status===`cancelled`?{executionId:e,status:t.status}:this.execute(e,t.input)}async get(e){let t=await this.getMeta(e,`status`);if(!t)throw new i(`Workflow execution ${e} not found`);let n=this.normalizeStatus(t);if(!n)throw new a(`Workflow execution ${e} has invalid status ${t}`);let r=await this.readInput(e),o=await this.readResult(e),s=await this.readStepSnapshots(e),c=await this.readNumberMeta(e,`createdAt`),l=await this.readNumberMeta(e,`updatedAt`),u=await this.getMeta(e,`error`),d=await this.readNumberMeta(e,`completedAt`),f=await this.readNumberMeta(e,`failedAt`),p=await this.readNumberMeta(e,`cancelledAt`);if(c===null)throw new a(`Workflow execution ${e} is missing createdAt`);if(l===null)throw new a(`Workflow execution ${e} is missing updatedAt`);return{id:e,name:this.options.name,status:n,input:r,result:o,error:u,createdAt:c,updatedAt:l,completedAt:d,failedAt:f,cancelledAt:p,steps:s}}async cancel(e){let t=await this.get(e);if(t.status===`completed`)throw new a(`Workflow execution ${e} is already completed`);let n=u();return await this.setMeta(e,`status`,`cancelled`),await this.setMeta(e,`updatedAt`,String(n)),await this.setMeta(e,`cancelledAt`,String(n)),await this.setMeta(e,`error`,``),await this.setMeta(e,`failedAt`,``),{executionId:e,createdAt:t.createdAt,cancelledAt:n,updatedAt:n,status:`cancelled`}}executionKey(e){return`workflow:${this.options.name}:execution:${e}`}metaKey(e){return`${this.executionKey(e)}:meta`}stepsKey(e){return`${this.executionKey(e)}:steps`}lockKey(e){return`${this.executionKey(e)}:lock`}async createExecution(e,n){let i=this.serializeInput(n),o=u();if(await this.getMeta(e,`status`))throw new a(`Workflow execution ${e} already exists`);let s={status:`pending`,input:i,result:``,error:``,createdAt:String(o),updatedAt:String(o),completedAt:``,failedAt:``,cancelledAt:``,steps:`[]`},[c]=await t.mightThrow(this.options.redis.hset(this.metaKey(e),s));if(c)throw new r(`Unable to persist metadata for execution ${e}`)}async execute(e,n){let r=crypto.randomUUID();if(await this.acquireLock(e,r),await this.getMeta(e,`status`)===`cancelled`)throw await this.releaseLock(e,r),new a(`Workflow execution ${e} was cancelled`);let i=u();await this.setMeta(e,`status`,`running`),await this.setMeta(e,`updatedAt`,String(i));let l=new AbortController,d=Math.floor(this.lockTTL/3),f=!1,p=setInterval(async()=>{let[n]=await t.mightThrow(this.extendLock(e,r));n&&(f=!0,l.abort(),clearInterval(p))},d);this.options.hooks?.onStart&&await this.runHook(()=>this.options.hooks?.onStart?.({executionId:e,input:n}));let m=await t.mightThrow(Promise.resolve(this.options.handler({input:n,executionId:e,signal:l.signal,step:async(t,r)=>{await this.throwIfCancelled(e,()=>{l.abort()});let i=await this.readStepOutput(e,t);return i.found?i.value:this.runStepWithRetries(e,n,t,r,l.signal,()=>{l.abort()})}})));if(clearInterval(p),f)throw await this.releaseLock(e,r),new c(`Lock expired during execution ${e}`);if(await this.isCancelled(e)){let t=u();return await this.setMeta(e,`status`,`cancelled`),await this.setMeta(e,`updatedAt`,String(t)),await this.setMeta(e,`cancelledAt`,String(t)),this.options.hooks?.onCancel&&await this.runHook(()=>this.options.hooks?.onCancel?.({executionId:e,input:n})),await this.releaseLock(e,r),{executionId:e,status:`cancelled`}}let[h,g]=m;if(h){let t=u();throw await this.setMeta(e,`status`,`failed`),await this.setMeta(e,`error`,h.message),await this.setMeta(e,`updatedAt`,String(t)),await this.setMeta(e,`failedAt`,String(t)),await this.releaseLock(e,r),new s(`Workflow execution ${e} failed: ${h.message}`)}let[_,v]=t.mightThrowSync(()=>this.serializeResult(g));if(_){let t=u();throw await this.setMeta(e,`status`,`failed`),await this.setMeta(e,`error`,_.message),await this.setMeta(e,`updatedAt`,String(t)),await this.setMeta(e,`failedAt`,String(t)),await this.releaseLock(e,r),new o(`Unable to serialize workflow result for ${e}`)}let y=u();return await this.setMeta(e,`result`,v),await this.setMeta(e,`status`,`completed`),await this.setMeta(e,`error`,``),await this.setMeta(e,`failedAt`,``),await this.setMeta(e,`updatedAt`,String(y)),await this.setMeta(e,`completedAt`,String(y)),this.options.hooks?.onComplete&&await this.runHook(()=>this.options.hooks?.onComplete?.({executionId:e,input:n,result:g})),await this.releaseLock(e,r),{executionId:e,status:`completed`}}async throwIfCancelled(e,t){if(await this.isCancelled(e))throw t(),new l(`Workflow execution ${e} was cancelled`)}async runStepWithRetries(e,n,r,i,a,o){let s=1,c=[];for(;;){await this.throwIfCancelled(e,o);let[l,f]=await t.mightThrow(Promise.resolve(i(n,a)));if(!l)return await this.writeStepOutput(e,r,f),f;let p=l.message;if(c.push({attempt:s,error:p,timestamp:u()}),s<=this.retries){let i=this.computeBackoffDelay(s);this.options.hooks?.onRetry&&await this.runHook(()=>this.options.hooks?.onRetry?.({executionId:e,input:n,stepName:r,error:p,attempt:s,nextRetryDelayMs:i,retriesRemaining:this.retries-s}));let[o]=await t.mightThrow(d(i,a,()=>this.isCancelled(e)));if(o)throw o;s++;continue}throw this.options.hooks?.onError&&await this.runHook(()=>this.options.hooks?.onError?.({executionId:e,input:n,stepName:r,error:p,totalAttempts:s,errorHistory:c})),l}}async acquireLock(e,n){let[r,i]=await t.mightThrow(this.options.redis.set(this.lockKey(e),n,`PX`,String(this.lockTTL),`NX`));if(r)throw new c(`Unable to acquire lock for execution ${e}`);if(i!==`OK`)throw new c(`Workflow execution ${e} is already running`)}async releaseLock(e,n){await t.mightThrow(this.options.redis.send(`EVAL`,[`if redis.call('GET', KEYS[1]) == ARGV[1] then return redis.call('DEL', KEYS[1]) else return 0 end`,`1`,this.lockKey(e),n]))}async extendLock(e,n){let[r,i]=await t.mightThrow(this.options.redis.send(`EVAL`,[`if redis.call('GET', KEYS[1]) == ARGV[1] then return redis.call('PEXPIRE', KEYS[1], ARGV[2]) else return 0 end`,`1`,this.lockKey(e),n,String(this.lockTTL)]));if(r)throw new c(`Unable to extend lock for execution ${e}`);if(i===0)throw new c(`Lock ownership lost for execution ${e}`)}async isCancelled(e){return await this.getMeta(e,`status`)===`cancelled`}async setMeta(e,n,i){let[a]=await t.mightThrow(this.options.redis.hset(this.metaKey(e),n,i));if(a)throw new r(`Unable to persist ${n} for execution ${e}`)}async getMeta(e,n){let[i,o]=await t.mightThrow(this.options.redis.hget(this.metaKey(e),n));if(i)throw new r(`Unable to read ${n} for execution ${e}`);if(o==null)return null;if(typeof o!=`string`)throw new a(`Invalid ${n} value for execution ${e}`);return o.length===0?null:o}async readNumberMeta(e,t){let n=await this.getMeta(e,t);if(!n)return null;let r=Number(n);if(!Number.isFinite(r))throw new a(`Invalid ${t} value for execution ${e}`);return r}runSerializer(e,n,r){let[i,a]=t.mightThrowSync(()=>n(e));if(i)throw new o(`Unable to serialize ${r}: ${i.message}`);if(typeof a!=`string`)throw new o(`${r} serializer must return a string`);return a}runDeserializer(e,n,r){let i=t.mightThrowSync(()=>n(e));if(i[0])throw new o(`Unable to deserialize ${r}: ${i[0].message}`);return i[1]}serializeInput(e){return this.runSerializer(e,this.options.serializeInput??f,`workflow input`)}deserializeInput(e){let t=this.options.deserializeInput??(e=>p(e));return this.runDeserializer(e,t,`workflow input`)}serializeResult(e){return e===null?f(null):this.runSerializer(e,this.options.serializeResult??f,`workflow result`)}deserializeResult(e){let t=this.options.deserializeResult??(e=>p(e));return this.runDeserializer(e,t,`workflow result`)}serializeStepOutput(e){return this.runSerializer(e,this.options.serializeStepOutput??f,`step output`)}deserializeStepOutput(e){let t=this.options.deserializeStepOutput??(e=>p(e));return this.runDeserializer(e,t,`step output`)}async readInput(e){let t=await this.getMeta(e,`input`);if(!t)throw new a(`Workflow execution ${e} input not found`);return this.deserializeInput(t)}async readResult(e){let t=await this.getMeta(e,`result`);return t?this.deserializeResult(t):null}async writeStepOutput(e,n,i){let a={output:this.serializeStepOutput(i),completedAt:u()},[s,c]=t.mightThrowSync(()=>JSON.stringify(a));if(s||typeof c!=`string`)throw new o(`Unable to persist step ${n} output`);let[l]=await t.mightThrow(this.options.redis.hset(this.stepsKey(e),n,c));if(l)throw new r(`Unable to persist step ${n} for execution ${e}`);let d=await this.readStepNames(e);if(!d.includes(n)){let r=[...d,n],[i,a]=t.mightThrowSync(()=>JSON.stringify(r));if(i||typeof a!=`string`)throw new o(`Unable to persist step history for execution ${e}`);await this.setMeta(e,`steps`,a)}await this.setMeta(e,`updatedAt`,String(u()))}async readStepOutput(e,n){let[i,o]=await t.mightThrow(this.options.redis.hget(this.stepsKey(e),n));if(i)throw new r(`Unable to read step ${n} for execution ${e}`);if(!o)return{found:!1,value:null};if(typeof o!=`string`)throw new a(`Invalid step payload for ${n} in execution ${e}`);let[s,c]=t.mightThrowSync(()=>JSON.parse(o));if(s||typeof c!=`object`||!c)throw new a(`Invalid step payload for ${n} in execution ${e}`);if(typeof c.output!=`string`)throw new a(`Invalid step output for ${n} in execution ${e}`);let l=c.output;return{found:!0,value:this.deserializeStepOutput(l)}}async readStepNames(e){let n=await this.getMeta(e,`steps`);if(!n)return[];let[r,i]=t.mightThrowSync(()=>JSON.parse(n));if(r||!Array.isArray(i))throw new a(`Invalid step index for execution ${e}`);let o=[];for(let e of i)typeof e==`string`&&o.push(e);return o}async readStepSnapshots(e){let n=await this.readStepNames(e),i=[];for(let o of n){let[n,s]=await t.mightThrow(this.options.redis.hget(this.stepsKey(e),o));if(n)throw new r(`Unable to read step ${o} for execution ${e}`);if(!s)continue;if(typeof s!=`string`)throw new a(`Invalid step payload for ${o} in execution ${e}`);let[c,l]=t.mightThrowSync(()=>JSON.parse(s));if(c||typeof l!=`object`||!l||typeof l.completedAt!=`number`)throw new a(`Invalid step payload for ${o} in execution ${e}`);i.push({name:o,completedAt:l.completedAt})}return i}normalizeStatus(e){for(let t of m)if(t===e)return t;return null}};const g=e=>{let t=new h(e);return{start:(e,n)=>t.start(e,n),run:(e,n)=>t.run(e,n),resume:e=>t.resume(e),get:e=>t.get(e),cancel:e=>t.cancel(e)}};exports.CancelledError=l,exports.ExecutionError=s,exports.LockError=c,exports.NotFoundError=i,exports.SerializationError=o,exports.StateError=a,exports.WorkflowError=r,exports.defineWorkflow=g;
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../../rolldown-runtime-CMqjfN_6.cjs"),t=require("../errors/index.cjs");let n=require("node:assert");n=e.t(n,1);var r=class extends Error{constructor(e){super(e),this.name=`WorkflowError`}},i=class extends Error{constructor(e){super(e),this.name=`NotFoundError`}},a=class extends Error{constructor(e){super(e),this.name=`StateError`}},o=class extends Error{constructor(e){super(e),this.name=`SerializationError`}},s=class extends Error{constructor(e){super(e),this.name=`ExecutionError`}},c=class extends Error{constructor(e){super(e),this.name=`LockError`}},l=class extends Error{constructor(e){super(e),this.name=`CancelledError`}};const u=()=>Date.now(),d=async(e,t,n)=>{if(t.aborted)throw new l(`Workflow execution was aborted during retry backoff`);let r=u()+e;for(;u()<r;){if(t.aborted)throw new l(`Workflow execution was aborted during retry backoff`);if(n&&await n())throw new l(`Workflow execution was cancelled during retry backoff`);let e=r-u();await new Promise(t=>{setTimeout(t,Math.min(50,e))})}},f=e=>JSON.stringify({value:e}),p=e=>{let[n,r]=t.mightThrowSync(()=>JSON.parse(e));if(n)throw n;if(typeof r==`object`&&r&&`value`in r)return r.value},m=[`pending`,`running`,`completed`,`failed`,`cancelled`];var h=class{options;lockTTL;retries;retryBaseDelay;retryMultiplier;retryMaxDelay;constructor(e){this.options=e,this.lockTTL=e.lockTTL??3e5,this.retries=e.retries??3,this.retryBaseDelay=e.retryBackoff?.baseDelay??1e3,this.retryMultiplier=e.retryBackoff?.multiplier??2,this.retryMaxDelay=e.retryBackoff?.maxDelay??3e4,n.default.ok(Number.isFinite(this.retries)&&this.retries>=0,`Invalid retries: must be a non-negative finite number`),n.default.ok(Number.isFinite(this.retryBaseDelay)&&this.retryBaseDelay>0,`Invalid retryBackoff.baseDelay: must be a positive finite number`),n.default.ok(Number.isFinite(this.retryMultiplier)&&this.retryMultiplier>0,`Invalid retryBackoff.multiplier: must be a positive finite number`),n.default.ok(Number.isFinite(this.retryMaxDelay)&&this.retryMaxDelay>0,`Invalid retryBackoff.maxDelay: must be a positive finite number`)}runHook(e){return t.mightThrow(Promise.resolve().then(()=>e()))}computeBackoffDelay(e){return Math.min(this.retryBaseDelay*this.retryMultiplier**(e-1),this.retryMaxDelay)}async start(e,t){let n=t?.executionId??crypto.randomUUID();return await this.createExecution(n,e),this.scheduleExecution(n,e),{executionId:n,status:`pending`}}async resume(e){let t=await this.get(e);return t.status===`completed`||t.status===`cancelled`?{executionId:e,status:t.status}:(this.scheduleExecution(e,t.input),{executionId:e,status:`pending`})}async get(e){let t=await this.getMeta(e,`status`);if(!t)throw new i(`Workflow execution ${e} not found`);let n=this.normalizeStatus(t);if(!n)throw new a(`Workflow execution ${e} has invalid status ${t}`);let r=await this.readInput(e),o=await this.readResult(e),s=await this.readStepSnapshots(e),c=await this.readNumberMeta(e,`createdAt`),l=await this.readNumberMeta(e,`updatedAt`),u=await this.getMeta(e,`error`),d=await this.readNumberMeta(e,`completedAt`),f=await this.readNumberMeta(e,`failedAt`),p=await this.readNumberMeta(e,`cancelledAt`);if(c===null)throw new a(`Workflow execution ${e} is missing createdAt`);if(l===null)throw new a(`Workflow execution ${e} is missing updatedAt`);return{id:e,name:this.options.name,status:n,input:r,result:o,error:u,createdAt:c,updatedAt:l,completedAt:d,failedAt:f,cancelledAt:p,steps:s}}async cancel(e){let t=await this.get(e);if(t.status===`completed`)throw new a(`Workflow execution ${e} is already completed`);let n=u();return await this.setMeta(e,`status`,`cancelled`),await this.setMeta(e,`updatedAt`,String(n)),await this.setMeta(e,`cancelledAt`,String(n)),await this.setMeta(e,`error`,``),await this.setMeta(e,`failedAt`,``),{executionId:e,createdAt:t.createdAt,cancelledAt:n,updatedAt:n,status:`cancelled`}}executionKey(e){return`workflow:${this.options.name}:execution:${e}`}metaKey(e){return`${this.executionKey(e)}:meta`}stepsKey(e){return`${this.executionKey(e)}:steps`}lockKey(e){return`${this.executionKey(e)}:lock`}async createExecution(e,n){let i=this.serializeInput(n),o=u();if(await this.getMeta(e,`status`))throw new a(`Workflow execution ${e} already exists`);let s={status:`pending`,input:i,result:``,error:``,createdAt:String(o),updatedAt:String(o),completedAt:``,failedAt:``,cancelledAt:``,steps:`[]`},[c]=await t.mightThrow(this.options.redis.hset(this.metaKey(e),s));if(c)throw new r(`Unable to persist metadata for execution ${e}`)}scheduleExecution(e,t){queueMicrotask(()=>{this.executeInBackground(e,t)})}async executeInBackground(e,n){let[r]=await t.mightThrow(this.execute(e,n));if(!r)return;let[i]=await t.mightThrow(this.recordBackgroundFailure(e,r));i&&console.error(`Unable to record background workflow failure`,{executionId:e,error:i})}async recordBackgroundFailure(e,t){if(await this.getMeta(e,`status`)!==`pending`)return;let n=u();await this.setMeta(e,`status`,`failed`),await this.setMeta(e,`error`,t.message),await this.setMeta(e,`updatedAt`,String(n)),await this.setMeta(e,`failedAt`,String(n))}async execute(e,n){let r=crypto.randomUUID();if(await this.acquireLock(e,r),await this.getMeta(e,`status`)===`cancelled`)throw await this.releaseLock(e,r),new a(`Workflow execution ${e} was cancelled`);let i=u();await this.setMeta(e,`status`,`running`),await this.setMeta(e,`updatedAt`,String(i));let l=new AbortController,d=Math.floor(this.lockTTL/3),f=!1,p=setInterval(async()=>{let[n]=await t.mightThrow(this.extendLock(e,r));n&&(f=!0,l.abort(),clearInterval(p))},d);this.options.hooks?.onStart&&await this.runHook(()=>this.options.hooks?.onStart?.({executionId:e,input:n}));let m=await t.mightThrow(Promise.resolve(this.options.handler({input:n,executionId:e,signal:l.signal,step:async(t,r)=>{await this.throwIfCancelled(e,()=>{l.abort()});let i=await this.readStepOutput(e,t);return i.found?i.value:this.runStepWithRetries(e,n,t,r,l.signal,()=>{l.abort()})}})));if(clearInterval(p),f)throw await this.releaseLock(e,r),new c(`Lock expired during execution ${e}`);if(await this.isCancelled(e)){let t=u();return await this.setMeta(e,`status`,`cancelled`),await this.setMeta(e,`updatedAt`,String(t)),await this.setMeta(e,`cancelledAt`,String(t)),this.options.hooks?.onCancel&&await this.runHook(()=>this.options.hooks?.onCancel?.({executionId:e,input:n})),await this.releaseLock(e,r),{executionId:e,status:`cancelled`}}let[h,g]=m;if(h){let t=u();throw await this.setMeta(e,`status`,`failed`),await this.setMeta(e,`error`,h.message),await this.setMeta(e,`updatedAt`,String(t)),await this.setMeta(e,`failedAt`,String(t)),await this.releaseLock(e,r),new s(`Workflow execution ${e} failed: ${h.message}`)}let[_,v]=t.mightThrowSync(()=>this.serializeResult(g));if(_){let t=u();throw await this.setMeta(e,`status`,`failed`),await this.setMeta(e,`error`,_.message),await this.setMeta(e,`updatedAt`,String(t)),await this.setMeta(e,`failedAt`,String(t)),await this.releaseLock(e,r),new o(`Unable to serialize workflow result for ${e}`)}let y=u();return await this.setMeta(e,`result`,v),await this.setMeta(e,`status`,`completed`),await this.setMeta(e,`error`,``),await this.setMeta(e,`failedAt`,``),await this.setMeta(e,`updatedAt`,String(y)),await this.setMeta(e,`completedAt`,String(y)),this.options.hooks?.onComplete&&await this.runHook(()=>this.options.hooks?.onComplete?.({executionId:e,input:n,result:g})),await this.releaseLock(e,r),{executionId:e,status:`completed`}}async throwIfCancelled(e,t){if(await this.isCancelled(e))throw t(),new l(`Workflow execution ${e} was cancelled`)}async runStepWithRetries(e,n,r,i,a,o){let s=1,c=[];for(;;){await this.throwIfCancelled(e,o);let[l,f]=await t.mightThrow(Promise.resolve(i(n,a)));if(!l)return await this.writeStepOutput(e,r,f),f;let p=l.message;if(c.push({attempt:s,error:p,timestamp:u()}),s<=this.retries){let i=this.computeBackoffDelay(s);this.options.hooks?.onRetry&&await this.runHook(()=>this.options.hooks?.onRetry?.({executionId:e,input:n,stepName:r,error:p,attempt:s,nextRetryDelayMs:i,retriesRemaining:this.retries-s}));let[o]=await t.mightThrow(d(i,a,()=>this.isCancelled(e)));if(o)throw o;s++;continue}throw this.options.hooks?.onError&&await this.runHook(()=>this.options.hooks?.onError?.({executionId:e,input:n,stepName:r,error:p,totalAttempts:s,errorHistory:c})),l}}async acquireLock(e,n){let[r,i]=await t.mightThrow(this.options.redis.set(this.lockKey(e),n,`PX`,String(this.lockTTL),`NX`));if(r)throw new c(`Unable to acquire lock for execution ${e}`);if(i!==`OK`)throw new c(`Workflow execution ${e} is already running`)}async releaseLock(e,n){await t.mightThrow(this.options.redis.send(`EVAL`,[`if redis.call('GET', KEYS[1]) == ARGV[1] then return redis.call('DEL', KEYS[1]) else return 0 end`,`1`,this.lockKey(e),n]))}async extendLock(e,n){let[r,i]=await t.mightThrow(this.options.redis.send(`EVAL`,[`if redis.call('GET', KEYS[1]) == ARGV[1] then return redis.call('PEXPIRE', KEYS[1], ARGV[2]) else return 0 end`,`1`,this.lockKey(e),n,String(this.lockTTL)]));if(r)throw new c(`Unable to extend lock for execution ${e}`);if(i===0)throw new c(`Lock ownership lost for execution ${e}`)}async isCancelled(e){return await this.getMeta(e,`status`)===`cancelled`}async setMeta(e,n,i){let[a]=await t.mightThrow(this.options.redis.hset(this.metaKey(e),n,i));if(a)throw new r(`Unable to persist ${n} for execution ${e}`)}async getMeta(e,n){let[i,o]=await t.mightThrow(this.options.redis.hget(this.metaKey(e),n));if(i)throw new r(`Unable to read ${n} for execution ${e}`);if(o==null)return null;if(typeof o!=`string`)throw new a(`Invalid ${n} value for execution ${e}`);return o.length===0?null:o}async readNumberMeta(e,t){let n=await this.getMeta(e,t);if(!n)return null;let r=Number(n);if(!Number.isFinite(r))throw new a(`Invalid ${t} value for execution ${e}`);return r}runSerializer(e,n,r){let[i,a]=t.mightThrowSync(()=>n(e));if(i)throw new o(`Unable to serialize ${r}: ${i.message}`);if(typeof a!=`string`)throw new o(`${r} serializer must return a string`);return a}runDeserializer(e,n,r){let i=t.mightThrowSync(()=>n(e));if(i[0])throw new o(`Unable to deserialize ${r}: ${i[0].message}`);return i[1]}serializeInput(e){return this.runSerializer(e,this.options.serializeInput??f,`workflow input`)}deserializeInput(e){let t=this.options.deserializeInput??(e=>p(e));return this.runDeserializer(e,t,`workflow input`)}serializeResult(e){return e===null?f(null):this.runSerializer(e,this.options.serializeResult??f,`workflow result`)}deserializeResult(e){let t=this.options.deserializeResult??(e=>p(e));return this.runDeserializer(e,t,`workflow result`)}serializeStepOutput(e){return this.runSerializer(e,this.options.serializeStepOutput??f,`step output`)}deserializeStepOutput(e){let t=this.options.deserializeStepOutput??(e=>p(e));return this.runDeserializer(e,t,`step output`)}async readInput(e){let t=await this.getMeta(e,`input`);if(!t)throw new a(`Workflow execution ${e} input not found`);return this.deserializeInput(t)}async readResult(e){let t=await this.getMeta(e,`result`);return t?this.deserializeResult(t):null}async writeStepOutput(e,n,i){let a={output:this.serializeStepOutput(i),completedAt:u()},[s,c]=t.mightThrowSync(()=>JSON.stringify(a));if(s||typeof c!=`string`)throw new o(`Unable to persist step ${n} output`);let[l]=await t.mightThrow(this.options.redis.hset(this.stepsKey(e),n,c));if(l)throw new r(`Unable to persist step ${n} for execution ${e}`);let d=await this.readStepNames(e);if(!d.includes(n)){let r=[...d,n],[i,a]=t.mightThrowSync(()=>JSON.stringify(r));if(i||typeof a!=`string`)throw new o(`Unable to persist step history for execution ${e}`);await this.setMeta(e,`steps`,a)}await this.setMeta(e,`updatedAt`,String(u()))}async readStepOutput(e,n){let[i,o]=await t.mightThrow(this.options.redis.hget(this.stepsKey(e),n));if(i)throw new r(`Unable to read step ${n} for execution ${e}`);if(!o)return{found:!1,value:null};if(typeof o!=`string`)throw new a(`Invalid step payload for ${n} in execution ${e}`);let[s,c]=t.mightThrowSync(()=>JSON.parse(o));if(s||typeof c!=`object`||!c)throw new a(`Invalid step payload for ${n} in execution ${e}`);if(typeof c.output!=`string`)throw new a(`Invalid step output for ${n} in execution ${e}`);let l=c.output;return{found:!0,value:this.deserializeStepOutput(l)}}async readStepNames(e){let n=await this.getMeta(e,`steps`);if(!n)return[];let[r,i]=t.mightThrowSync(()=>JSON.parse(n));if(r||!Array.isArray(i))throw new a(`Invalid step index for execution ${e}`);let o=[];for(let e of i)typeof e==`string`&&o.push(e);return o}async readStepSnapshots(e){let n=await this.readStepNames(e),i=[];for(let o of n){let[n,s]=await t.mightThrow(this.options.redis.hget(this.stepsKey(e),o));if(n)throw new r(`Unable to read step ${o} for execution ${e}`);if(!s)continue;if(typeof s!=`string`)throw new a(`Invalid step payload for ${o} in execution ${e}`);let[c,l]=t.mightThrowSync(()=>JSON.parse(s));if(c||typeof l!=`object`||!l||typeof l.completedAt!=`number`)throw new a(`Invalid step payload for ${o} in execution ${e}`);i.push({name:o,completedAt:l.completedAt})}return i}normalizeStatus(e){for(let t of m)if(t===e)return t;return null}};const g=e=>{let t=new h(e);return{start:(e,n)=>t.start(e,n),resume:e=>t.resume(e),get:e=>t.get(e),cancel:e=>t.cancel(e)}};exports.CancelledError=l,exports.ExecutionError=s,exports.LockError=c,exports.NotFoundError=i,exports.SerializationError=o,exports.StateError=a,exports.WorkflowError=r,exports.defineWorkflow=g;
|
|
@@ -115,7 +115,6 @@ type WorkflowMeta = {
|
|
|
115
115
|
type WorkflowMetaField = keyof WorkflowMeta;
|
|
116
116
|
type Workflow<TInput, TResult> = {
|
|
117
117
|
start: (input: TInput, options?: WorkflowStartOptions) => Promise<WorkflowStartResult>;
|
|
118
|
-
run: (input: TInput, options?: WorkflowStartOptions) => Promise<TResult | null>;
|
|
119
118
|
resume: (executionId: string) => Promise<WorkflowStartResult>;
|
|
120
119
|
get: (executionId: string) => Promise<WorkflowExecution<TInput, TResult>>;
|
|
121
120
|
cancel: (executionId: string) => Promise<WorkflowCancelResult>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{mightThrow as e,mightThrowSync as t}from"../errors/index.mjs";import n from"node:assert";var r=class extends Error{constructor(e){super(e),this.name=`WorkflowError`}},i=class extends Error{constructor(e){super(e),this.name=`NotFoundError`}},a=class extends Error{constructor(e){super(e),this.name=`StateError`}},o=class extends Error{constructor(e){super(e),this.name=`SerializationError`}},s=class extends Error{constructor(e){super(e),this.name=`ExecutionError`}},c=class extends Error{constructor(e){super(e),this.name=`LockError`}},l=class extends Error{constructor(e){super(e),this.name=`CancelledError`}};const u=()=>Date.now(),d=async(e,t,n)=>{if(t.aborted)throw new l(`Workflow execution was aborted during retry backoff`);let r=u()+e;for(;u()<r;){if(t.aborted)throw new l(`Workflow execution was aborted during retry backoff`);if(n&&await n())throw new l(`Workflow execution was cancelled during retry backoff`);let e=r-u();await new Promise(t=>{setTimeout(t,Math.min(50,e))})}},f=e=>JSON.stringify({value:e}),p=e=>{let[n,r]=t(()=>JSON.parse(e));if(n)throw n;if(typeof r==`object`&&r&&`value`in r)return r.value},m=[`pending`,`running`,`completed`,`failed`,`cancelled`];var h=class{options;lockTTL;retries;retryBaseDelay;retryMultiplier;retryMaxDelay;constructor(e){this.options=e,this.lockTTL=e.lockTTL??3e5,this.retries=e.retries??3,this.retryBaseDelay=e.retryBackoff?.baseDelay??1e3,this.retryMultiplier=e.retryBackoff?.multiplier??2,this.retryMaxDelay=e.retryBackoff?.maxDelay??3e4,n.ok(Number.isFinite(this.retries)&&this.retries>=0,`Invalid retries: must be a non-negative finite number`),n.ok(Number.isFinite(this.retryBaseDelay)&&this.retryBaseDelay>0,`Invalid retryBackoff.baseDelay: must be a positive finite number`),n.ok(Number.isFinite(this.retryMultiplier)&&this.retryMultiplier>0,`Invalid retryBackoff.multiplier: must be a positive finite number`),n.ok(Number.isFinite(this.retryMaxDelay)&&this.retryMaxDelay>0,`Invalid retryBackoff.maxDelay: must be a positive finite number`)}runHook(t){return e(Promise.resolve().then(()=>t()))}computeBackoffDelay(e){return Math.min(this.retryBaseDelay*this.retryMultiplier**(e-1),this.retryMaxDelay)}async start(e,t){let n=t?.executionId??crypto.randomUUID();return await this.createExecution(n,e),this.execute(n,e)}async run(e,t){let n=await this.start(e,t);if(n.status===`cancelled`)throw new l(`Workflow execution ${n.executionId} was cancelled`);return(await this.get(n.executionId)).result}async resume(e){let t=await this.get(e);return t.status===`completed`||t.status===`cancelled`?{executionId:e,status:t.status}:this.execute(e,t.input)}async get(e){let t=await this.getMeta(e,`status`);if(!t)throw new i(`Workflow execution ${e} not found`);let n=this.normalizeStatus(t);if(!n)throw new a(`Workflow execution ${e} has invalid status ${t}`);let r=await this.readInput(e),o=await this.readResult(e),s=await this.readStepSnapshots(e),c=await this.readNumberMeta(e,`createdAt`),l=await this.readNumberMeta(e,`updatedAt`),u=await this.getMeta(e,`error`),d=await this.readNumberMeta(e,`completedAt`),f=await this.readNumberMeta(e,`failedAt`),p=await this.readNumberMeta(e,`cancelledAt`);if(c===null)throw new a(`Workflow execution ${e} is missing createdAt`);if(l===null)throw new a(`Workflow execution ${e} is missing updatedAt`);return{id:e,name:this.options.name,status:n,input:r,result:o,error:u,createdAt:c,updatedAt:l,completedAt:d,failedAt:f,cancelledAt:p,steps:s}}async cancel(e){let t=await this.get(e);if(t.status===`completed`)throw new a(`Workflow execution ${e} is already completed`);let n=u();return await this.setMeta(e,`status`,`cancelled`),await this.setMeta(e,`updatedAt`,String(n)),await this.setMeta(e,`cancelledAt`,String(n)),await this.setMeta(e,`error`,``),await this.setMeta(e,`failedAt`,``),{executionId:e,createdAt:t.createdAt,cancelledAt:n,updatedAt:n,status:`cancelled`}}executionKey(e){return`workflow:${this.options.name}:execution:${e}`}metaKey(e){return`${this.executionKey(e)}:meta`}stepsKey(e){return`${this.executionKey(e)}:steps`}lockKey(e){return`${this.executionKey(e)}:lock`}async createExecution(t,n){let i=this.serializeInput(n),o=u();if(await this.getMeta(t,`status`))throw new a(`Workflow execution ${t} already exists`);let s={status:`pending`,input:i,result:``,error:``,createdAt:String(o),updatedAt:String(o),completedAt:``,failedAt:``,cancelledAt:``,steps:`[]`},[c]=await e(this.options.redis.hset(this.metaKey(t),s));if(c)throw new r(`Unable to persist metadata for execution ${t}`)}async execute(n,r){let i=crypto.randomUUID();if(await this.acquireLock(n,i),await this.getMeta(n,`status`)===`cancelled`)throw await this.releaseLock(n,i),new a(`Workflow execution ${n} was cancelled`);let l=u();await this.setMeta(n,`status`,`running`),await this.setMeta(n,`updatedAt`,String(l));let d=new AbortController,f=Math.floor(this.lockTTL/3),p=!1,m=setInterval(async()=>{let[t]=await e(this.extendLock(n,i));t&&(p=!0,d.abort(),clearInterval(m))},f);this.options.hooks?.onStart&&await this.runHook(()=>this.options.hooks?.onStart?.({executionId:n,input:r}));let h=await e(Promise.resolve(this.options.handler({input:r,executionId:n,signal:d.signal,step:async(e,t)=>{await this.throwIfCancelled(n,()=>{d.abort()});let i=await this.readStepOutput(n,e);return i.found?i.value:this.runStepWithRetries(n,r,e,t,d.signal,()=>{d.abort()})}})));if(clearInterval(m),p)throw await this.releaseLock(n,i),new c(`Lock expired during execution ${n}`);if(await this.isCancelled(n)){let e=u();return await this.setMeta(n,`status`,`cancelled`),await this.setMeta(n,`updatedAt`,String(e)),await this.setMeta(n,`cancelledAt`,String(e)),this.options.hooks?.onCancel&&await this.runHook(()=>this.options.hooks?.onCancel?.({executionId:n,input:r})),await this.releaseLock(n,i),{executionId:n,status:`cancelled`}}let[g,_]=h;if(g){let e=u();throw await this.setMeta(n,`status`,`failed`),await this.setMeta(n,`error`,g.message),await this.setMeta(n,`updatedAt`,String(e)),await this.setMeta(n,`failedAt`,String(e)),await this.releaseLock(n,i),new s(`Workflow execution ${n} failed: ${g.message}`)}let[v,y]=t(()=>this.serializeResult(_));if(v){let e=u();throw await this.setMeta(n,`status`,`failed`),await this.setMeta(n,`error`,v.message),await this.setMeta(n,`updatedAt`,String(e)),await this.setMeta(n,`failedAt`,String(e)),await this.releaseLock(n,i),new o(`Unable to serialize workflow result for ${n}`)}let b=u();return await this.setMeta(n,`result`,y),await this.setMeta(n,`status`,`completed`),await this.setMeta(n,`error`,``),await this.setMeta(n,`failedAt`,``),await this.setMeta(n,`updatedAt`,String(b)),await this.setMeta(n,`completedAt`,String(b)),this.options.hooks?.onComplete&&await this.runHook(()=>this.options.hooks?.onComplete?.({executionId:n,input:r,result:_})),await this.releaseLock(n,i),{executionId:n,status:`completed`}}async throwIfCancelled(e,t){if(await this.isCancelled(e))throw t(),new l(`Workflow execution ${e} was cancelled`)}async runStepWithRetries(t,n,r,i,a,o){let s=1,c=[];for(;;){await this.throwIfCancelled(t,o);let[l,f]=await e(Promise.resolve(i(n,a)));if(!l)return await this.writeStepOutput(t,r,f),f;let p=l.message;if(c.push({attempt:s,error:p,timestamp:u()}),s<=this.retries){let i=this.computeBackoffDelay(s);this.options.hooks?.onRetry&&await this.runHook(()=>this.options.hooks?.onRetry?.({executionId:t,input:n,stepName:r,error:p,attempt:s,nextRetryDelayMs:i,retriesRemaining:this.retries-s}));let[o]=await e(d(i,a,()=>this.isCancelled(t)));if(o)throw o;s++;continue}throw this.options.hooks?.onError&&await this.runHook(()=>this.options.hooks?.onError?.({executionId:t,input:n,stepName:r,error:p,totalAttempts:s,errorHistory:c})),l}}async acquireLock(t,n){let[r,i]=await e(this.options.redis.set(this.lockKey(t),n,`PX`,String(this.lockTTL),`NX`));if(r)throw new c(`Unable to acquire lock for execution ${t}`);if(i!==`OK`)throw new c(`Workflow execution ${t} is already running`)}async releaseLock(t,n){await e(this.options.redis.send(`EVAL`,[`if redis.call('GET', KEYS[1]) == ARGV[1] then return redis.call('DEL', KEYS[1]) else return 0 end`,`1`,this.lockKey(t),n]))}async extendLock(t,n){let[r,i]=await e(this.options.redis.send(`EVAL`,[`if redis.call('GET', KEYS[1]) == ARGV[1] then return redis.call('PEXPIRE', KEYS[1], ARGV[2]) else return 0 end`,`1`,this.lockKey(t),n,String(this.lockTTL)]));if(r)throw new c(`Unable to extend lock for execution ${t}`);if(i===0)throw new c(`Lock ownership lost for execution ${t}`)}async isCancelled(e){return await this.getMeta(e,`status`)===`cancelled`}async setMeta(t,n,i){let[a]=await e(this.options.redis.hset(this.metaKey(t),n,i));if(a)throw new r(`Unable to persist ${n} for execution ${t}`)}async getMeta(t,n){let[i,o]=await e(this.options.redis.hget(this.metaKey(t),n));if(i)throw new r(`Unable to read ${n} for execution ${t}`);if(o==null)return null;if(typeof o!=`string`)throw new a(`Invalid ${n} value for execution ${t}`);return o.length===0?null:o}async readNumberMeta(e,t){let n=await this.getMeta(e,t);if(!n)return null;let r=Number(n);if(!Number.isFinite(r))throw new a(`Invalid ${t} value for execution ${e}`);return r}runSerializer(e,n,r){let[i,a]=t(()=>n(e));if(i)throw new o(`Unable to serialize ${r}: ${i.message}`);if(typeof a!=`string`)throw new o(`${r} serializer must return a string`);return a}runDeserializer(e,n,r){let i=t(()=>n(e));if(i[0])throw new o(`Unable to deserialize ${r}: ${i[0].message}`);return i[1]}serializeInput(e){return this.runSerializer(e,this.options.serializeInput??f,`workflow input`)}deserializeInput(e){let t=this.options.deserializeInput??(e=>p(e));return this.runDeserializer(e,t,`workflow input`)}serializeResult(e){return e===null?f(null):this.runSerializer(e,this.options.serializeResult??f,`workflow result`)}deserializeResult(e){let t=this.options.deserializeResult??(e=>p(e));return this.runDeserializer(e,t,`workflow result`)}serializeStepOutput(e){return this.runSerializer(e,this.options.serializeStepOutput??f,`step output`)}deserializeStepOutput(e){let t=this.options.deserializeStepOutput??(e=>p(e));return this.runDeserializer(e,t,`step output`)}async readInput(e){let t=await this.getMeta(e,`input`);if(!t)throw new a(`Workflow execution ${e} input not found`);return this.deserializeInput(t)}async readResult(e){let t=await this.getMeta(e,`result`);return t?this.deserializeResult(t):null}async writeStepOutput(n,i,a){let s={output:this.serializeStepOutput(a),completedAt:u()},[c,l]=t(()=>JSON.stringify(s));if(c||typeof l!=`string`)throw new o(`Unable to persist step ${i} output`);let[d]=await e(this.options.redis.hset(this.stepsKey(n),i,l));if(d)throw new r(`Unable to persist step ${i} for execution ${n}`);let f=await this.readStepNames(n);if(!f.includes(i)){let e=[...f,i],[r,a]=t(()=>JSON.stringify(e));if(r||typeof a!=`string`)throw new o(`Unable to persist step history for execution ${n}`);await this.setMeta(n,`steps`,a)}await this.setMeta(n,`updatedAt`,String(u()))}async readStepOutput(n,i){let[o,s]=await e(this.options.redis.hget(this.stepsKey(n),i));if(o)throw new r(`Unable to read step ${i} for execution ${n}`);if(!s)return{found:!1,value:null};if(typeof s!=`string`)throw new a(`Invalid step payload for ${i} in execution ${n}`);let[c,l]=t(()=>JSON.parse(s));if(c||typeof l!=`object`||!l)throw new a(`Invalid step payload for ${i} in execution ${n}`);if(typeof l.output!=`string`)throw new a(`Invalid step output for ${i} in execution ${n}`);let u=l.output;return{found:!0,value:this.deserializeStepOutput(u)}}async readStepNames(e){let n=await this.getMeta(e,`steps`);if(!n)return[];let[r,i]=t(()=>JSON.parse(n));if(r||!Array.isArray(i))throw new a(`Invalid step index for execution ${e}`);let o=[];for(let e of i)typeof e==`string`&&o.push(e);return o}async readStepSnapshots(n){let i=await this.readStepNames(n),o=[];for(let s of i){let[i,c]=await e(this.options.redis.hget(this.stepsKey(n),s));if(i)throw new r(`Unable to read step ${s} for execution ${n}`);if(!c)continue;if(typeof c!=`string`)throw new a(`Invalid step payload for ${s} in execution ${n}`);let[l,u]=t(()=>JSON.parse(c));if(l||typeof u!=`object`||!u||typeof u.completedAt!=`number`)throw new a(`Invalid step payload for ${s} in execution ${n}`);o.push({name:s,completedAt:u.completedAt})}return o}normalizeStatus(e){for(let t of m)if(t===e)return t;return null}};const g=e=>{let t=new h(e);return{start:(e,n)=>t.start(e,n),run:(e,n)=>t.run(e,n),resume:e=>t.resume(e),get:e=>t.get(e),cancel:e=>t.cancel(e)}};export{l as CancelledError,s as ExecutionError,c as LockError,i as NotFoundError,o as SerializationError,a as StateError,r as WorkflowError,g as defineWorkflow};
|
|
1
|
+
import{mightThrow as e,mightThrowSync as t}from"../errors/index.mjs";import n from"node:assert";var r=class extends Error{constructor(e){super(e),this.name=`WorkflowError`}},i=class extends Error{constructor(e){super(e),this.name=`NotFoundError`}},a=class extends Error{constructor(e){super(e),this.name=`StateError`}},o=class extends Error{constructor(e){super(e),this.name=`SerializationError`}},s=class extends Error{constructor(e){super(e),this.name=`ExecutionError`}},c=class extends Error{constructor(e){super(e),this.name=`LockError`}},l=class extends Error{constructor(e){super(e),this.name=`CancelledError`}};const u=()=>Date.now(),d=async(e,t,n)=>{if(t.aborted)throw new l(`Workflow execution was aborted during retry backoff`);let r=u()+e;for(;u()<r;){if(t.aborted)throw new l(`Workflow execution was aborted during retry backoff`);if(n&&await n())throw new l(`Workflow execution was cancelled during retry backoff`);let e=r-u();await new Promise(t=>{setTimeout(t,Math.min(50,e))})}},f=e=>JSON.stringify({value:e}),p=e=>{let[n,r]=t(()=>JSON.parse(e));if(n)throw n;if(typeof r==`object`&&r&&`value`in r)return r.value},m=[`pending`,`running`,`completed`,`failed`,`cancelled`];var h=class{options;lockTTL;retries;retryBaseDelay;retryMultiplier;retryMaxDelay;constructor(e){this.options=e,this.lockTTL=e.lockTTL??3e5,this.retries=e.retries??3,this.retryBaseDelay=e.retryBackoff?.baseDelay??1e3,this.retryMultiplier=e.retryBackoff?.multiplier??2,this.retryMaxDelay=e.retryBackoff?.maxDelay??3e4,n.ok(Number.isFinite(this.retries)&&this.retries>=0,`Invalid retries: must be a non-negative finite number`),n.ok(Number.isFinite(this.retryBaseDelay)&&this.retryBaseDelay>0,`Invalid retryBackoff.baseDelay: must be a positive finite number`),n.ok(Number.isFinite(this.retryMultiplier)&&this.retryMultiplier>0,`Invalid retryBackoff.multiplier: must be a positive finite number`),n.ok(Number.isFinite(this.retryMaxDelay)&&this.retryMaxDelay>0,`Invalid retryBackoff.maxDelay: must be a positive finite number`)}runHook(t){return e(Promise.resolve().then(()=>t()))}computeBackoffDelay(e){return Math.min(this.retryBaseDelay*this.retryMultiplier**(e-1),this.retryMaxDelay)}async start(e,t){let n=t?.executionId??crypto.randomUUID();return await this.createExecution(n,e),this.scheduleExecution(n,e),{executionId:n,status:`pending`}}async resume(e){let t=await this.get(e);return t.status===`completed`||t.status===`cancelled`?{executionId:e,status:t.status}:(this.scheduleExecution(e,t.input),{executionId:e,status:`pending`})}async get(e){let t=await this.getMeta(e,`status`);if(!t)throw new i(`Workflow execution ${e} not found`);let n=this.normalizeStatus(t);if(!n)throw new a(`Workflow execution ${e} has invalid status ${t}`);let r=await this.readInput(e),o=await this.readResult(e),s=await this.readStepSnapshots(e),c=await this.readNumberMeta(e,`createdAt`),l=await this.readNumberMeta(e,`updatedAt`),u=await this.getMeta(e,`error`),d=await this.readNumberMeta(e,`completedAt`),f=await this.readNumberMeta(e,`failedAt`),p=await this.readNumberMeta(e,`cancelledAt`);if(c===null)throw new a(`Workflow execution ${e} is missing createdAt`);if(l===null)throw new a(`Workflow execution ${e} is missing updatedAt`);return{id:e,name:this.options.name,status:n,input:r,result:o,error:u,createdAt:c,updatedAt:l,completedAt:d,failedAt:f,cancelledAt:p,steps:s}}async cancel(e){let t=await this.get(e);if(t.status===`completed`)throw new a(`Workflow execution ${e} is already completed`);let n=u();return await this.setMeta(e,`status`,`cancelled`),await this.setMeta(e,`updatedAt`,String(n)),await this.setMeta(e,`cancelledAt`,String(n)),await this.setMeta(e,`error`,``),await this.setMeta(e,`failedAt`,``),{executionId:e,createdAt:t.createdAt,cancelledAt:n,updatedAt:n,status:`cancelled`}}executionKey(e){return`workflow:${this.options.name}:execution:${e}`}metaKey(e){return`${this.executionKey(e)}:meta`}stepsKey(e){return`${this.executionKey(e)}:steps`}lockKey(e){return`${this.executionKey(e)}:lock`}async createExecution(t,n){let i=this.serializeInput(n),o=u();if(await this.getMeta(t,`status`))throw new a(`Workflow execution ${t} already exists`);let s={status:`pending`,input:i,result:``,error:``,createdAt:String(o),updatedAt:String(o),completedAt:``,failedAt:``,cancelledAt:``,steps:`[]`},[c]=await e(this.options.redis.hset(this.metaKey(t),s));if(c)throw new r(`Unable to persist metadata for execution ${t}`)}scheduleExecution(e,t){queueMicrotask(()=>{this.executeInBackground(e,t)})}async executeInBackground(t,n){let[r]=await e(this.execute(t,n));if(!r)return;let[i]=await e(this.recordBackgroundFailure(t,r));i&&console.error(`Unable to record background workflow failure`,{executionId:t,error:i})}async recordBackgroundFailure(e,t){if(await this.getMeta(e,`status`)!==`pending`)return;let n=u();await this.setMeta(e,`status`,`failed`),await this.setMeta(e,`error`,t.message),await this.setMeta(e,`updatedAt`,String(n)),await this.setMeta(e,`failedAt`,String(n))}async execute(n,r){let i=crypto.randomUUID();if(await this.acquireLock(n,i),await this.getMeta(n,`status`)===`cancelled`)throw await this.releaseLock(n,i),new a(`Workflow execution ${n} was cancelled`);let l=u();await this.setMeta(n,`status`,`running`),await this.setMeta(n,`updatedAt`,String(l));let d=new AbortController,f=Math.floor(this.lockTTL/3),p=!1,m=setInterval(async()=>{let[t]=await e(this.extendLock(n,i));t&&(p=!0,d.abort(),clearInterval(m))},f);this.options.hooks?.onStart&&await this.runHook(()=>this.options.hooks?.onStart?.({executionId:n,input:r}));let h=await e(Promise.resolve(this.options.handler({input:r,executionId:n,signal:d.signal,step:async(e,t)=>{await this.throwIfCancelled(n,()=>{d.abort()});let i=await this.readStepOutput(n,e);return i.found?i.value:this.runStepWithRetries(n,r,e,t,d.signal,()=>{d.abort()})}})));if(clearInterval(m),p)throw await this.releaseLock(n,i),new c(`Lock expired during execution ${n}`);if(await this.isCancelled(n)){let e=u();return await this.setMeta(n,`status`,`cancelled`),await this.setMeta(n,`updatedAt`,String(e)),await this.setMeta(n,`cancelledAt`,String(e)),this.options.hooks?.onCancel&&await this.runHook(()=>this.options.hooks?.onCancel?.({executionId:n,input:r})),await this.releaseLock(n,i),{executionId:n,status:`cancelled`}}let[g,_]=h;if(g){let e=u();throw await this.setMeta(n,`status`,`failed`),await this.setMeta(n,`error`,g.message),await this.setMeta(n,`updatedAt`,String(e)),await this.setMeta(n,`failedAt`,String(e)),await this.releaseLock(n,i),new s(`Workflow execution ${n} failed: ${g.message}`)}let[v,y]=t(()=>this.serializeResult(_));if(v){let e=u();throw await this.setMeta(n,`status`,`failed`),await this.setMeta(n,`error`,v.message),await this.setMeta(n,`updatedAt`,String(e)),await this.setMeta(n,`failedAt`,String(e)),await this.releaseLock(n,i),new o(`Unable to serialize workflow result for ${n}`)}let b=u();return await this.setMeta(n,`result`,y),await this.setMeta(n,`status`,`completed`),await this.setMeta(n,`error`,``),await this.setMeta(n,`failedAt`,``),await this.setMeta(n,`updatedAt`,String(b)),await this.setMeta(n,`completedAt`,String(b)),this.options.hooks?.onComplete&&await this.runHook(()=>this.options.hooks?.onComplete?.({executionId:n,input:r,result:_})),await this.releaseLock(n,i),{executionId:n,status:`completed`}}async throwIfCancelled(e,t){if(await this.isCancelled(e))throw t(),new l(`Workflow execution ${e} was cancelled`)}async runStepWithRetries(t,n,r,i,a,o){let s=1,c=[];for(;;){await this.throwIfCancelled(t,o);let[l,f]=await e(Promise.resolve(i(n,a)));if(!l)return await this.writeStepOutput(t,r,f),f;let p=l.message;if(c.push({attempt:s,error:p,timestamp:u()}),s<=this.retries){let i=this.computeBackoffDelay(s);this.options.hooks?.onRetry&&await this.runHook(()=>this.options.hooks?.onRetry?.({executionId:t,input:n,stepName:r,error:p,attempt:s,nextRetryDelayMs:i,retriesRemaining:this.retries-s}));let[o]=await e(d(i,a,()=>this.isCancelled(t)));if(o)throw o;s++;continue}throw this.options.hooks?.onError&&await this.runHook(()=>this.options.hooks?.onError?.({executionId:t,input:n,stepName:r,error:p,totalAttempts:s,errorHistory:c})),l}}async acquireLock(t,n){let[r,i]=await e(this.options.redis.set(this.lockKey(t),n,`PX`,String(this.lockTTL),`NX`));if(r)throw new c(`Unable to acquire lock for execution ${t}`);if(i!==`OK`)throw new c(`Workflow execution ${t} is already running`)}async releaseLock(t,n){await e(this.options.redis.send(`EVAL`,[`if redis.call('GET', KEYS[1]) == ARGV[1] then return redis.call('DEL', KEYS[1]) else return 0 end`,`1`,this.lockKey(t),n]))}async extendLock(t,n){let[r,i]=await e(this.options.redis.send(`EVAL`,[`if redis.call('GET', KEYS[1]) == ARGV[1] then return redis.call('PEXPIRE', KEYS[1], ARGV[2]) else return 0 end`,`1`,this.lockKey(t),n,String(this.lockTTL)]));if(r)throw new c(`Unable to extend lock for execution ${t}`);if(i===0)throw new c(`Lock ownership lost for execution ${t}`)}async isCancelled(e){return await this.getMeta(e,`status`)===`cancelled`}async setMeta(t,n,i){let[a]=await e(this.options.redis.hset(this.metaKey(t),n,i));if(a)throw new r(`Unable to persist ${n} for execution ${t}`)}async getMeta(t,n){let[i,o]=await e(this.options.redis.hget(this.metaKey(t),n));if(i)throw new r(`Unable to read ${n} for execution ${t}`);if(o==null)return null;if(typeof o!=`string`)throw new a(`Invalid ${n} value for execution ${t}`);return o.length===0?null:o}async readNumberMeta(e,t){let n=await this.getMeta(e,t);if(!n)return null;let r=Number(n);if(!Number.isFinite(r))throw new a(`Invalid ${t} value for execution ${e}`);return r}runSerializer(e,n,r){let[i,a]=t(()=>n(e));if(i)throw new o(`Unable to serialize ${r}: ${i.message}`);if(typeof a!=`string`)throw new o(`${r} serializer must return a string`);return a}runDeserializer(e,n,r){let i=t(()=>n(e));if(i[0])throw new o(`Unable to deserialize ${r}: ${i[0].message}`);return i[1]}serializeInput(e){return this.runSerializer(e,this.options.serializeInput??f,`workflow input`)}deserializeInput(e){let t=this.options.deserializeInput??(e=>p(e));return this.runDeserializer(e,t,`workflow input`)}serializeResult(e){return e===null?f(null):this.runSerializer(e,this.options.serializeResult??f,`workflow result`)}deserializeResult(e){let t=this.options.deserializeResult??(e=>p(e));return this.runDeserializer(e,t,`workflow result`)}serializeStepOutput(e){return this.runSerializer(e,this.options.serializeStepOutput??f,`step output`)}deserializeStepOutput(e){let t=this.options.deserializeStepOutput??(e=>p(e));return this.runDeserializer(e,t,`step output`)}async readInput(e){let t=await this.getMeta(e,`input`);if(!t)throw new a(`Workflow execution ${e} input not found`);return this.deserializeInput(t)}async readResult(e){let t=await this.getMeta(e,`result`);return t?this.deserializeResult(t):null}async writeStepOutput(n,i,a){let s={output:this.serializeStepOutput(a),completedAt:u()},[c,l]=t(()=>JSON.stringify(s));if(c||typeof l!=`string`)throw new o(`Unable to persist step ${i} output`);let[d]=await e(this.options.redis.hset(this.stepsKey(n),i,l));if(d)throw new r(`Unable to persist step ${i} for execution ${n}`);let f=await this.readStepNames(n);if(!f.includes(i)){let e=[...f,i],[r,a]=t(()=>JSON.stringify(e));if(r||typeof a!=`string`)throw new o(`Unable to persist step history for execution ${n}`);await this.setMeta(n,`steps`,a)}await this.setMeta(n,`updatedAt`,String(u()))}async readStepOutput(n,i){let[o,s]=await e(this.options.redis.hget(this.stepsKey(n),i));if(o)throw new r(`Unable to read step ${i} for execution ${n}`);if(!s)return{found:!1,value:null};if(typeof s!=`string`)throw new a(`Invalid step payload for ${i} in execution ${n}`);let[c,l]=t(()=>JSON.parse(s));if(c||typeof l!=`object`||!l)throw new a(`Invalid step payload for ${i} in execution ${n}`);if(typeof l.output!=`string`)throw new a(`Invalid step output for ${i} in execution ${n}`);let u=l.output;return{found:!0,value:this.deserializeStepOutput(u)}}async readStepNames(e){let n=await this.getMeta(e,`steps`);if(!n)return[];let[r,i]=t(()=>JSON.parse(n));if(r||!Array.isArray(i))throw new a(`Invalid step index for execution ${e}`);let o=[];for(let e of i)typeof e==`string`&&o.push(e);return o}async readStepSnapshots(n){let i=await this.readStepNames(n),o=[];for(let s of i){let[i,c]=await e(this.options.redis.hget(this.stepsKey(n),s));if(i)throw new r(`Unable to read step ${s} for execution ${n}`);if(!c)continue;if(typeof c!=`string`)throw new a(`Invalid step payload for ${s} in execution ${n}`);let[l,u]=t(()=>JSON.parse(c));if(l||typeof u!=`object`||!u||typeof u.completedAt!=`number`)throw new a(`Invalid step payload for ${s} in execution ${n}`);o.push({name:s,completedAt:u.completedAt})}return o}normalizeStatus(e){for(let t of m)if(t===e)return t;return null}};const g=e=>{let t=new h(e);return{start:(e,n)=>t.start(e,n),resume:e=>t.resume(e),get:e=>t.get(e),cancel:e=>t.cancel(e)}};export{l as CancelledError,s as ExecutionError,c as LockError,i as NotFoundError,o as SerializationError,a as StateError,r as WorkflowError,g as defineWorkflow};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "semola",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.2",
|
|
4
4
|
"description": "Zero-dependency TypeScript utilities for Bun. Type-safe APIs, Redis queues, pub/sub, i18n, caching & auth with tree-shakeable imports.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -111,6 +111,16 @@
|
|
|
111
111
|
"default": "./dist/lib/prompts/index.cjs"
|
|
112
112
|
}
|
|
113
113
|
},
|
|
114
|
+
"./cli": {
|
|
115
|
+
"import": {
|
|
116
|
+
"types": "./dist/lib/cli/index.d.mts",
|
|
117
|
+
"default": "./dist/lib/cli/index.mjs"
|
|
118
|
+
},
|
|
119
|
+
"require": {
|
|
120
|
+
"types": "./dist/lib/cli/index.d.cts",
|
|
121
|
+
"default": "./dist/lib/cli/index.cjs"
|
|
122
|
+
}
|
|
123
|
+
},
|
|
114
124
|
"./workflow": {
|
|
115
125
|
"import": {
|
|
116
126
|
"types": "./dist/lib/workflow/index.d.mts",
|