@aigne/afs 1.11.0-beta → 1.11.0-beta.10
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.md +17 -84
- package/README.md +4 -13
- package/dist/_virtual/rolldown_runtime.mjs +7 -0
- package/dist/afs.cjs +1330 -0
- package/dist/afs.d.cts +275 -0
- package/dist/afs.d.cts.map +1 -0
- package/dist/afs.d.mts +275 -0
- package/dist/afs.d.mts.map +1 -0
- package/dist/afs.mjs +1331 -0
- package/dist/afs.mjs.map +1 -0
- package/dist/capabilities/index.d.mts +2 -0
- package/dist/capabilities/types.d.cts +100 -0
- package/dist/capabilities/types.d.cts.map +1 -0
- package/dist/capabilities/types.d.mts +100 -0
- package/dist/capabilities/types.d.mts.map +1 -0
- package/dist/capabilities/world-mapping.cjs +20 -0
- package/dist/capabilities/world-mapping.d.cts +139 -0
- package/dist/capabilities/world-mapping.d.cts.map +1 -0
- package/dist/capabilities/world-mapping.d.mts +139 -0
- package/dist/capabilities/world-mapping.d.mts.map +1 -0
- package/dist/capabilities/world-mapping.mjs +20 -0
- package/dist/capabilities/world-mapping.mjs.map +1 -0
- package/dist/error.cjs +63 -0
- package/dist/error.d.cts +39 -0
- package/dist/error.d.cts.map +1 -0
- package/dist/error.d.mts +39 -0
- package/dist/error.d.mts.map +1 -0
- package/dist/error.mjs +59 -0
- package/dist/error.mjs.map +1 -0
- package/dist/index.cjs +72 -345
- package/dist/index.d.cts +18 -300
- package/dist/index.d.mts +20 -300
- package/dist/index.mjs +16 -342
- package/dist/loader/index.cjs +110 -0
- package/dist/loader/index.d.cts +48 -0
- package/dist/loader/index.d.cts.map +1 -0
- package/dist/loader/index.d.mts +48 -0
- package/dist/loader/index.d.mts.map +1 -0
- package/dist/loader/index.mjs +110 -0
- package/dist/loader/index.mjs.map +1 -0
- package/dist/meta/index.cjs +4 -0
- package/dist/meta/index.mjs +6 -0
- package/dist/meta/kind.cjs +161 -0
- package/dist/meta/kind.d.cts +134 -0
- package/dist/meta/kind.d.cts.map +1 -0
- package/dist/meta/kind.d.mts +134 -0
- package/dist/meta/kind.d.mts.map +1 -0
- package/dist/meta/kind.mjs +157 -0
- package/dist/meta/kind.mjs.map +1 -0
- package/dist/meta/path.cjs +116 -0
- package/dist/meta/path.d.cts +43 -0
- package/dist/meta/path.d.cts.map +1 -0
- package/dist/meta/path.d.mts +43 -0
- package/dist/meta/path.d.mts.map +1 -0
- package/dist/meta/path.mjs +112 -0
- package/dist/meta/path.mjs.map +1 -0
- package/dist/meta/type.d.cts +96 -0
- package/dist/meta/type.d.cts.map +1 -0
- package/dist/meta/type.d.mts +96 -0
- package/dist/meta/type.d.mts.map +1 -0
- package/dist/meta/validation.cjs +77 -0
- package/dist/meta/validation.d.cts +19 -0
- package/dist/meta/validation.d.cts.map +1 -0
- package/dist/meta/validation.d.mts +19 -0
- package/dist/meta/validation.d.mts.map +1 -0
- package/dist/meta/validation.mjs +77 -0
- package/dist/meta/validation.mjs.map +1 -0
- package/dist/meta/well-known-kinds.cjs +228 -0
- package/dist/meta/well-known-kinds.d.cts +52 -0
- package/dist/meta/well-known-kinds.d.cts.map +1 -0
- package/dist/meta/well-known-kinds.d.mts +52 -0
- package/dist/meta/well-known-kinds.d.mts.map +1 -0
- package/dist/meta/well-known-kinds.mjs +219 -0
- package/dist/meta/well-known-kinds.mjs.map +1 -0
- package/dist/node_modules/.pnpm/@types_json-schema@7.0.15/node_modules/@types/json-schema/index.d.cts +141 -0
- package/dist/node_modules/.pnpm/@types_json-schema@7.0.15/node_modules/@types/json-schema/index.d.cts.map +1 -0
- package/dist/node_modules/.pnpm/@types_json-schema@7.0.15/node_modules/@types/json-schema/index.d.mts +141 -0
- package/dist/node_modules/.pnpm/@types_json-schema@7.0.15/node_modules/@types/json-schema/index.d.mts.map +1 -0
- package/dist/path.cjs +255 -0
- package/dist/path.d.cts +93 -0
- package/dist/path.d.cts.map +1 -0
- package/dist/path.d.mts +93 -0
- package/dist/path.d.mts.map +1 -0
- package/dist/path.mjs +249 -0
- package/dist/path.mjs.map +1 -0
- package/dist/provider/base.cjs +425 -0
- package/dist/provider/base.d.cts +175 -0
- package/dist/provider/base.d.cts.map +1 -0
- package/dist/provider/base.d.mts +175 -0
- package/dist/provider/base.d.mts.map +1 -0
- package/dist/provider/base.mjs +426 -0
- package/dist/provider/base.mjs.map +1 -0
- package/dist/provider/decorators.cjs +268 -0
- package/dist/provider/decorators.d.cts +244 -0
- package/dist/provider/decorators.d.cts.map +1 -0
- package/dist/provider/decorators.d.mts +244 -0
- package/dist/provider/decorators.d.mts.map +1 -0
- package/dist/provider/decorators.mjs +256 -0
- package/dist/provider/decorators.mjs.map +1 -0
- package/dist/provider/index.cjs +19 -0
- package/dist/provider/index.d.cts +5 -0
- package/dist/provider/index.d.mts +5 -0
- package/dist/provider/index.mjs +5 -0
- package/dist/provider/router.cjs +185 -0
- package/dist/provider/router.d.cts +50 -0
- package/dist/provider/router.d.cts.map +1 -0
- package/dist/provider/router.d.mts +50 -0
- package/dist/provider/router.d.mts.map +1 -0
- package/dist/provider/router.mjs +185 -0
- package/dist/provider/router.mjs.map +1 -0
- package/dist/provider/types.d.cts +113 -0
- package/dist/provider/types.d.cts.map +1 -0
- package/dist/provider/types.d.mts +113 -0
- package/dist/provider/types.d.mts.map +1 -0
- package/dist/registry.cjs +358 -0
- package/dist/registry.d.cts +96 -0
- package/dist/registry.d.cts.map +1 -0
- package/dist/registry.d.mts +96 -0
- package/dist/registry.d.mts.map +1 -0
- package/dist/registry.mjs +360 -0
- package/dist/registry.mjs.map +1 -0
- package/dist/type.cjs +34 -0
- package/dist/type.d.cts +420 -0
- package/dist/type.d.cts.map +1 -0
- package/dist/type.d.mts +420 -0
- package/dist/type.d.mts.map +1 -0
- package/dist/type.mjs +33 -0
- package/dist/type.mjs.map +1 -0
- package/dist/utils/camelize.d.cts.map +1 -1
- package/dist/utils/camelize.d.mts.map +1 -1
- package/dist/utils/schema.cjs +129 -0
- package/dist/utils/schema.d.cts +65 -0
- package/dist/utils/schema.d.cts.map +1 -0
- package/dist/utils/schema.d.mts +65 -0
- package/dist/utils/schema.d.mts.map +1 -0
- package/dist/utils/schema.mjs +124 -0
- package/dist/utils/schema.mjs.map +1 -0
- package/dist/utils/type-utils.d.cts.map +1 -1
- package/dist/utils/type-utils.d.mts.map +1 -1
- package/dist/utils/uri-template.cjs +123 -0
- package/dist/utils/uri-template.d.cts +48 -0
- package/dist/utils/uri-template.d.cts.map +1 -0
- package/dist/utils/uri-template.d.mts +48 -0
- package/dist/utils/uri-template.d.mts.map +1 -0
- package/dist/utils/uri-template.mjs +120 -0
- package/dist/utils/uri-template.mjs.map +1 -0
- package/dist/utils/uri.cjs +49 -0
- package/dist/utils/uri.d.cts +34 -0
- package/dist/utils/uri.d.cts.map +1 -0
- package/dist/utils/uri.d.mts +34 -0
- package/dist/utils/uri.d.mts.map +1 -0
- package/dist/utils/uri.mjs +49 -0
- package/dist/utils/uri.mjs.map +1 -0
- package/dist/utils/zod.cjs +6 -8
- package/dist/utils/zod.d.cts +2 -2
- package/dist/utils/zod.d.cts.map +1 -1
- package/dist/utils/zod.d.mts +2 -2
- package/dist/utils/zod.d.mts.map +1 -1
- package/dist/utils/zod.mjs +6 -8
- package/dist/utils/zod.mjs.map +1 -1
- package/package.json +27 -4
- package/dist/index.d.cts.map +0 -1
- package/dist/index.d.mts.map +0 -1
- package/dist/index.mjs.map +0 -1
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
|
|
2
|
+
//#region src/provider/router.ts
|
|
3
|
+
/**
|
|
4
|
+
* Calculate specificity score for a pattern.
|
|
5
|
+
* Higher score = higher priority.
|
|
6
|
+
*
|
|
7
|
+
* Scoring rules:
|
|
8
|
+
* - Static segment: +100
|
|
9
|
+
* - Named parameter (single segment): +10
|
|
10
|
+
* - Wildcard ((.*) or (.+) or * or +): +1
|
|
11
|
+
* - Bonus for more segments: +5 per segment
|
|
12
|
+
*
|
|
13
|
+
* Examples:
|
|
14
|
+
* - /:path(.*) = 1 + 5 = 6 (low)
|
|
15
|
+
* - /:path(.*)/.meta = 1 + 100 + 10 = 111 (higher - has static .meta)
|
|
16
|
+
* - /:path(.*)/.meta/.kinds = 1 + 100 + 100 + 15 = 216 (highest)
|
|
17
|
+
*/
|
|
18
|
+
function calculateSpecificity(pattern) {
|
|
19
|
+
let score = 0;
|
|
20
|
+
const segments = pattern.split("/").filter(Boolean);
|
|
21
|
+
for (const segment of segments) if (segment.endsWith("*") || segment.endsWith("+") || segment.endsWith("(.*)") || segment.endsWith("(.+)")) score += 1;
|
|
22
|
+
else if (segment.startsWith(":")) score += 10;
|
|
23
|
+
else score += 100;
|
|
24
|
+
score += segments.length * 5;
|
|
25
|
+
return score;
|
|
26
|
+
}
|
|
27
|
+
function convertToURLPattern(pattern) {
|
|
28
|
+
let result = pattern.replace(/\/\*\*$/g, "/:_(.*)");
|
|
29
|
+
result = result.replace(/\/\*\*\//g, "/:_(.*)/");
|
|
30
|
+
if (result.includes("/**")) result = result.replace(/\/\*\*/g, "/:_(.*)");
|
|
31
|
+
result = result.replace(/\/:(\w+)\*(\/.+)/g, "{/:$1(.*)}?$2");
|
|
32
|
+
const segments = result.split("/").filter(Boolean);
|
|
33
|
+
if (segments.length >= 2) {
|
|
34
|
+
const lastSegment = segments[segments.length - 1];
|
|
35
|
+
if (lastSegment && /^:\w+\*$/.test(lastSegment)) {
|
|
36
|
+
const wildcardName = lastSegment.slice(1, -1);
|
|
37
|
+
result = `${`/${segments.slice(0, -1).join("/")}`}{/:${wildcardName}(.*)}?`;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
result = result.replace(/:(\w+)\*/g, ":$1(.*)");
|
|
41
|
+
result = result.replace(/:(\w+)\+/g, ":$1(.+)");
|
|
42
|
+
return result;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Provider router using native URLPattern for type-safe route handling.
|
|
46
|
+
* Supports suffix patterns like /:path*\/.meta for flexible routing.
|
|
47
|
+
*/
|
|
48
|
+
var ProviderRouter = class {
|
|
49
|
+
routers = /* @__PURE__ */ new Map();
|
|
50
|
+
allPatterns = /* @__PURE__ */ new Set();
|
|
51
|
+
constructor() {
|
|
52
|
+
for (const op of [
|
|
53
|
+
"list",
|
|
54
|
+
"read",
|
|
55
|
+
"write",
|
|
56
|
+
"delete",
|
|
57
|
+
"exec",
|
|
58
|
+
"search",
|
|
59
|
+
"stat",
|
|
60
|
+
"explain",
|
|
61
|
+
"rename"
|
|
62
|
+
]) this.routers.set(op, { routes: [] });
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Register a route with the router
|
|
66
|
+
*/
|
|
67
|
+
registerRoute(pattern, operation, handler, description, listOptions) {
|
|
68
|
+
const storage = this.routers.get(operation);
|
|
69
|
+
if (!storage) throw new Error(`Unknown operation: ${operation}`);
|
|
70
|
+
if (storage.routes.find((r) => r.originalPattern === pattern)) {
|
|
71
|
+
console.warn(`[AFSBaseProvider] Route conflict: ${operation} ${pattern} is being overwritten`);
|
|
72
|
+
storage.routes = storage.routes.filter((r) => r.originalPattern !== pattern);
|
|
73
|
+
}
|
|
74
|
+
const definition = {
|
|
75
|
+
pattern,
|
|
76
|
+
operation,
|
|
77
|
+
handler,
|
|
78
|
+
description,
|
|
79
|
+
listOptions
|
|
80
|
+
};
|
|
81
|
+
const urlPatternPath = convertToURLPattern(pattern);
|
|
82
|
+
const urlPattern = new URLPattern({ pathname: urlPatternPath });
|
|
83
|
+
const specificity = calculateSpecificity(urlPatternPath);
|
|
84
|
+
const compiledRoute = {
|
|
85
|
+
pattern: urlPattern,
|
|
86
|
+
originalPattern: pattern,
|
|
87
|
+
definition,
|
|
88
|
+
specificity
|
|
89
|
+
};
|
|
90
|
+
let inserted = false;
|
|
91
|
+
for (let i = 0; i < storage.routes.length; i++) {
|
|
92
|
+
const existingRoute = storage.routes[i];
|
|
93
|
+
if (existingRoute && specificity > existingRoute.specificity) {
|
|
94
|
+
storage.routes.splice(i, 0, compiledRoute);
|
|
95
|
+
inserted = true;
|
|
96
|
+
break;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
if (!inserted) storage.routes.push(compiledRoute);
|
|
100
|
+
this.allPatterns.add(pattern);
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Match a path against registered routes for an operation.
|
|
104
|
+
* Routes are checked in specificity order (most specific first).
|
|
105
|
+
*/
|
|
106
|
+
match(path, operation) {
|
|
107
|
+
const storage = this.routers.get(operation);
|
|
108
|
+
if (!storage) return null;
|
|
109
|
+
const normalizedPath = path.startsWith("/") ? path : `/${path}`;
|
|
110
|
+
for (const route of storage.routes) {
|
|
111
|
+
const result = route.pattern.exec({ pathname: normalizedPath });
|
|
112
|
+
if (result) {
|
|
113
|
+
const params = {};
|
|
114
|
+
const groups = result.pathname.groups;
|
|
115
|
+
for (const [key, value] of Object.entries(groups)) params[key] = value !== void 0 ? decodeURIComponent(value) : value;
|
|
116
|
+
return {
|
|
117
|
+
route: route.definition,
|
|
118
|
+
params
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Get static children paths for a given path.
|
|
126
|
+
* Used for list auto-expansion.
|
|
127
|
+
*
|
|
128
|
+
* This analyzes all registered patterns to find which ones
|
|
129
|
+
* would be direct children of the given path.
|
|
130
|
+
*
|
|
131
|
+
* Excludes .meta and .actions as they are implicit paths.
|
|
132
|
+
*/
|
|
133
|
+
getStaticChildren(basePath) {
|
|
134
|
+
const children = [];
|
|
135
|
+
const normalizedBase = basePath === "/" ? "" : basePath;
|
|
136
|
+
for (const pattern of this.allPatterns) {
|
|
137
|
+
if (pattern.endsWith("/.meta") || pattern.endsWith("/.actions")) continue;
|
|
138
|
+
const childPath = this.findStaticChild(normalizedBase, pattern);
|
|
139
|
+
if (childPath && !children.includes(childPath)) children.push(childPath);
|
|
140
|
+
}
|
|
141
|
+
return children;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Find a static child path from a pattern relative to basePath
|
|
145
|
+
*
|
|
146
|
+
* For patterns like "/:table/new" and basePath "/users",
|
|
147
|
+
* we need to check if the pattern could match and what static
|
|
148
|
+
* segment comes after.
|
|
149
|
+
*/
|
|
150
|
+
findStaticChild(basePath, pattern) {
|
|
151
|
+
const baseSegments = basePath ? basePath.split("/").filter(Boolean) : [];
|
|
152
|
+
const patternSegments = pattern.split("/").filter(Boolean);
|
|
153
|
+
if (patternSegments.length <= baseSegments.length) return null;
|
|
154
|
+
for (let i = 0; i < baseSegments.length; i++) {
|
|
155
|
+
const patternSeg = patternSegments[i];
|
|
156
|
+
const baseSeg = baseSegments[i];
|
|
157
|
+
const isParam$1 = patternSeg?.startsWith(":");
|
|
158
|
+
const isWildcard$1 = patternSeg === "**" || patternSeg?.endsWith("*") || patternSeg?.endsWith("+") || patternSeg?.endsWith("(.*)") || patternSeg?.endsWith("(.+)");
|
|
159
|
+
if (patternSeg !== baseSeg && !isParam$1 && !isWildcard$1) return null;
|
|
160
|
+
}
|
|
161
|
+
const nextSegment = patternSegments[baseSegments.length];
|
|
162
|
+
if (!nextSegment) return null;
|
|
163
|
+
const isParam = nextSegment.startsWith(":");
|
|
164
|
+
const isWildcard = nextSegment === "**" || nextSegment.endsWith("*") || nextSegment.endsWith("+") || nextSegment.endsWith("(.*)") || nextSegment.endsWith("(.+)");
|
|
165
|
+
if (isParam || isWildcard) return null;
|
|
166
|
+
return `${basePath}/${nextSegment}`;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Get all registered patterns
|
|
170
|
+
*/
|
|
171
|
+
getAllPatterns() {
|
|
172
|
+
return Array.from(this.allPatterns);
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Get all routes for an operation
|
|
176
|
+
*/
|
|
177
|
+
getRoutesForOperation(operation) {
|
|
178
|
+
const storage = this.routers.get(operation);
|
|
179
|
+
if (!storage) return [];
|
|
180
|
+
return storage.routes.map((r) => r.definition);
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
//#endregion
|
|
185
|
+
exports.ProviderRouter = ProviderRouter;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { ListDecoratorOptions, RouteDefinition, RouteHandler, RouteMatch, RouteOperation } from "./types.cjs";
|
|
2
|
+
|
|
3
|
+
//#region src/provider/router.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Provider router using native URLPattern for type-safe route handling.
|
|
6
|
+
* Supports suffix patterns like /:path*\/.meta for flexible routing.
|
|
7
|
+
*/
|
|
8
|
+
declare class ProviderRouter {
|
|
9
|
+
private routers;
|
|
10
|
+
private allPatterns;
|
|
11
|
+
constructor();
|
|
12
|
+
/**
|
|
13
|
+
* Register a route with the router
|
|
14
|
+
*/
|
|
15
|
+
registerRoute(pattern: string, operation: RouteOperation, handler: RouteHandler, description?: string, listOptions?: ListDecoratorOptions): void;
|
|
16
|
+
/**
|
|
17
|
+
* Match a path against registered routes for an operation.
|
|
18
|
+
* Routes are checked in specificity order (most specific first).
|
|
19
|
+
*/
|
|
20
|
+
match(path: string, operation: RouteOperation): RouteMatch | null;
|
|
21
|
+
/**
|
|
22
|
+
* Get static children paths for a given path.
|
|
23
|
+
* Used for list auto-expansion.
|
|
24
|
+
*
|
|
25
|
+
* This analyzes all registered patterns to find which ones
|
|
26
|
+
* would be direct children of the given path.
|
|
27
|
+
*
|
|
28
|
+
* Excludes .meta and .actions as they are implicit paths.
|
|
29
|
+
*/
|
|
30
|
+
getStaticChildren(basePath: string): string[];
|
|
31
|
+
/**
|
|
32
|
+
* Find a static child path from a pattern relative to basePath
|
|
33
|
+
*
|
|
34
|
+
* For patterns like "/:table/new" and basePath "/users",
|
|
35
|
+
* we need to check if the pattern could match and what static
|
|
36
|
+
* segment comes after.
|
|
37
|
+
*/
|
|
38
|
+
private findStaticChild;
|
|
39
|
+
/**
|
|
40
|
+
* Get all registered patterns
|
|
41
|
+
*/
|
|
42
|
+
getAllPatterns(): string[];
|
|
43
|
+
/**
|
|
44
|
+
* Get all routes for an operation
|
|
45
|
+
*/
|
|
46
|
+
getRoutesForOperation(operation: RouteOperation): RouteDefinition[];
|
|
47
|
+
}
|
|
48
|
+
//#endregion
|
|
49
|
+
export { ProviderRouter };
|
|
50
|
+
//# sourceMappingURL=router.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"router.d.cts","names":[],"sources":["../../src/provider/router.ts"],"mappings":";;;;;AA0HA;;cAAa,cAAA;EAAA,QACH,OAAA;EAAA,QACA,WAAA;;EA2FuB;;;EAlE/B,aAAA,CACE,OAAA,UACA,SAAA,EAAW,cAAA,EACX,OAAA,EAAS,YAAA,EACT,WAAA,WACA,WAAA,GAAc,oBAAA;EA8LiD;;;;EAjIjE,KAAA,CAAM,IAAA,UAAc,SAAA,EAAW,cAAA,GAAiB,UAAA;EAlEhD;;;;;;;;;EA6GA,iBAAA,CAAkB,QAAA;EA3CZ;;;;;;;EAAA,QAsEE,eAAA;EA2DR;;;EAPA,cAAA,CAAA;EAOiE;;;EAAjE,qBAAA,CAAsB,SAAA,EAAW,cAAA,GAAiB,eAAA;AAAA"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { ListDecoratorOptions, RouteDefinition, RouteHandler, RouteMatch, RouteOperation } from "./types.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/provider/router.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Provider router using native URLPattern for type-safe route handling.
|
|
6
|
+
* Supports suffix patterns like /:path*\/.meta for flexible routing.
|
|
7
|
+
*/
|
|
8
|
+
declare class ProviderRouter {
|
|
9
|
+
private routers;
|
|
10
|
+
private allPatterns;
|
|
11
|
+
constructor();
|
|
12
|
+
/**
|
|
13
|
+
* Register a route with the router
|
|
14
|
+
*/
|
|
15
|
+
registerRoute(pattern: string, operation: RouteOperation, handler: RouteHandler, description?: string, listOptions?: ListDecoratorOptions): void;
|
|
16
|
+
/**
|
|
17
|
+
* Match a path against registered routes for an operation.
|
|
18
|
+
* Routes are checked in specificity order (most specific first).
|
|
19
|
+
*/
|
|
20
|
+
match(path: string, operation: RouteOperation): RouteMatch | null;
|
|
21
|
+
/**
|
|
22
|
+
* Get static children paths for a given path.
|
|
23
|
+
* Used for list auto-expansion.
|
|
24
|
+
*
|
|
25
|
+
* This analyzes all registered patterns to find which ones
|
|
26
|
+
* would be direct children of the given path.
|
|
27
|
+
*
|
|
28
|
+
* Excludes .meta and .actions as they are implicit paths.
|
|
29
|
+
*/
|
|
30
|
+
getStaticChildren(basePath: string): string[];
|
|
31
|
+
/**
|
|
32
|
+
* Find a static child path from a pattern relative to basePath
|
|
33
|
+
*
|
|
34
|
+
* For patterns like "/:table/new" and basePath "/users",
|
|
35
|
+
* we need to check if the pattern could match and what static
|
|
36
|
+
* segment comes after.
|
|
37
|
+
*/
|
|
38
|
+
private findStaticChild;
|
|
39
|
+
/**
|
|
40
|
+
* Get all registered patterns
|
|
41
|
+
*/
|
|
42
|
+
getAllPatterns(): string[];
|
|
43
|
+
/**
|
|
44
|
+
* Get all routes for an operation
|
|
45
|
+
*/
|
|
46
|
+
getRoutesForOperation(operation: RouteOperation): RouteDefinition[];
|
|
47
|
+
}
|
|
48
|
+
//#endregion
|
|
49
|
+
export { ProviderRouter };
|
|
50
|
+
//# sourceMappingURL=router.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"router.d.mts","names":[],"sources":["../../src/provider/router.ts"],"mappings":";;;;;AA0HA;;cAAa,cAAA;EAAA,QACH,OAAA;EAAA,QACA,WAAA;;EA2FuB;;;EAlE/B,aAAA,CACE,OAAA,UACA,SAAA,EAAW,cAAA,EACX,OAAA,EAAS,YAAA,EACT,WAAA,WACA,WAAA,GAAc,oBAAA;EA8LiD;;;;EAjIjE,KAAA,CAAM,IAAA,UAAc,SAAA,EAAW,cAAA,GAAiB,UAAA;EAlEhD;;;;;;;;;EA6GA,iBAAA,CAAkB,QAAA;EA3CZ;;;;;;;EAAA,QAsEE,eAAA;EA2DR;;;EAPA,cAAA,CAAA;EAOiE;;;EAAjE,qBAAA,CAAsB,SAAA,EAAW,cAAA,GAAiB,eAAA;AAAA"}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
//#region src/provider/router.ts
|
|
2
|
+
/**
|
|
3
|
+
* Calculate specificity score for a pattern.
|
|
4
|
+
* Higher score = higher priority.
|
|
5
|
+
*
|
|
6
|
+
* Scoring rules:
|
|
7
|
+
* - Static segment: +100
|
|
8
|
+
* - Named parameter (single segment): +10
|
|
9
|
+
* - Wildcard ((.*) or (.+) or * or +): +1
|
|
10
|
+
* - Bonus for more segments: +5 per segment
|
|
11
|
+
*
|
|
12
|
+
* Examples:
|
|
13
|
+
* - /:path(.*) = 1 + 5 = 6 (low)
|
|
14
|
+
* - /:path(.*)/.meta = 1 + 100 + 10 = 111 (higher - has static .meta)
|
|
15
|
+
* - /:path(.*)/.meta/.kinds = 1 + 100 + 100 + 15 = 216 (highest)
|
|
16
|
+
*/
|
|
17
|
+
function calculateSpecificity(pattern) {
|
|
18
|
+
let score = 0;
|
|
19
|
+
const segments = pattern.split("/").filter(Boolean);
|
|
20
|
+
for (const segment of segments) if (segment.endsWith("*") || segment.endsWith("+") || segment.endsWith("(.*)") || segment.endsWith("(.+)")) score += 1;
|
|
21
|
+
else if (segment.startsWith(":")) score += 10;
|
|
22
|
+
else score += 100;
|
|
23
|
+
score += segments.length * 5;
|
|
24
|
+
return score;
|
|
25
|
+
}
|
|
26
|
+
function convertToURLPattern(pattern) {
|
|
27
|
+
let result = pattern.replace(/\/\*\*$/g, "/:_(.*)");
|
|
28
|
+
result = result.replace(/\/\*\*\//g, "/:_(.*)/");
|
|
29
|
+
if (result.includes("/**")) result = result.replace(/\/\*\*/g, "/:_(.*)");
|
|
30
|
+
result = result.replace(/\/:(\w+)\*(\/.+)/g, "{/:$1(.*)}?$2");
|
|
31
|
+
const segments = result.split("/").filter(Boolean);
|
|
32
|
+
if (segments.length >= 2) {
|
|
33
|
+
const lastSegment = segments[segments.length - 1];
|
|
34
|
+
if (lastSegment && /^:\w+\*$/.test(lastSegment)) {
|
|
35
|
+
const wildcardName = lastSegment.slice(1, -1);
|
|
36
|
+
result = `${`/${segments.slice(0, -1).join("/")}`}{/:${wildcardName}(.*)}?`;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
result = result.replace(/:(\w+)\*/g, ":$1(.*)");
|
|
40
|
+
result = result.replace(/:(\w+)\+/g, ":$1(.+)");
|
|
41
|
+
return result;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Provider router using native URLPattern for type-safe route handling.
|
|
45
|
+
* Supports suffix patterns like /:path*\/.meta for flexible routing.
|
|
46
|
+
*/
|
|
47
|
+
var ProviderRouter = class {
|
|
48
|
+
routers = /* @__PURE__ */ new Map();
|
|
49
|
+
allPatterns = /* @__PURE__ */ new Set();
|
|
50
|
+
constructor() {
|
|
51
|
+
for (const op of [
|
|
52
|
+
"list",
|
|
53
|
+
"read",
|
|
54
|
+
"write",
|
|
55
|
+
"delete",
|
|
56
|
+
"exec",
|
|
57
|
+
"search",
|
|
58
|
+
"stat",
|
|
59
|
+
"explain",
|
|
60
|
+
"rename"
|
|
61
|
+
]) this.routers.set(op, { routes: [] });
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Register a route with the router
|
|
65
|
+
*/
|
|
66
|
+
registerRoute(pattern, operation, handler, description, listOptions) {
|
|
67
|
+
const storage = this.routers.get(operation);
|
|
68
|
+
if (!storage) throw new Error(`Unknown operation: ${operation}`);
|
|
69
|
+
if (storage.routes.find((r) => r.originalPattern === pattern)) {
|
|
70
|
+
console.warn(`[AFSBaseProvider] Route conflict: ${operation} ${pattern} is being overwritten`);
|
|
71
|
+
storage.routes = storage.routes.filter((r) => r.originalPattern !== pattern);
|
|
72
|
+
}
|
|
73
|
+
const definition = {
|
|
74
|
+
pattern,
|
|
75
|
+
operation,
|
|
76
|
+
handler,
|
|
77
|
+
description,
|
|
78
|
+
listOptions
|
|
79
|
+
};
|
|
80
|
+
const urlPatternPath = convertToURLPattern(pattern);
|
|
81
|
+
const urlPattern = new URLPattern({ pathname: urlPatternPath });
|
|
82
|
+
const specificity = calculateSpecificity(urlPatternPath);
|
|
83
|
+
const compiledRoute = {
|
|
84
|
+
pattern: urlPattern,
|
|
85
|
+
originalPattern: pattern,
|
|
86
|
+
definition,
|
|
87
|
+
specificity
|
|
88
|
+
};
|
|
89
|
+
let inserted = false;
|
|
90
|
+
for (let i = 0; i < storage.routes.length; i++) {
|
|
91
|
+
const existingRoute = storage.routes[i];
|
|
92
|
+
if (existingRoute && specificity > existingRoute.specificity) {
|
|
93
|
+
storage.routes.splice(i, 0, compiledRoute);
|
|
94
|
+
inserted = true;
|
|
95
|
+
break;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
if (!inserted) storage.routes.push(compiledRoute);
|
|
99
|
+
this.allPatterns.add(pattern);
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Match a path against registered routes for an operation.
|
|
103
|
+
* Routes are checked in specificity order (most specific first).
|
|
104
|
+
*/
|
|
105
|
+
match(path, operation) {
|
|
106
|
+
const storage = this.routers.get(operation);
|
|
107
|
+
if (!storage) return null;
|
|
108
|
+
const normalizedPath = path.startsWith("/") ? path : `/${path}`;
|
|
109
|
+
for (const route of storage.routes) {
|
|
110
|
+
const result = route.pattern.exec({ pathname: normalizedPath });
|
|
111
|
+
if (result) {
|
|
112
|
+
const params = {};
|
|
113
|
+
const groups = result.pathname.groups;
|
|
114
|
+
for (const [key, value] of Object.entries(groups)) params[key] = value !== void 0 ? decodeURIComponent(value) : value;
|
|
115
|
+
return {
|
|
116
|
+
route: route.definition,
|
|
117
|
+
params
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Get static children paths for a given path.
|
|
125
|
+
* Used for list auto-expansion.
|
|
126
|
+
*
|
|
127
|
+
* This analyzes all registered patterns to find which ones
|
|
128
|
+
* would be direct children of the given path.
|
|
129
|
+
*
|
|
130
|
+
* Excludes .meta and .actions as they are implicit paths.
|
|
131
|
+
*/
|
|
132
|
+
getStaticChildren(basePath) {
|
|
133
|
+
const children = [];
|
|
134
|
+
const normalizedBase = basePath === "/" ? "" : basePath;
|
|
135
|
+
for (const pattern of this.allPatterns) {
|
|
136
|
+
if (pattern.endsWith("/.meta") || pattern.endsWith("/.actions")) continue;
|
|
137
|
+
const childPath = this.findStaticChild(normalizedBase, pattern);
|
|
138
|
+
if (childPath && !children.includes(childPath)) children.push(childPath);
|
|
139
|
+
}
|
|
140
|
+
return children;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Find a static child path from a pattern relative to basePath
|
|
144
|
+
*
|
|
145
|
+
* For patterns like "/:table/new" and basePath "/users",
|
|
146
|
+
* we need to check if the pattern could match and what static
|
|
147
|
+
* segment comes after.
|
|
148
|
+
*/
|
|
149
|
+
findStaticChild(basePath, pattern) {
|
|
150
|
+
const baseSegments = basePath ? basePath.split("/").filter(Boolean) : [];
|
|
151
|
+
const patternSegments = pattern.split("/").filter(Boolean);
|
|
152
|
+
if (patternSegments.length <= baseSegments.length) return null;
|
|
153
|
+
for (let i = 0; i < baseSegments.length; i++) {
|
|
154
|
+
const patternSeg = patternSegments[i];
|
|
155
|
+
const baseSeg = baseSegments[i];
|
|
156
|
+
const isParam$1 = patternSeg?.startsWith(":");
|
|
157
|
+
const isWildcard$1 = patternSeg === "**" || patternSeg?.endsWith("*") || patternSeg?.endsWith("+") || patternSeg?.endsWith("(.*)") || patternSeg?.endsWith("(.+)");
|
|
158
|
+
if (patternSeg !== baseSeg && !isParam$1 && !isWildcard$1) return null;
|
|
159
|
+
}
|
|
160
|
+
const nextSegment = patternSegments[baseSegments.length];
|
|
161
|
+
if (!nextSegment) return null;
|
|
162
|
+
const isParam = nextSegment.startsWith(":");
|
|
163
|
+
const isWildcard = nextSegment === "**" || nextSegment.endsWith("*") || nextSegment.endsWith("+") || nextSegment.endsWith("(.*)") || nextSegment.endsWith("(.+)");
|
|
164
|
+
if (isParam || isWildcard) return null;
|
|
165
|
+
return `${basePath}/${nextSegment}`;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Get all registered patterns
|
|
169
|
+
*/
|
|
170
|
+
getAllPatterns() {
|
|
171
|
+
return Array.from(this.allPatterns);
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Get all routes for an operation
|
|
175
|
+
*/
|
|
176
|
+
getRoutesForOperation(operation) {
|
|
177
|
+
const storage = this.routers.get(operation);
|
|
178
|
+
if (!storage) return [];
|
|
179
|
+
return storage.routes.map((r) => r.definition);
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
//#endregion
|
|
184
|
+
export { ProviderRouter };
|
|
185
|
+
//# sourceMappingURL=router.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"router.mjs","names":["isParam","isWildcard"],"sources":["../../src/provider/router.ts"],"sourcesContent":["import type {\n ListDecoratorOptions,\n RouteDefinition,\n RouteHandler,\n RouteMatch,\n RouteOperation,\n} from \"./types.js\";\n\n/**\n * Compiled route with URLPattern and metadata\n */\ninterface CompiledRoute {\n /** URLPattern instance for matching */\n pattern: URLPattern;\n /** Original pattern string (e.g., /:path*\\/.meta) */\n originalPattern: string;\n /** Route definition */\n definition: RouteDefinition;\n /** Specificity score for priority sorting */\n specificity: number;\n}\n\n/**\n * Internal storage for routes by operation\n */\ninterface RouterStorage {\n routes: CompiledRoute[];\n}\n\n/**\n * Calculate specificity score for a pattern.\n * Higher score = higher priority.\n *\n * Scoring rules:\n * - Static segment: +100\n * - Named parameter (single segment): +10\n * - Wildcard ((.*) or (.+) or * or +): +1\n * - Bonus for more segments: +5 per segment\n *\n * Examples:\n * - /:path(.*) = 1 + 5 = 6 (low)\n * - /:path(.*)/.meta = 1 + 100 + 10 = 111 (higher - has static .meta)\n * - /:path(.*)/.meta/.kinds = 1 + 100 + 100 + 15 = 216 (highest)\n */\nfunction calculateSpecificity(pattern: string): number {\n let score = 0;\n const segments = pattern.split(\"/\").filter(Boolean);\n\n for (const segment of segments) {\n // Check for wildcard patterns: ends with *, +, (.*), or (.+)\n const isWildcard =\n segment.endsWith(\"*\") ||\n segment.endsWith(\"+\") ||\n segment.endsWith(\"(.*)\") ||\n segment.endsWith(\"(.+)\");\n\n if (isWildcard) {\n // Wildcard: lowest priority\n score += 1;\n } else if (segment.startsWith(\":\")) {\n // Named parameter\n score += 10;\n } else {\n // Static segment: highest priority\n score += 100;\n }\n }\n\n // Bonus for more segments (longer patterns are more specific)\n score += segments.length * 5;\n\n return score;\n}\n\n// Convert AFS route pattern syntax to URLPattern syntax.\n// Conversions:\n// - Standalone wildcard (e.g. at end) → /:_(.*) or /:name(.*)\n// - Suffix patterns (wildcard followed by more path) → optional group {/:name(.*)}?/suffix\n// - Trailing wildcard preceded by segments → optional group {/:name(.*)}?\n// - :name+ → :name(.+) (one or more segments)\nfunction convertToURLPattern(pattern: string): string {\n // Replace standalone /** with /:_(.*)\n let result = pattern.replace(/\\/\\*\\*$/g, \"/:_(.*)\");\n result = result.replace(/\\/\\*\\*\\//g, \"/:_(.*)/\");\n\n // Handle /** at start or middle\n if (result.includes(\"/**\")) {\n result = result.replace(/\\/\\*\\*/g, \"/:_(.*)\");\n }\n\n // Convert :name* followed by more path (suffix pattern) to optional group\n // e.g., /:path*/.meta → {/:path(.*)}?/.meta\n result = result.replace(/\\/:(\\w+)\\*(\\/.+)/g, \"{/:$1(.*)}?$2\");\n\n // Convert trailing :name* (preceded by other segments) to optional group\n // e.g., /:branch/:path* → /:branch{/:path(.*)}?\n // This allows /main to match with path=undefined, and /main/foo to match with path=\"foo\"\n // Only apply when there are at least 2 segments (prefix + wildcard)\n const segments = result.split(\"/\").filter(Boolean);\n if (segments.length >= 2) {\n const lastSegment = segments[segments.length - 1];\n if (lastSegment && /^:\\w+\\*$/.test(lastSegment)) {\n // Last segment is a wildcard like :path*\n const wildcardName = lastSegment.slice(1, -1); // Remove : and *\n const prefix = `/${segments.slice(0, -1).join(\"/\")}`;\n result = `${prefix}{/:${wildcardName}(.*)}?`;\n }\n }\n\n // Convert standalone :name* to :name(.*) for zero-or-more matching (including empty)\n result = result.replace(/:(\\w+)\\*/g, \":$1(.*)\");\n\n // Convert :name+ to :name(.+) for one-or-more matching\n result = result.replace(/:(\\w+)\\+/g, \":$1(.+)\");\n\n return result;\n}\n\n/**\n * Provider router using native URLPattern for type-safe route handling.\n * Supports suffix patterns like /:path*\\/.meta for flexible routing.\n */\nexport class ProviderRouter {\n private routers: Map<RouteOperation, RouterStorage> = new Map();\n private allPatterns: Set<string> = new Set();\n\n constructor() {\n // Initialize routers for each operation type\n const operations: RouteOperation[] = [\n \"list\",\n \"read\",\n \"write\",\n \"delete\",\n \"exec\",\n \"search\",\n \"stat\",\n \"explain\",\n \"rename\",\n ];\n for (const op of operations) {\n this.routers.set(op, {\n routes: [],\n });\n }\n }\n\n /**\n * Register a route with the router\n */\n registerRoute(\n pattern: string,\n operation: RouteOperation,\n handler: RouteHandler,\n description?: string,\n listOptions?: ListDecoratorOptions,\n ): void {\n const storage = this.routers.get(operation);\n if (!storage) {\n throw new Error(`Unknown operation: ${operation}`);\n }\n\n // Check for conflict\n const existing = storage.routes.find((r) => r.originalPattern === pattern);\n if (existing) {\n console.warn(\n `[AFSBaseProvider] Route conflict: ${operation} ${pattern} is being overwritten`,\n );\n // Remove the existing route\n storage.routes = storage.routes.filter((r) => r.originalPattern !== pattern);\n }\n\n const definition: RouteDefinition = {\n pattern,\n operation,\n handler,\n description,\n listOptions,\n };\n\n // Convert pattern to URLPattern syntax\n const urlPatternPath = convertToURLPattern(pattern);\n\n // Create URLPattern (using pathname only)\n const urlPattern = new URLPattern({ pathname: urlPatternPath });\n\n const specificity = calculateSpecificity(urlPatternPath);\n\n const compiledRoute: CompiledRoute = {\n pattern: urlPattern,\n originalPattern: pattern,\n definition,\n specificity,\n };\n\n // Insert in sorted order (highest specificity first)\n let inserted = false;\n for (let i = 0; i < storage.routes.length; i++) {\n const existingRoute = storage.routes[i];\n if (existingRoute && specificity > existingRoute.specificity) {\n storage.routes.splice(i, 0, compiledRoute);\n inserted = true;\n break;\n }\n }\n if (!inserted) {\n storage.routes.push(compiledRoute);\n }\n\n this.allPatterns.add(pattern);\n }\n\n /**\n * Match a path against registered routes for an operation.\n * Routes are checked in specificity order (most specific first).\n */\n match(path: string, operation: RouteOperation): RouteMatch | null {\n const storage = this.routers.get(operation);\n if (!storage) {\n return null;\n }\n\n // Ensure path starts with /\n const normalizedPath = path.startsWith(\"/\") ? path : `/${path}`;\n\n // Try routes in order (already sorted by specificity)\n for (const route of storage.routes) {\n const result = route.pattern.exec({ pathname: normalizedPath });\n if (result) {\n // Extract params from URLPattern groups\n const params: Record<string, string | undefined> = {};\n const groups = result.pathname.groups;\n\n for (const [key, value] of Object.entries(groups)) {\n // URLPattern may return empty string for optional wildcards\n // We preserve the original value (could be undefined or empty string)\n // Decode URL-encoded characters (e.g., %20 for spaces)\n params[key] = value !== undefined ? decodeURIComponent(value) : value;\n }\n\n return {\n route: route.definition,\n params: params as Record<string, string>,\n };\n }\n }\n\n return null;\n }\n\n /**\n * Get static children paths for a given path.\n * Used for list auto-expansion.\n *\n * This analyzes all registered patterns to find which ones\n * would be direct children of the given path.\n *\n * Excludes .meta and .actions as they are implicit paths.\n */\n getStaticChildren(basePath: string): string[] {\n const children: string[] = [];\n const normalizedBase = basePath === \"/\" ? \"\" : basePath;\n\n for (const pattern of this.allPatterns) {\n // Skip .meta and .actions - they are implicit\n if (pattern.endsWith(\"/.meta\") || pattern.endsWith(\"/.actions\")) {\n continue;\n }\n\n // Try to find a static child segment in this pattern\n const childPath = this.findStaticChild(normalizedBase, pattern);\n if (childPath && !children.includes(childPath)) {\n children.push(childPath);\n }\n }\n\n return children;\n }\n\n /**\n * Find a static child path from a pattern relative to basePath\n *\n * For patterns like \"/:table/new\" and basePath \"/users\",\n * we need to check if the pattern could match and what static\n * segment comes after.\n */\n private findStaticChild(basePath: string, pattern: string): string | null {\n const baseSegments = basePath ? basePath.split(\"/\").filter(Boolean) : [];\n const patternSegments = pattern.split(\"/\").filter(Boolean);\n\n // Pattern must be longer than base to have a child\n if (patternSegments.length <= baseSegments.length) {\n return null;\n }\n\n // Check if pattern could match basePath\n for (let i = 0; i < baseSegments.length; i++) {\n const patternSeg = patternSegments[i];\n const baseSeg = baseSegments[i];\n\n // Pattern segment must either match exactly or be a parameter/wildcard\n const isParam = patternSeg?.startsWith(\":\");\n const isWildcard =\n patternSeg === \"**\" ||\n patternSeg?.endsWith(\"*\") ||\n patternSeg?.endsWith(\"+\") ||\n patternSeg?.endsWith(\"(.*)\") ||\n patternSeg?.endsWith(\"(.+)\");\n if (patternSeg !== baseSeg && !isParam && !isWildcard) {\n return null;\n }\n }\n\n // Get the next segment after basePath\n const nextSegment = patternSegments[baseSegments.length];\n\n // Must be a static segment (not a parameter or wildcard)\n if (!nextSegment) {\n return null;\n }\n const isParam = nextSegment.startsWith(\":\");\n const isWildcard =\n nextSegment === \"**\" ||\n nextSegment.endsWith(\"*\") ||\n nextSegment.endsWith(\"+\") ||\n nextSegment.endsWith(\"(.*)\") ||\n nextSegment.endsWith(\"(.+)\");\n if (isParam || isWildcard) {\n return null;\n }\n\n // Build the child path\n return `${basePath}/${nextSegment}`;\n }\n\n /**\n * Get all registered patterns\n */\n getAllPatterns(): string[] {\n return Array.from(this.allPatterns);\n }\n\n /**\n * Get all routes for an operation\n */\n getRoutesForOperation(operation: RouteOperation): RouteDefinition[] {\n const storage = this.routers.get(operation);\n if (!storage) {\n return [];\n }\n return storage.routes.map((r) => r.definition);\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { AFSExplainResult } from "../meta/type.cjs";
|
|
2
|
+
import { AFSDeleteOptions, AFSDeleteResult, AFSEntry, AFSExecOptions, AFSExecResult, AFSListOptions, AFSReadOptions, AFSRenameResult, AFSSearchOptions, AFSSearchResult, AFSStatResult, AFSWriteEntryPayload, AFSWriteOptions, AFSWriteResult } from "../type.cjs";
|
|
3
|
+
|
|
4
|
+
//#region src/provider/types.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Route operation types matching AFSModule methods
|
|
7
|
+
*/
|
|
8
|
+
type RouteOperation = "list" | "read" | "write" | "delete" | "exec" | "search" | "stat" | "explain" | "rename";
|
|
9
|
+
/**
|
|
10
|
+
* Union type for all possible operation options
|
|
11
|
+
*/
|
|
12
|
+
type RouteOptions = AFSListOptions | AFSReadOptions | AFSWriteOptions | AFSDeleteOptions | AFSExecOptions | AFSSearchOptions;
|
|
13
|
+
/**
|
|
14
|
+
* Context passed to route handlers
|
|
15
|
+
*
|
|
16
|
+
* Note: Wildcard params (e.g., :path*) may be undefined for paths that
|
|
17
|
+
* don't include that segment (e.g., root paths). Always check for undefined
|
|
18
|
+
* when using optional wildcard params.
|
|
19
|
+
*/
|
|
20
|
+
interface RouteContext<TParams = Record<string, string | undefined>> {
|
|
21
|
+
/** The full request path */
|
|
22
|
+
path: string;
|
|
23
|
+
/** Parameters extracted from the route pattern */
|
|
24
|
+
params: TParams;
|
|
25
|
+
/** Operation options (type depends on operation) */
|
|
26
|
+
options?: RouteOptions;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Result type for @List handlers
|
|
30
|
+
* - data: array of entries
|
|
31
|
+
* - total: optional, if present indicates complete dataset size
|
|
32
|
+
* if absent, data.length IS the total (all data returned)
|
|
33
|
+
* - noExpand: optional, paths that should not be expanded during BFS depth traversal
|
|
34
|
+
* (internal use only, not exposed in public API)
|
|
35
|
+
*/
|
|
36
|
+
interface ListHandlerResult {
|
|
37
|
+
data: AFSEntry[];
|
|
38
|
+
total?: number;
|
|
39
|
+
/** Paths that should not be expanded during BFS (internal, not exposed in public API) */
|
|
40
|
+
noExpand?: string[];
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Handler function types for each operation
|
|
44
|
+
*/
|
|
45
|
+
type ListRouteHandler<TParams = Record<string, string | undefined>> = (ctx: RouteContext<TParams>) => Promise<ListHandlerResult>;
|
|
46
|
+
type ReadRouteHandler<TParams = Record<string, string | undefined>> = (ctx: RouteContext<TParams>) => Promise<AFSEntry | undefined>;
|
|
47
|
+
type WriteRouteHandler<TParams = Record<string, string | undefined>> = (ctx: RouteContext<TParams>, content: AFSWriteEntryPayload) => Promise<AFSWriteResult>;
|
|
48
|
+
type DeleteRouteHandler<TParams = Record<string, string | undefined>> = (ctx: RouteContext<TParams>) => Promise<AFSDeleteResult>;
|
|
49
|
+
type ExecRouteHandler<TParams = Record<string, string | undefined>> = (ctx: RouteContext<TParams>, args: Record<string, unknown>) => Promise<AFSExecResult>;
|
|
50
|
+
type SearchRouteHandler<TParams = Record<string, string | undefined>> = (ctx: RouteContext<TParams>, query: string, options?: AFSSearchOptions) => Promise<AFSSearchResult>;
|
|
51
|
+
type StatRouteHandler<TParams = Record<string, string | undefined>> = (ctx: RouteContext<TParams>) => Promise<AFSStatResult>;
|
|
52
|
+
type ExplainRouteHandler<TParams = Record<string, string | undefined>> = (ctx: RouteContext<TParams>) => Promise<AFSExplainResult>;
|
|
53
|
+
type RenameRouteHandler<TParams = Record<string, string | undefined>> = (ctx: RouteContext<TParams>, newPath: string) => Promise<AFSRenameResult>;
|
|
54
|
+
/**
|
|
55
|
+
* Union type for all route handlers
|
|
56
|
+
*/
|
|
57
|
+
type RouteHandler = ListRouteHandler | ReadRouteHandler | WriteRouteHandler | DeleteRouteHandler | ExecRouteHandler | SearchRouteHandler | StatRouteHandler | ExplainRouteHandler | RenameRouteHandler;
|
|
58
|
+
/**
|
|
59
|
+
* Route definition stored in the router
|
|
60
|
+
*/
|
|
61
|
+
interface RouteDefinition {
|
|
62
|
+
/** Route pattern (e.g., "/:table/:pk") */
|
|
63
|
+
pattern: string;
|
|
64
|
+
/** Operation type */
|
|
65
|
+
operation: RouteOperation;
|
|
66
|
+
/** Handler function */
|
|
67
|
+
handler: RouteHandler;
|
|
68
|
+
/** Optional description for documentation */
|
|
69
|
+
description?: string;
|
|
70
|
+
/** Options specific to list operations */
|
|
71
|
+
listOptions?: ListDecoratorOptions;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Options for @List decorator
|
|
75
|
+
*/
|
|
76
|
+
interface ListDecoratorOptions {
|
|
77
|
+
/**
|
|
78
|
+
* Whether the handler handles maxDepth recursion itself.
|
|
79
|
+
* - false (default): Base provider will auto-expand depth via BFS
|
|
80
|
+
* - true: Handler is responsible for depth traversal
|
|
81
|
+
*
|
|
82
|
+
* Most providers can use the default (false) and just return single-level results.
|
|
83
|
+
* Set to true for providers that need custom depth handling (like S3 with delimiter optimization).
|
|
84
|
+
*/
|
|
85
|
+
handleDepth?: boolean;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Metadata stored by decorators for later collection
|
|
89
|
+
*/
|
|
90
|
+
interface RouteMetadata {
|
|
91
|
+
/** Route pattern */
|
|
92
|
+
pattern: string;
|
|
93
|
+
/** Operation type */
|
|
94
|
+
operation: RouteOperation;
|
|
95
|
+
/** Method name on the class */
|
|
96
|
+
methodName: string;
|
|
97
|
+
/** Optional description */
|
|
98
|
+
description?: string;
|
|
99
|
+
/** Options specific to list operations */
|
|
100
|
+
listOptions?: ListDecoratorOptions;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Match result from router
|
|
104
|
+
*/
|
|
105
|
+
interface RouteMatch {
|
|
106
|
+
/** The matched route definition */
|
|
107
|
+
route: RouteDefinition;
|
|
108
|
+
/** Extracted parameters (wildcards may be undefined or empty string) */
|
|
109
|
+
params: Record<string, string | undefined>;
|
|
110
|
+
}
|
|
111
|
+
//#endregion
|
|
112
|
+
export { DeleteRouteHandler, ExecRouteHandler, ExplainRouteHandler, ListDecoratorOptions, ListHandlerResult, ListRouteHandler, ReadRouteHandler, RenameRouteHandler, RouteContext, RouteDefinition, RouteHandler, RouteMatch, RouteMetadata, RouteOperation, SearchRouteHandler, StatRouteHandler, WriteRouteHandler };
|
|
113
|
+
//# sourceMappingURL=types.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.cts","names":[],"sources":["../../src/provider/types.ts"],"mappings":";;;;;;;KAqBY,cAAA;;;;KAcA,YAAA,GACR,cAAA,GACA,cAAA,GACA,eAAA,GACA,gBAAA,GACA,cAAA,GACA,gBAAA;AANJ;;;;;;;AAAA,UAeiB,YAAA,WAAuB,MAAA;EATpC;EAWF,IAAA;EAXkB;EAclB,MAAA,EAAQ,OAAA;EAlBN;EAqBF,OAAA,GAAU,YAAA;AAAA;;;;;AARZ;;;;UAmBiB,iBAAA;EACf,IAAA,EAAM,QAAA;EACN,KAAA;EAbsB;EAetB,QAAA;AAAA;;;;KAMU,gBAAA,WAA2B,MAAA,iCACrC,GAAA,EAAK,YAAA,CAAa,OAAA,MACf,OAAA,CAAQ,iBAAA;AAAA,KAED,gBAAA,WAA2B,MAAA,iCACrC,GAAA,EAAK,YAAA,CAAa,OAAA,MACf,OAAA,CAAQ,QAAA;AAAA,KAED,iBAAA,WAA4B,MAAA,iCACtC,GAAA,EAAK,YAAA,CAAa,OAAA,GAClB,OAAA,EAAS,oBAAA,KACN,OAAA,CAAQ,cAAA;AAAA,KAED,kBAAA,WAA6B,MAAA,iCACvC,GAAA,EAAK,YAAA,CAAa,OAAA,MACf,OAAA,CAAQ,eAAA;AAAA,KAED,gBAAA,WAA2B,MAAA,iCACrC,GAAA,EAAK,YAAA,CAAa,OAAA,GAClB,IAAA,EAAM,MAAA,sBACH,OAAA,CAAQ,aAAA;AAAA,KAED,kBAAA,WAA6B,MAAA,iCACvC,GAAA,EAAK,YAAA,CAAa,OAAA,GAClB,KAAA,UACA,OAAA,GAAU,gBAAA,KACP,OAAA,CAAQ,eAAA;AAAA,KAED,gBAAA,WAA2B,MAAA,iCACrC,GAAA,EAAK,YAAA,CAAa,OAAA,MACf,OAAA,CAAQ,aAAA;AAAA,KAED,mBAAA,WAA8B,MAAA,iCACxC,GAAA,EAAK,YAAA,CAAa,OAAA,MACf,OAAA,CAAQ,gBAAA;AAAA,KAED,kBAAA,WAA6B,MAAA,iCACvC,GAAA,EAAK,YAAA,CAAa,OAAA,GAClB,OAAA,aACG,OAAA,CAAQ,eAAA;;;;KAKD,YAAA,GACR,gBAAA,GACA,gBAAA,GACA,iBAAA,GACA,kBAAA,GACA,gBAAA,GACA,kBAAA,GACA,gBAAA,GACA,mBAAA,GACA,kBAAA;;AArDJ;;UA0DiB,eAAA;EA1DsB;EA4DrC,OAAA;EA3DK;EA8DL,SAAA,EAAW,cAAA;EA7DR;EAgEH,OAAA,EAAS,YAAA;EAhEC;EAmEV,WAAA;EArEqC;EAwErC,WAAA,GAAc,oBAAA;AAAA;;;;UAMC,oBAAA;EA5Ea;AAE9B;;;;;;;EAmFE,WAAA;AAAA;;;;UAMe,aAAA;EAxFG;EA0FlB,OAAA;EAzFG;EA4FH,SAAA,EAAW,cAAA;EA5FQ;EA+FnB,UAAA;EA7FU;EAgGV,WAAA;EAhG2B;EAmG3B,WAAA,GAAc,oBAAA;AAAA;;;;UAMC,UAAA;EAtGL;EAwGV,KAAA,EAAO,eAAA;EA3GqB;EA8G5B,MAAA,EAAQ,MAAA;AAAA"}
|