@danceroutine/tango-adapters-core 0.1.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Pedro Del Moral Lopez
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,82 @@
1
+ # @danceroutine/tango-adapters-core
2
+
3
+ `@danceroutine/tango-adapters-core` defines the contract that every Tango web-framework adapter implements.
4
+
5
+ Most Tango application developers will never need this package directly, because they will install a concrete adapter such as `@danceroutine/tango-adapters-express` or `@danceroutine/tango-adapters-next`. This package exists so that Tango can support multiple host frameworks while providing a sane standardization surface for Tango to integrate against. If you are building a new adapter for Fastify, Hono, Koa, or another runtime, this is the boundary you implement against.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ pnpm add @danceroutine/tango-adapters-core
11
+ ```
12
+
13
+ ## Use cases
14
+
15
+ Reach for this package when you are working on adapter infrastructure rather than on an application:
16
+
17
+ - you are implementing a new Tango adapter for a host framework
18
+ - you want to type a function that accepts any Tango-compatible adapter
19
+ - you are reading the adapter layer and want the canonical contract first
20
+
21
+ If you are building an application, install the concrete adapter for your framework instead.
22
+
23
+ ## Adapter contract
24
+
25
+ Tango keeps its resource and viewset layer independent of any one HTTP framework. That architectural choice is what allows the same API layer to run inside Express, Next.js, and future integrations. The adapter contract is the point where a framework-specific request lifecycle is translated into Tango's handler model.
26
+
27
+ That means an adapter is responsible for questions such as:
28
+
29
+ - how the host framework passes requests and route params
30
+ - how Tango handlers are invoked
31
+ - how a Tango response is turned back into the framework's response type
32
+
33
+ The contract stays narrow so that adapter authors can focus on translation, rather than having to reimplement Tango's higher-level behavior.
34
+
35
+ ## Quick example
36
+
37
+ ```ts
38
+ import type { FrameworkAdapter } from '@danceroutine/tango-adapters-core';
39
+
40
+ function registerAdapter(adapter: FrameworkAdapter): FrameworkAdapter {
41
+ return adapter;
42
+ }
43
+ ```
44
+
45
+ In practice, you usually implement `FrameworkAdapter` in a package of your own and then expose framework-specific registration helpers on top of it.
46
+
47
+ ## Public API
48
+
49
+ The root export includes:
50
+
51
+ - `FrameworkAdapter`, the main adapter contract
52
+ - `FrameworkAdapterOptions`, the shared options type
53
+ - `FRAMEWORK_ADAPTER_BRAND` and `isFrameworkAdapter`, which support runtime identification of adapter instances
54
+
55
+ You can import these from the package root or from the `adapter` subpath, if you're used to Django's domain-drill-down style import paths:
56
+
57
+ ```ts
58
+ import type { FrameworkAdapter } from '@danceroutine/tango-adapters-core';
59
+ import { adapter } from '@danceroutine/tango-adapters-core';
60
+ ```
61
+
62
+ ## Documentation
63
+
64
+ - Official documentation: <https://tangowebframework.dev>
65
+ - Architecture topic: <https://tangowebframework.dev/topics/architecture>
66
+ - Contributor package catalog: <https://tangowebframework.dev/contributors/package-catalog>
67
+
68
+ ## Development
69
+
70
+ ```bash
71
+ pnpm --filter @danceroutine/tango-adapters-core build
72
+ pnpm --filter @danceroutine/tango-adapters-core typecheck
73
+ pnpm --filter @danceroutine/tango-adapters-core test
74
+ ```
75
+
76
+ For the wider contributor workflow, use:
77
+
78
+ - <https://tangowebframework.dev/contributing>
79
+
80
+ ## License
81
+
82
+ MIT
@@ -8,9 +8,14 @@ import type { RequestContext, BaseUser } from '@danceroutine/tango-resources';
8
8
  export interface FrameworkAdapter<TResponse = Response, THandlerType = unknown, TRequest = unknown> {
9
9
  adapt(handler: (ctx: RequestContext, ...args: unknown[]) => Promise<TResponse>, options?: FrameworkAdapterOptions<TRequest>): THandlerType;
10
10
  }
11
+ export declare const FRAMEWORK_ADAPTER_BRAND: "tango.adapter.framework";
11
12
  /**
12
13
  * Options for the framework adapter.
13
14
  */
14
15
  export interface FrameworkAdapterOptions<TRequest = unknown> {
15
16
  getUser?: (request: TRequest) => Promise<BaseUser | null> | BaseUser | null;
16
17
  }
18
+ /**
19
+ * Runtime guard for framework adapter instances using Tango branding.
20
+ */
21
+ export declare function isFrameworkAdapter(value: unknown): value is FrameworkAdapter;
@@ -2,3 +2,4 @@
2
2
  * Domain boundary barrel: centralizes this subdomain's public contract.
3
3
  */
4
4
  export type { FrameworkAdapter, FrameworkAdapterOptions } from './FrameworkAdapter';
5
+ export { FRAMEWORK_ADAPTER_BRAND, isFrameworkAdapter } from './FrameworkAdapter';
@@ -1 +1,3 @@
1
- import "../adapter-D6a8o0SO.js";
1
+ import { FRAMEWORK_ADAPTER_BRAND, isFrameworkAdapter } from "../adapter-zLqtqfpR.js";
2
+
3
+ export { FRAMEWORK_ADAPTER_BRAND, isFrameworkAdapter };
@@ -0,0 +1,19 @@
1
+ import { __export } from "./chunk-BkvOhyD0.js";
2
+
3
+ //#region src/adapter/FrameworkAdapter.ts
4
+ const FRAMEWORK_ADAPTER_BRAND = "tango.adapter.framework";
5
+ function isFrameworkAdapter(value) {
6
+ return typeof value === "object" && value !== null && typeof value.adapt === "function" && value.__tangoBrand === FRAMEWORK_ADAPTER_BRAND;
7
+ }
8
+
9
+ //#endregion
10
+ //#region src/adapter/index.ts
11
+ var adapter_exports = {};
12
+ __export(adapter_exports, {
13
+ FRAMEWORK_ADAPTER_BRAND: () => FRAMEWORK_ADAPTER_BRAND,
14
+ isFrameworkAdapter: () => isFrameworkAdapter
15
+ });
16
+
17
+ //#endregion
18
+ export { FRAMEWORK_ADAPTER_BRAND, adapter_exports, isFrameworkAdapter };
19
+ //# sourceMappingURL=adapter-zLqtqfpR.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter-zLqtqfpR.js","names":["value: unknown"],"sources":["../src/adapter/FrameworkAdapter.ts","../src/adapter/index.ts"],"sourcesContent":["import type { RequestContext, BaseUser } from '@danceroutine/tango-resources';\n/**\n * Adapter interface for integrating Tango with a given framework.\n * @template TResponse - The response type.\n * @template THandlerType - The handler type.\n * @template TRequest - The request type.\n */\nexport interface FrameworkAdapter<TResponse = Response, THandlerType = unknown, TRequest = unknown> {\n adapt(\n handler: (ctx: RequestContext, ...args: unknown[]) => Promise<TResponse>,\n options?: FrameworkAdapterOptions<TRequest>\n ): THandlerType;\n}\n\nexport const FRAMEWORK_ADAPTER_BRAND = 'tango.adapter.framework' as const;\n\n/**\n * Options for the framework adapter.\n */\nexport interface FrameworkAdapterOptions<TRequest = unknown> {\n getUser?: (request: TRequest) => Promise<BaseUser | null> | BaseUser | null;\n}\n\ntype FrameworkAdapterShape = {\n __tangoBrand?: unknown;\n adapt?: unknown;\n};\n\n/**\n * Runtime guard for framework adapter instances using Tango branding.\n */\nexport function isFrameworkAdapter(value: unknown): value is FrameworkAdapter {\n return (\n typeof value === 'object' &&\n value !== null &&\n typeof (value as FrameworkAdapterShape).adapt === 'function' &&\n (value as FrameworkAdapterShape).__tangoBrand === FRAMEWORK_ADAPTER_BRAND\n );\n}\n","/**\n * Domain boundary barrel: centralizes this subdomain's public contract.\n */\n\nexport type { FrameworkAdapter, FrameworkAdapterOptions } from './FrameworkAdapter';\nexport { FRAMEWORK_ADAPTER_BRAND, isFrameworkAdapter } from './FrameworkAdapter';\n"],"mappings":";;;MAca,0BAA0B;AAiBhC,SAAS,mBAAmBA,OAA2C;AAC1E,eACW,UAAU,YACjB,UAAU,eACF,MAAgC,UAAU,cACjD,MAAgC,iBAAiB;AAEzD"}
@@ -0,0 +1,12 @@
1
+
2
+ //#region rolldown:runtime
3
+ var __defProp = Object.defineProperty;
4
+ var __export = (target, all) => {
5
+ for (var name in all) __defProp(target, name, {
6
+ get: all[name],
7
+ enumerable: true
8
+ });
9
+ };
10
+
11
+ //#endregion
12
+ export { __export };
@@ -0,0 +1,3 @@
1
+ export { InternalHttpMethod } from './internal/InternalHttpMethod';
2
+ export { InternalActionScope } from './internal/InternalActionScope';
3
+ export { InternalActionMatchKind } from './internal/InternalActionMatchKind';
@@ -0,0 +1,3 @@
1
+ import { InternalActionMatchKind, InternalActionScope, InternalHttpMethod } from "../domain-12_cfgMU.js";
2
+
3
+ export { InternalActionMatchKind, InternalActionScope, InternalHttpMethod };
@@ -0,0 +1,5 @@
1
+ export declare const InternalActionMatchKind: {
2
+ readonly DETAIL: "detail";
3
+ readonly COLLECTION: "collection";
4
+ readonly METHOD_NOT_ALLOWED: "method_not_allowed";
5
+ };
@@ -0,0 +1,4 @@
1
+ export declare const InternalActionScope: {
2
+ readonly DETAIL: "detail";
3
+ readonly COLLECTION: "collection";
4
+ };
@@ -0,0 +1,7 @@
1
+ export declare const InternalHttpMethod: {
2
+ readonly GET: "GET";
3
+ readonly POST: "POST";
4
+ readonly PUT: "PUT";
5
+ readonly PATCH: "PATCH";
6
+ readonly DELETE: "DELETE";
7
+ };
@@ -0,0 +1,38 @@
1
+ import { __export } from "./chunk-BkvOhyD0.js";
2
+
3
+ //#region src/domain/internal/InternalHttpMethod.ts
4
+ const InternalHttpMethod = {
5
+ GET: "GET",
6
+ POST: "POST",
7
+ PUT: "PUT",
8
+ PATCH: "PATCH",
9
+ DELETE: "DELETE"
10
+ };
11
+
12
+ //#endregion
13
+ //#region src/domain/internal/InternalActionScope.ts
14
+ const InternalActionScope = {
15
+ DETAIL: "detail",
16
+ COLLECTION: "collection"
17
+ };
18
+
19
+ //#endregion
20
+ //#region src/domain/internal/InternalActionMatchKind.ts
21
+ const InternalActionMatchKind = {
22
+ DETAIL: "detail",
23
+ COLLECTION: "collection",
24
+ METHOD_NOT_ALLOWED: "method_not_allowed"
25
+ };
26
+
27
+ //#endregion
28
+ //#region src/domain/index.ts
29
+ var domain_exports = {};
30
+ __export(domain_exports, {
31
+ InternalActionMatchKind: () => InternalActionMatchKind,
32
+ InternalActionScope: () => InternalActionScope,
33
+ InternalHttpMethod: () => InternalHttpMethod
34
+ });
35
+
36
+ //#endregion
37
+ export { InternalActionMatchKind, InternalActionScope, InternalHttpMethod, domain_exports };
38
+ //# sourceMappingURL=domain-12_cfgMU.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"domain-12_cfgMU.js","names":[],"sources":["../src/domain/internal/InternalHttpMethod.ts","../src/domain/internal/InternalActionScope.ts","../src/domain/internal/InternalActionMatchKind.ts","../src/domain/index.ts"],"sourcesContent":["export const InternalHttpMethod = {\n GET: 'GET',\n POST: 'POST',\n PUT: 'PUT',\n PATCH: 'PATCH',\n DELETE: 'DELETE',\n} as const;\n","export const InternalActionScope = {\n DETAIL: 'detail',\n COLLECTION: 'collection',\n} as const;\n","export const InternalActionMatchKind = {\n DETAIL: 'detail',\n COLLECTION: 'collection',\n METHOD_NOT_ALLOWED: 'method_not_allowed',\n} as const;\n","export { InternalHttpMethod } from './internal/InternalHttpMethod';\nexport { InternalActionScope } from './internal/InternalActionScope';\nexport { InternalActionMatchKind } from './internal/InternalActionMatchKind';\n"],"mappings":";;;MAAa,qBAAqB;CAC9B,KAAK;CACL,MAAM;CACN,KAAK;CACL,OAAO;CACP,QAAQ;AACX;;;;MCNY,sBAAsB;CAC/B,QAAQ;CACR,YAAY;AACf;;;;MCHY,0BAA0B;CACnC,QAAQ;CACR,YAAY;CACZ,oBAAoB;AACvB"}
package/dist/index.d.ts CHANGED
@@ -3,4 +3,7 @@
3
3
  * top-level symbols for TS-native ergonomic imports.
4
4
  */
5
5
  export * as adapter from './adapter/index';
6
+ export * as domain from './domain/index';
6
7
  export type { FrameworkAdapter, FrameworkAdapterOptions } from './adapter/index';
8
+ export { FRAMEWORK_ADAPTER_BRAND, isFrameworkAdapter } from './adapter/index';
9
+ export { InternalHttpMethod, InternalActionScope, InternalActionMatchKind } from './domain/index';
package/dist/index.js CHANGED
@@ -1,3 +1,4 @@
1
- import { adapter_exports } from "./adapter-D6a8o0SO.js";
1
+ import { FRAMEWORK_ADAPTER_BRAND, adapter_exports, isFrameworkAdapter } from "./adapter-zLqtqfpR.js";
2
+ import { InternalActionMatchKind, InternalActionScope, InternalHttpMethod, domain_exports } from "./domain-12_cfgMU.js";
2
3
 
3
- export { adapter_exports as adapter };
4
+ export { FRAMEWORK_ADAPTER_BRAND, InternalActionMatchKind, InternalActionScope, InternalHttpMethod, adapter_exports as adapter, domain_exports as domain, isFrameworkAdapter };
package/package.json CHANGED
@@ -1,49 +1,55 @@
1
1
  {
2
- "name": "@danceroutine/tango-adapters-core",
3
- "version": "0.1.0",
4
- "description": "Core types and utilities for Tango adapters",
5
- "type": "module",
6
- "main": "./dist/index.js",
7
- "types": "./dist/index.d.ts",
8
- "exports": {
9
- ".": {
10
- "types": "./dist/index.d.ts",
11
- "import": "./dist/index.js"
12
- },
13
- "./adapter": {
14
- "types": "./dist/adapter/index.d.ts",
15
- "import": "./dist/adapter/index.js"
16
- }
2
+ "name": "@danceroutine/tango-adapters-core",
3
+ "version": "1.0.0",
4
+ "description": "Core types and utilities for Tango adapters",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
17
12
  },
18
- "files": [
19
- "dist"
20
- ],
21
- "scripts": {
22
- "build": "tsdown",
23
- "test": "vitest run --coverage",
24
- "test:watch": "vitest",
25
- "typecheck": "tsc --noEmit"
13
+ "./adapter": {
14
+ "types": "./dist/adapter/index.d.ts",
15
+ "import": "./dist/adapter/index.js"
26
16
  },
27
- "keywords": [
28
- "tango",
29
- "adapters",
30
- "core",
31
- "adapter"
32
- ],
33
- "author": "Pedro Del Moral Lopez",
34
- "license": "MIT",
35
- "repository": {
36
- "type": "git",
37
- "url": "https://github.com/danceroutine/tango.git",
38
- "directory": "packages/adapters/core"
39
- },
40
- "dependencies": {
41
- "@danceroutine/tango-resources": "workspace:*"
42
- },
43
- "devDependencies": {
44
- "@types/node": "^22.9.0",
45
- "tsdown": "^0.4.0",
46
- "typescript": "^5.6.3",
47
- "vitest": "^4.0.6"
17
+ "./domain": {
18
+ "types": "./dist/domain/index.d.ts",
19
+ "import": "./dist/domain/index.js"
48
20
  }
49
- }
21
+ },
22
+ "files": [
23
+ "dist"
24
+ ],
25
+ "keywords": [
26
+ "tango",
27
+ "adapters",
28
+ "core",
29
+ "adapter"
30
+ ],
31
+ "author": "Pedro Del Moral Lopez",
32
+ "license": "MIT",
33
+ "repository": {
34
+ "type": "git",
35
+ "url": "https://github.com/danceroutine/tango.git",
36
+ "directory": "packages/adapters/core"
37
+ },
38
+ "dependencies": {
39
+ "@danceroutine/tango-resources": "1.0.0"
40
+ },
41
+ "devDependencies": {
42
+ "@types/node": "^22.9.0",
43
+ "tsdown": "^0.4.0",
44
+ "typescript": "^5.6.3",
45
+ "vitest": "^4.0.6"
46
+ },
47
+ "scripts": {
48
+ "build": "tsdown",
49
+ "test": "vitest run --coverage",
50
+ "test:watch": "vitest",
51
+ "typecheck": "pnpm run typecheck:prod && pnpm run typecheck:test",
52
+ "typecheck:prod": "tsc --noEmit -p tsconfig.json",
53
+ "typecheck:test": "tsc --noEmit -p tsconfig.tests.json"
54
+ }
55
+ }
@@ -1,7 +0,0 @@
1
-
2
- //#region src/adapter/index.ts
3
- var adapter_exports = {};
4
-
5
- //#endregion
6
- export { adapter_exports };
7
- //# sourceMappingURL=adapter-D6a8o0SO.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"adapter-D6a8o0SO.js","names":[],"sources":["../src/adapter/index.ts"],"sourcesContent":["/**\n * Domain boundary barrel: centralizes this subdomain's public contract.\n */\n\nexport type { FrameworkAdapter, FrameworkAdapterOptions } from './FrameworkAdapter';\n"],"mappings":""}