@open-mercato/shared 0.9.1-develop.7476.1.342138d35e → 0.9.1-develop.7496.1.3346415f94
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/.turbo/turbo-build.log +1 -1
- package/dist/lib/bootstrap/dynamicLoader.js +46 -6
- package/dist/lib/bootstrap/dynamicLoader.js.map +2 -2
- package/dist/lib/bootstrap/next-subpath-resolve-hook-worker.js +6 -0
- package/dist/lib/bootstrap/next-subpath-resolve-hook-worker.js.map +7 -0
- package/dist/lib/bootstrap/next-subpath-resolve-hook.js +62 -0
- package/dist/lib/bootstrap/next-subpath-resolve-hook.js.map +7 -0
- package/dist/lib/crud/ids.js +13 -1
- package/dist/lib/crud/ids.js.map +2 -2
- package/dist/lib/openapi/generator.js +84 -67
- package/dist/lib/openapi/generator.js.map +2 -2
- package/dist/lib/version.js +1 -1
- package/dist/lib/version.js.map +1 -1
- package/dist/modules/registry.js.map +2 -2
- package/package.json +2 -2
- package/src/lib/bootstrap/__tests__/dynamicLoader.appDi.test.ts +2 -2
- package/src/lib/bootstrap/__tests__/dynamicLoader.appModuleOverrides.test.ts +2 -2
- package/src/lib/bootstrap/__tests__/dynamicLoader.cacheRecovery.test.ts +2 -2
- package/src/lib/bootstrap/__tests__/dynamicLoader.commandInterceptors.test.ts +2 -2
- package/src/lib/bootstrap/__tests__/dynamicLoader.externalSubpath.test.ts +141 -0
- package/src/lib/bootstrap/__tests__/dynamicLoader.tsconfig.test.ts +2 -2
- package/src/lib/bootstrap/__tests__/next-subpath-resolve-hook.test.ts +174 -0
- package/src/lib/bootstrap/dynamicLoader.ts +63 -5
- package/src/lib/bootstrap/next-subpath-resolve-hook-worker.ts +3 -0
- package/src/lib/bootstrap/next-subpath-resolve-hook.ts +130 -0
- package/src/lib/crud/__tests__/ids.test.ts +34 -1
- package/src/lib/crud/ids.ts +24 -0
- package/src/lib/openapi/__tests__/optional-path-params.test.ts +102 -0
- package/src/lib/openapi/generator.ts +106 -77
- package/src/modules/registry.ts +5 -0
|
@@ -59,6 +59,19 @@ function normalizePath(path) {
|
|
|
59
59
|
}).join("/");
|
|
60
60
|
return { path: "/" + normalized, params };
|
|
61
61
|
}
|
|
62
|
+
function expandOptionalPathParams(normalized) {
|
|
63
|
+
const required = normalized.params.filter((param) => !param.optional);
|
|
64
|
+
const optionalParam = normalized.params.find((param) => param.optional);
|
|
65
|
+
const fullVariant = {
|
|
66
|
+
path: normalized.path,
|
|
67
|
+
params: normalized.params.map((param) => ({ ...param, optional: false }))
|
|
68
|
+
};
|
|
69
|
+
if (!optionalParam) return [fullVariant];
|
|
70
|
+
const placeholder = `/{${optionalParam.name}}`;
|
|
71
|
+
if (!normalized.path.endsWith(placeholder)) return [fullVariant];
|
|
72
|
+
const basePath = normalized.path.slice(0, -placeholder.length) || "/";
|
|
73
|
+
return [fullVariant, { path: basePath, params: required, omittedParam: optionalParam.name }];
|
|
74
|
+
}
|
|
62
75
|
function unwrap(schema) {
|
|
63
76
|
if (!schema) {
|
|
64
77
|
return { schema: void 0, optional: true, nullable: false };
|
|
@@ -564,14 +577,14 @@ function buildParameters(schema, location, pathParamNames) {
|
|
|
564
577
|
const params = [];
|
|
565
578
|
if (location === "path" && pathParamNames && pathParamNames.length) {
|
|
566
579
|
const merged = mergePathParamSchemas(schema, pathParamNames);
|
|
567
|
-
for (const { name, schema: paramSchema
|
|
580
|
+
for (const { name, schema: paramSchema } of merged) {
|
|
568
581
|
const jsonSchema = zodToJsonSchema(paramSchema);
|
|
569
582
|
const example = generateExample(paramSchema);
|
|
570
583
|
const description = extractZodDescription(paramSchema);
|
|
571
584
|
params.push({
|
|
572
585
|
name,
|
|
573
586
|
in: "path",
|
|
574
|
-
required:
|
|
587
|
+
required: true,
|
|
575
588
|
schema: jsonSchema ?? { type: "string" },
|
|
576
589
|
example,
|
|
577
590
|
...description ? { description } : {}
|
|
@@ -631,8 +644,7 @@ function mergePathParamSchemas(schema, params) {
|
|
|
631
644
|
for (const param of params) {
|
|
632
645
|
merged.push({
|
|
633
646
|
name: param.name,
|
|
634
|
-
schema: map[param.name]
|
|
635
|
-
optional: !!param.optional
|
|
647
|
+
schema: map[param.name]
|
|
636
648
|
});
|
|
637
649
|
}
|
|
638
650
|
return merged;
|
|
@@ -883,6 +895,7 @@ function buildOpenApiDocument(modules, options = {}) {
|
|
|
883
895
|
ensureSecurityComponents(doc);
|
|
884
896
|
const includeAccessControlMetadata = options.includeAccessControlMetadata !== false;
|
|
885
897
|
const tags = /* @__PURE__ */ new Map();
|
|
898
|
+
const derivedOperations = /* @__PURE__ */ new Set();
|
|
886
899
|
for (const moduleEntry of modules) {
|
|
887
900
|
const defaultTag = moduleEntry.info?.title ?? toTitle(moduleEntry.id);
|
|
888
901
|
if (defaultTag) tags.set(defaultTag, moduleEntry.info?.description);
|
|
@@ -890,71 +903,75 @@ function buildOpenApiDocument(modules, options = {}) {
|
|
|
890
903
|
for (const api of apis) {
|
|
891
904
|
const routeDoc = collectRouteDoc(api, moduleEntry.id);
|
|
892
905
|
const moduleTag = routeDoc?.tag ?? defaultTag;
|
|
893
|
-
const normalized = normalizePath(api.path ?? api.path ?? "");
|
|
894
|
-
const pathKey = normalized.path;
|
|
895
|
-
if (!doc.paths[pathKey]) doc.paths[pathKey] = {};
|
|
896
906
|
const availableMethods = "handlers" in api ? HTTP_METHODS.filter((method) => typeof api.handlers?.[method] === "function") : [api.method];
|
|
897
|
-
for (const
|
|
898
|
-
const
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
descriptionParts
|
|
907
|
+
for (const normalized of expandOptionalPathParams(normalizePath(api.path ?? ""))) {
|
|
908
|
+
const pathKey = normalized.path;
|
|
909
|
+
if (!doc.paths[pathKey]) doc.paths[pathKey] = {};
|
|
910
|
+
for (const method of availableMethods) {
|
|
911
|
+
const methodLower = method.toLowerCase();
|
|
912
|
+
const operationKey = `${methodLower} ${pathKey}`;
|
|
913
|
+
const existing = doc.paths[pathKey][methodLower];
|
|
914
|
+
if (existing && (normalized.omittedParam || !derivedOperations.has(operationKey))) continue;
|
|
915
|
+
if (normalized.omittedParam) derivedOperations.add(operationKey);
|
|
916
|
+
else derivedOperations.delete(operationKey);
|
|
917
|
+
const metadata = "handlers" in api ? api.metadata?.[method] : void 0;
|
|
918
|
+
const methodDoc = routeDoc?.methods?.[method];
|
|
919
|
+
const summary = methodDoc?.summary ?? routeDoc?.summary ?? `${method} ${pathKey}`;
|
|
920
|
+
const baseDescription = methodDoc?.description ?? routeDoc?.description;
|
|
921
|
+
const meta = metadata && typeof metadata === "object" ? metadata : void 0;
|
|
922
|
+
const requireFeatures = Array.isArray(meta?.["requireFeatures"]) ? meta["requireFeatures"] : void 0;
|
|
923
|
+
const requireRoles = Array.isArray(meta?.["requireRoles"]) ? meta["requireRoles"] : void 0;
|
|
924
|
+
const requireAuth = meta?.["requireAuth"] === true;
|
|
925
|
+
const descriptionParts = [];
|
|
926
|
+
if (baseDescription) descriptionParts.push(baseDescription);
|
|
927
|
+
if (includeAccessControlMetadata && Array.isArray(requireFeatures) && requireFeatures.length) {
|
|
928
|
+
descriptionParts.push(`Requires features: ${requireFeatures.join(", ")}`);
|
|
929
|
+
}
|
|
930
|
+
if (includeAccessControlMetadata && Array.isArray(requireRoles) && requireRoles.length) {
|
|
931
|
+
descriptionParts.push(`Requires roles: ${requireRoles.join(", ")}`);
|
|
932
|
+
}
|
|
933
|
+
const querySchema = methodDoc?.query;
|
|
934
|
+
const pathSchema = methodDoc?.pathParams ?? routeDoc?.pathParams;
|
|
935
|
+
const headerSchema = methodDoc?.headers;
|
|
936
|
+
const requestBody = methodDoc?.requestBody;
|
|
937
|
+
const examples = collectExamples(querySchema, requestBody?.schema, pathSchema, headerSchema, metadata);
|
|
938
|
+
const curlSample = buildCurlSample(
|
|
939
|
+
method,
|
|
940
|
+
pathKey,
|
|
941
|
+
normalized.params,
|
|
942
|
+
examples,
|
|
943
|
+
options.baseUrlForExamples ?? "https://api.open-mercato.local",
|
|
944
|
+
metadata,
|
|
945
|
+
requestBody
|
|
946
|
+
);
|
|
947
|
+
doc.paths[pathKey][methodLower] = {
|
|
948
|
+
operationId: methodDoc?.operationId ? normalized.omittedParam ? `${methodDoc.operationId}_without_${normalizeOperationIdSegment(normalized.omittedParam)}` : methodDoc.operationId : resolveOperationId(moduleEntry.id, pathKey, method),
|
|
949
|
+
summary,
|
|
950
|
+
description: descriptionParts.length ? descriptionParts.join("\n\n") : void 0,
|
|
951
|
+
tags: methodDoc?.tags ?? (moduleTag ? [moduleTag] : void 0),
|
|
952
|
+
deprecated: methodDoc?.deprecated,
|
|
953
|
+
externalDocs: methodDoc?.externalDocs,
|
|
954
|
+
parameters: [
|
|
955
|
+
...buildParameters(pathSchema, "path", normalized.params),
|
|
956
|
+
...buildParameters(querySchema, "query"),
|
|
957
|
+
...buildParameters(headerSchema, "header")
|
|
958
|
+
].filter(Boolean),
|
|
959
|
+
requestBody: buildRequestBody(requestBody),
|
|
960
|
+
responses: buildResponses(method, methodDoc?.responses, methodDoc?.errors, metadata),
|
|
961
|
+
security: buildSecurity(metadata, methodDoc, options.defaultSecurity),
|
|
962
|
+
"x-codeSamples": methodDoc?.codeSamples ?? [
|
|
963
|
+
{
|
|
964
|
+
lang: "curl",
|
|
965
|
+
label: "cURL",
|
|
966
|
+
source: curlSample
|
|
967
|
+
}
|
|
968
|
+
],
|
|
969
|
+
...includeAccessControlMetadata && Array.isArray(requireFeatures) && requireFeatures.length ? { "x-require-features": requireFeatures } : {},
|
|
970
|
+
...includeAccessControlMetadata && Array.isArray(requireRoles) && requireRoles.length ? { "x-require-roles": requireRoles } : {},
|
|
971
|
+
...requireAuth ? { "x-require-auth": true } : {},
|
|
972
|
+
...methodDoc?.extensions ?? {}
|
|
973
|
+
};
|
|
916
974
|
}
|
|
917
|
-
const querySchema = methodDoc?.query;
|
|
918
|
-
const pathSchema = methodDoc?.pathParams ?? routeDoc?.pathParams;
|
|
919
|
-
const headerSchema = methodDoc?.headers;
|
|
920
|
-
const requestBody = methodDoc?.requestBody;
|
|
921
|
-
const examples = collectExamples(querySchema, requestBody?.schema, pathSchema, headerSchema, metadata);
|
|
922
|
-
const curlSample = buildCurlSample(
|
|
923
|
-
method,
|
|
924
|
-
pathKey,
|
|
925
|
-
normalized.params,
|
|
926
|
-
examples,
|
|
927
|
-
options.baseUrlForExamples ?? "https://api.open-mercato.local",
|
|
928
|
-
metadata,
|
|
929
|
-
requestBody
|
|
930
|
-
);
|
|
931
|
-
doc.paths[pathKey][methodLower] = {
|
|
932
|
-
operationId: methodDoc?.operationId ?? resolveOperationId(moduleEntry.id, pathKey, method),
|
|
933
|
-
summary,
|
|
934
|
-
description: descriptionParts.length ? descriptionParts.join("\n\n") : void 0,
|
|
935
|
-
tags: methodDoc?.tags ?? (moduleTag ? [moduleTag] : void 0),
|
|
936
|
-
deprecated: methodDoc?.deprecated,
|
|
937
|
-
externalDocs: methodDoc?.externalDocs,
|
|
938
|
-
parameters: [
|
|
939
|
-
...buildParameters(pathSchema, "path", normalized.params),
|
|
940
|
-
...buildParameters(querySchema, "query"),
|
|
941
|
-
...buildParameters(headerSchema, "header")
|
|
942
|
-
].filter(Boolean),
|
|
943
|
-
requestBody: buildRequestBody(requestBody),
|
|
944
|
-
responses: buildResponses(method, methodDoc?.responses, methodDoc?.errors, metadata),
|
|
945
|
-
security: buildSecurity(metadata, methodDoc, options.defaultSecurity),
|
|
946
|
-
"x-codeSamples": methodDoc?.codeSamples ?? [
|
|
947
|
-
{
|
|
948
|
-
lang: "curl",
|
|
949
|
-
label: "cURL",
|
|
950
|
-
source: curlSample
|
|
951
|
-
}
|
|
952
|
-
],
|
|
953
|
-
...includeAccessControlMetadata && Array.isArray(requireFeatures) && requireFeatures.length ? { "x-require-features": requireFeatures } : {},
|
|
954
|
-
...includeAccessControlMetadata && Array.isArray(requireRoles) && requireRoles.length ? { "x-require-roles": requireRoles } : {},
|
|
955
|
-
...requireAuth ? { "x-require-auth": true } : {},
|
|
956
|
-
...methodDoc?.extensions ?? {}
|
|
957
|
-
};
|
|
958
975
|
}
|
|
959
976
|
}
|
|
960
977
|
}
|