unconventional 1.12.0 → 1.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ import { BaseModel } from "./base.model";
2
+ /** A predicate that matches a model to a given condition */
3
+ export type ModelPredicate = (model: typeof BaseModel) => boolean;
4
+ /** Middleware base class with methods that can find the ancestors of a model */
5
+ export declare class AbstractBaseMiddleware<M extends typeof BaseModel> {
6
+ protected model: M;
7
+ constructor(model: M);
8
+ /**
9
+ * Finds an ancestor that matches the predicate
10
+ * @param id - The ID of the model to find the ancestor for
11
+ * @param predicate - The predicate to match the ancestor
12
+ * @returns The ancestor that matches the predicate or null if no ancestor is found
13
+ */
14
+ findAncestor(id: string | number, predicate: ModelPredicate): Promise<any | null>;
15
+ /**
16
+ * Builds the relation path to reach an ancestor that matches the predicate
17
+ * @param predicate - The predicate to match the ancestor
18
+ * @returns The relation path (e.g. ['comments', 'post', 'user']) to the ancestor or null if no ancestor is found
19
+ */
20
+ protected buildAncestralPath(predicate: ModelPredicate): string[] | null;
21
+ }
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AbstractBaseMiddleware = void 0;
4
+ const types_1 = require("../types");
5
+ const utils_1 = require("../utils");
6
+ /** Middleware base class with methods that can find the ancestors of a model */
7
+ class AbstractBaseMiddleware {
8
+ model;
9
+ constructor(model) {
10
+ this.model = model;
11
+ }
12
+ /**
13
+ * Finds an ancestor that matches the predicate
14
+ * @param id - The ID of the model to find the ancestor for
15
+ * @param predicate - The predicate to match the ancestor
16
+ * @returns The ancestor that matches the predicate or null if no ancestor is found
17
+ */
18
+ async findAncestor(id, predicate) {
19
+ const expansion = this.buildAncestralPath(predicate);
20
+ if (!expansion)
21
+ return null;
22
+ const result = await this.model.findById(id, {
23
+ expand: (0, utils_1.buildExpansionString)(expansion)
24
+ });
25
+ if (!result)
26
+ return null;
27
+ // Navigate through the expanded chain to get the owner
28
+ return expansion.reduce((obj, key) => obj?.[key], result);
29
+ }
30
+ /**
31
+ * Builds the relation path to reach an ancestor that matches the predicate
32
+ * @param predicate - The predicate to match the ancestor
33
+ * @returns The relation path (e.g. ['comments', 'post', 'user']) to the ancestor or null if no ancestor is found
34
+ */
35
+ buildAncestralPath(predicate) {
36
+ let currentModel = this.model;
37
+ const path = [];
38
+ const visited = new Set();
39
+ while (!visited.has(currentModel)) {
40
+ // Found model that matches predicate
41
+ if (predicate(currentModel)) {
42
+ return path;
43
+ }
44
+ visited.add(currentModel);
45
+ // Find first BelongsTo relation
46
+ const belongsToRelation = Object.entries(currentModel.schema.props)
47
+ .find(([_, prop]) => prop.relation?.type === types_1.RelationType.BelongsTo);
48
+ if (!belongsToRelation)
49
+ return null;
50
+ const [relationKey, prop] = belongsToRelation;
51
+ const parentModel = (0, utils_1.getRelationModel)(prop.relation.model);
52
+ path.push(relationKey);
53
+ currentModel = parentModel;
54
+ }
55
+ return null; // Circular reference found or no matching owner
56
+ }
57
+ }
58
+ exports.AbstractBaseMiddleware = AbstractBaseMiddleware;
@@ -1,4 +1,5 @@
1
1
  export * from './abstractbase.controller';
2
+ export * from './abstractbase.middleware';
2
3
  export * from './api-error';
3
4
  export * from './base.cache';
4
5
  export * from './base.model';
@@ -15,6 +15,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./abstractbase.controller"), exports);
18
+ __exportStar(require("./abstractbase.middleware"), exports);
18
19
  __exportStar(require("./api-error"), exports);
19
20
  __exportStar(require("./base.cache"), exports);
20
21
  __exportStar(require("./base.model"), exports);
@@ -5,3 +5,8 @@ import { BaseHandler, Env } from "../types/api.types";
5
5
  * the logical OR of their results.
6
6
  */
7
7
  export declare function Or<E extends Env = Env, P extends string = any, I extends Input = Input, T extends BaseHandler<E, P, I> | MiddlewareHandler<E, P, I> = MiddlewareHandler<E, P, I>>(...methods: Array<T>): MiddlewareHandler<E, P, I>;
8
+ /**
9
+ * Converts an array of relation paths into a nested expansion string
10
+ * @example buildExpansionString(['comments', 'post', 'user']) => 'comments[post[user]]'
11
+ */
12
+ export declare function buildExpansionString(path: string[]): string;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Or = void 0;
3
+ exports.buildExpansionString = exports.Or = void 0;
4
4
  /**
5
5
  * Combines any number of RequestHandlers into one function that performs
6
6
  * the logical OR of their results.
@@ -16,3 +16,11 @@ function Or(...methods) {
16
16
  };
17
17
  }
18
18
  exports.Or = Or;
19
+ /**
20
+ * Converts an array of relation paths into a nested expansion string
21
+ * @example buildExpansionString(['comments', 'post', 'user']) => 'comments[post[user]]'
22
+ */
23
+ function buildExpansionString(path) {
24
+ return path.reduceRight((acc, curr) => acc ? `${curr}[${acc}]` : curr, '');
25
+ }
26
+ exports.buildExpansionString = buildExpansionString;
@@ -1,7 +1,12 @@
1
+ /// <reference types="@cloudflare/workers-types" />
1
2
  import { DBFactory } from "../types";
3
+ import { Context } from "hono";
4
+ import { HTTPResponseError } from "hono/types";
2
5
  /** Default CORS middleware permitting all origins and methods */
3
6
  export declare const defaultCors: import("hono").MiddlewareHandler;
4
7
  /** Binds the database proxy to the BaseModel */
5
8
  export declare const bindDatabase: (getDB: DBFactory) => (ctx: any, next: any) => Promise<void>;
6
9
  /** Catches and formats errors in a standard way */
7
- export declare const defaultErrorHandler: (err: any, ctx: any) => any;
10
+ export declare const defaultErrorHandler: (err: Error | HTTPResponseError, ctx: Context) => Response & import("hono").TypedResponse<{
11
+ error: string;
12
+ }, import("hono/utils/http-status").StatusCode, "json">;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "unconventional",
3
- "version": "1.12.0",
3
+ "version": "1.13.0",
4
4
  "description": "A complete server built on Cloudflare Workers/Pages",
5
5
  "keywords": [
6
6
  "cloudflare",