@typed/app 1.0.0-beta.1

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.
Files changed (116) hide show
  1. package/README.md +166 -0
  2. package/dist/HttpApiVirtualModulePlugin.d.ts +26 -0
  3. package/dist/HttpApiVirtualModulePlugin.d.ts.map +1 -0
  4. package/dist/HttpApiVirtualModulePlugin.js +301 -0
  5. package/dist/RouterVirtualModulePlugin.d.ts +23 -0
  6. package/dist/RouterVirtualModulePlugin.d.ts.map +1 -0
  7. package/dist/RouterVirtualModulePlugin.js +176 -0
  8. package/dist/createTypeInfoApiSessionForApp.d.ts +29 -0
  9. package/dist/createTypeInfoApiSessionForApp.d.ts.map +1 -0
  10. package/dist/createTypeInfoApiSessionForApp.js +46 -0
  11. package/dist/httpapi/defineApiHandler.d.ts +70 -0
  12. package/dist/httpapi/defineApiHandler.d.ts.map +1 -0
  13. package/dist/httpapi/defineApiHandler.js +23 -0
  14. package/dist/index.d.ts +9 -0
  15. package/dist/index.d.ts.map +1 -0
  16. package/dist/index.js +7 -0
  17. package/dist/internal/appConfigTypes.d.ts +11 -0
  18. package/dist/internal/appConfigTypes.d.ts.map +1 -0
  19. package/dist/internal/appConfigTypes.js +1 -0
  20. package/dist/internal/appLayerTypes.d.ts +24 -0
  21. package/dist/internal/appLayerTypes.d.ts.map +1 -0
  22. package/dist/internal/appLayerTypes.js +28 -0
  23. package/dist/internal/buildRouteDescriptors.d.ts +48 -0
  24. package/dist/internal/buildRouteDescriptors.d.ts.map +1 -0
  25. package/dist/internal/buildRouteDescriptors.js +371 -0
  26. package/dist/internal/emitHttpApiSource.d.ts +18 -0
  27. package/dist/internal/emitHttpApiSource.d.ts.map +1 -0
  28. package/dist/internal/emitHttpApiSource.js +404 -0
  29. package/dist/internal/emitRouterHelpers.d.ts +17 -0
  30. package/dist/internal/emitRouterHelpers.d.ts.map +1 -0
  31. package/dist/internal/emitRouterHelpers.js +74 -0
  32. package/dist/internal/emitRouterSource.d.ts +8 -0
  33. package/dist/internal/emitRouterSource.d.ts.map +1 -0
  34. package/dist/internal/emitRouterSource.js +139 -0
  35. package/dist/internal/extractHttpApiLiterals.d.ts +17 -0
  36. package/dist/internal/extractHttpApiLiterals.d.ts.map +1 -0
  37. package/dist/internal/extractHttpApiLiterals.js +45 -0
  38. package/dist/internal/httpapiDescriptorTree.d.ts +75 -0
  39. package/dist/internal/httpapiDescriptorTree.d.ts.map +1 -0
  40. package/dist/internal/httpapiDescriptorTree.js +182 -0
  41. package/dist/internal/httpapiEndpointContract.d.ts +32 -0
  42. package/dist/internal/httpapiEndpointContract.d.ts.map +1 -0
  43. package/dist/internal/httpapiEndpointContract.js +79 -0
  44. package/dist/internal/httpapiFileRoles.d.ts +67 -0
  45. package/dist/internal/httpapiFileRoles.d.ts.map +1 -0
  46. package/dist/internal/httpapiFileRoles.js +145 -0
  47. package/dist/internal/httpapiId.d.ts +30 -0
  48. package/dist/internal/httpapiId.d.ts.map +1 -0
  49. package/dist/internal/httpapiId.js +57 -0
  50. package/dist/internal/httpapiOpenApiConfig.d.ts +87 -0
  51. package/dist/internal/httpapiOpenApiConfig.d.ts.map +1 -0
  52. package/dist/internal/httpapiOpenApiConfig.js +144 -0
  53. package/dist/internal/httpapiSort.d.ts +16 -0
  54. package/dist/internal/httpapiSort.d.ts.map +1 -0
  55. package/dist/internal/httpapiSort.js +29 -0
  56. package/dist/internal/path.d.ts +16 -0
  57. package/dist/internal/path.d.ts.map +1 -0
  58. package/dist/internal/path.js +38 -0
  59. package/dist/internal/resolveConfig.d.ts +8 -0
  60. package/dist/internal/resolveConfig.d.ts.map +1 -0
  61. package/dist/internal/resolveConfig.js +13 -0
  62. package/dist/internal/routeIdentifiers.d.ts +18 -0
  63. package/dist/internal/routeIdentifiers.d.ts.map +1 -0
  64. package/dist/internal/routeIdentifiers.js +90 -0
  65. package/dist/internal/routeTypeNode.d.ts +45 -0
  66. package/dist/internal/routeTypeNode.d.ts.map +1 -0
  67. package/dist/internal/routeTypeNode.js +93 -0
  68. package/dist/internal/routerDescriptorTree.d.ts +110 -0
  69. package/dist/internal/routerDescriptorTree.d.ts.map +1 -0
  70. package/dist/internal/routerDescriptorTree.js +230 -0
  71. package/dist/internal/typeTargetBootstrap.d.ts +2 -0
  72. package/dist/internal/typeTargetBootstrap.d.ts.map +1 -0
  73. package/dist/internal/typeTargetBootstrap.js +23 -0
  74. package/dist/internal/typeTargetBootstrapHttpApi.d.ts +2 -0
  75. package/dist/internal/typeTargetBootstrapHttpApi.d.ts.map +1 -0
  76. package/dist/internal/typeTargetBootstrapHttpApi.js +21 -0
  77. package/dist/internal/typeTargetSpecs.d.ts +15 -0
  78. package/dist/internal/typeTargetSpecs.d.ts.map +1 -0
  79. package/dist/internal/typeTargetSpecs.js +32 -0
  80. package/dist/internal/validation.d.ts +12 -0
  81. package/dist/internal/validation.d.ts.map +1 -0
  82. package/dist/internal/validation.js +32 -0
  83. package/package.json +45 -0
  84. package/src/HttpApiVirtualModulePlugin.test.ts +1062 -0
  85. package/src/HttpApiVirtualModulePlugin.ts +376 -0
  86. package/src/RouterVirtualModulePlugin.test.ts +1254 -0
  87. package/src/RouterVirtualModulePlugin.ts +242 -0
  88. package/src/createTypeInfoApiSessionForApp.ts +57 -0
  89. package/src/defineApiHandler.test.ts +100 -0
  90. package/src/httpapi/defineApiHandler.ts +141 -0
  91. package/src/httpapiDescriptorTree.test.ts +124 -0
  92. package/src/httpapiEndpointContract.test.ts +160 -0
  93. package/src/httpapiFileRoles.test.ts +105 -0
  94. package/src/index.ts +40 -0
  95. package/src/internal/appConfigTypes.ts +12 -0
  96. package/src/internal/appLayerTypes.ts +79 -0
  97. package/src/internal/buildRouteDescriptors.ts +489 -0
  98. package/src/internal/emitHttpApiSource.ts +563 -0
  99. package/src/internal/emitRouterHelpers.ts +89 -0
  100. package/src/internal/emitRouterSource.ts +191 -0
  101. package/src/internal/extractHttpApiLiterals.ts +67 -0
  102. package/src/internal/httpapiDescriptorTree.ts +283 -0
  103. package/src/internal/httpapiEndpointContract.ts +110 -0
  104. package/src/internal/httpapiFileRoles.ts +204 -0
  105. package/src/internal/httpapiId.ts +78 -0
  106. package/src/internal/httpapiOpenApiConfig.ts +228 -0
  107. package/src/internal/httpapiSort.ts +39 -0
  108. package/src/internal/path.ts +46 -0
  109. package/src/internal/resolveConfig.ts +15 -0
  110. package/src/internal/routeIdentifiers.ts +93 -0
  111. package/src/internal/routeTypeNode.ts +120 -0
  112. package/src/internal/routerDescriptorTree.ts +366 -0
  113. package/src/internal/typeTargetBootstrap.ts +24 -0
  114. package/src/internal/typeTargetBootstrapHttpApi.ts +22 -0
  115. package/src/internal/typeTargetSpecs.ts +35 -0
  116. package/src/internal/validation.ts +46 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"httpapiId.d.ts","sourceRoot":"","sources":["../../src/internal/httpapiId.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,eAAO,MAAM,6BAA6B,SAAS,CAAC;AAEpD,MAAM,MAAM,iCAAiC,GACzC;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAA;CAAE,GACzD;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEpD;;;GAGG;AACH,wBAAgB,2BAA2B,CACzC,EAAE,EAAE,MAAM,EACV,MAAM,GAAE,MAAsC,GAC7C,iCAAiC,CAwBnC;AAED,MAAM,MAAM,mCAAmC,GAC3C;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAA;CAAE,GACvD;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEpD;;;GAGG;AACH,wBAAgB,6BAA6B,CAC3C,EAAE,EAAE,MAAM,EACV,QAAQ,EAAE,MAAM,EAChB,MAAM,GAAE,MAAsC,GAC7C,mCAAmC,CAiBrC"}
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Parse and resolve `api:` virtual module IDs (router-plugin semantics).
3
+ * Used by HttpApi virtual module plugin for target-directory resolution.
4
+ */
5
+ import { dirname } from "node:path";
6
+ import { pathIsUnderBase, resolvePathUnderBase, toPosixPath } from "./path.js";
7
+ import { validateNonEmptyString, validatePathSegment } from "./validation.js";
8
+ export const HTTPAPI_VIRTUAL_MODULE_PREFIX = "api:";
9
+ /**
10
+ * Parses an `api:./<directory>` (or `api:<directory>`) ID.
11
+ * Normalizes bare directory to `./<directory>`.
12
+ */
13
+ export function parseHttpApiVirtualModuleId(id, prefix = HTTPAPI_VIRTUAL_MODULE_PREFIX) {
14
+ const idResult = validateNonEmptyString(id, "id");
15
+ if (!idResult.ok)
16
+ return { ok: false, reason: idResult.reason };
17
+ const prefixResult = validateNonEmptyString(prefix, "prefix");
18
+ if (!prefixResult.ok)
19
+ return { ok: false, reason: prefixResult.reason };
20
+ if (!id.startsWith(prefix)) {
21
+ return { ok: false, reason: `id must start with "${prefix}"` };
22
+ }
23
+ let relativeDirectory = id.slice(prefix.length);
24
+ if (relativeDirectory.length > 0 &&
25
+ relativeDirectory !== "." &&
26
+ relativeDirectory !== ".." &&
27
+ !relativeDirectory.startsWith("./") &&
28
+ !relativeDirectory.startsWith("../") &&
29
+ !relativeDirectory.startsWith("/")) {
30
+ relativeDirectory = `./${relativeDirectory}`;
31
+ }
32
+ const relativeResult = validatePathSegment(relativeDirectory, "relativeDirectory");
33
+ if (!relativeResult.ok)
34
+ return { ok: false, reason: relativeResult.reason };
35
+ return { ok: true, relativeDirectory: relativeResult.value };
36
+ }
37
+ /**
38
+ * Resolves the target directory for an `api:` ID relative to the importer.
39
+ * Rejects paths that escape the importer base directory.
40
+ */
41
+ export function resolveHttpApiTargetDirectory(id, importer, prefix = HTTPAPI_VIRTUAL_MODULE_PREFIX) {
42
+ const parsed = parseHttpApiVirtualModuleId(id, prefix);
43
+ if (!parsed.ok)
44
+ return parsed;
45
+ const importerResult = validatePathSegment(importer, "importer");
46
+ if (!importerResult.ok)
47
+ return { ok: false, reason: importerResult.reason };
48
+ const importerDir = dirname(toPosixPath(importerResult.value));
49
+ const resolved = resolvePathUnderBase(importerDir, parsed.relativeDirectory);
50
+ if (!resolved.ok) {
51
+ return { ok: false, reason: "resolved target directory escapes importer base directory" };
52
+ }
53
+ if (!pathIsUnderBase(importerDir, resolved.path)) {
54
+ return { ok: false, reason: "resolved target directory is outside importer base directory" };
55
+ }
56
+ return { ok: true, targetDirectory: toPosixPath(resolved.path) };
57
+ }
@@ -0,0 +1,87 @@
1
+ /**
2
+ * OpenAPI config mapper for HttpApi virtual module plugin.
3
+ * Maps convention/option layers to Effect-backed surfaces:
4
+ * - OpenApi.annotations keys
5
+ * - OpenApi.fromApi additionalProperties (API scope only)
6
+ * - Exposure: jsonPath, swaggerPath, scalar (json/swagger/scalar modes)
7
+ * Scope validation and route-conflict diagnostics are applied.
8
+ */
9
+ /** Supported OpenApi.annotation keys (Effect-backed). */
10
+ export declare const OPENAPI_ANNOTATION_KEYS: readonly ["identifier", "title", "version", "description", "license", "summary", "deprecated", "externalDocs", "servers", "format", "override", "exclude", "transform"];
11
+ export type OpenApiAnnotationKey = (typeof OPENAPI_ANNOTATION_KEYS)[number];
12
+ export declare const OPENAPI_ANNOTATION_KEY_SET: Set<string>;
13
+ /** Scope at which OpenAPI config is applied. */
14
+ export type OpenApiConfigScope = "api" | "group" | "endpoint";
15
+ /** Annotation-only config (allowed at api, group, endpoint). */
16
+ export interface OpenApiAnnotationsConfig {
17
+ readonly [key: string]: unknown;
18
+ }
19
+ /** Spec generation options (API scope only). */
20
+ export interface OpenApiGenerationConfig {
21
+ readonly additionalProperties?: boolean | Record<string, unknown>;
22
+ }
23
+ /** Scalar exposure config. */
24
+ export interface OpenApiScalarExposureConfig {
25
+ readonly path?: `/${string}`;
26
+ readonly source?: "inline" | "cdn";
27
+ readonly version?: string;
28
+ readonly config?: Record<string, unknown>;
29
+ }
30
+ /** Exposure routes (API scope only). */
31
+ export interface OpenApiExposureConfig {
32
+ readonly jsonPath?: `/${string}` | false;
33
+ readonly swaggerPath?: `/${string}` | false;
34
+ readonly scalar?: OpenApiScalarExposureConfig | false;
35
+ }
36
+ /** Normalized OpenAPI config after scope validation. */
37
+ export interface NormalizedOpenApiConfig {
38
+ readonly annotations: OpenApiAnnotationsConfig;
39
+ readonly generation: OpenApiGenerationConfig;
40
+ readonly exposure: OpenApiExposureConfig;
41
+ }
42
+ /** Diagnostic for OpenAPI config validation. */
43
+ export interface OpenApiConfigDiagnostic {
44
+ readonly code: string;
45
+ readonly message: string;
46
+ readonly scope?: OpenApiConfigScope;
47
+ }
48
+ /**
49
+ * Validates that generation options (e.g. additionalProperties) are only at API scope.
50
+ */
51
+ export declare function validateOpenApiGenerationScope(scope: OpenApiConfigScope, generation: OpenApiGenerationConfig): OpenApiConfigDiagnostic[];
52
+ /**
53
+ * Validates that exposure options (jsonPath, swaggerPath, scalar) are only at API scope.
54
+ */
55
+ export declare function validateOpenApiExposureScope(scope: OpenApiConfigScope, exposure: OpenApiExposureConfig): OpenApiConfigDiagnostic[];
56
+ /**
57
+ * Collects exposure route paths and detects conflicts (same path, different mode).
58
+ */
59
+ export interface ExposureRouteEntry {
60
+ readonly path: string;
61
+ readonly mode: "json" | "swagger" | "scalar";
62
+ }
63
+ export declare function collectExposureRoutes(exposure: OpenApiExposureConfig): ExposureRouteEntry[];
64
+ /**
65
+ * Detects route conflicts: same path used for more than one exposure mode.
66
+ */
67
+ export declare function validateOpenApiExposureRouteConflicts(exposure: OpenApiExposureConfig): OpenApiConfigDiagnostic[];
68
+ /**
69
+ * Filters raw annotation keys to Effect-supported set; emits diagnostic for unsupported keys.
70
+ */
71
+ export declare function filterAnnotationKeys(raw: Record<string, unknown>): {
72
+ annotations: OpenApiAnnotationsConfig;
73
+ diagnostics: OpenApiConfigDiagnostic[];
74
+ };
75
+ /**
76
+ * Normalizes and validates OpenAPI config for API scope.
77
+ * Merges annotations, validates generation/exposure scope and route conflicts.
78
+ */
79
+ export declare function normalizeOpenApiConfig(scope: OpenApiConfigScope, raw: {
80
+ annotations?: Record<string, unknown>;
81
+ generation?: OpenApiGenerationConfig;
82
+ exposure?: OpenApiExposureConfig;
83
+ }): {
84
+ config: NormalizedOpenApiConfig;
85
+ diagnostics: OpenApiConfigDiagnostic[];
86
+ };
87
+ //# sourceMappingURL=httpapiOpenApiConfig.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"httpapiOpenApiConfig.d.ts","sourceRoot":"","sources":["../../src/internal/httpapiOpenApiConfig.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,144 @@
1
+ /**
2
+ * OpenAPI config mapper for HttpApi virtual module plugin.
3
+ * Maps convention/option layers to Effect-backed surfaces:
4
+ * - OpenApi.annotations keys
5
+ * - OpenApi.fromApi additionalProperties (API scope only)
6
+ * - Exposure: jsonPath, swaggerPath, scalar (json/swagger/scalar modes)
7
+ * Scope validation and route-conflict diagnostics are applied.
8
+ */
9
+ /** Supported OpenApi.annotation keys (Effect-backed). */
10
+ export const OPENAPI_ANNOTATION_KEYS = [
11
+ "identifier",
12
+ "title",
13
+ "version",
14
+ "description",
15
+ "license",
16
+ "summary",
17
+ "deprecated",
18
+ "externalDocs",
19
+ "servers",
20
+ "format",
21
+ "override",
22
+ "exclude",
23
+ "transform",
24
+ ];
25
+ export const OPENAPI_ANNOTATION_KEY_SET = new Set(OPENAPI_ANNOTATION_KEYS);
26
+ const DIAG_SCOPE_GENERATION = "AVM-OPENAPI-001";
27
+ const DIAG_SCOPE_EXPOSURE = "AVM-OPENAPI-002";
28
+ const DIAG_ROUTE_CONFLICT = "AVM-OPENAPI-003";
29
+ const DIAG_INVALID_ANNOTATION_KEY = "AVM-OPENAPI-004";
30
+ /**
31
+ * Validates that generation options (e.g. additionalProperties) are only at API scope.
32
+ */
33
+ export function validateOpenApiGenerationScope(scope, generation) {
34
+ const diagnostics = [];
35
+ if (scope === "api")
36
+ return diagnostics;
37
+ const hasGen = generation.additionalProperties !== undefined &&
38
+ (typeof generation.additionalProperties === "boolean" ||
39
+ (typeof generation.additionalProperties === "object" && generation.additionalProperties !== null));
40
+ if (hasGen) {
41
+ diagnostics.push({
42
+ code: DIAG_SCOPE_GENERATION,
43
+ message: "OpenAPI generation options (e.g. additionalProperties) are allowed at API scope only.",
44
+ scope,
45
+ });
46
+ }
47
+ return diagnostics;
48
+ }
49
+ /**
50
+ * Validates that exposure options (jsonPath, swaggerPath, scalar) are only at API scope.
51
+ */
52
+ export function validateOpenApiExposureScope(scope, exposure) {
53
+ const diagnostics = [];
54
+ if (scope === "api")
55
+ return diagnostics;
56
+ const hasExposure = exposure.jsonPath !== undefined ||
57
+ exposure.swaggerPath !== undefined ||
58
+ exposure.scalar !== undefined;
59
+ if (hasExposure) {
60
+ diagnostics.push({
61
+ code: DIAG_SCOPE_EXPOSURE,
62
+ message: "OpenAPI exposure options (jsonPath, swaggerPath, scalar) are allowed at API scope only.",
63
+ scope,
64
+ });
65
+ }
66
+ return diagnostics;
67
+ }
68
+ export function collectExposureRoutes(exposure) {
69
+ const entries = [];
70
+ if (exposure.jsonPath && typeof exposure.jsonPath === "string") {
71
+ entries.push({ path: exposure.jsonPath, mode: "json" });
72
+ }
73
+ if (exposure.swaggerPath && typeof exposure.swaggerPath === "string") {
74
+ entries.push({ path: exposure.swaggerPath, mode: "swagger" });
75
+ }
76
+ if (exposure.scalar && typeof exposure.scalar === "object" && exposure.scalar.path) {
77
+ entries.push({ path: exposure.scalar.path, mode: "scalar" });
78
+ }
79
+ return entries;
80
+ }
81
+ /**
82
+ * Detects route conflicts: same path used for more than one exposure mode.
83
+ */
84
+ export function validateOpenApiExposureRouteConflicts(exposure) {
85
+ const routes = collectExposureRoutes(exposure);
86
+ const byPath = new Map();
87
+ for (const { path, mode } of routes) {
88
+ const normalized = path.toLowerCase().replace(/\/+$/, "") || "/";
89
+ const list = byPath.get(normalized) ?? [];
90
+ list.push(mode);
91
+ byPath.set(normalized, list);
92
+ }
93
+ const diagnostics = [];
94
+ for (const [path, modes] of byPath) {
95
+ if (modes.length > 1) {
96
+ diagnostics.push({
97
+ code: DIAG_ROUTE_CONFLICT,
98
+ message: `OpenAPI exposure route conflict: path "${path}" used for multiple modes: ${[...new Set(modes)].join(", ")}`,
99
+ });
100
+ }
101
+ }
102
+ return diagnostics;
103
+ }
104
+ /**
105
+ * Filters raw annotation keys to Effect-supported set; emits diagnostic for unsupported keys.
106
+ */
107
+ export function filterAnnotationKeys(raw) {
108
+ const annotations = {};
109
+ const diagnostics = [];
110
+ for (const [key, value] of Object.entries(raw)) {
111
+ if (OPENAPI_ANNOTATION_KEY_SET.has(key)) {
112
+ annotations[key] = value;
113
+ }
114
+ else {
115
+ diagnostics.push({
116
+ code: DIAG_INVALID_ANNOTATION_KEY,
117
+ message: `Unsupported OpenAPI annotation key: "${key}". Supported: ${OPENAPI_ANNOTATION_KEYS.join(", ")}`,
118
+ });
119
+ }
120
+ }
121
+ return { annotations, diagnostics };
122
+ }
123
+ /**
124
+ * Normalizes and validates OpenAPI config for API scope.
125
+ * Merges annotations, validates generation/exposure scope and route conflicts.
126
+ */
127
+ export function normalizeOpenApiConfig(scope, raw) {
128
+ const diagnostics = [];
129
+ const { annotations: ann, diagnostics: annDiag } = filterAnnotationKeys((raw.annotations ?? {}));
130
+ diagnostics.push(...annDiag);
131
+ const generation = raw.generation ?? {};
132
+ diagnostics.push(...validateOpenApiGenerationScope(scope, generation));
133
+ const exposure = raw.exposure ?? {};
134
+ diagnostics.push(...validateOpenApiExposureScope(scope, exposure));
135
+ if (scope === "api") {
136
+ diagnostics.push(...validateOpenApiExposureRouteConflicts(exposure));
137
+ }
138
+ const config = {
139
+ annotations: ann,
140
+ generation,
141
+ exposure,
142
+ };
143
+ return { config, diagnostics };
144
+ }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Deterministic ordering for HttpApi discovery: paths, roles, and AST nodes.
3
+ * Centralizes stable sort so AST nodes and file roles have consistent order.
4
+ */
5
+ import type { HttpApiTreeNode } from "./httpapiDescriptorTree.js";
6
+ import { compareHttpApiPathOrder, normalizeHttpApiRelativePath, sortHttpApiPaths } from "./httpapiFileRoles.js";
7
+ export { compareHttpApiPathOrder, normalizeHttpApiRelativePath, sortHttpApiPaths };
8
+ /**
9
+ * Stable comparison for tree nodes (by path or dirPath).
10
+ */
11
+ export declare function compareHttpApiTreeNodeOrder(a: HttpApiTreeNode, b: HttpApiTreeNode): number;
12
+ /**
13
+ * Returns a new array of tree nodes in deterministic order.
14
+ */
15
+ export declare function sortHttpApiTreeNodes(nodes: readonly HttpApiTreeNode[]): HttpApiTreeNode[];
16
+ //# sourceMappingURL=httpapiSort.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"httpapiSort.d.ts","sourceRoot":"","sources":["../../src/internal/httpapiSort.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAClE,OAAO,EACL,uBAAuB,EACvB,4BAA4B,EAC5B,gBAAgB,EACjB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAAE,uBAAuB,EAAE,4BAA4B,EAAE,gBAAgB,EAAE,CAAC;AAcnF;;GAEG;AACH,wBAAgB,2BAA2B,CAAC,CAAC,EAAE,eAAe,EAAE,CAAC,EAAE,eAAe,GAAG,MAAM,CAE1F;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,SAAS,eAAe,EAAE,GAAG,eAAe,EAAE,CAEzF"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Deterministic ordering for HttpApi discovery: paths, roles, and AST nodes.
3
+ * Centralizes stable sort so AST nodes and file roles have consistent order.
4
+ */
5
+ import { compareHttpApiPathOrder, normalizeHttpApiRelativePath, sortHttpApiPaths, } from "./httpapiFileRoles.js";
6
+ export { compareHttpApiPathOrder, normalizeHttpApiRelativePath, sortHttpApiPaths };
7
+ function nodeOrderKey(n) {
8
+ switch (n.type) {
9
+ case "endpoint":
10
+ return n.path;
11
+ case "group":
12
+ case "pathless_directory":
13
+ return n.dirPath;
14
+ default:
15
+ return "";
16
+ }
17
+ }
18
+ /**
19
+ * Stable comparison for tree nodes (by path or dirPath).
20
+ */
21
+ export function compareHttpApiTreeNodeOrder(a, b) {
22
+ return compareHttpApiPathOrder(nodeOrderKey(a), nodeOrderKey(b));
23
+ }
24
+ /**
25
+ * Returns a new array of tree nodes in deterministic order.
26
+ */
27
+ export function sortHttpApiTreeNodes(nodes) {
28
+ return [...nodes].sort(compareHttpApiTreeNodeOrder);
29
+ }
@@ -0,0 +1,16 @@
1
+ export declare const toPosixPath: (path: string) => string;
2
+ /** Strip the extension from a path using extname; returns path unchanged if no extension. */
3
+ export declare const stripScriptExtension: (path: string) => string;
4
+ export declare const resolveRelativePath: (baseDir: string, relativePath: string) => string;
5
+ /**
6
+ * Resolves relativePath against baseDir and ensures the result stays under baseDir.
7
+ */
8
+ export declare function resolvePathUnderBase(baseDir: string, relativePath: string): {
9
+ ok: true;
10
+ path: string;
11
+ } | {
12
+ ok: false;
13
+ error: "path-escapes-base";
14
+ };
15
+ export declare function pathIsUnderBase(baseDir: string, absolutePath: string): boolean;
16
+ //# sourceMappingURL=path.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"path.d.ts","sourceRoot":"","sources":["../../src/internal/path.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,WAAW,GAAI,MAAM,MAAM,KAAG,MAAoC,CAAC;AAEhF,6FAA6F;AAC7F,eAAO,MAAM,oBAAoB,GAAI,MAAM,MAAM,KAAG,MAGnD,CAAC;AAEF,eAAO,MAAM,mBAAmB,GAAI,SAAS,MAAM,EAAE,cAAc,MAAM,KAAG,MAC/B,CAAC;AAE9C;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,MAAM,GACnB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,mBAAmB,CAAA;CAAE,CAQxE;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAe9E"}
@@ -0,0 +1,38 @@
1
+ import { realpathSync } from "node:fs";
2
+ import { extname, isAbsolute, relative, resolve } from "node:path";
3
+ export const toPosixPath = (path) => path.replaceAll("\\", "/");
4
+ /** Strip the extension from a path using extname; returns path unchanged if no extension. */
5
+ export const stripScriptExtension = (path) => {
6
+ const ext = extname(path);
7
+ return ext ? path.slice(0, -ext.length) : path;
8
+ };
9
+ export const resolveRelativePath = (baseDir, relativePath) => toPosixPath(resolve(baseDir, relativePath));
10
+ /**
11
+ * Resolves relativePath against baseDir and ensures the result stays under baseDir.
12
+ */
13
+ export function resolvePathUnderBase(baseDir, relativePath) {
14
+ const baseAbs = resolve(baseDir);
15
+ const resolved = resolve(baseDir, relativePath);
16
+ const rel = relative(baseAbs, resolved);
17
+ if (rel.startsWith("..") || isAbsolute(rel)) {
18
+ return { ok: false, error: "path-escapes-base" };
19
+ }
20
+ return { ok: true, path: toPosixPath(resolved) };
21
+ }
22
+ export function pathIsUnderBase(baseDir, absolutePath) {
23
+ let baseAbs;
24
+ let resolvedAbs;
25
+ try {
26
+ baseAbs = realpathSync(resolve(baseDir));
27
+ resolvedAbs = realpathSync(resolve(absolutePath));
28
+ }
29
+ catch {
30
+ baseAbs = resolve(baseDir);
31
+ resolvedAbs = resolve(absolutePath);
32
+ }
33
+ const rel = relative(baseAbs, resolvedAbs);
34
+ if (rel.startsWith("..") || isAbsolute(rel)) {
35
+ return false;
36
+ }
37
+ return true;
38
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Resolves a config field: raw value or yield* Config.
3
+ * Requires ConfigProvider when value is Config.
4
+ */
5
+ import * as Config from "effect/Config";
6
+ import * as Effect from "effect/Effect";
7
+ export declare function resolveConfig<T>(value: T | Config.Config<T> | undefined, def: T): Effect.Effect<T, Config.ConfigError>;
8
+ //# sourceMappingURL=resolveConfig.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolveConfig.d.ts","sourceRoot":"","sources":["../../src/internal/resolveConfig.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAExC,wBAAgB,aAAa,CAAC,CAAC,EAC7B,KAAK,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,SAAS,EACvC,GAAG,EAAE,CAAC,GACL,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,WAAW,CAAC,CAItC"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Resolves a config field: raw value or yield* Config.
3
+ * Requires ConfigProvider when value is Config.
4
+ */
5
+ import * as Config from "effect/Config";
6
+ import * as Effect from "effect/Effect";
7
+ export function resolveConfig(value, def) {
8
+ if (value === undefined)
9
+ return Effect.succeed(def);
10
+ if (Config.isConfig(value))
11
+ return value.asEffect();
12
+ return Effect.succeed(value);
13
+ }
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Path relative to baseDir → valid JS identifier.
3
+ * Safe for special chars in filenames; never emits invalid identifiers.
4
+ */
5
+ export declare function pathToIdentifier(relativeFilePath: string): string;
6
+ /**
7
+ * Route module identifier: prefix with M to avoid clashing with Router/Fx/Effect/Stream.
8
+ */
9
+ export declare function routeModuleIdentifier(relativeFilePath: string): string;
10
+ /**
11
+ * Assign unique var names when proposed names collide (e.g. users/[id].ts and users/id.ts both → UsersId).
12
+ * First occurrence keeps the base name; others get base + "Param" (if path has [x]), "Literal", or numeric suffix.
13
+ */
14
+ export declare function makeUniqueVarNames(entries: readonly {
15
+ path: string;
16
+ proposedName: string;
17
+ }[]): Map<string, string>;
18
+ //# sourceMappingURL=routeIdentifiers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routeIdentifiers.d.ts","sourceRoot":"","sources":["../../src/internal/routeIdentifiers.ts"],"names":[],"mappings":"AAaA;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,gBAAgB,EAAE,MAAM,GAAG,MAAM,CAUjE;AAYD;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,gBAAgB,EAAE,MAAM,GAAG,MAAM,CAGtE;AAOD;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,SAAS;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,EAAE,GACzD,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAkCrB"}
@@ -0,0 +1,90 @@
1
+ import { stripScriptExtension, toPosixPath } from "./path.js";
2
+ /**
3
+ * Sanitize a path segment for use in a JS identifier: strip _ and brackets, keep only [a-zA-Z0-9], capitalize.
4
+ * Empty after sanitization is skipped (returns "").
5
+ */
6
+ function segmentToIdentifierPart(seg) {
7
+ let name = seg.trim().startsWith("_") ? seg.trim().slice(1) : seg.trim();
8
+ name = name.replace(/[[\]]/g, "").replace(/[^a-zA-Z0-9]/g, "");
9
+ if (!name)
10
+ return "";
11
+ return name.charAt(0).toUpperCase() + name.slice(1);
12
+ }
13
+ /**
14
+ * Path relative to baseDir → valid JS identifier.
15
+ * Safe for special chars in filenames; never emits invalid identifiers.
16
+ */
17
+ export function pathToIdentifier(relativeFilePath) {
18
+ const posix = toPosixPath(relativeFilePath);
19
+ const withoutExt = stripScriptExtension(posix);
20
+ const raw = withoutExt.split("/").filter(Boolean).map(segmentToIdentifierPart).filter(Boolean).join("") ||
21
+ "Module";
22
+ const safe = raw.replace(/[^a-zA-Z0-9_$]/g, "");
23
+ if (!safe)
24
+ return "Module";
25
+ if (/^\d/.test(safe))
26
+ return `M${safe}`;
27
+ return safe;
28
+ }
29
+ /** Final guard: ensure a string is a valid JS identifier (no spaces, brackets, or leading digit). */
30
+ function toSafeIdentifier(s) {
31
+ const cleaned = s.replace(/[\s[\]]/g, "").replace(/[^a-zA-Z0-9_$]/g, "");
32
+ if (!cleaned)
33
+ return "Module";
34
+ if (/^\d/.test(cleaned))
35
+ return `M${cleaned}`;
36
+ return cleaned;
37
+ }
38
+ const RESERVED_NAMES = new Set(["Router", "Fx", "Effect", "Stream"]);
39
+ /**
40
+ * Route module identifier: prefix with M to avoid clashing with Router/Fx/Effect/Stream.
41
+ */
42
+ export function routeModuleIdentifier(relativeFilePath) {
43
+ const base = pathToIdentifier(relativeFilePath);
44
+ return RESERVED_NAMES.has(base) ? `M${base}` : base;
45
+ }
46
+ /** True if the path has a dynamic segment (bracket). */
47
+ function pathHasParamSegment(relativePath) {
48
+ return /\[[^\]]*\]/.test(relativePath);
49
+ }
50
+ /**
51
+ * Assign unique var names when proposed names collide (e.g. users/[id].ts and users/id.ts both → UsersId).
52
+ * First occurrence keeps the base name; others get base + "Param" (if path has [x]), "Literal", or numeric suffix.
53
+ */
54
+ export function makeUniqueVarNames(entries) {
55
+ const sorted = [...entries].sort((a, b) => a.path.localeCompare(b.path));
56
+ const nameToPaths = new Map();
57
+ for (const { path, proposedName } of sorted) {
58
+ const base = toSafeIdentifier(proposedName);
59
+ const list = nameToPaths.get(base) ?? [];
60
+ list.push(path);
61
+ nameToPaths.set(base, list);
62
+ }
63
+ const pathToUnique = new Map();
64
+ const used = new Set();
65
+ for (const [base, paths] of nameToPaths) {
66
+ for (let i = 0; i < paths.length; i++) {
67
+ const path = paths[i];
68
+ let name;
69
+ if (paths.length === 1) {
70
+ name = base;
71
+ }
72
+ else if (i === 0) {
73
+ name = base;
74
+ }
75
+ else {
76
+ const suffix = pathHasParamSegment(path) ? "Param" : "Literal";
77
+ let candidate = base + suffix;
78
+ let n = 0;
79
+ while (used.has(candidate)) {
80
+ n += 1;
81
+ candidate = base + String(n);
82
+ }
83
+ name = candidate;
84
+ }
85
+ used.add(name);
86
+ pathToUnique.set(path, name);
87
+ }
88
+ }
89
+ return pathToUnique;
90
+ }
@@ -0,0 +1,45 @@
1
+ import type { ConstructorTypeNode, FunctionTypeNode, OverloadSetTypeNode, TypeInfoApi, TypeNode } from "@typed/virtual-modules";
2
+ /** True when the node represents a callable (function, overload set, or constructor). */
3
+ export declare function isCallableNode(node: TypeNode): node is FunctionTypeNode | OverloadSetTypeNode | ConstructorTypeNode;
4
+ /** First signature's return type for function-like nodes; undefined otherwise. */
5
+ export declare function getCallableReturnType(node: TypeNode): TypeNode | undefined;
6
+ /**
7
+ * True iff the type is structurally assignable to Route.
8
+ */
9
+ export declare function typeNodeIsRouteCompatible(node: TypeNode, api: TypeInfoApi): boolean;
10
+ export type RuntimeKind = "fx" | "effect" | "stream" | "plain" | "unknown";
11
+ /**
12
+ * Structurally determines runtime kind via api.isAssignableTo. No fallbacks.
13
+ * Never returns "unknown"; use callers' failWhenNoTargetsResolved for that.
14
+ */
15
+ export declare function typeNodeToRuntimeKind(node: TypeNode, api: TypeInfoApi): RuntimeKind;
16
+ /** Dependency export form for targeted .provide() lifts. */
17
+ export type DepsExportKind = "layer" | "servicemap" | "array";
18
+ /** Result of classifyDepsExport; "unknown" means validation must fail. */
19
+ export type DepsExportClassification = DepsExportKind | "unknown";
20
+ /** Classify dependency default export for optimal provide lift. Uses api; node.kind "array" for T[]. */
21
+ export declare function classifyDepsExport(node: TypeNode, api: TypeInfoApi): DepsExportClassification;
22
+ /** True iff the type node is a function whose first parameter expects RefSubject. */
23
+ export declare function typeNodeExpectsRefSubjectParam(node: TypeNode, api: TypeInfoApi): boolean;
24
+ /**
25
+ * True iff the function's return type is Effect and Effect's success type (first type arg) is assignable to Option.
26
+ */
27
+ export declare function typeNodeIsEffectOptionReturn(node: TypeNode, api: TypeInfoApi): boolean;
28
+ /**
29
+ * Classify catch handler form: native (RefSubject=>Fx), fn-cause ((Cause)=>...), fn-error ((E)=>...), or value.
30
+ */
31
+ export type CatchForm = {
32
+ form: "native";
33
+ returnKind: RuntimeKind;
34
+ } | {
35
+ form: "value";
36
+ returnKind: RuntimeKind;
37
+ } | {
38
+ form: "fn-cause";
39
+ returnKind: RuntimeKind;
40
+ } | {
41
+ form: "fn-error";
42
+ returnKind: RuntimeKind;
43
+ };
44
+ export declare function classifyCatchForm(node: TypeNode, api: TypeInfoApi): CatchForm;
45
+ //# sourceMappingURL=routeTypeNode.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routeTypeNode.d.ts","sourceRoot":"","sources":["../../src/internal/routeTypeNode.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,mBAAmB,EACnB,gBAAgB,EAChB,mBAAmB,EACnB,WAAW,EACX,QAAQ,EACT,MAAM,wBAAwB,CAAC;AAEhC,yFAAyF;AACzF,wBAAgB,cAAc,CAC5B,IAAI,EAAE,QAAQ,GACb,IAAI,IAAI,gBAAgB,GAAG,mBAAmB,GAAG,mBAAmB,CAEtE;AAeD,kFAAkF;AAClF,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAQ1E;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,WAAW,GAAG,OAAO,CAEnF;AAED,MAAM,MAAM,WAAW,GAAG,IAAI,GAAG,QAAQ,GAAG,QAAQ,GAAG,OAAO,GAAG,SAAS,CAAC;AAE3E;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,WAAW,GAAG,WAAW,CAKnF;AAED,4DAA4D;AAC5D,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,YAAY,GAAG,OAAO,CAAC;AAE9D,0EAA0E;AAC1E,MAAM,MAAM,wBAAwB,GAAG,cAAc,GAAG,SAAS,CAAC;AAElE,wGAAwG;AACxG,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,QAAQ,EACd,GAAG,EAAE,WAAW,GACf,wBAAwB,CAK1B;AAED,qFAAqF;AACrF,wBAAgB,8BAA8B,CAAC,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,WAAW,GAAG,OAAO,CAKxF;AAED;;GAEG;AACH,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,WAAW,GAAG,OAAO,CAMtF;AAED;;GAEG;AACH,MAAM,MAAM,SAAS,GACjB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,UAAU,EAAE,WAAW,CAAA;CAAE,GAC3C;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,UAAU,EAAE,WAAW,CAAA;CAAE,GAC1C;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,UAAU,EAAE,WAAW,CAAA;CAAE,GAC7C;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,UAAU,EAAE,WAAW,CAAA;CAAE,CAAC;AAElD,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,WAAW,GAAG,SAAS,CAe7E"}