@techspokes/typescript-wsdl-client 1.1.4 → 1.1.8
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/README.md +81 -35
- package/dist/app/generateApp.d.ts +0 -1
- package/dist/app/generateApp.js +8 -6
- package/dist/app/generateCheckedApp.d.ts +38 -0
- package/dist/app/generateCheckedApp.js +108 -0
- package/dist/checkedPipeline.d.ts +155 -0
- package/dist/checkedPipeline.js +448 -0
- package/dist/checkedPlanning.d.ts +123 -0
- package/dist/checkedPlanning.js +245 -0
- package/dist/cli.d.ts +0 -1
- package/dist/cli.js +123 -5
- package/dist/client/checkedDirectRuntime.d.ts +96 -0
- package/dist/client/checkedDirectRuntime.js +43 -0
- package/dist/client/directClientRuntime.d.ts +74 -0
- package/dist/client/directClientRuntime.js +165 -0
- package/dist/client/directClientVersion.d.ts +6 -0
- package/dist/client/directClientVersion.js +6 -0
- package/dist/client/generateClient.d.ts +0 -1
- package/dist/client/generateClient.js +26 -12
- package/dist/client/generateDirectClient.d.ts +32 -0
- package/dist/client/generateDirectClient.js +268 -0
- package/dist/client/generateOperations.d.ts +0 -1
- package/dist/client/generateTypes.d.ts +0 -1
- package/dist/client/generateUtils.d.ts +0 -1
- package/dist/client/generateUtils.js +3 -1
- package/dist/compiler/applicationGroups.d.ts +53 -0
- package/dist/compiler/applicationGroups.js +403 -0
- package/dist/compiler/buildCanonicalGraph.d.ts +6 -0
- package/dist/compiler/buildCanonicalGraph.js +381 -0
- package/dist/compiler/canonicalGraph.d.ts +197 -0
- package/dist/compiler/canonicalGraph.js +37 -0
- package/dist/compiler/catalogErrors.d.ts +17 -0
- package/dist/compiler/catalogErrors.js +86 -0
- package/dist/compiler/catalogProvenance.d.ts +14 -0
- package/dist/compiler/catalogProvenance.js +229 -0
- package/dist/compiler/checkedAssessment.d.ts +90 -0
- package/dist/compiler/checkedAssessment.js +300 -0
- package/dist/compiler/checkedComponentSource.d.ts +16 -0
- package/dist/compiler/checkedComponentSource.js +31 -0
- package/dist/compiler/checkedSourcePreparation.d.ts +72 -0
- package/dist/compiler/checkedSourcePreparation.js +202 -0
- package/dist/compiler/complexTypeContent.d.ts +58 -0
- package/dist/compiler/complexTypeContent.js +558 -0
- package/dist/compiler/componentCorrespondence.d.ts +32 -0
- package/dist/compiler/componentCorrespondence.js +140 -0
- package/dist/compiler/componentRecordProjection.d.ts +109 -0
- package/dist/compiler/componentRecordProjection.js +319 -0
- package/dist/compiler/componentSoapPreparation.d.ts +20 -0
- package/dist/compiler/componentSoapPreparation.js +36 -0
- package/dist/compiler/composeCanonicalGraph.d.ts +68 -0
- package/dist/compiler/composeCanonicalGraph.js +252 -0
- package/dist/compiler/dataOwnership.d.ts +21 -0
- package/dist/compiler/dataOwnership.js +167 -0
- package/dist/compiler/datatypeValues.d.ts +46 -0
- package/dist/compiler/datatypeValues.js +275 -0
- package/dist/compiler/directCodec.d.ts +116 -0
- package/dist/compiler/directCodec.js +377 -0
- package/dist/compiler/directExecutionPolicy.d.ts +9 -0
- package/dist/compiler/directExecutionPolicy.js +17 -0
- package/dist/compiler/directOperation.d.ts +114 -0
- package/dist/compiler/directOperation.js +373 -0
- package/dist/compiler/directSoap.d.ts +66 -0
- package/dist/compiler/directSoap.js +391 -0
- package/dist/compiler/directSoapSource.d.ts +38 -0
- package/dist/compiler/directSoapSource.js +233 -0
- package/dist/compiler/directSourceCapsule.d.ts +169 -0
- package/dist/compiler/directSourceCapsule.js +727 -0
- package/dist/compiler/directStructure.d.ts +128 -0
- package/dist/compiler/directStructure.js +543 -0
- package/dist/compiler/directStructurePlan.d.ts +149 -0
- package/dist/compiler/directStructurePlan.js +623 -0
- package/dist/compiler/directValues.d.ts +128 -0
- package/dist/compiler/directValues.js +1116 -0
- package/dist/compiler/finiteRe01Construction.d.ts +69 -0
- package/dist/compiler/finiteRe01Construction.js +422 -0
- package/dist/compiler/finiteRe01Verification.d.ts +218 -0
- package/dist/compiler/finiteRe01Verification.js +1217 -0
- package/dist/compiler/generateCatalog.d.ts +0 -1
- package/dist/compiler/graphTraversal.d.ts +10 -0
- package/dist/compiler/graphTraversal.js +37 -0
- package/dist/compiler/hypotheticalScopedIdentity.d.ts +22 -0
- package/dist/compiler/hypotheticalScopedIdentity.js +81 -0
- package/dist/compiler/occurrenceAnalysis.d.ts +66 -0
- package/dist/compiler/occurrenceAnalysis.js +316 -0
- package/dist/compiler/originalSourceMembership.d.ts +5 -0
- package/dist/compiler/originalSourceMembership.js +31 -0
- package/dist/compiler/particleAttribution.d.ts +16 -0
- package/dist/compiler/particleAttribution.js +494 -0
- package/dist/compiler/particleDeclarationConsistency.d.ts +23 -0
- package/dist/compiler/particleDeclarationConsistency.js +206 -0
- package/dist/compiler/particleExtension.d.ts +21 -0
- package/dist/compiler/particleExtension.js +123 -0
- package/dist/compiler/particleLocalAssessment.d.ts +19 -0
- package/dist/compiler/particleLocalAssessment.js +92 -0
- package/dist/compiler/particleRestriction.d.ts +23 -0
- package/dist/compiler/particleRestriction.js +494 -0
- package/dist/compiler/particleSemanticView.d.ts +51 -0
- package/dist/compiler/particleSemanticView.js +310 -0
- package/dist/compiler/particleWildcardRelation.d.ts +87 -0
- package/dist/compiler/particleWildcardRelation.js +143 -0
- package/dist/compiler/projectionScalar.d.ts +32 -0
- package/dist/compiler/projectionScalar.js +184 -0
- package/dist/compiler/re01CandidateAssignments.d.ts +95 -0
- package/dist/compiler/re01CandidateAssignments.js +341 -0
- package/dist/compiler/re01CandidateCorrespondence.d.ts +85 -0
- package/dist/compiler/re01CandidateCorrespondence.js +701 -0
- package/dist/compiler/re01TypeProperties.d.ts +70 -0
- package/dist/compiler/re01TypeProperties.js +120 -0
- package/dist/compiler/re01TypePropertyValidation.d.ts +22 -0
- package/dist/compiler/re01TypePropertyValidation.js +161 -0
- package/dist/compiler/resolveCanonicalGraph.d.ts +41 -0
- package/dist/compiler/resolveCanonicalGraph.js +240 -0
- package/dist/compiler/scalarSchemaAssessment.d.ts +424 -0
- package/dist/compiler/scalarSchemaAssessment.js +5198 -0
- package/dist/compiler/schemaAttributeGroupProperties.d.ts +16 -0
- package/dist/compiler/schemaAttributeGroupProperties.js +53 -0
- package/dist/compiler/schemaAttributeProperties.d.ts +9 -0
- package/dist/compiler/schemaAttributeProperties.js +11 -0
- package/dist/compiler/schemaAttributeUses.d.ts +110 -0
- package/dist/compiler/schemaAttributeUses.js +798 -0
- package/dist/compiler/schemaBinaryWordReconstruction.d.ts +9 -0
- package/dist/compiler/schemaBinaryWordReconstruction.js +33 -0
- package/dist/compiler/schemaBuiltinFacets.d.ts +13 -0
- package/dist/compiler/schemaBuiltinFacets.js +51 -0
- package/dist/compiler/schemaCalendarImages.d.ts +7 -0
- package/dist/compiler/schemaCalendarImages.js +204 -0
- package/dist/compiler/schemaCalendarLanguage.d.ts +10 -0
- package/dist/compiler/schemaCalendarLanguage.js +227 -0
- package/dist/compiler/schemaCompiler.d.ts +0 -1
- package/dist/compiler/schemaComponentEquality.d.ts +27 -0
- package/dist/compiler/schemaComponentEquality.js +446 -0
- package/dist/compiler/schemaConstructionAssessment.d.ts +79 -0
- package/dist/compiler/schemaConstructionAssessment.js +745 -0
- package/dist/compiler/schemaDatatypeValues.d.ts +3 -0
- package/dist/compiler/schemaDatatypeValues.js +2 -0
- package/dist/compiler/schemaDecimalLanguage.d.ts +6 -0
- package/dist/compiler/schemaDecimalLanguage.js +102 -0
- package/dist/compiler/schemaDeclarationPrimitives.d.ts +39 -0
- package/dist/compiler/schemaDeclarationPrimitives.js +211 -0
- package/dist/compiler/schemaDocumentSyntax.d.ts +54 -0
- package/dist/compiler/schemaDocumentSyntax.js +294 -0
- package/dist/compiler/schemaDurationLanguage.d.ts +10 -0
- package/dist/compiler/schemaDurationLanguage.js +170 -0
- package/dist/compiler/schemaElementInstance.d.ts +30 -0
- package/dist/compiler/schemaElementInstance.js +45 -0
- package/dist/compiler/schemaElementProperties.d.ts +15 -0
- package/dist/compiler/schemaElementProperties.js +23 -0
- package/dist/compiler/schemaEndpointWordCapacity.d.ts +35 -0
- package/dist/compiler/schemaEndpointWordCapacity.js +39 -0
- package/dist/compiler/schemaExactCalendar.d.ts +72 -0
- package/dist/compiler/schemaExactCalendar.js +264 -0
- package/dist/compiler/schemaFacetAnnotation.d.ts +31 -0
- package/dist/compiler/schemaFacetAnnotation.js +199 -0
- package/dist/compiler/schemaGeneratedScalarShape.d.ts +34 -0
- package/dist/compiler/schemaGeneratedScalarShape.js +178 -0
- package/dist/compiler/schemaIdentityConstraints.d.ts +72 -0
- package/dist/compiler/schemaIdentityConstraints.js +362 -0
- package/dist/compiler/schemaIeeeLanguage.d.ts +42 -0
- package/dist/compiler/schemaIeeeLanguage.js +759 -0
- package/dist/compiler/schemaIntegerImages.d.ts +10 -0
- package/dist/compiler/schemaIntegerImages.js +113 -0
- package/dist/compiler/schemaLexicalPredicates.d.ts +28 -0
- package/dist/compiler/schemaLexicalPredicates.js +63 -0
- package/dist/compiler/schemaNotationProperties.d.ts +31 -0
- package/dist/compiler/schemaNotationProperties.js +84 -0
- package/dist/compiler/schemaNumericImageConditions.d.ts +23 -0
- package/dist/compiler/schemaNumericImageConditions.js +66 -0
- package/dist/compiler/schemaParticleWildcardProperties.d.ts +19 -0
- package/dist/compiler/schemaParticleWildcardProperties.js +43 -0
- package/dist/compiler/schemaPattern.d.ts +1061 -0
- package/dist/compiler/schemaPattern.js +581 -0
- package/dist/compiler/schemaRegularLanguage.d.ts +66 -0
- package/dist/compiler/schemaRegularLanguage.js +1166 -0
- package/dist/compiler/schemaScalarContext.d.ts +85 -0
- package/dist/compiler/schemaScalarContext.js +78 -0
- package/dist/compiler/schemaScalarKernel.d.ts +181 -0
- package/dist/compiler/schemaScalarKernel.js +391 -0
- package/dist/compiler/schemaScalarWitnesses.d.ts +5 -0
- package/dist/compiler/schemaScalarWitnesses.js +118 -0
- package/dist/compiler/schemaSimpleTypeProperties.d.ts +94 -0
- package/dist/compiler/schemaSimpleTypeProperties.js +103 -0
- package/dist/compiler/schemaSourceGrammar.d.ts +26 -0
- package/dist/compiler/schemaSourceGrammar.js +290 -0
- package/dist/compiler/schemaSourceLexical.d.ts +3 -0
- package/dist/compiler/schemaSourceLexical.js +12 -0
- package/dist/compiler/schemaSourceValues.d.ts +50 -0
- package/dist/compiler/schemaSourceValues.js +225 -0
- package/dist/compiler/schemaSourceWildcards.d.ts +27 -0
- package/dist/compiler/schemaSourceWildcards.js +249 -0
- package/dist/compiler/schemaSymbolicSequences.d.ts +15 -0
- package/dist/compiler/schemaSymbolicSequences.js +99 -0
- package/dist/compiler/schemaSymbolicValueSets.d.ts +31 -0
- package/dist/compiler/schemaSymbolicValueSets.js +149 -0
- package/dist/compiler/schemaSyntaxAssessment.d.ts +24 -0
- package/dist/compiler/schemaSyntaxAssessment.js +361 -0
- package/dist/compiler/schemaTemporalAliases.d.ts +5 -0
- package/dist/compiler/schemaTemporalAliases.js +195 -0
- package/dist/compiler/schemaTokenImages.d.ts +8 -0
- package/dist/compiler/schemaTokenImages.js +142 -0
- package/dist/compiler/schemaTypeIdentity.d.ts +38 -0
- package/dist/compiler/schemaTypeIdentity.js +80 -0
- package/dist/compiler/schemaTypeRelations.d.ts +37 -0
- package/dist/compiler/schemaTypeRelations.js +576 -0
- package/dist/compiler/schemaUri.d.ts +12 -0
- package/dist/compiler/schemaUri.js +103 -0
- package/dist/compiler/schemaValueContext.d.ts +25 -0
- package/dist/compiler/schemaValueContext.js +1 -0
- package/dist/compiler/schemaValueImages.d.ts +9 -0
- package/dist/compiler/schemaValueImages.js +142 -0
- package/dist/compiler/schemaValueSequences.d.ts +14 -0
- package/dist/compiler/schemaValueSequences.js +19 -0
- package/dist/compiler/semanticBudget.d.ts +67 -0
- package/dist/compiler/semanticBudget.js +193 -0
- package/dist/compiler/semanticCatalog.d.ts +121 -0
- package/dist/compiler/semanticCatalog.js +160 -0
- package/dist/compiler/semanticContext.d.ts +183 -0
- package/dist/compiler/semanticContext.js +1207 -0
- package/dist/compiler/semanticTypeDependencies.d.ts +7 -0
- package/dist/compiler/semanticTypeDependencies.js +64 -0
- package/dist/compiler/semanticTypeReference.d.ts +23 -0
- package/dist/compiler/semanticTypeReference.js +36 -0
- package/dist/compiler/shapeResolver.d.ts +1 -1
- package/dist/compiler/shapeResolver.js +7 -9
- package/dist/compiler/soapHeaders.d.ts +16 -0
- package/dist/compiler/soapHeaders.js +42 -0
- package/dist/compiler/sourceSchemaBinding.d.ts +25 -0
- package/dist/compiler/sourceSchemaBinding.js +39 -0
- package/dist/compiler/standardSchemaComponents.d.ts +71 -0
- package/dist/compiler/standardSchemaComponents.js +74 -0
- package/dist/compiler/standardSchemaConstruction.d.ts +20 -0
- package/dist/compiler/standardSchemaConstruction.js +34 -0
- package/dist/compiler/structuralCompanions.d.ts +15 -0
- package/dist/compiler/structuralCompanions.js +232 -0
- package/dist/compiler/validateSemanticGraph.d.ts +4 -0
- package/dist/compiler/validateSemanticGraph.js +376 -0
- package/dist/compiler/wildcardAlgebra.d.ts +25 -0
- package/dist/compiler/wildcardAlgebra.js +155 -0
- package/dist/compiler/wsdlPolicyRequirements.d.ts +43 -0
- package/dist/compiler/wsdlPolicyRequirements.js +239 -0
- package/dist/config.d.ts +0 -1
- package/dist/gateway/generateCheckedGateway.d.ts +32 -0
- package/dist/gateway/generateCheckedGateway.js +293 -0
- package/dist/gateway/generateGateway.d.ts +0 -1
- package/dist/gateway/generateGateway.js +2 -2
- package/dist/gateway/generators.d.ts +0 -1
- package/dist/gateway/helpers.d.ts +0 -1
- package/dist/generation/componentShape.d.ts +14 -0
- package/dist/generation/componentShape.js +269 -0
- package/dist/generation/preamble.d.ts +0 -1
- package/dist/generation/sourceLayout.d.ts +13 -0
- package/dist/generation/sourceLayout.js +40 -0
- package/dist/generation/writeGeneratedSource.d.ts +0 -1
- package/dist/index.d.ts +9 -1
- package/dist/index.js +3 -0
- package/dist/loader/fetch.d.ts +0 -1
- package/dist/loader/orderedSyntax.d.ts +84 -0
- package/dist/loader/orderedSyntax.js +222 -0
- package/dist/loader/resolutionDepth.d.ts +6 -0
- package/dist/loader/resolutionDepth.js +65 -0
- package/dist/loader/schemaInput.d.ts +80 -0
- package/dist/loader/schemaInput.js +249 -0
- package/dist/loader/schemaResources.d.ts +60 -0
- package/dist/loader/schemaResources.js +333 -0
- package/dist/loader/wsdlLoader.d.ts +0 -1
- package/dist/openapi/casing.d.ts +0 -1
- package/dist/openapi/generateOpenAPI.d.ts +0 -1
- package/dist/openapi/generateOpenAPI.js +2 -2
- package/dist/openapi/generatePaths.d.ts +0 -1
- package/dist/openapi/generateSchemas.d.ts +0 -1
- package/dist/openapi/security.d.ts +0 -1
- package/dist/pipeline.d.ts +6 -2
- package/dist/pipeline.js +13 -0
- package/dist/test/generateCheckedTests.d.ts +17 -0
- package/dist/test/generateCheckedTests.js +60 -0
- package/dist/test/generateTests.d.ts +0 -1
- package/dist/test/generateTests.js +2 -2
- package/dist/test/generators.d.ts +0 -1
- package/dist/test/mockData.d.ts +0 -1
- package/dist/test/mockData.js +20 -14
- package/dist/util/attributeWildcards.d.ts +0 -1
- package/dist/util/builder.d.ts +0 -1
- package/dist/util/catalogMeta.d.ts +0 -1
- package/dist/util/checkedCliDiagnostics.d.ts +11 -0
- package/dist/util/checkedCliDiagnostics.js +22 -0
- package/dist/util/cli.d.ts +0 -1
- package/dist/util/errors.d.ts +0 -1
- package/dist/util/imports.d.ts +0 -1
- package/dist/util/runtimeSource.d.ts +0 -1
- package/dist/util/runtimeSource.js +3 -5
- package/dist/util/securityConfig.d.ts +0 -1
- package/dist/util/streamConfig.d.ts +0 -1
- package/dist/util/tools.d.ts +0 -1
- package/dist/util/xmlWhitespace.d.ts +2 -0
- package/dist/util/xmlWhitespace.js +4 -0
- package/dist/xsd/primitives.d.ts +0 -1
- package/docs/agent-skill.md +2 -0
- package/docs/api-reference.md +1 -1
- package/docs/checked-gateway.md +210 -0
- package/docs/checked-generation.md +161 -0
- package/docs/cli-reference.md +43 -1
- package/docs/concepts.md +136 -1
- package/docs/configuration.md +5 -1
- package/docs/corpus.md +33 -0
- package/docs/direct-values.md +311 -0
- package/docs/examples/checked-forecast.wsdl +19 -0
- package/docs/gateway-guide.md +1 -1
- package/docs/generated-code.md +10 -5
- package/docs/mapping-contract.md +114 -0
- package/docs/migration-playbook.md +1 -1
- package/docs/output-anatomy.md +1 -1
- package/docs/start-here.md +8 -2
- package/docs/supported-patterns.md +17 -5
- package/docs/testing.md +117 -31
- package/llms.txt +7 -7
- package/package.json +79 -25
- package/src/generation/preambles/direct-client/typescript.preamble +3 -0
- package/src/runtime/checkedGatewayHost.tpl.txt +157 -0
- package/src/runtime/streamXml.ts +1 -1
- package/dist/app/generateApp.d.ts.map +0 -1
- package/dist/cli.d.ts.map +0 -1
- package/dist/client/generateClient.d.ts.map +0 -1
- package/dist/client/generateOperations.d.ts.map +0 -1
- package/dist/client/generateTypes.d.ts.map +0 -1
- package/dist/client/generateUtils.d.ts.map +0 -1
- package/dist/compiler/generateCatalog.d.ts.map +0 -1
- package/dist/compiler/schemaCompiler.d.ts.map +0 -1
- package/dist/compiler/shapeResolver.d.ts.map +0 -1
- package/dist/config.d.ts.map +0 -1
- package/dist/gateway/generateGateway.d.ts.map +0 -1
- package/dist/gateway/generators.d.ts.map +0 -1
- package/dist/gateway/helpers.d.ts.map +0 -1
- package/dist/generation/preamble.d.ts.map +0 -1
- package/dist/generation/writeGeneratedSource.d.ts.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/loader/fetch.d.ts.map +0 -1
- package/dist/loader/wsdlLoader.d.ts.map +0 -1
- package/dist/openapi/casing.d.ts.map +0 -1
- package/dist/openapi/generateOpenAPI.d.ts.map +0 -1
- package/dist/openapi/generatePaths.d.ts.map +0 -1
- package/dist/openapi/generateSchemas.d.ts.map +0 -1
- package/dist/openapi/security.d.ts.map +0 -1
- package/dist/pipeline.d.ts.map +0 -1
- package/dist/runtime/jsonArray.d.ts +0 -24
- package/dist/runtime/jsonArray.d.ts.map +0 -1
- package/dist/runtime/jsonArray.js +0 -52
- package/dist/runtime/ndjson.d.ts +0 -24
- package/dist/runtime/ndjson.d.ts.map +0 -1
- package/dist/runtime/ndjson.js +0 -30
- package/dist/runtime/streamXml.d.ts +0 -45
- package/dist/runtime/streamXml.d.ts.map +0 -1
- package/dist/runtime/streamXml.js +0 -212
- package/dist/test/generateTests.d.ts.map +0 -1
- package/dist/test/generators.d.ts.map +0 -1
- package/dist/test/mockData.d.ts.map +0 -1
- package/dist/util/attributeWildcards.d.ts.map +0 -1
- package/dist/util/builder.d.ts.map +0 -1
- package/dist/util/catalogMeta.d.ts.map +0 -1
- package/dist/util/cli.d.ts.map +0 -1
- package/dist/util/errors.d.ts.map +0 -1
- package/dist/util/imports.d.ts.map +0 -1
- package/dist/util/runtimeSource.d.ts.map +0 -1
- package/dist/util/securityConfig.d.ts.map +0 -1
- package/dist/util/streamConfig.d.ts.map +0 -1
- package/dist/util/tools.d.ts.map +0 -1
- package/dist/xsd/primitives.d.ts.map +0 -1
- package/docs/AGENTS.md +0 -47
- package/docs/README.md +0 -56
- package/docs/architecture.md +0 -149
- package/docs/decisions/001-test-generation.md +0 -36
- package/docs/decisions/002-streamable-responses.md +0 -330
- package/docs/file-naming-and-path-organization.md +0 -213
- package/docs/releases/README.md +0 -94
- package/docs/releases/v0.20.0.md +0 -22
- package/docs/releases/v0.21.0.md +0 -30
- package/docs/releases/v0.22.0.md +0 -30
- package/docs/releases/v0.23.0.md +0 -31
- package/docs/releases/v0.24.0.md +0 -38
- package/docs/releases/v0.25.0.md +0 -31
- package/docs/releases/v0.25.2.md +0 -32
- package/docs/releases/v0.26.0.md +0 -32
- package/docs/releases/v0.27.0.md +0 -31
- package/docs/releases/v0.28.0.md +0 -32
- package/docs/releases/v0.29.0.md +0 -32
- package/docs/releases/v0.30.0.md +0 -30
- package/docs/releases/v0.30.1.md +0 -31
- package/docs/releases/v0.30.2.md +0 -30
- package/docs/releases/v0.30.3.md +0 -33
- package/docs/releases/v0.31.0.md +0 -33
- package/docs/releases/v0.32.0.md +0 -33
- package/docs/releases/v0.33.0.md +0 -34
- package/docs/releases/v0.34.0.md +0 -30
- package/docs/releases/v0.35.0.md +0 -33
- package/docs/releases/v0.36.0.md +0 -32
- package/docs/releases/v0.37.0.md +0 -33
- package/docs/releases/v0.38.0.md +0 -35
- package/docs/releases/v0.39.0.md +0 -35
- package/docs/releases/v0.40.0.md +0 -45
- package/docs/releases/v0.40.1.md +0 -34
- package/docs/releases/v1.0.0.md +0 -42
- package/docs/releases/v1.0.1.md +0 -38
- package/docs/releases/v1.0.2.md +0 -51
- package/docs/releases/v1.0.3.md +0 -37
- package/docs/releases/v1.0.4.md +0 -45
- package/docs/releases/v1.0.5.md +0 -41
- package/docs/releases/v1.0.6.md +0 -35
- package/docs/releases/v1.0.7.md +0 -36
- package/docs/releases/v1.1.0.md +0 -42
- package/docs/releases/v1.1.1.md +0 -44
- package/docs/releases/v1.1.2.md +0 -42
- package/docs/releases/v1.1.3.md +0 -36
- package/docs/releases/v1.1.4.md +0 -36
- package/docs/roadmap/README.md +0 -107
- package/docs/roadmap/v1.0-capability-conformance-framework.md +0 -582
- package/docs/roadmap/v1.0-choice-union-mode.md +0 -90
- package/docs/roadmap/v1.0-contract-audit.md +0 -75
- package/docs/roadmap/v1.0-json-array-streaming.md +0 -101
- package/docs/roadmap/v1.0-openapi-fastify-compatibility.md +0 -99
- package/docs/roadmap/v1.0-release-candidate-gates.md +0 -92
- package/docs/roadmap/v1.0-wsdl-coverage-matrix.md +0 -200
- package/docs/roadmap/v1.0-xs-anyattribute-wildcard-bag.md +0 -932
- package/src/runtime/jsonArray.ts +0 -55
- package/src/runtime/ndjson.ts +0 -32
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
/** Contextual schema traversal; consumes ordered syntax, never payload hints. */
|
|
2
|
+
import { parseOrderedSyntax, SchemaLoadingError, syntaxAttribute, syntaxElements, XSD_NAMESPACE, WSDL_NAMESPACE } from "./orderedSyntax.js";
|
|
3
|
+
import { SchemaResourceLoader, resolveResourceUri } from "./schemaResources.js";
|
|
4
|
+
import { resolutionDepthBound } from "./resolutionDepth.js";
|
|
5
|
+
import { normalizeWhitespace } from '../util/xmlWhitespace.js';
|
|
6
|
+
// Source-syntax evidence is issued only by this loader, never by a copied shape.
|
|
7
|
+
const loadedInputs = new WeakSet();
|
|
8
|
+
// Private original authorized snapshot; never reconstructed from syntax/digests.
|
|
9
|
+
const originalSources = new WeakMap();
|
|
10
|
+
/** Internal bridge for one retained-source invocation. Returned bytes are data, not authority. */
|
|
11
|
+
export function copyOriginalSchemaResource(input, uri, chargeWork) {
|
|
12
|
+
assertLoadedSchemaInput(input);
|
|
13
|
+
const bytes = originalSources.get(input)?.get(uri);
|
|
14
|
+
if (!bytes)
|
|
15
|
+
throw new TypeError('Original semantic source bytes unavailable');
|
|
16
|
+
chargeWork(512 + bytes.byteLength * 8);
|
|
17
|
+
return new Uint8Array(bytes);
|
|
18
|
+
}
|
|
19
|
+
export function assertLoadedSchemaInput(input) {
|
|
20
|
+
if (!loadedInputs.has(input))
|
|
21
|
+
throw new TypeError("Unauthenticated loaded schema input");
|
|
22
|
+
}
|
|
23
|
+
export function schemaInterpretationKey(node, targetNamespace, context) {
|
|
24
|
+
return JSON.stringify([node.source.digest, node.source.uri, node.baseUri, targetNamespace, context.kind, context.namespace, node.source.path]);
|
|
25
|
+
}
|
|
26
|
+
/** Prepare a closed input set from independently authorized physical metadata snapshots.
|
|
27
|
+
* @remarks Logical import URIs never initiate I/O here. The later native loader still checks their explicit origin/root
|
|
28
|
+
* permissions. Missing snapshots refuse rather than falling back to network or to artifact-embedded bytes.
|
|
29
|
+
* @returns The actual physical root URI and complete offline loading configuration.
|
|
30
|
+
* @throws SchemaLoadingError For non-file physical inputs, duplicates, denied roots or unavailable files.
|
|
31
|
+
*/
|
|
32
|
+
export async function prepareSchemaSnapshotFiles(root, files, options) {
|
|
33
|
+
const physical = async (reference) => {
|
|
34
|
+
if (new URL(resolveResourceUri(reference)).protocol !== 'file:')
|
|
35
|
+
throw new SchemaLoadingError('unsupported-capability', 'Physical schema snapshot file required');
|
|
36
|
+
return loader.fetchResource(reference);
|
|
37
|
+
};
|
|
38
|
+
const loader = await SchemaResourceLoader.create({ fileRoots: options.policy.fileRoots }, options.limits, undefined, options.chargeWork, options.signal);
|
|
39
|
+
const source = await physical(root), offlineResources = new Map([[source.uri, source]]);
|
|
40
|
+
for (const entry of files) {
|
|
41
|
+
options.chargeWork?.(1);
|
|
42
|
+
const uri = resolveResourceUri(entry.uri);
|
|
43
|
+
if (offlineResources.has(uri))
|
|
44
|
+
throw new SchemaLoadingError('invalid-schema', 'Duplicate logical schema snapshot');
|
|
45
|
+
offlineResources.set(uri, { ...await physical(entry.file), canonicalUri: entry.canonicalUri });
|
|
46
|
+
}
|
|
47
|
+
return { source: source.uri, loading: { ...options, offlineResources } };
|
|
48
|
+
}
|
|
49
|
+
/** A fresh compilation-scoped snapshot, with no implicit network or filesystem permission. */
|
|
50
|
+
export function loadSchemaInput(source, options) {
|
|
51
|
+
return loadSchemaInputWithValues(source, options, false);
|
|
52
|
+
}
|
|
53
|
+
/** Internal faithful source entry; preserves syntax and the legacy public entry. */
|
|
54
|
+
export function loadSemanticSchemaInput(source, options) {
|
|
55
|
+
return loadSchemaInputWithValues(source, options, true);
|
|
56
|
+
}
|
|
57
|
+
async function loadSchemaInputWithValues(source, options, semanticValues) {
|
|
58
|
+
// @why Snapshot caller configuration before the first asynchronous resource read.
|
|
59
|
+
const namespaceLocations = new Map();
|
|
60
|
+
if (options.namespaceLocations)
|
|
61
|
+
for (const [namespace, location] of options.namespaceLocations) {
|
|
62
|
+
if (typeof namespace !== 'string' || typeof location !== 'string' || !location)
|
|
63
|
+
throw new TypeError('Namespace locations require string namespace names and nonempty resource locations');
|
|
64
|
+
options.chargeWork?.(256 + (namespace.length + location.length) * 32);
|
|
65
|
+
namespaceLocations.set(namespace, resolveResourceUri(location));
|
|
66
|
+
}
|
|
67
|
+
const loader = await SchemaResourceLoader.create(options.policy, options.limits, options.offlineResources, options.chargeWork, options.signal);
|
|
68
|
+
const documents = new Map();
|
|
69
|
+
const originalBytes = new Map();
|
|
70
|
+
const schemas = new Map();
|
|
71
|
+
const edges = [];
|
|
72
|
+
const active = new Set();
|
|
73
|
+
const wsdlVisited = new Set();
|
|
74
|
+
const depthGraph = new Map();
|
|
75
|
+
const depthTargets = new Map();
|
|
76
|
+
const recordDepthArc = (from, to, cost) => {
|
|
77
|
+
const target = JSON.stringify([to, cost]);
|
|
78
|
+
const targets = depthTargets.get(from) ?? new Set();
|
|
79
|
+
if (targets.has(target))
|
|
80
|
+
return;
|
|
81
|
+
targets.add(target);
|
|
82
|
+
depthTargets.set(from, targets);
|
|
83
|
+
const arcs = depthGraph.get(from) ?? [];
|
|
84
|
+
arcs.push({ to, cost });
|
|
85
|
+
depthGraph.set(from, arcs);
|
|
86
|
+
};
|
|
87
|
+
const recordEdge = (edge) => {
|
|
88
|
+
options.chargeWork?.(256);
|
|
89
|
+
const frozen = Object.freeze(edge);
|
|
90
|
+
edges.push(frozen);
|
|
91
|
+
if (edge.to)
|
|
92
|
+
recordDepthArc(edge.from, edge.to, 1);
|
|
93
|
+
};
|
|
94
|
+
const checkDepth = (depth, node) => {
|
|
95
|
+
if (depth > loader.limits.resolutionDepth)
|
|
96
|
+
throw new SchemaLoadingError("resource-limit", `Schema resolution depth exceeds ${loader.limits.resolutionDepth} edges`, node?.source);
|
|
97
|
+
};
|
|
98
|
+
const getDocument = async (uri) => {
|
|
99
|
+
const resource = await loader.fetchResource(uri);
|
|
100
|
+
let doc = documents.get(resource.uri);
|
|
101
|
+
if (!doc) {
|
|
102
|
+
doc = parseOrderedSyntax(resource.bytes, resource.uri, { maxDepth: loader.limits.syntaxDepth, metadataEncoding: true });
|
|
103
|
+
if (semanticValues) {
|
|
104
|
+
options.chargeWork?.(128);
|
|
105
|
+
originalBytes.set(resource.uri, resource.bytes);
|
|
106
|
+
}
|
|
107
|
+
documents.set(resource.uri, doc);
|
|
108
|
+
options.onDocument?.(doc);
|
|
109
|
+
}
|
|
110
|
+
return doc;
|
|
111
|
+
};
|
|
112
|
+
const is = (node, namespace, local) => node.name.namespace === namespace && node.name.local === local;
|
|
113
|
+
// Only XSD anyURI properties use this mapping. Original syntax and namespace
|
|
114
|
+
// bindings, WSDL transport names, and arbitrary resource URLs remain intact.
|
|
115
|
+
// Source byte/resource limits govern this phase, before semantic preparation.
|
|
116
|
+
const xsdUri = (node, name) => {
|
|
117
|
+
const value = syntaxAttribute(node, name);
|
|
118
|
+
options.chargeWork?.(64 + (value?.length ?? 0) * 16);
|
|
119
|
+
return value === undefined || !semanticValues ? value : normalizeWhitespace(value, 'collapse');
|
|
120
|
+
};
|
|
121
|
+
// Cached interpretations still consume resolution depth on a later, deeper route.
|
|
122
|
+
const checkCachedDepth = (key, depth) => {
|
|
123
|
+
if (depth + resolutionDepthBound(key, depthGraph, active) > loader.limits.resolutionDepth) {
|
|
124
|
+
throw new SchemaLoadingError("resource-limit", `Schema resolution depth exceeds ${loader.limits.resolutionDepth} edges`, schemas.get(key)?.syntax.source ?? documents.get(key)?.root.source);
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
const referencedDocument = async (reference, node) => {
|
|
128
|
+
try {
|
|
129
|
+
const referenceUri = resolveResourceUri(reference, node.baseUri);
|
|
130
|
+
if (new URL(node.source.uri).protocol !== 'file:' && new URL(referenceUri).protocol === 'file:') {
|
|
131
|
+
throw new SchemaLoadingError('unsupported-capability', 'Remote metadata cannot select local resources');
|
|
132
|
+
}
|
|
133
|
+
return { referenceUri, doc: await getDocument(referenceUri) };
|
|
134
|
+
}
|
|
135
|
+
catch (error) {
|
|
136
|
+
if (error instanceof SchemaLoadingError && !error.source)
|
|
137
|
+
throw new SchemaLoadingError(error.category, error.message, node.source);
|
|
138
|
+
throw error;
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
const interpret = async (node, context, depth) => {
|
|
142
|
+
options.chargeWork?.(4096 + (node.source.path.length + node.source.uri.length + node.baseUri.length + context.namespace.length) * 32 + node.children.length * 128);
|
|
143
|
+
checkDepth(depth, node);
|
|
144
|
+
if (!is(node, XSD_NAMESPACE, "schema"))
|
|
145
|
+
throw new SchemaLoadingError("invalid-schema", "Expected an XSD schema root", node.source);
|
|
146
|
+
const declaredValue = xsdUri(node, "targetNamespace");
|
|
147
|
+
if (semanticValues && declaredValue === '')
|
|
148
|
+
throw new SchemaLoadingError("invalid-schema", "A present schema target namespace must not be empty", node.source);
|
|
149
|
+
const declaredNamespace = declaredValue ?? "";
|
|
150
|
+
const targetNamespace = context.kind === "include" && !declaredNamespace ? context.namespace : declaredNamespace;
|
|
151
|
+
if (context.kind === "include" && declaredNamespace && declaredNamespace !== context.namespace) {
|
|
152
|
+
throw new SchemaLoadingError("invalid-schema", "Included schema target namespace differs from its including schema", node.source);
|
|
153
|
+
}
|
|
154
|
+
if (context.kind === "import" && targetNamespace !== context.namespace) {
|
|
155
|
+
throw new SchemaLoadingError("invalid-schema", "Imported schema target namespace differs from the declared import namespace", node.source);
|
|
156
|
+
}
|
|
157
|
+
const key = schemaInterpretationKey(node, targetNamespace, context);
|
|
158
|
+
if (schemas.has(key)) {
|
|
159
|
+
if (!active.has(key))
|
|
160
|
+
checkCachedDepth(key, depth);
|
|
161
|
+
return key;
|
|
162
|
+
}
|
|
163
|
+
const instance = Object.freeze({ key, syntax: node, documentUri: node.source.uri, digest: node.source.digest, baseUri: node.baseUri, targetNamespace, context: Object.freeze(context) });
|
|
164
|
+
schemas.set(key, instance);
|
|
165
|
+
active.add(key);
|
|
166
|
+
for (const child of syntaxElements(node, XSD_NAMESPACE)) {
|
|
167
|
+
if (child.name.local !== "include" && child.name.local !== "import")
|
|
168
|
+
continue;
|
|
169
|
+
const kind = child.name.local;
|
|
170
|
+
const location = xsdUri(child, "schemaLocation");
|
|
171
|
+
const importedNamespace = xsdUri(child, "namespace");
|
|
172
|
+
const missingLocation = semanticValues ? location === undefined : !location;
|
|
173
|
+
if (missingLocation && kind === "include")
|
|
174
|
+
throw new SchemaLoadingError("invalid-schema", "Schema include requires schemaLocation", child.source);
|
|
175
|
+
const suppliedLocation = missingLocation && kind === 'import' ? namespaceLocations.get(importedNamespace ?? '') : undefined;
|
|
176
|
+
if (missingLocation && suppliedLocation === undefined) {
|
|
177
|
+
recordEdge({ kind, from: key, source: child.source, cycle: false });
|
|
178
|
+
continue;
|
|
179
|
+
}
|
|
180
|
+
checkDepth(depth + 1, child);
|
|
181
|
+
const namespace = kind === "include" ? targetNamespace : importedNamespace ?? "";
|
|
182
|
+
if (kind === "import" && namespace === targetNamespace)
|
|
183
|
+
throw new SchemaLoadingError("invalid-schema", "Schema import must name a different namespace", child.source);
|
|
184
|
+
const { referenceUri, doc } = await referencedDocument(suppliedLocation ?? location, child);
|
|
185
|
+
const childDeclaredNamespace = xsdUri(doc.root, "targetNamespace");
|
|
186
|
+
// A successfully supplied import referent must match both presence and
|
|
187
|
+
// value. An explicit empty import namespace without a referent is not
|
|
188
|
+
// by itself forbidden by the anyURI datatype or src-import clause 3.
|
|
189
|
+
if (semanticValues && kind === 'import' && (importedNamespace === undefined) !== (childDeclaredNamespace === undefined)) {
|
|
190
|
+
throw new SchemaLoadingError("invalid-schema", "Imported schema target namespace presence differs from the declared import namespace", child.source);
|
|
191
|
+
}
|
|
192
|
+
const childContext = { kind, namespace };
|
|
193
|
+
const childNamespace = kind === "include" ? childDeclaredNamespace || namespace : childDeclaredNamespace ?? "";
|
|
194
|
+
const childKey = schemaInterpretationKey(doc.root, childNamespace, childContext);
|
|
195
|
+
const cycle = active.has(childKey);
|
|
196
|
+
const to = await interpret(doc.root, childContext, depth + 1);
|
|
197
|
+
recordEdge({ kind, from: key, to, referenceUri, source: child.source, cycle });
|
|
198
|
+
}
|
|
199
|
+
active.delete(key);
|
|
200
|
+
return key;
|
|
201
|
+
};
|
|
202
|
+
const visitWsdl = async (doc, depth) => {
|
|
203
|
+
checkDepth(depth, doc.root);
|
|
204
|
+
if (!is(doc.root, WSDL_NAMESPACE, "definitions"))
|
|
205
|
+
throw new SchemaLoadingError("invalid-schema", "Expected WSDL 1.1 definitions", doc.root.source);
|
|
206
|
+
if (wsdlVisited.has(doc.uri)) {
|
|
207
|
+
if (!active.has(doc.uri))
|
|
208
|
+
checkCachedDepth(doc.uri, depth);
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
wsdlVisited.add(doc.uri);
|
|
212
|
+
active.add(doc.uri);
|
|
213
|
+
for (const child of syntaxElements(doc.root, WSDL_NAMESPACE)) {
|
|
214
|
+
if (child.name.local === "types") {
|
|
215
|
+
for (const schema of syntaxElements(child, XSD_NAMESPACE, "schema")) {
|
|
216
|
+
const key = await interpret(schema, { kind: "inline", namespace: "" }, depth);
|
|
217
|
+
recordDepthArc(doc.uri, key, 0);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
else if (child.name.local === "import") {
|
|
221
|
+
const location = syntaxAttribute(child, "location");
|
|
222
|
+
if (!location)
|
|
223
|
+
throw new SchemaLoadingError("invalid-schema", "WSDL import requires location", child.source);
|
|
224
|
+
checkDepth(depth + 1, child);
|
|
225
|
+
const { referenceUri, doc: imported } = await referencedDocument(location, child);
|
|
226
|
+
if ((syntaxAttribute(imported.root, "targetNamespace") ?? "") !== (syntaxAttribute(child, "namespace") ?? "")) {
|
|
227
|
+
throw new SchemaLoadingError("invalid-schema", "WSDL import namespace mismatch", child.source);
|
|
228
|
+
}
|
|
229
|
+
const cycle = active.has(imported.uri);
|
|
230
|
+
await visitWsdl(imported, depth + 1);
|
|
231
|
+
recordEdge({ kind: "wsdl-import", from: doc.uri, to: imported.uri, referenceUri, source: child.source, cycle });
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
active.delete(doc.uri);
|
|
235
|
+
};
|
|
236
|
+
const root = await getDocument(resolveResourceUri(source));
|
|
237
|
+
if (is(root.root, XSD_NAMESPACE, "schema"))
|
|
238
|
+
await interpret(root.root, { kind: "root", namespace: "" }, 0);
|
|
239
|
+
else if (is(root.root, WSDL_NAMESPACE, "definitions"))
|
|
240
|
+
await visitWsdl(root, 0);
|
|
241
|
+
else
|
|
242
|
+
throw new SchemaLoadingError("unsupported-capability", "Only WSDL 1.1 or XSD schema inputs are accepted; payload hints cannot resolve schemas", root.root.source);
|
|
243
|
+
const input = Object.freeze({ root, documents: Object.freeze([...documents.values()]), schemas: Object.freeze([...schemas.values()]),
|
|
244
|
+
resources: loader.metadata, resourceAliases: loader.resourceAliases, edges: Object.freeze(edges), limits: loader.limits, metrics: loader.metrics });
|
|
245
|
+
loadedInputs.add(input);
|
|
246
|
+
if (semanticValues)
|
|
247
|
+
originalSources.set(input, originalBytes);
|
|
248
|
+
return input;
|
|
249
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
export declare const DEFAULT_LOADING_LIMITS: Readonly<{
|
|
2
|
+
resources: 128;
|
|
3
|
+
resourceBytes: number;
|
|
4
|
+
totalBytes: number;
|
|
5
|
+
resolutionDepth: 32;
|
|
6
|
+
redirects: 5;
|
|
7
|
+
resourceMs: 15000;
|
|
8
|
+
totalIoMs: 120000;
|
|
9
|
+
syntaxDepth: 256;
|
|
10
|
+
}>;
|
|
11
|
+
export type LoadingLimits = Readonly<{
|
|
12
|
+
[K in keyof typeof DEFAULT_LOADING_LIMITS]: number;
|
|
13
|
+
}>;
|
|
14
|
+
export type SchemaResourcePolicy = Readonly<{
|
|
15
|
+
fileRoots?: readonly string[];
|
|
16
|
+
/** Exact HTTP(S) origins, including ports. No implicit host or scheme permission. */
|
|
17
|
+
allowedOrigins?: readonly string[];
|
|
18
|
+
}>;
|
|
19
|
+
export type OfflineSchemaResource = Readonly<{
|
|
20
|
+
bytes: Uint8Array;
|
|
21
|
+
digest: string;
|
|
22
|
+
canonicalUri?: string;
|
|
23
|
+
}>;
|
|
24
|
+
export type ResourceMetadata = Readonly<{
|
|
25
|
+
uri: string;
|
|
26
|
+
digest: string;
|
|
27
|
+
byteLength: number;
|
|
28
|
+
}>;
|
|
29
|
+
export type FetchedSchemaResource = ResourceMetadata & Readonly<{
|
|
30
|
+
bytes: Uint8Array;
|
|
31
|
+
}>;
|
|
32
|
+
export declare function loadingLimits(overrides?: Partial<LoadingLimits>): LoadingLimits;
|
|
33
|
+
/** Canonical URL spelling; queries remain distinct, fragments are not retrieval identity. */
|
|
34
|
+
export declare function resolveResourceUri(reference: string, baseUri?: string): string;
|
|
35
|
+
/** One instance per compilation. Bytes and aliases are confined to this I/O boundary. */
|
|
36
|
+
export declare class SchemaResourceLoader {
|
|
37
|
+
private readonly roots;
|
|
38
|
+
private readonly lexicalRoots;
|
|
39
|
+
private readonly origins;
|
|
40
|
+
private readonly offline?;
|
|
41
|
+
private readonly charge?;
|
|
42
|
+
private readonly signal?;
|
|
43
|
+
readonly limits: LoadingLimits;
|
|
44
|
+
private readonly resources;
|
|
45
|
+
private readonly aliases;
|
|
46
|
+
private readonly resourceKeys;
|
|
47
|
+
private totalBytes;
|
|
48
|
+
private ioMs;
|
|
49
|
+
private constructor();
|
|
50
|
+
static create(policy: SchemaResourcePolicy, overrides?: Partial<LoadingLimits>, offline?: ReadonlyMap<string, OfflineSchemaResource>, charge?: (amount: number) => void, signal?: AbortSignal): Promise<SchemaResourceLoader>;
|
|
51
|
+
get metadata(): readonly ResourceMetadata[];
|
|
52
|
+
get metrics(): Readonly<{
|
|
53
|
+
resources: number;
|
|
54
|
+
totalBytes: number;
|
|
55
|
+
ioMs: number;
|
|
56
|
+
}>;
|
|
57
|
+
get resourceAliases(): ReadonlyMap<string, string>;
|
|
58
|
+
private authorize;
|
|
59
|
+
fetchResource(reference: string): Promise<FetchedSchemaResource>;
|
|
60
|
+
}
|
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
/** Policy-checked, bounded I/O for schema inputs only. Legacy fetching is separate. */
|
|
2
|
+
import { createHash } from "node:crypto";
|
|
3
|
+
import { open, realpath, lstat } from "node:fs/promises";
|
|
4
|
+
import { constants } from "node:fs";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
7
|
+
import { SchemaLoadingError } from "./orderedSyntax.js";
|
|
8
|
+
export const DEFAULT_LOADING_LIMITS = Object.freeze({
|
|
9
|
+
resources: 128, resourceBytes: 8 * 1024 * 1024, totalBytes: 64 * 1024 * 1024,
|
|
10
|
+
resolutionDepth: 32, redirects: 5, resourceMs: 15_000, totalIoMs: 120_000, syntaxDepth: 256,
|
|
11
|
+
});
|
|
12
|
+
export function loadingLimits(overrides = {}) {
|
|
13
|
+
const limits = { ...DEFAULT_LOADING_LIMITS, ...overrides };
|
|
14
|
+
for (const [key, value] of Object.entries(limits)) {
|
|
15
|
+
if (!Number.isSafeInteger(value) || value < (['redirects', 'resourceMs', 'totalIoMs'].includes(key) ? 0 : 1)) {
|
|
16
|
+
throw new RangeError(`Invalid schema loading limit: ${key}`);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return Object.freeze(limits);
|
|
20
|
+
}
|
|
21
|
+
/** Canonical URL spelling; queries remain distinct, fragments are not retrieval identity. */
|
|
22
|
+
export function resolveResourceUri(reference, baseUri) {
|
|
23
|
+
let url;
|
|
24
|
+
try {
|
|
25
|
+
url = baseUri ? new URL(reference, baseUri)
|
|
26
|
+
: /^[a-z][a-z0-9+.-]*:/i.test(reference) && !/^[a-z]:[\\/]/i.test(reference)
|
|
27
|
+
? new URL(reference) : pathToFileURL(path.resolve(reference));
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
throw new SchemaLoadingError("invalid-schema", "Invalid schema resource URI");
|
|
31
|
+
}
|
|
32
|
+
if (!["file:", "http:", "https:"].includes(url.protocol)) {
|
|
33
|
+
throw new SchemaLoadingError("unsupported-capability", "Unsupported schema resource scheme");
|
|
34
|
+
}
|
|
35
|
+
if (url.username || url.password)
|
|
36
|
+
throw new SchemaLoadingError("unsupported-capability", "Credential-bearing resource URIs are forbidden");
|
|
37
|
+
if (url.protocol === "file:" && (url.search || (url.hostname && url.hostname !== "localhost"))) {
|
|
38
|
+
throw new SchemaLoadingError("unsupported-capability", "File URI queries and remote file authorities are forbidden");
|
|
39
|
+
}
|
|
40
|
+
url.hash = "";
|
|
41
|
+
return url.href;
|
|
42
|
+
}
|
|
43
|
+
function withinRoot(file, root) {
|
|
44
|
+
const relative = path.relative(root, file);
|
|
45
|
+
return relative === "" || (!path.isAbsolute(relative) && relative !== ".." && !relative.startsWith(`..${path.sep}`));
|
|
46
|
+
}
|
|
47
|
+
/** One instance per compilation. Bytes and aliases are confined to this I/O boundary. */
|
|
48
|
+
export class SchemaResourceLoader {
|
|
49
|
+
roots;
|
|
50
|
+
lexicalRoots;
|
|
51
|
+
origins;
|
|
52
|
+
offline;
|
|
53
|
+
charge;
|
|
54
|
+
signal;
|
|
55
|
+
limits;
|
|
56
|
+
resources = new Map();
|
|
57
|
+
aliases = new Map();
|
|
58
|
+
resourceKeys = new Map();
|
|
59
|
+
totalBytes = 0;
|
|
60
|
+
ioMs = 0;
|
|
61
|
+
constructor(roots, lexicalRoots, origins, limits, offline, charge, signal) {
|
|
62
|
+
this.roots = roots;
|
|
63
|
+
this.lexicalRoots = lexicalRoots;
|
|
64
|
+
this.origins = origins;
|
|
65
|
+
this.offline = offline;
|
|
66
|
+
this.charge = charge;
|
|
67
|
+
this.signal = signal;
|
|
68
|
+
this.limits = limits;
|
|
69
|
+
}
|
|
70
|
+
static async create(policy, overrides, offline, charge, signal) {
|
|
71
|
+
charge?.(1024 + (policy.fileRoots?.length ?? 0) * 128 + (policy.allowedOrigins?.length ?? 0) * 128 + (offline?.size ?? 0) * 256);
|
|
72
|
+
const configuredRoots = (policy.fileRoots ?? []).map(root => { charge?.(128 + root.length * 32); return path.resolve(root); });
|
|
73
|
+
let roots;
|
|
74
|
+
try {
|
|
75
|
+
roots = await Promise.all(configuredRoots.map(root => realpath(root)));
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
throw new SchemaLoadingError("transport", "An authorized schema root is unavailable");
|
|
79
|
+
}
|
|
80
|
+
const origins = new Set((policy.allowedOrigins ?? []).map(origin => {
|
|
81
|
+
charge?.(128 + origin.length * 32);
|
|
82
|
+
const url = new URL(origin);
|
|
83
|
+
if (!["http:", "https:"].includes(url.protocol) || url.username || url.password || url.pathname !== "/" || url.search || url.hash) {
|
|
84
|
+
throw new RangeError("allowedOrigins must contain HTTP(S) origins only");
|
|
85
|
+
}
|
|
86
|
+
return url.origin;
|
|
87
|
+
}));
|
|
88
|
+
// Copy the manifest; byte copies occur only after per-resource/aggregate checks.
|
|
89
|
+
const snapshots = offline ? new Map() : undefined;
|
|
90
|
+
if (offline)
|
|
91
|
+
for (const [uri, value] of offline) {
|
|
92
|
+
charge?.(256 + uri.length * 32);
|
|
93
|
+
snapshots.set(resolveResourceUri(uri), { bytes: value.bytes, digest: value.digest, canonicalUri: value.canonicalUri });
|
|
94
|
+
}
|
|
95
|
+
return new SchemaResourceLoader(roots, [...configuredRoots, ...roots], origins, loadingLimits(overrides), snapshots, charge, signal);
|
|
96
|
+
}
|
|
97
|
+
get metadata() {
|
|
98
|
+
this.charge?.(128 + this.resources.size * 256);
|
|
99
|
+
return Object.freeze([...this.resources.values()].map(({ uri, digest, byteLength }) => Object.freeze({ uri, digest, byteLength })));
|
|
100
|
+
}
|
|
101
|
+
get metrics() {
|
|
102
|
+
return Object.freeze({ resources: this.resources.size, totalBytes: this.totalBytes, ioMs: this.ioMs });
|
|
103
|
+
}
|
|
104
|
+
get resourceAliases() { return new Map(this.aliases); }
|
|
105
|
+
async authorize(uri) {
|
|
106
|
+
this.charge?.(1024 + uri.length * 32 + this.roots.length * 256);
|
|
107
|
+
const url = new URL(resolveResourceUri(uri));
|
|
108
|
+
if (url.protocol !== "file:") {
|
|
109
|
+
if (!this.origins.has(url.origin))
|
|
110
|
+
throw new SchemaLoadingError("unsupported-capability", "Schema resource origin is not authorized");
|
|
111
|
+
return url.href;
|
|
112
|
+
}
|
|
113
|
+
const file = fileURLToPath(url);
|
|
114
|
+
// Check lexical traversal before touching the filesystem, then symlink-resolved identity.
|
|
115
|
+
if (!this.lexicalRoots.some(root => withinRoot(file, root)))
|
|
116
|
+
throw new SchemaLoadingError("unsupported-capability", "Schema file is outside authorized roots");
|
|
117
|
+
const actual = await realpath(file);
|
|
118
|
+
if (!this.roots.some(root => withinRoot(actual, root)))
|
|
119
|
+
throw new SchemaLoadingError("unsupported-capability", "Schema symlink is outside authorized roots");
|
|
120
|
+
return pathToFileURL(actual).href;
|
|
121
|
+
}
|
|
122
|
+
async fetchResource(reference) {
|
|
123
|
+
this.charge?.(256 + reference.length * 4);
|
|
124
|
+
const requested = resolveResourceUri(reference);
|
|
125
|
+
// A previously authorized alias returns the compilation's pinned bytes without new I/O.
|
|
126
|
+
const pinned = this.resources.get(this.resourceKeys.get(this.aliases.get(requested) ?? requested) ?? "");
|
|
127
|
+
if (pinned)
|
|
128
|
+
return pinned;
|
|
129
|
+
const started = performance.now();
|
|
130
|
+
const remaining = this.limits.totalIoMs === 0 ? Infinity : this.limits.totalIoMs - this.ioMs;
|
|
131
|
+
if (remaining < 0)
|
|
132
|
+
throw new SchemaLoadingError("transport", "Total schema I/O deadline exhausted");
|
|
133
|
+
const budget = Math.min(this.limits.resourceMs === 0 ? Infinity : this.limits.resourceMs, remaining);
|
|
134
|
+
const controller = new AbortController();
|
|
135
|
+
const abort = () => controller.abort(this.signal?.reason);
|
|
136
|
+
this.signal?.addEventListener('abort', abort, { once: true });
|
|
137
|
+
if (this.signal?.aborted)
|
|
138
|
+
abort();
|
|
139
|
+
let timer;
|
|
140
|
+
let performedIo = new URL(requested).protocol === "file:";
|
|
141
|
+
const timeout = new Promise((_, reject) => {
|
|
142
|
+
// Limits are inclusive: an exactly-at-deadline completed resource is admitted.
|
|
143
|
+
if (Number.isFinite(budget))
|
|
144
|
+
timer = setTimeout(() => { controller.abort(); reject(new SchemaLoadingError("transport", "Schema resource or total I/O deadline exceeded")); }, budget + 1);
|
|
145
|
+
});
|
|
146
|
+
try {
|
|
147
|
+
const task = (async () => {
|
|
148
|
+
let uri = await this.authorize(requested);
|
|
149
|
+
if (controller.signal.aborted || performance.now() - started > budget)
|
|
150
|
+
throw new SchemaLoadingError("transport", "Schema I/O deadline exceeded");
|
|
151
|
+
const cached = this.resources.get(this.resourceKeys.get(this.aliases.get(uri) ?? uri) ?? "");
|
|
152
|
+
if (cached)
|
|
153
|
+
return cached;
|
|
154
|
+
const checkResourceCount = () => {
|
|
155
|
+
if (this.resources.size >= this.limits.resources)
|
|
156
|
+
throw new SchemaLoadingError("resource-limit", `Schema resource count exceeds ${this.limits.resources}`);
|
|
157
|
+
};
|
|
158
|
+
performedIo = true;
|
|
159
|
+
const redirectAliases = [requested, uri];
|
|
160
|
+
const chunks = [];
|
|
161
|
+
let byteLength = 0;
|
|
162
|
+
const accept = (chunk) => {
|
|
163
|
+
if (controller.signal.aborted || performance.now() - started > budget)
|
|
164
|
+
throw new SchemaLoadingError("transport", "Schema I/O deadline exceeded");
|
|
165
|
+
// Reserve copying, hashing, decoding and bounded syntax preparation before retaining bytes.
|
|
166
|
+
this.charge?.(64 + chunk.byteLength * 32);
|
|
167
|
+
byteLength += chunk.byteLength;
|
|
168
|
+
if (byteLength > this.limits.resourceBytes || this.totalBytes + byteLength > this.limits.totalBytes) {
|
|
169
|
+
throw new SchemaLoadingError("resource-limit", "Decompressed schema byte budget exceeded");
|
|
170
|
+
}
|
|
171
|
+
chunks.push(Uint8Array.from(chunk));
|
|
172
|
+
};
|
|
173
|
+
if (this.offline) {
|
|
174
|
+
const snapshot = this.offline.get(uri);
|
|
175
|
+
if (!snapshot)
|
|
176
|
+
throw new SchemaLoadingError("transport", "Schema resource is absent from the offline snapshot");
|
|
177
|
+
if (snapshot.bytes.byteLength > this.limits.resourceBytes)
|
|
178
|
+
throw new SchemaLoadingError('resource-limit', 'Decompressed schema byte budget exceeded');
|
|
179
|
+
const snapshotDigest = (value) => {
|
|
180
|
+
if (controller.signal.aborted || performance.now() - started > budget)
|
|
181
|
+
throw new SchemaLoadingError('transport', 'Schema I/O deadline exceeded');
|
|
182
|
+
this.charge?.(64 + value.bytes.byteLength * 8);
|
|
183
|
+
return createHash('sha256').update(value.bytes).digest('hex');
|
|
184
|
+
};
|
|
185
|
+
if (snapshot.canonicalUri) {
|
|
186
|
+
if (new URL(uri).protocol !== 'file:' && new URL(resolveResourceUri(snapshot.canonicalUri)).protocol === 'file:')
|
|
187
|
+
throw new SchemaLoadingError('unsupported-capability', 'Remote metadata cannot select local resources');
|
|
188
|
+
const canonical = await this.authorize(snapshot.canonicalUri);
|
|
189
|
+
const target = this.offline.get(canonical);
|
|
190
|
+
if (target && (target.digest !== snapshot.digest || target.bytes.byteLength !== snapshot.bytes.byteLength)) {
|
|
191
|
+
throw new SchemaLoadingError('invalid-schema', 'Conflicting offline alias bytes');
|
|
192
|
+
}
|
|
193
|
+
if (target) {
|
|
194
|
+
if (target.bytes.byteLength > this.limits.resourceBytes)
|
|
195
|
+
throw new SchemaLoadingError('resource-limit', 'Decompressed schema byte budget exceeded');
|
|
196
|
+
if (snapshotDigest(target) !== target.digest)
|
|
197
|
+
throw new SchemaLoadingError('invalid-schema', 'Offline schema digest mismatch');
|
|
198
|
+
if (target.canonicalUri && resolveResourceUri(target.canonicalUri) !== canonical)
|
|
199
|
+
throw new SchemaLoadingError('unsupported-capability', 'Offline aliases must name a canonical snapshot');
|
|
200
|
+
}
|
|
201
|
+
uri = canonical;
|
|
202
|
+
redirectAliases.push(uri);
|
|
203
|
+
const cached = this.resources.get(this.resourceKeys.get(uri) ?? '');
|
|
204
|
+
if (cached) {
|
|
205
|
+
if (snapshot.digest !== cached.digest || snapshotDigest(snapshot) !== snapshot.digest) {
|
|
206
|
+
throw new SchemaLoadingError('invalid-schema', 'Conflicting offline alias bytes');
|
|
207
|
+
}
|
|
208
|
+
for (const alias of redirectAliases)
|
|
209
|
+
this.aliases.set(alias, uri);
|
|
210
|
+
return cached;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
checkResourceCount();
|
|
214
|
+
accept(snapshot.bytes);
|
|
215
|
+
const digest = createHash("sha256").update(snapshot.bytes).digest("hex");
|
|
216
|
+
if (digest !== snapshot.digest)
|
|
217
|
+
throw new SchemaLoadingError("invalid-schema", "Offline schema digest mismatch");
|
|
218
|
+
}
|
|
219
|
+
else if (new URL(uri).protocol === "file:") {
|
|
220
|
+
checkResourceCount();
|
|
221
|
+
const localPath = fileURLToPath(uri);
|
|
222
|
+
if (!(await lstat(localPath)).isFile())
|
|
223
|
+
throw new SchemaLoadingError("unsupported-capability", "Schema resource must be a regular file");
|
|
224
|
+
const file = await open(localPath, constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0) | (constants.O_NONBLOCK ?? 0));
|
|
225
|
+
try {
|
|
226
|
+
if (!(await file.stat()).isFile())
|
|
227
|
+
throw new SchemaLoadingError("unsupported-capability", "Schema resource must be a regular file");
|
|
228
|
+
// @why Cancellation during metadata I/O must not construct an already-aborted stream that can emit outside iterator handling.
|
|
229
|
+
if (controller.signal.aborted)
|
|
230
|
+
throw new SchemaLoadingError("transport", "Schema resource I/O cancelled");
|
|
231
|
+
const stream = file.createReadStream({ autoClose: false, signal: controller.signal });
|
|
232
|
+
try {
|
|
233
|
+
for await (const chunk of stream)
|
|
234
|
+
accept(chunk);
|
|
235
|
+
}
|
|
236
|
+
finally {
|
|
237
|
+
stream.destroy();
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
finally {
|
|
241
|
+
await file.close();
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
else {
|
|
245
|
+
for (let redirects = 0;; redirects++) {
|
|
246
|
+
const response = await fetch(uri, { redirect: "manual", signal: controller.signal, headers: { Accept: "application/xml,text/xml" } });
|
|
247
|
+
if ([301, 302, 303, 307, 308].includes(response.status)) {
|
|
248
|
+
await response.body?.cancel();
|
|
249
|
+
if (redirects >= this.limits.redirects)
|
|
250
|
+
throw new SchemaLoadingError("resource-limit", `Schema redirects exceed ${this.limits.redirects}`);
|
|
251
|
+
const location = response.headers.get("location");
|
|
252
|
+
if (!location)
|
|
253
|
+
throw new SchemaLoadingError("transport", "Schema redirect has no location");
|
|
254
|
+
const redirected = resolveResourceUri(location, uri);
|
|
255
|
+
if (new URL(redirected).protocol === "file:")
|
|
256
|
+
throw new SchemaLoadingError("unsupported-capability", "HTTP redirects cannot select file resources");
|
|
257
|
+
uri = await this.authorize(redirected);
|
|
258
|
+
redirectAliases.push(uri);
|
|
259
|
+
const redirectedCache = this.resources.get(this.resourceKeys.get(this.aliases.get(uri) ?? uri) ?? "");
|
|
260
|
+
if (redirectedCache) {
|
|
261
|
+
if (controller.signal.aborted || performance.now() - started > budget)
|
|
262
|
+
throw new SchemaLoadingError("transport", "Schema I/O deadline exceeded");
|
|
263
|
+
for (const alias of redirectAliases)
|
|
264
|
+
this.aliases.set(alias, redirectedCache.uri);
|
|
265
|
+
return redirectedCache;
|
|
266
|
+
}
|
|
267
|
+
continue;
|
|
268
|
+
}
|
|
269
|
+
if (!response.ok) {
|
|
270
|
+
await response.body?.cancel();
|
|
271
|
+
throw new SchemaLoadingError("transport", `Schema retrieval returned HTTP ${response.status}`);
|
|
272
|
+
}
|
|
273
|
+
if (this.resources.size >= this.limits.resources) {
|
|
274
|
+
await response.body?.cancel();
|
|
275
|
+
checkResourceCount();
|
|
276
|
+
}
|
|
277
|
+
// Manual fetch must preserve identity; an opaque/auto-following transport is rejected.
|
|
278
|
+
if (response.redirected || (response.url && resolveResourceUri(response.url) !== uri)) {
|
|
279
|
+
await response.body?.cancel();
|
|
280
|
+
throw new SchemaLoadingError("unsupported-capability", "Schema transport changed retrieval identity without policy checks");
|
|
281
|
+
}
|
|
282
|
+
const reader = response.body?.getReader();
|
|
283
|
+
if (reader) {
|
|
284
|
+
const abort = () => { void reader.cancel().catch(() => { }); };
|
|
285
|
+
controller.signal.addEventListener("abort", abort, { once: true });
|
|
286
|
+
try {
|
|
287
|
+
for (;;) {
|
|
288
|
+
const chunk = await reader.read();
|
|
289
|
+
if (chunk.done)
|
|
290
|
+
break;
|
|
291
|
+
accept(chunk.value);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
finally {
|
|
295
|
+
controller.signal.removeEventListener("abort", abort);
|
|
296
|
+
await reader.cancel().catch(() => { });
|
|
297
|
+
reader.releaseLock();
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
break;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
if (controller.signal.aborted || performance.now() - started > budget)
|
|
304
|
+
throw new SchemaLoadingError("transport", "Schema I/O deadline exceeded");
|
|
305
|
+
const bytes = Buffer.concat(chunks, byteLength);
|
|
306
|
+
const digest = createHash("sha256").update(bytes).digest("hex");
|
|
307
|
+
const resource = Object.freeze({ uri, digest, byteLength, bytes });
|
|
308
|
+
// Byte cache identity is (final canonical URI, digest); aliases never change context's final URI.
|
|
309
|
+
const resourceKey = JSON.stringify([uri, digest]);
|
|
310
|
+
this.resources.set(resourceKey, resource);
|
|
311
|
+
this.resourceKeys.set(uri, resourceKey);
|
|
312
|
+
for (const alias of redirectAliases)
|
|
313
|
+
this.aliases.set(alias, uri);
|
|
314
|
+
this.totalBytes += byteLength;
|
|
315
|
+
return resource;
|
|
316
|
+
})();
|
|
317
|
+
return await Promise.race([task, timeout]);
|
|
318
|
+
}
|
|
319
|
+
catch (error) {
|
|
320
|
+
controller.abort();
|
|
321
|
+
if (error instanceof SchemaLoadingError)
|
|
322
|
+
throw error;
|
|
323
|
+
// Do not expose filesystem paths, response text or credential-bearing transport errors.
|
|
324
|
+
throw new SchemaLoadingError("transport", "Unable to retrieve schema resource under the configured policy");
|
|
325
|
+
}
|
|
326
|
+
finally {
|
|
327
|
+
this.signal?.removeEventListener('abort', abort);
|
|
328
|
+
clearTimeout(timer);
|
|
329
|
+
if (performedIo)
|
|
330
|
+
this.ioMs += performance.now() - started;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
}
|
package/dist/openapi/casing.d.ts
CHANGED